MAX7219 no-op method

Mike Axe

Member
Good morning, this is my first ever post since joining a few years ago. This forum has provided me with such useful information in programming my Picaxe and really appreciate its helpful contributors.

I need to say up front that I am not proficient at programming, as I am an early 60's starter with programming "anything", but I get by and get much enjoyment from the small projects I do. (Some abbreviations and terminology goes right over my head :) )

I am desperate for some clarification using the MAX7219 8x8 led matrix, I have read many posts on here and learned a lot, I have also searched the WWW and cannot get what I actually need. My problem is that when using a pre-made cascade of 4 matrix units. I can scroll displays along easily enough, but I have a problem with adding a new display to an individual 8x8 matrix.

For example if I successfully position say, a square of leds in matrix 3, then whatever I place in Matrix one, it will shift matrix 3 across to matrix 4. Also if I send empty data it all scrolls across obviously.
Eg. If I want to put the square in section 3 only, without pausing the programme permanently, any next operation I do I would need to send no data, square, no data, no data again, and no matter how fast this happens you will still see remnants of the square moving to the given point if I were to loop this operation.


I have quoted a post below from 2011 by contributor MartinM57 (to whom I owe a big thank you) which illustrates my problem.

The problem I have is how to **actually write** the no-op.
Quote "to write to the second, send Address, Data, No-Op, No-Op"

I know the no-op is $x0. I have tried writing it in at all the points without success, that makes sense to me in my program.

I would be really grateful if somebody could give me an actual example of how it would be written in its most basic form as would work in my attached program.

I have attached the modified program from another persons work which illustrates my problem when you run it. (It is one led as opposed to a square)

Thank you for your time with this, it is much appreciated. Mike.

Quoted text:
"Can you get one MAX7219 to work correctly?
Connect DOUT of the first MAX7219 to DIN of the second MAX7219 as shown in the datasheet.

Then to write to both MAX7219 then just send two sets of address/data values - the first set you send will initially go to the first MAX7219 - the second set will also go to the first MAX7219, but will cause the first MAX7219 to send what it had out of DOUT into DIN of the second.

To write to only one of them you have to use the No-Op register (register code x0)...

...to write to the first, send No-Op, No-Op, Address, Data (the No-Ops end up in the second one (so nothing changes in it), the data ends up in the first one)

...to write to the second, send Address, Data, No-Op, No-Op (the data ends up in the second one, the No-Ops end up in the first one (so nothing changes in it))


It sounds a bit confusing, but it does work :)


Last edited:
Feb 16, 2011"
 

Attachments

Aries

New Member
My interpretation of the datasheet is that each chip requires a 16-bit packet, so No-Op is $X0XX (as it says on page 10 of the datasheet). You write (address+data) as the 16-bit packet for the chip you want to change, and 16-bit No-Ops for the other ones (in the right order).
 

Mike Axe

Member
Thank you for your quick reply Aries. I am trying to use what you said without success.

What I do know is, that when using the compiler, the hex code $X0XX isn't recognised, however $0X0 is. But I still am no further on.

I know this question sounds stupid, but I am late to this programming as I said above, is (address+data) the same as (register+data)?

If you look at my attached file, you will see I send:

most significant bit msb = ? (row..... (address I believe)) and least significant bit lsb = ? (Data)

so eg: msb = 5 lsb = 8 then I send this to be processed in the subroutine at the end which works but I don't fully understand.

So I am attempting, again unsuccessfully, to insert the above hex number into one of these parameters. I know I am lacking a missing link in my understanding.

Just a note, I know my questions are basic, but I have adapted my knowledge to create an actual interactive animated game on one 8x8 matrix, so I am not a lost cause, just not program language proficient.😟

Thanks again for your help.
 

hippy

Technical Support
Staff member
What I do know is, that when using the compiler, the hex code $X0XX isn't recognised, however $0X0 is.
The compiler shouldn't accept either and PE6 doesn't for me. Any 'X' specified in $X0XX is intended to indicate a holding place to be substituted with a hexadecimal digit; it's not a value in its own right.

'0X0' without the leading '$' is valid, because '0x0' is just a shorter form of '0x00' an alternative to '$00', zero specified as hexadecimal. That may be where things have become confused.

Unfortunately, while operation of cascaded MAX7219's is easy enough to comprehend once one has comprehended it, it's not so easy to describe. But basically it requires multiple sets of 16-bits to be clocked out per transaction, then LOAD pulsed high. So, for a set of four 8x8 displays -

$0000 $0000 $0000 $0000 LOAD

Would send a NOP to each of the displays

$0000 $0000 $01FF $0000 LOAD

Should set a single row or column all on for the third display while sending NOP to the others. Thus only the third display should be affected.

$01FF $0000 $0000 $0000 LOAD

Should do the same but affecting only the first display, not the others.

To update a complete display of four 8x8 would require four 16-bit words to be sent followed by a LOAD, all done 8 times with the digit address changing 1 through 7.

Updating a display as if a bitmap by interacting with the displays themselves is always a tricky business and not recommended. The usual way this would be done is to use RAM or Scratchpad to hold what you want displayed. Manipulate that when updating or scrolling and then blat it out in full to completely refresh the display. That would require 32 bytes for a four 8x8 display.
 

AllyCat

Senior Member
Hi,
the hex code $X0XX isn't recognised, however $0X0 is.
Could you give a PE5/6 example of that?

I don't know if it's documented in any (Maxim) Data Sheets, but Traditionally an X means "DON'T CARE", but you must still specify a legitimate value in any Program instruction. Legitimate values are 0 or 1 for binary values or 0 - 9 and A - F for Hexadecimal values.

Perhaps the confusion is because one method of specifying a Hex value to differentiate from a Decimal value is to add an "0x" as a prefix, e.g. 0x12 = 18 (decimal) or %10010 (binary), etc. The preferred method for PICaxe is the $ prefix, but a 0x prefix is accepted as an alternative. However, particularly if 0x0 is accepted as a valid "number", then IMHO perhaps it's another example where the compiler is excessively tolerant of Syntax Errors, and not really in the interests of good Educational practice?

Cheers, Alan.
 
Last edited:

hippy

Technical Support
Staff member
Would it be possible to run the code below and report back what it shows ?

It's untested but hopefully will work or at least show something. Ideally it will show "ABCDE" but possibly some sort of "EDCBA" mess, possibly mirrored, upside down or rotated.

If you could let us know what PICAXE you are using, whether you can move or rotate your display or not, that will help.

Code without initialisation removed - See Post #10 below for code with initialisation
 
Last edited:

Mike Axe

Member
The compiler shouldn't accept either and PE6 doesn't for me. Any 'X' specified in $X0XX is intended to indicate a holding place to be substituted with a hexadecimal digit; it's not a value in its own right.

'0X0' without the leading '$' is valid, because '0x0' is just a shorter form of '0x00' an alternative to '$00', zero specified as hexadecimal. That may be where things have become confused.

Unfortunately, while operation of cascaded MAX7219's is easy enough to comprehend once one has comprehended it, it's not so easy to describe. But basically it requires multiple sets of 16-bits to be clocked out per transaction, then LOAD pulsed high. So, for a set of four 8x8 displays -

$0000 $0000 $0000 $0000 LOAD

Would send a NOP to each of the displays

$0000 $0000 $01FF $0000 LOAD

Should set a single row or column all on for the third display while sending NOP to the others. Thus only the third display should be affected.

$01FF $0000 $0000 $0000 LOAD

Should do the same but affecting only the first display, not the others.

To update a complete display of four 8x8 would require four 16-bit words to be sent followed by a LOAD, all done 8 times with the digit address changing 1 through 7.

Updating a display as if a bitmap by interacting with the displays themselves is always a tricky business and not recommended. The usual way this would be done is to use RAM or Scratchpad to hold what you want displayed. Manipulate that when updating or scrolling and then blat it out in full to completely refresh the display. That would require 32 bytes for a four 8x8 display.

Thank you Hippy, I came on here this morning to specifically thank you for the time you took in writing this out to explain to me. I am trying to digest it and integrate it with my progam. I know I will be taking some time I but wanted to register my acknowledgement. Thank you.
I will come back when I can say something constructive.
 

Mike Axe

Member
Would it be possible to run the code below and report back what it shows ?

It's untested but hopefully will work or at least show something. Ideally it will show "ABCDE" but possibly some sort of "EDCBA" mess, possibly mirrored, upside down or rotated.

If you could let us know what PICAXE you are using, whether you can move or rotate your display or not, that will help.
Actually, I have loaded this on to my picaxe 20M2. The result is completely blank screen I'm afraid. Unless of course that is what you expected?
 

hippy

Technical Support
Staff member
I have loaded this on to my picaxe 20M2. The result is completely blank screen I'm afraid. Unless of course that is what you expected?
No, I would have expected something. Unless it's having included a #NO_DATA in the code which would make it blank the entire display I will have to think what could be wrong. Unfortunately I don't have hardware to test it with but I will see what I can do and would welcome anyone else's input.
 

hippy

Technical Support
Staff member
Looks like I should have included at least some kind of initialisation. This should fare better -
Code:
#Picaxe 20M2

Symbol DIN        = C.0
Symbol LOAD       = C.1
Symbol CLK        = C.2

Symbol reserveW0  = w0 ; b1:b0

Symbol reserveW1  = w1 ; b3:b2
Symbol lsb        = b2
Symbol msb        = b3     

Symbol displayPtr = b4
Symbol digit      = b5
Symbol column     = b6
Symbol pixels     = b7
Symbol bitCount   = b8

;                ; .----------.
Data (%01111110) ; | .######. |
Data (%00010001) ; | ...#...# |
Data (%00010001) ; | ...#...# |
Data (%00010001) ; | ...#...# |
Data (%01111110) ; | .######. |
Data (%00000000) ; | ........ |
Data (%01111111) ; | .####### |
Data (%01001001) ; | .#..#..# |
;                ; |----------|
Data (%01001001) ; | .#..#..# |
Data (%01001001) ; | .#..#..# |
Data (%00110110) ; | ..##.##. |
Data (%00000000) ; | ........ |
Data (%00111110) ; | ..#####. |
Data (%01000001) ; | .#.....# |
Data (%01000001) ; | .#.....# |
Data (%01000001) ; | .#.....# |
;                ; |----------|
Data (%00100100) ; | ..#...#. |
Data (%00000000) ; | ........ |
Data (%01111111) ; | .####### |
Data (%10000001) ; | .#.....# |
Data (%10000001) ; | .#.....# |
Data (%10000001) ; | .#.....# |
Data (%01111110) ; | ..#####. |
Data (%00000000) ; | ........ |
;                ; |----------|
Data (%01111111) ; | .####### |
Data (%01001001) ; | .#..#..# |
Data (%01001001) ; | .#..#..# |
Data (%01001001) ; | .#..#..# |
Data (%01000001) ; | .#.....# |
Data (%00000000) ; | ........ |
Data (%00000000) ; | ........ |
Data (%00000000) ; | ........ |
;                ; `----------'
	
PowerOnReset:
  Low LOAD
  Low CLK
  
  msb = $C : lsb = $01 : Gosub InitialiseDisplay ; Shutdown Mode = 1, normal operation
  msb = $B : lsb = $07 : Gosub InitialiseDisplay ; Scan Limit    = 7, all rows or columns
  msb = $9 : lsb = $00 : Gosub InitialiseDisplay ; Decode Mode   = 0, none, raw pixels
  msb = $F : lsb = $00 : Gosub InitialiseDisplay ; Display Test  = 0, normal operation
  msb = $A : lsb = $0F : Gosub InitialiseDisplay ; Brightness    = 15, maximum
  
MainLoop:
  Do
    Gosub ShowDisplay
    Pause 2000
  Loop

InitialiseDisplay:
  For digit = 1 To 4
    w0 = w1 : Gosub Send_W0_As_16_Bits_Msb_First
  Next
  High LOAD
  Low  LOAD
  Return

ShowDisplay:
  displayPtr = 0
  For column = 1 To 8
    For digit = 1 To 4
      Read displayPtr, pixels
      w0 = column * 256 + pixels
      Gosub Send_W0_As_16_Bits_Msb_First
      displayPtr = displayPtr + 8
    Next
    High LOAD
    Low  LOAD
    displayPtr = displayPtr - 31
   Next
  Return

Send_W0_As_16_Bits_Msb_First:
  For bitCount = 1 To 16
    If w0 >= $8000 Then
      High DIN
    Else
      Low  DIN
    End If
    High CLK
    Low  CLK
    w0 = w0 + w0 ; w0 = w0 << 1
  Next
  Return
 

Mike Axe

Member
Looks like I should have included at least some kind of initialisation. This should fare better -
Code:
#Picaxe 20M2

Symbol DIN        = C.0
Symbol LOAD       = C.1
Symbol CLK        = C.2

Symbol reserveW0  = w0 ; b1:b0

Symbol reserveW1  = w1 ; b3:b2
Symbol lsb        = b2
Symbol msb        = b3    

Symbol displayPtr = b4
Symbol digit      = b5
Symbol column     = b6
Symbol pixels     = b7
Symbol bitCount   = b8

;                ; .----------.
Data (%01111110) ; | .######. |
Data (%00010001) ; | ...#...# |
Data (%00010001) ; | ...#...# |
Data (%00010001) ; | ...#...# |
Data (%01111110) ; | .######. |
Data (%00000000) ; | ........ |
Data (%01111111) ; | .####### |
Data (%01001001) ; | .#..#..# |
;                ; |----------|
Data (%01001001) ; | .#..#..# |
Data (%01001001) ; | .#..#..# |
Data (%00110110) ; | ..##.##. |
Data (%00000000) ; | ........ |
Data (%00111110) ; | ..#####. |
Data (%01000001) ; | .#.....# |
Data (%01000001) ; | .#.....# |
Data (%01000001) ; | .#.....# |
;                ; |----------|
Data (%00100100) ; | ..#...#. |
Data (%00000000) ; | ........ |
Data (%01111111) ; | .####### |
Data (%10000001) ; | .#.....# |
Data (%10000001) ; | .#.....# |
Data (%10000001) ; | .#.....# |
Data (%01111110) ; | ..#####. |
Data (%00000000) ; | ........ |
;                ; |----------|
Data (%01111111) ; | .####### |
Data (%01001001) ; | .#..#..# |
Data (%01001001) ; | .#..#..# |
Data (%01001001) ; | .#..#..# |
Data (%01000001) ; | .#.....# |
Data (%00000000) ; | ........ |
Data (%00000000) ; | ........ |
Data (%00000000) ; | ........ |
;                ; `----------'
   
PowerOnReset:
  Low LOAD
  Low CLK
 
  msb = $C : lsb = $01 : Gosub InitialiseDisplay ; Shutdown Mode = 1, normal operation
  msb = $B : lsb = $07 : Gosub InitialiseDisplay ; Scan Limit    = 7, all rows or columns
  msb = $9 : lsb = $00 : Gosub InitialiseDisplay ; Decode Mode   = 0, none, raw pixels
  msb = $F : lsb = $00 : Gosub InitialiseDisplay ; Display Test  = 0, normal operation
  msb = $A : lsb = $0F : Gosub InitialiseDisplay ; Brightness    = 15, maximum
 
MainLoop:
  Do
    Gosub ShowDisplay
    Pause 2000
  Loop

InitialiseDisplay:
  For digit = 1 To 4
    w0 = w1 : Gosub Send_W0_As_16_Bits_Msb_First
  Next
  High LOAD
  Low  LOAD
  Return

ShowDisplay:
  displayPtr = 0
  For column = 1 To 8
    For digit = 1 To 4
      Read displayPtr, pixels
      w0 = column * 256 + pixels
      Gosub Send_W0_As_16_Bits_Msb_First
      displayPtr = displayPtr + 8
    Next
    High LOAD
    Low  LOAD
    displayPtr = displayPtr - 31
   Next
  Return

Send_W0_As_16_Bits_Msb_First:
  For bitCount = 1 To 16
    If w0 >= $8000 Then
      High DIN
    Else
      Low  DIN
    End If
    High CLK
    Low  CLK
    w0 = w0 + w0 ; w0 = w0 << 1
  Next
  Return


Excellent, this came up with an array of letters, I will attach photo. The letters "animate" into their final state, at some point in this process the viewable display becomes so intense you cannot look at it without sunglasses. lol. But yes it works.

Further to this, before I saw this program I uploaded your previous one, but I deleted the "#no_data", this did the same as this one (and it wasn't so bright) BUT when I removed the supply and re-initiated it, nothing happened at all, until I downloaded it again. I thought you knowing this might be of use to you.

P.S. the photo is of the display of the first program and therefore not so bright.

I am going to have to study how you have done this, it initially looks like it is in a format I might be able to follow, so grateful for your input, thanks again.9526.jpg
 

hippy

Technical Support
Staff member
That's good news, and also revealed an error in my definition of the "D" of the text displayed.

Not sure why the first code was less bright than the second when run after it as it should have been using the same initialisation of the second. That's perhaps something to worry about later.

The animation I would guess comes down to operating the PICAXE at default speed and not using an optimised output routine. It should be possible to improve on that..

The biggest challenge is the rotation in each digit. That's not unresolvable but might take a bit of thinking about. I suspect it's better to have the fastest display update speed and handle any resulting complexity when it comes to updating the PICAXE's internal bitmap. In which case ...

Code:
#Picaxe 20M2

Symbol DIN        = C.0 : Symbol DIN_PIN = pinC.0
Symbol LOAD       = C.1
Symbol CLK        = C.2

Symbol reserveW0  = w0 ; b1:b0
Symbol lsb        = b0
Symbol msb        = b1     

;                ; .----------.
Data (%01110011) ; | .###..## |
Data (%11000111) ;            | ##...### |
Data (%00111100) ;                       | ..####.. |
Data (%11111000) ;                                  | #####... |
Data (%10001010) ; | #...#.#. |
Data (%00101000) ;            | ..#.#... |
Data (%10100010) ;                       | #.#...#. |
Data (%10000000) ;                                  | #....... |
Data (%10001010) ; | #...#.#. |
Data (%00101000) ;            | ..#.#... |
Data (%00100010) ;                       | ..#...#. |
Data (%10000000) ;                                  | #....... |
Data (%10001011) ; | #...#.## |
Data (%11001000) ;            | ##..#... |
Data (%00100010) ;                       | ..#...#. |
Data (%11110000) ;                                  | ####.... |
Data (%11111010) ; | #####.#. |
Data (%00101000) ;            | ..#.#... |
Data (%00100010) ;                       | ..#...#. |
Data (%10000000) ;                                  | #....... |
Data (%10001010) ; | #...#.#. |
Data (%00101000) ;            | ..#.#... |
Data (%10100010) ;                       | #.#...#. |
Data (%10000000) ;                                  | #....... |
Data (%10001011) ; | #...#.## |
Data (%11000111) ;            | ##...### |
Data (%00111100) ;                       | ..####.. |
Data (%11111000) ;                                  | #####... |
Data (%00000000) ; | ........ |
Data (%00000000) ;            | ........ |
Data (%00000000) ;                       | ........ |
Data (%00000000) ;                                  | ........ |
;                ; `----------'
	
PowerOnReset:
  SetFreq M32

  Low LOAD
  Low CLK
  Low DIN
  
  msb = $9 : lsb = $00 : Gosub InitialiseDisplay ; $9 $00 : Decode Mode   = 0, none, raw pixels
             lsb = $07 : Gosub InitialiseDisplay ; $A $07 : Brightness    = 7, half brightness
             lsb = $07 : Gosub InitialiseDisplay ; $B $07 : Scan Limit    = 7, all rows or columns
             lsb = $01 : Gosub InitialiseDisplay ; $C $01 : Shutdown Mode = 1, normal operation
  msb = $F : lsb = $00 : Gosub InitialiseDisplay ; $F $00 : Display Test  = 0, normal operation
  
MainLoop:
  Do
    Gosub ShowDisplay
    Pause 8000
  Loop

InitialiseDisplay:
  Gosub Send_W0_As_16_Bits_Msb_First
  Gosub Send_W0_As_16_Bits_Msb_First
  Gosub Send_W0_As_16_Bits_Msb_First
  Gosub Send_W0_As_16_Bits_Msb_First
  PulsOut LOAD, 1
  msb = msb + 1
  Return

ShowDisplay:
  bPtr = 0
  For msb = 1 To 8
    Gosub Get_And_Send_Column
    Gosub Get_And_Send_Column
    Gosub Get_And_Send_Column
    Gosub Get_And_Send_Column
    PulsOut LOAD, 1
  Next
  Return

Get_And_Send_Column:
  Read bPtr, lsb 
  bPtr = bPtr + 1

Send_W0_As_16_Bits_Msb_First:
                    PulsOut CLK, 1 ; 15
                    PulsOut CLK, 1 ; 14
                    PulsOut CLK, 1 ; 13
                    PulsOut CLK, 1 ; 12
  DIN_PIN = bit11 : PulsOut CLK, 1 ; 11
  DIN_PIN = bit10 : PulsOut CLK, 1 ; 10
  DIN_PIN = bit9  : PulsOut CLK, 1 ; 9
  DIN_PIN = bit8  : PulsOut CLK, 1 ; 8
  DIN_PIN = bit7  : PulsOut CLK, 1 ; 7
  DIN_PIN = bit6  : PulsOut CLK, 1 ; 6
  DIN_PIN = bit5  : PulsOut CLK, 1 ; 5
  DIN_PIN = bit4  : PulsOut CLK, 1 ; 4
  DIN_PIN = bit3  : PulsOut CLK, 1 ; 3
  DIN_PIN = bit2  : PulsOut CLK, 1 ; 2
  DIN_PIN = bit1  : PulsOut CLK, 1 ; 1
  DIN_PIN = bit0  : PulsOut CLK, 1 ; 0
  Return
 

Mike Axe

Member
That's good news, and also revealed an error in my definition of the "D" of the text displayed.

Not sure why the first code was less bright than the second when run after it as it should have been using the same initialisation of the second. That's perhaps something to worry about later.

The animation I would guess comes down to operating the PICAXE at default speed and not using an optimised output routine. It should be possible to improve on that..

The biggest challenge is the rotation in each digit. That's not unresolvable but might take a bit of thinking about. I suspect it's better to have the fastest display update speed and handle any resulting complexity when it comes to updating the PICAXE's internal bitmap. In which case ...

Code:
#Picaxe 20M2

Symbol DIN        = C.0 : Symbol DIN_PIN = pinC.0
Symbol LOAD       = C.1
Symbol CLK        = C.2

Symbol reserveW0  = w0 ; b1:b0
Symbol lsb        = b0
Symbol msb        = b1    

;                ; .----------.
Data (%01110011) ; | .###..## |
Data (%11000111) ;            | ##...### |
Data (%00111100) ;                       | ..####.. |
Data (%11111000) ;                                  | #####... |
Data (%10001010) ; | #...#.#. |
Data (%00101000) ;            | ..#.#... |
Data (%10100010) ;                       | #.#...#. |
Data (%10000000) ;                                  | #....... |
Data (%10001010) ; | #...#.#. |
Data (%00101000) ;            | ..#.#... |
Data (%00100010) ;                       | ..#...#. |
Data (%10000000) ;                                  | #....... |
Data (%10001011) ; | #...#.## |
Data (%11001000) ;            | ##..#... |
Data (%00100010) ;                       | ..#...#. |
Data (%11110000) ;                                  | ####.... |
Data (%11111010) ; | #####.#. |
Data (%00101000) ;            | ..#.#... |
Data (%00100010) ;                       | ..#...#. |
Data (%10000000) ;                                  | #....... |
Data (%10001010) ; | #...#.#. |
Data (%00101000) ;            | ..#.#... |
Data (%10100010) ;                       | #.#...#. |
Data (%10000000) ;                                  | #....... |
Data (%10001011) ; | #...#.## |
Data (%11000111) ;            | ##...### |
Data (%00111100) ;                       | ..####.. |
Data (%11111000) ;                                  | #####... |
Data (%00000000) ; | ........ |
Data (%00000000) ;            | ........ |
Data (%00000000) ;                       | ........ |
Data (%00000000) ;                                  | ........ |
;                ; `----------'
   
PowerOnReset:
  SetFreq M32

  Low LOAD
  Low CLK
  Low DIN
 
  msb = $9 : lsb = $00 : Gosub InitialiseDisplay ; $9 $00 : Decode Mode   = 0, none, raw pixels
             lsb = $07 : Gosub InitialiseDisplay ; $A $07 : Brightness    = 7, half brightness
             lsb = $07 : Gosub InitialiseDisplay ; $B $07 : Scan Limit    = 7, all rows or columns
             lsb = $01 : Gosub InitialiseDisplay ; $C $01 : Shutdown Mode = 1, normal operation
  msb = $F : lsb = $00 : Gosub InitialiseDisplay ; $F $00 : Display Test  = 0, normal operation
 
MainLoop:
  Do
    Gosub ShowDisplay
    Pause 8000
  Loop

InitialiseDisplay:
  Gosub Send_W0_As_16_Bits_Msb_First
  Gosub Send_W0_As_16_Bits_Msb_First
  Gosub Send_W0_As_16_Bits_Msb_First
  Gosub Send_W0_As_16_Bits_Msb_First
  PulsOut LOAD, 1
  msb = msb + 1
  Return

ShowDisplay:
  bPtr = 0
  For msb = 1 To 8
    Gosub Get_And_Send_Column
    Gosub Get_And_Send_Column
    Gosub Get_And_Send_Column
    Gosub Get_And_Send_Column
    PulsOut LOAD, 1
  Next
  Return

Get_And_Send_Column:
  Read bPtr, lsb
  bPtr = bPtr + 1

Send_W0_As_16_Bits_Msb_First:
                    PulsOut CLK, 1 ; 15
                    PulsOut CLK, 1 ; 14
                    PulsOut CLK, 1 ; 13
                    PulsOut CLK, 1 ; 12
  DIN_PIN = bit11 : PulsOut CLK, 1 ; 11
  DIN_PIN = bit10 : PulsOut CLK, 1 ; 10
  DIN_PIN = bit9  : PulsOut CLK, 1 ; 9
  DIN_PIN = bit8  : PulsOut CLK, 1 ; 8
  DIN_PIN = bit7  : PulsOut CLK, 1 ; 7
  DIN_PIN = bit6  : PulsOut CLK, 1 ; 6
  DIN_PIN = bit5  : PulsOut CLK, 1 ; 5
  DIN_PIN = bit4  : PulsOut CLK, 1 ; 4
  DIN_PIN = bit3  : PulsOut CLK, 1 ; 3
  DIN_PIN = bit2  : PulsOut CLK, 1 ; 2
  DIN_PIN = bit1  : PulsOut CLK, 1 ; 1
  DIN_PIN = bit0  : PulsOut CLK, 1 ; 0
  Return

I haven't read your last post fully, as I came on to the forum to tell you something that will have confused you without doubt, and you have picked up on it, the letter D orientation, That is not your fault. I purchased this array recently and Have since realised that everything is inverted, i.e. column 1 is column 8 2 is 7 etc, plus, and not fully tested this, I believe the binary display is also reversed,
i.e. 3 is 11000000 and not as it should be 00000111.
It would be interesting if ANYONE has had this before?
So sorry for the confusion, I was hoping to get this note to you before you acted on my last reply.
I will have to read your last post later as I am otherwise occupied at the moment. But thank you for your ongoing interest in my education.
 

hippy

Technical Support
Staff member
It would be interesting if ANYONE has had this before?
Yes, that's quite common. There is no standard and manufacturers often design boards with little concern as to how they map to a bitmap which would be held in a microcontroller. Multi-module displays can swap rows and columns, reverse their order, place the 8x8 displays in any order. I am not even sure there are any modules which are wired how anyone would like them to be.

The intent of using a bitmap in the controller, and interacting with that, is it can be in the form you would like it to be in, no matter how the module has been constructed. The issues of upside-down, back to front, even 'that's insane!' can simply be abstracted away. You can consider top-left of your bitmap to be top-left of the display and so forth, even if the module itself doesn't match that.

It allows you to only be concerned with the bitmap, not the display itself.

So sorry for the confusion, I was hoping to get this note to you before you acted on my last reply.
The code I gave was primarily intended to discover what your particular manufacturer had done so no need to worry.

The first step is to discover how the ordering of things is on the board - Done as per Post #11.

The current step is proving a suitable bitmap can be correctly displayed across the display in the right order.

The step after that is to adjust for how you wish to mount the display, to compensate for any upside-down, back-to-front , mirrored or flipped, problems., and then prove we have overcome them.

Once we have got that far, have "ABCDE" displayed as you would want it displayed in your project if that were ever to be displayed, we will have a definition of how the bitmap in the PICAXE maps to the display.

Then it's just a matter of defining how you would interact with that internal bitmap so the display shows what you want displayed.

Then there might be some tweaking to simplify or speed-up those interaction routines even if it means slightly complicating the display routine. That can be a trial and error process, rely on intuition and experience, but whatever is done it will be transparent to using them, only affect performance.
 

Bum

New member
Zdravím také pomocí picaxe 08m2 řídím jeden modul víc pak pomocí PC. Pokud máš víc modulů například dva u PICAXE já vždy odešlu data 16-bitová hodnota 2x a pak potvrdím příkazem že data jsou platná dvakrát NOP. Mám to pro inspiraci na webu www.mojeelektronika.mzf.cz v sekci "další články ovládání max7219 PICAXE, počítačem" je tam i program pro ovládání jednoho modulu s PICAXE který se dá hravě rozšířit pro více modulů. Pomocí PC jsem řídil 10 modulů víc jsem jich neměl. Hlavně nezapomeň že pokud chceš ovládat maticový led displej musíš si dříve inicializovat modul na bodový režim po zapnutí je modul nastaven do textového módu.
 
Last edited:

eclectic

Moderator
Greetings also using picax 08m2 I control one more module then using a PC. If you have more modules, for example two at PICAX, I always send the data 16-bit value 2x and then I confirm with the command that the data is valid twice NOP. I have it for inspiration on the website www.mojeelektronika.mzf.cz in the section "other control articles max7219 PICAXE, computer" there is also a program for controlling one module with PICAXE which can be easily expanded for more modules. Using a PC, I controlled 10 modules, I didn't have more. Mainly don't forget that if you want to control the matrix LED display, you must first initialize the module to point mode. After switching on, the module is set to text mode.

Courtesy of Google translate. e
 

Mike Axe

Member
Yes, that's quite common. There is no standard and manufacturers often design boards with little concern as to how they map to a bitmap which would be held in a microcontroller. Multi-module displays can swap rows and columns, reverse their order, place the 8x8 displays in any order. I am not even sure there are any modules which are wired how anyone would like them to be.

The intent of using a bitmap in the controller, and interacting with that, is it can be in the form you would like it to be in, no matter how the module has been constructed. The issues of upside-down, back to front, even 'that's insane!' can simply be abstracted away. You can consider top-left of your bitmap to be top-left of the display and so forth, even if the module itself doesn't match that.

It allows you to only be concerned with the bitmap, not the display itself.


The code I gave was primarily intended to discover what your particular manufacturer had done so no need to worry.

The first step is to discover how the ordering of things is on the board - Done as per Post #11.

The current step is proving a suitable bitmap can be correctly displayed across the display in the right order.

The step after that is to adjust for how you wish to mount the display, to compensate for any upside-down, back-to-front , mirrored or flipped, problems., and then prove we have overcome them.

Once we have got that far, have "ABCDE" displayed as you would want it displayed in your project if that were ever to be displayed, we will have a definition of how the bitmap in the PICAXE maps to the display.

Then it's just a matter of defining how you would interact with that internal bitmap so the display shows what you want displayed.

Then there might be some tweaking to simplify or speed-up those interaction routines even if it means slightly complicating the display routine. That can be a trial and error process, rely on intuition and experience, but whatever is done it will be transparent to using them, only affect performance.

Firstly my apologies for not being able to get back to your reply sooner, I am not able to dedicate as much time as I would like to programming as I would really like to, so apologies for delays when replying.

Thank you for your reply again, as I said I would look at it in more detail after my last post.
On examination I found that I was able to follow much of what you had done but some aspects were too advanced for me and I hope the result is still more in order for you to learn about the orientation of my set up than it was for me to understand what you have done.

This is the first time I have come across bPtr and had to read what it is for. And from what I understand you have used it in this case to "point" at the Data patterns at the beginning.

If I am correct then I can only say I am in awe of you using this method to form the perfectly formed letters A to D on my display. (For your information they are formed correctly reading from the opposite end of the in going pins. To my understanding I thought this to be upside down? ) i.e. ABCDE reading left to right towards the pins on the right.

I appreciate your help in this, and I am sure you are now aware of my level of programming and hope that you are not wasting your time as your future answers may be beyond me at my level of understanding at present.

One of the positive things from this, is that I adjusted the brightness from $07 to $00, now I can look at the display with ease.

I hope you have the information you require from my reply and it is enough to move on to the next stage as you mentioned.
Thank you for your patience.
 

hippy

Technical Support
Staff member
Firstly my apologies for not being able to get back to your reply sooner, I am not able to dedicate as much time as I would like to programming as I would really like to, so apologies for delays when replying.
No problem at all.
On examination I found that I was able to follow much of what you had done but some aspects were too advanced for me and I hope the result is still more in order for you to learn about the orientation of my set up than it was for me to understand what you have done.
Yes, that's the main intent. Once that's done it should then be possible to provide "a solution" which is easy enough to use without necessarily understanding how it does it, but any unfamiliar concepts can be explained in detail.
If I am correct then I can only say I am in awe of you using this method to form the perfectly formed letters A to D on my display. (For your information they are formed correctly reading from the opposite end of the in going pins. To my understanding I thought this to be upside down? ) i.e. ABCDE reading left to right towards the pins on the right.
That sounds like great news. It seems all that needs to be done is to tip the display upside down, or maybe what I would call mirrored ?

It might be best to provide a photo of what it is showing taken with the display in the orientation you would prefer to have it.
 
Top