Scrolling text on a 32 x 8 pixel display using MAX7219 HC-16 boards.

This project aims to display a message of about 18 (or more if required) alphanumeric characters on four 8x8 LED matrix displays (i.e. 32x8 pixels) using pixel by pixel (column by column) scrolling.

The hardware in use is (four off) the FC-16 board & display shown in the attached pictures, which are available from a well known internet auction site for less than £0.89 (yes really!) per board complete with soldered MAX7219 and the LED matrix display (price when bought as three sets of four boards).


For minimal cost and simplicity a PICAXE-08M2 is used as the controller but the more sophisticated -X2 processors can work faster if a higher speed is required.



The overall cost (excluding PCB & PSU) is about £5 (UKP) at 2019 prices.

Firstly, some notes about the hardware. The FC-16 board (normally blue in colour) can be bought in various kit forms:
  1. all the parts completely unassembled;
  2. all the parts with the surface-mount (SM) components soldered;
  3. fully assembled boards;
  4. four off fully assembled boards.

The latter is very convenient for this project as it should connect simply to the three relevant pins on the 08M2 with minimal extra hardware. The first on the list is only suitable if you have an extremely fine soldering iron, a very good magnifying glass, three or four hands, and can position components to within about 1/20th of a millimetre.

There are also other similar boards available which I haven't tested and may not be suitable:
  1. a green PCB with a DIL 24-pin MAX7219 in a socket outside the matrix display area on the PCB (see below);
  2. a red/orange or green PCB with SM MAX7219 and four extra pairs of 2-pin headers in the corners (see previous image lower left).

The former may not work because the orientation of the matrix displays when assembled side-by-side to make a continuous display looks as though it's 90° rotated compared to the boards used in this project. It may well be usable as a multi-character display but the software would need significant changes.

The latter may be suitable as the LED display seems to have the right orientation, but would need to be tested.

If assembling/soldering these (blue FC-16) boards yourself (kits without the connectors & sockets soldered), firstly check the correct location for the sockets for the LED displays. The sockets are on the same side as the MAX7219 therefore soldered from the other side. To ensure the sockets are exactly square to the PCB, push the sockets carefully onto the pins of the LED array then insert the sockets into the PCB (covering the MAX7219) and solder one pin on each socket. Check that it all looks square before soldering the rest - you could easily desolder one pin on each side if it's wrong but more than one gets very difficult.



The display then needs to be carefully removed (so as not to bend the pins) before soldering the pin headers. A similar principle applies; solder one pin and check for correct positioning before soldering the rest of the pins. Note that the distance between the two headers is not a multiple of 0.1" so Veroboard or similar can't be used to hold the headers in place.



When all the headers and sockets are soldered, the LED matrix display needs to be reinserted in its sockets. Obviously there are two ways it could be put, this is the right way:



The 5 volt supply needs to be capable of supplying at least 700mA - this is what the four displays etc take when all 32 x 8 LEDs are full on during the display test at maximum brightness. However, this is probably on the limit of the power dissipation of the MAX7219 devices. The RSET resistor (R1 in above picture) on the boards is 10k which, with the VLED (forward LED voltage) of about 1.8V, sets a peak segment current of more than 40mA. It would not be a good idea to leave the display with all LEDs on at maximum brightness for a long time. See the Maxim MAX7219 data sheet for more detailed information.

For optimum long term reliability it would probably be better (with the given displays) to change the RSET value to 12k for 40mA (ISEG current), 18k for about 28mA or 39k for approximately 15mA. The ambient light level the display is used in will determine how bright the displays need to be - there's a very big difference between needing to be seen in bright sunlight or a dimly lit room.

In operation with the hardware and software as shown, the current varies between about 30mA with no LEDs on, to 50 - 60mA with many characters on the display. The software sets the brightness to 3/32 of the peak segment current which still gives a very bright display. Setting higher values than this will obviously take more current.

The software has been written using elements of WestAus55's helpful tutorial on the MAX7219 and Hippy's excellent routines from the Active PicAxe forum together with my own display routines.

In the latter thread are other examples of code to do the same things on other PICAXE processors and in more versatile ways. The code here is limited to four 8 x 8 LED displays and could be adapted to a smaller display but not larger.

I've tried to put plenty of comments in the code by way of explanation but such things can always be improved.

In addition to the code is a complete set of alphanumeric characters from which to build up a new message. It should be fairly obvious how these are used from looking at the example. Note that each character has an inter-character space at the end which needs to be preserved. Longer characters can easily be constructed if required as could 'smileys' and similar.

Here is what it looks like when running:
 

Attachments

Last edited:

hippy

Technical Support
Staff member
While it is undoubtedly easy and convenient to just link the displays linearly -
Code:
.----.   .----.   .----.   .----.
|aOOO|   |bOOO|   |cOOO|   |dOOO|   .--------.
|OOOO|===|OOOO|===|OOOO|===|OOOO|===| PICAXE |
|OOOO|===|OOOO|===|OOOO|===|OOOO|===| driver |
|OOOO|   |OOOO|   |OOOO|   |OOOO|   `--------'
`----'   `----'   `----'   `----'
I might have taken advantage of the opportunity to rotate each display to make control easier for the software
Code:
  ..---.   ..---.   ..---.   ..---
  ||   |   ||   |   ||   |   ||   |
.----. | .----. | .----. | .----. |
|OOOO| | |OOOO| | |OOOO| | |OOOO| | .--------.
|OOOO| | |OOOO| | |OOOO| | |OOOO| }-| PICAXE |
|OOOO| | |OOOO| | |OOOO| | |OOOO| `-| driver |
|aOOO| | |bOOO| | |cOOO| | |dOOO|   `--------'
`----' | `----' | `----' | `----'
       `---''   `---''   `---''
It would be easy enough to link the boards by not fitting the headers and just linking with flying wires soldered into appropriate holes.
 

techElder

Well-known member
Hairy Animal, this is a little bit more to what Hippy just posted on the physical nature of these modules versus how your character array is developed. This is not necessarily for you, but can add to someone's perception of your project.

This is a photo from my notebook, where I mapped out the location of all physical pins of my module. The module has a schematic, and the LED matrix has a schematic. Yours could be different than mine, because there are different manufacturers of these types of modules.

I was looking for this base for you project, but everyone commenting was deep into the design of the software. When I did my two module display (with scrolling routines based on Westy's software routines), I had to consider "which-way-round" the display had to be mounted. There was only one way the user could view the display, but there were two ways the display could be positioned within my project. So, as Hippy alludes to, the characters bits had to be pushed through the serial pipeline in a particular direction for the display to present words to the user while scrolling.

Here's the way my module is designed. I would like to see the same on the modules that you used.

23120

EDIT 29 AUG 2019: After analyzing the photographs above and similar photos on eBay for these modules, I'm confident in saying that all these modules have the same basic design and wiring. The change made by engineering a surface mount IC didn't change the schematic. The change only made the PCB fit into the same profile as the LED 8x8 matrix.
 
Last edited:

techElder

Well-known member
Sorry for the delay in completing my post, but stuff happens.

The rest of the story involved in getting the visual display that you want is to document how your characters in memory will map to the physical display. My notebook further reveals that mapping as follows:

23121

I refer you to the data sheet for the Maxim MAX7219 which has the function diagram with the data lines D7-D0 as MSB to LSB as they are shifted into the IC. You can also refer to the Table 6 for the segment mapping to D7-D0.

I have to admit that, as an electronic technician, I did a lot of "Try this" before I sat down and figured out the hardware. :D
 
Last edited:

BESQUEUT

Senior Member
Enhanced code with text encoded on the fly :
- you can change the text when you want,
- text can be very long
- you can display numbers, time, date,...
- code shorter than 440 bytes

Code:
'-----------------  PICAXE   20X2 connected to four 8x8 displays
' This program uses a PICAXE-20X2 to shift-out SPI data to
' four MAX7219 LED display drivers to display
' This code is for 4 matrix 8X8 displays

#Picaxe 20X2


setfreq m64
' Hardware interface to the MAX7219
let dirsB = %11111111
'                  40X2
'symbol sData     =  C.6     ' data out line to Max7219
'symbol clock     =  D.7     ' clock line
'symbol sLoad     =  C.7     ' pulse briefly to load data onto LED Matrix


'                  20X2
symbol sData     = B.4       ' data out line to Max7219
symbol clock     = B.2      ' clock line
symbol sLoad     = B.3      ' pulse briefly to load data onto LED Matrix


' Register addresses for the MAX7219
symbol decode = $09'9            ' decode register; specify digits to decode
symbol brite  = $0A             ' intensity (brightness) register; 15 = 100%
symbol scan   = $0B'11             ' scan-limit register; specify # of LEDs
symbol on_off = $0C '12            ' 1 = display on; 0 = display off
symbol TEST = $0F '15

'-----Variables ------
symbol outByte = b0                 ' data byte to be transmitted to the LED
symbol maxReg  = b1                 ' MAX register that receives the data byte
                '

EEPROM( 52, 55, 58, 63, 67, 69, 73, 75 )          ' ()*+,-./
EEPROM( 79, 83, 86, 90, 94, 98, 102, 106 )          ' 01234567
EEPROM( 110, 114, 118, 119, 121, 124, 127, 130 )      ' 89:;<=>?
EEPROM( 134, 139, 143, 147, 151, 155, 159, 163 )      ' @ABCDEFG
EEPROM( 167, 171, 174, 178, 182, 186, 191, 196 )      ' HIJKLMNO
EEPROM( 200, 204, 208, 212, 216, 221, 225, 230 )      ' PQRSTUVW
EEPROM( 235, 240, 245, 249 )                  ' XYZ

EEPROM( %00011100, %00100010, %01000001 ) ' (
EEPROM( %01000001, %00100010, %00011100 ) ' )
EEPROM( %00101000, %00011000, %00001110, %00011000, %00101000 ) ' *
EEPROM( %00001000, %00001000, %00111110, %00001000 ) ' +
EEPROM( %10110000, %01110000 ) ' ,
EEPROM( %00001000, %00001000, %00001000, %00001000 ) ' -
EEPROM( %01100000, %01100000 ) ' .
EEPROM( %01100000, %00011000, %00000110, %00000001 ) ' /
EEPROM( %00111110, %01000001, %01000001, %00111110 ) ' 0
EEPROM( %01000010, %01111111, %01000000 ) ' 1
EEPROM( %01100010, %01010001, %01001001, %01000110 ) ' 2
EEPROM( %00100010, %01000001, %01001001, %00110110 ) ' 3
EEPROM( %00011000, %00010100, %00010010, %01111111 ) ' 4
EEPROM( %00100111, %01000101, %01000101, %00111001 ) ' 5
EEPROM( %00111110, %01001001, %01001001, %00110000 ) ' 6
EEPROM( %01100001, %00010001, %00001001, %00000111 ) ' 7
EEPROM( %00110110, %01001001, %01001001, %00110110 ) ' 8
EEPROM( %00000110, %01001001, %01001001, %00111110 ) ' 9
EEPROM( %01010000 ) ' :
EEPROM( %10000000, %01010000 ) ' ;
EEPROM( %00010000, %00101000, %01000100 ) ' <
EEPROM( %00010100, %00010100, %00010100 ) ' =
EEPROM( %01000100, %00101000, %00010000 ) ' >
EEPROM( %00000010, %01011001, %00001001, %00000110 ) ' ?
EEPROM( %00111110, %01001001, %01010101, %01011101, %00001110 ) ' @
EEPROM( %01111110, %00010001, %00010001, %01111110 ) ' A
EEPROM( %01111111, %01001001, %01001001, %00110110 ) ' B
EEPROM( %00111110, %01000001, %01000001, %00100010 ) ' C
EEPROM( %01111111, %01000001, %01000001, %00111110 ) ' D
EEPROM( %01111111, %01001001, %01001001, %01000001 ) ' E
EEPROM( %01111111, %00001001, %00001001, %00000001 ) ' F
EEPROM( %00111110, %01000001, %01001001, %01111010 ) ' G
EEPROM( %01111111, %00001000, %00001000, %01111111 ) ' H
EEPROM( %01000001, %01111111, %01000001 ) ' I
EEPROM( %00110000, %01000000, %01000001, %00111111 ) ' J
EEPROM( %01111111, %00001000, %00010100, %01100011 ) ' K
EEPROM( %01111111, %01000000, %01000000, %01000000 ) ' L
EEPROM( %01111111, %00000010, %00001100, %00000010, %01111111 ) ' M
EEPROM( %01111111, %00000100, %00001000, %00010000, %01111111 ) ' N
EEPROM( %00111110, %01000001, %01000001, %00111110 ) ' O
EEPROM( %01111111, %00001001, %00001001, %00000110 ) ' P
EEPROM( %00111110, %01000001, %01000001, %10111110 ) ' Q
EEPROM( %01111111, %00001001, %00001001, %01110110 ) ' R
EEPROM( %01000110, %01001001, %01001001, %00110010 ) ' S
EEPROM( %00000001, %00000001, %01111111, %00000001, %00000001 ) ' T
EEPROM( %00111111, %01000000, %01000000, %00111111 ) ' U
EEPROM( %00001111, %00110000, %01000000, %00110000, %00001111 ) ' V
EEPROM( %00111111, %01000000, %00111000, %01000000, %00111111 ) ' W
EEPROM( %01100011, %00010100, %00001000, %00010100, %01100011 ) ' X
EEPROM( %00000111, %00001000, %01110000, %00001000, %00000111 ) ' Y
EEPROM( %01100001, %01010001, %01001001, %01000111 ) ' Z
EEPROM( 0,0,0,0,0 ) ' space

symbol Bitmap=20
symbol Space=250
symbol iText=b4
symbol nbText=3
symbol iChar=b5
symbol nbChar=b6
symbol ASCII=b7
symbol PixEnd=b8
symbol iPix=b9
symbol Pixels=b10
symbol Line=b11
symbol Mask=b12
symbol Nbr=b13


#macro SetParam(Reg,Val)
    b1=Reg
    b0=Val
    GOSUB SHOUTNP
#endmacro

  LOW SData
  LOW Clock
  LOW sload
  
  pause 500

  SetParam(TEST,0)
  SetParam(scan,7)
  SetParam(brite,8)
  SetParam(decode,0)
  SetParam(on_off,1)



iText=nbText-1
iPix=0
pixEnd=1
nbChar=0
iChar=1

DO
    inc iPix
    if iPix=PixEnd then
        iPix=Space        ' leading blank column
        PixEnd=0
    elseif iPix>PixEnd then
        inc iChar
        if iChar>nbChar then
            random w8
            iText=W8 % 4 MAX 2
            iChar=0
        endif
        ON iText GOSUB T0,T1,T2

        if ASCII=" " then
            iPix=Space
            PixEnd=iPix+3
        else
            ASCII=ASCII - "("
 
            read ASCII,iPix
            inc ASCII
            read ASCII, PixEnd
        endif
    endif
    read iPix,Pixels

     
    bptr=Bitmap
    Mask=1
    FOR Line=1 to 8

        bit31=Pixels & Mask MAX 1
     
        b0=@bptr : @bptrinc=b0*2 + bit31
        b1=@bptr : @bptrinc=b1*2 + bit7
        b2=@bptr : @bptrinc=b2*2 + bit15
        b3=@bptr : @bptrinc=b3*2 + bit23


        shiftout clock,sData,MSBFirst_L,(Line,b3,Line,b2,Line,b1,Line,b0)
        pulsout sLoad,1
        Mask=Mask*2
    NEXT Line

'    pause 200
    inc Nbr
LOOP

end


 
T0:nbChar=26 : Lookup iChar,("THAT IS THE FIRST TEXT +++ "),ASCII : RETURN
T1:nbChar=27 : Lookup iChar,("THAT IS THE SECOND TEXT ... "),ASCII : RETURN
T2:
    nbChar=10
    BINtoASCII Nbr,b0,b1,b2
    Lookup iChar,("NBR=", b0,b1,b2, "--- "),ASCII
RETURN


SHOUTNP:
    shiftout clock,sData,MSBFirst_L,(b1,b0,b1,b0,b1,b0,b1,b0)
    pulsout sLoad,1
return
VIDEO is worst the reality...
 

Attachments

Last edited:

BESQUEUT

Senior Member
Version for M2 Picaxe : bit bang data :
Code:
'-----------------  PICAXE   20M2 connected to four 8x8 displays
' This program uses a PICAXE-20M2 to shift-out SPI data to
' four MAX7219 LED display drivers to display
' This code is for 4 matrix 8X8 displays


#Picaxe 20M2


setfreq m32
' Hardware interface to the MAX7219
let dirsB = %11111111

symbol sData     = pinB.4       ' data out line to Max7219
symbol clock     = B.2      ' clock line
symbol sLoad     = B.3      ' pulse briefly to load data onto LED Matrix


' Register addresses for the MAX7219
symbol decode = $09'9            ' decode register; specify digits to decode
symbol brite  = $0A             ' intensity (brightness) register; 15 = 100%
symbol scan   = $0B'11             ' scan-limit register; specify # of LEDs
symbol on_off = $0C '12            ' 1 = display on; 0 = display off
symbol TEST = $0F '15

'-----Variables ------
symbol outByte = b0                 ' data byte to be transmitted to the LED
symbol maxReg  = b1                 ' MAX register that receives the data byte
                '

EEPROM( 52, 55, 58, 63, 67, 69, 73, 75 )          ' ()*+,-./
EEPROM( 79, 83, 86, 90, 94, 98, 102, 106 )          ' 01234567
EEPROM( 110, 114, 118, 119, 121, 124, 127, 130 )      ' 89:;<=>?
EEPROM( 134, 139, 143, 147, 151, 155, 159, 163 )      ' @ABCDEFG
EEPROM( 167, 171, 174, 178, 182, 186, 191, 196 )      ' HIJKLMNO
EEPROM( 200, 204, 208, 212, 216, 221, 225, 230 )      ' PQRSTUVW
EEPROM( 235, 240, 245, 249 )                  ' XYZ

EEPROM( %00011100, %00100010, %01000001 ) ' (
EEPROM( %01000001, %00100010, %00011100 ) ' )
EEPROM( %00101000, %00011000, %00001110, %00011000, %00101000 ) ' *
EEPROM( %00001000, %00001000, %00111110, %00001000 ) ' +
EEPROM( %10110000, %01110000 ) ' ,
EEPROM( %00001000, %00001000, %00001000, %00001000 ) ' -
EEPROM( %01100000, %01100000 ) ' .
EEPROM( %01100000, %00011000, %00000110, %00000001 ) ' /
EEPROM( %00111110, %01000001, %01000001, %00111110 ) ' 0
EEPROM( %01000010, %01111111, %01000000 ) ' 1
EEPROM( %01100010, %01010001, %01001001, %01000110 ) ' 2
EEPROM( %00100010, %01000001, %01001001, %00110110 ) ' 3
EEPROM( %00011000, %00010100, %00010010, %01111111 ) ' 4
EEPROM( %00100111, %01000101, %01000101, %00111001 ) ' 5
EEPROM( %00111110, %01001001, %01001001, %00110000 ) ' 6
EEPROM( %01100001, %00010001, %00001001, %00000111 ) ' 7
EEPROM( %00110110, %01001001, %01001001, %00110110 ) ' 8
EEPROM( %00000110, %01001001, %01001001, %00111110 ) ' 9
EEPROM( %01010000 ) ' :
EEPROM( %10000000, %01010000 ) ' ;
EEPROM( %00010000, %00101000, %01000100 ) ' <
EEPROM( %00010100, %00010100, %00010100 ) ' =
EEPROM( %01000100, %00101000, %00010000 ) ' >
EEPROM( %00000010, %01011001, %00001001, %00000110 ) ' ?
EEPROM( %00111110, %01001001, %01010101, %01011101, %00001110 ) ' @
EEPROM( %01111110, %00010001, %00010001, %01111110 ) ' A
EEPROM( %01111111, %01001001, %01001001, %00110110 ) ' B
EEPROM( %00111110, %01000001, %01000001, %00100010 ) ' C
EEPROM( %01111111, %01000001, %01000001, %00111110 ) ' D
EEPROM( %01111111, %01001001, %01001001, %01000001 ) ' E
EEPROM( %01111111, %00001001, %00001001, %00000001 ) ' F
EEPROM( %00111110, %01000001, %01001001, %01111010 ) ' G
EEPROM( %01111111, %00001000, %00001000, %01111111 ) ' H
EEPROM( %01000001, %01111111, %01000001 ) ' I
EEPROM( %00110000, %01000000, %01000001, %00111111 ) ' J
EEPROM( %01111111, %00001000, %00010100, %01100011 ) ' K
EEPROM( %01111111, %01000000, %01000000, %01000000 ) ' L
EEPROM( %01111111, %00000010, %00001100, %00000010, %01111111 ) ' M
EEPROM( %01111111, %00000100, %00001000, %00010000, %01111111 ) ' N
EEPROM( %00111110, %01000001, %01000001, %00111110 ) ' O
EEPROM( %01111111, %00001001, %00001001, %00000110 ) ' P
EEPROM( %00111110, %01000001, %01000001, %10111110 ) ' Q
EEPROM( %01111111, %00001001, %00001001, %01110110 ) ' R
EEPROM( %01000110, %01001001, %01001001, %00110010 ) ' S
EEPROM( %00000001, %00000001, %01111111, %00000001, %00000001 ) ' T
EEPROM( %00111111, %01000000, %01000000, %00111111 ) ' U
EEPROM( %00001111, %00110000, %01000000, %00110000, %00001111 ) ' V
EEPROM( %00111111, %01000000, %00111000, %01000000, %00111111 ) ' W
EEPROM( %01100011, %00010100, %00001000, %00010100, %01100011 ) ' X
EEPROM( %00000111, %00001000, %01110000, %00001000, %00000111 ) ' Y
EEPROM( %01100001, %01010001, %01001001, %01000111 ) ' Z
EEPROM( 0,0,0,0,0 ) ' space

symbol Bitmap=20
symbol Space=250
symbol iText=b4
symbol nbText=3
symbol iChar=b5
symbol nbChar=b6
symbol ASCII=b7
symbol PixEnd=b8
symbol iPix=b9
symbol Pixels=b10
symbol Line=b11
symbol Mask=b12
symbol Nbr=b13


#macro SetParam(Reg,Val)
    Line=Reg
    b0=Val
    b1=Val
    b2=Val
    b3=Val
    GOSUB send_bits
#endmacro

  SData=0
  low Clock
  low sload
   
  pause 500

  SetParam(TEST,0)
  SetParam(scan,7)
  SetParam(brite,8)
  SetParam(decode,0)
  SetParam(on_off,1)



iText=nbText-1
iPix=0
pixEnd=1
nbChar=0
iChar=1

DO
    inc iPix
    if iPix=PixEnd then
        iPix=Space        ' leading blank column
        PixEnd=0
    elseif iPix>PixEnd then
        inc iChar
        if iChar>nbChar then
            random w8
            iText=W8 % 4 MAX 2
            iChar=0
        endif
        ON iText GOSUB T0,T1,T2

        if ASCII=" " then
            iPix=Space
            PixEnd=iPix+3
        else
            ASCII=ASCII - "("
  
            read ASCII,iPix
            inc ASCII
            read ASCII, PixEnd
        endif
    endif
    read iPix,Pixels

      
    bptr=Bitmap
    Mask=1
    FOR Line=1 to 8

        bit31=Pixels & Mask MAX 1
      
        b0=@bptr : @bptrinc=b0*2 + bit31
        b1=@bptr : @bptrinc=b1*2 + bit7
        b2=@bptr : @bptrinc=b2*2 + bit15
        b3=@bptr : @bptrinc=b3*2 + bit23
      
        GOSUB Send_bits

        Mask=Mask*2
    NEXT Line

    pause 400
    inc Nbr
LOOP

end


  
T0:nbChar=26 : Lookup iChar,("THAT IS THE FIRST TEXT +++ "),ASCII : RETURN
T1:nbChar=27 : Lookup iChar,("THAT IS THE SECOND TEXT ... "),ASCII : RETURN
T2:
    nbChar=10
    BINtoASCII Nbr,b0,b1,b2
    Lookup iChar,("NBR=", b0,b1,b2, "--- "),ASCII
RETURN



Send_bits:
    GOSUB Send_Line
    sData = bit31 : PULSOUT Clock, 1
    sData = bit30 : PULSOUT Clock, 1
    sData = bit29 : PULSOUT Clock, 1
    sData = bit28 : PULSOUT Clock, 1
    sData = bit27 : PULSOUT Clock, 1
    sData = bit26 : PULSOUT Clock, 1
    sData = bit25 : PULSOUT Clock, 1
    sData = bit24 : PULSOUT Clock, 1
    GOSUB Send_Line
    sData = bit23 : PULSOUT Clock, 1
    sData = bit22 : PULSOUT Clock, 1
    sData = bit21 : PULSOUT Clock, 1
    sData = bit20 : PULSOUT Clock, 1
    sData = bit19 : PULSOUT Clock, 1
    sData = bit18 : PULSOUT Clock, 1
    sData = bit17 : PULSOUT Clock, 1
    sData = bit16 : PULSOUT Clock, 1
    GOSUB Send_Line
    sData = bit15 : PULSOUT Clock, 1
    sData = bit14 : PULSOUT Clock, 1
    sData = bit13 : PULSOUT Clock, 1
    sData = bit12 : PULSOUT Clock, 1
    sData = bit11 : PULSOUT Clock, 1
    sData = bit10 : PULSOUT Clock, 1
    sData = bit9 : PULSOUT Clock, 1
    sData = bit8 : PULSOUT Clock, 1
    GOSUB Send_Line
    sData = bit7 : PULSOUT Clock, 1
    sData = bit6 : PULSOUT Clock, 1
    sData = bit5 : PULSOUT Clock, 1
    sData = bit4 : PULSOUT Clock, 1
    sData = bit3 : PULSOUT Clock, 1
    sData = bit2 : PULSOUT Clock, 1
    sData = bit1 : PULSOUT Clock, 1
    sData = bit0 : PULSOUT Clock, 1
  
    pulsout sLoad,1
RETURN

Send_Line:
    sdata=0
    PULSOUT Clock, 1
    PULSOUT Clock, 1
    PULSOUT Clock, 1
    PULSOUT Clock, 1
    sdata=Line & %1000 MAX 1 : PULSOUT Clock, 1
    sdata=Line & %0100 MAX 1 : PULSOUT Clock, 1
    sdata=Line & %0010 MAX 1 : PULSOUT Clock, 1
    sdata=Line & %0001 MAX 1 : PULSOUT Clock, 1
RETURN
 
While it is undoubtedly easy and convenient to just link the displays linearly -
Code:
Omitted to save space
I might have taken advantage of the opportunity to rotate each display to make control easier for the software
Code:
Omitted
It would be easy enough to link the boards by not fitting the headers and just linking with flying wires soldered into appropriate holes.
This is a very good point which I hadn't considered and may indeed make the coding easier and more efficient. It would undoubtedly better suit the DIL MAX7219 boards:
23123
which I think can only be mounted side by side in this alternative orientation.

Similarly, the boards with corner pins could be mounted together using the corner pins to physically hold the boards together while using jumper leads to connect the ins/outs:
23124

However, the cheapest option (that I've found on the well known auction site) for the hardware is the four-off ready made display:
23125

I assumed at first that these would be four of the individual boards linked internally, but they're not, they are actually a single PCB:
23126

This board works exactly the same with my/your code and also, I'm pleased to discover, with Besqueut's code, even on an 08M2.
 

BESQUEUT

Senior Member
As said in the memory_map.pdf there are only 8 pixels to update when we rotate 256...
So hardware optimisation is of little interest.
By the way, did you note that you can write any text any time, even varying numbers, time and date ?
 
Here's the way my module is designed. I would like to see the same on the modules that you used.

EDIT 29 AUG 2019: After analyzing the photographs above and similar photos on eBay for these modules, I'm confident in saying that all these modules have the same basic design and wiring. The change made by engineering a surface mount IC didn't change the schematic. The change only made the PCB fit into the same profile as the LED 8x8 matrix.
I think that you are right about the different modules all having the same circuit. This is the diagram for the blue PCB modules I have (FC-16):

23127

which does seem to be the same as your sketches. I'm not certain about the value of the decoupling capacitor as it's not marked, but 100nF would be a sensible value given the spikey nature of the current draw by the MAX7219. The pin numbering I've used for the 1088AS in above diagram does seem to coincide with a data sheet I've found which is lucky as I didn't check while I was probing the board and drawing the diagram. Note that the ident for the display is on the edge of the side of the display where pin 1 is. For the software so far generated these displays/boards need to be assembled with the 1088AS text along the bottom edges of the displays.

In the case of the DIL module, I've just found a photo which shows this ident on the side of the board:

23128

Assuming that the circuit for these modules is the same (as your notes suggest techElder), then these boards can't physically be 'stacked' in a row with the 1088AS along the bottom edges, but instead have to be with the markings on the side. This would orient the boards as Hippy suggested, with the row addressing in the MAX7219 now forming the columns, making the software easier and more efficient.

I think this would also make it easier to write the software for a display of more than four 8 x 8 displays: the 32 x 8 pixels have to be written a 32-bit row at a time; a display with five or six units in it would need 40 or 48 bits to be updated simultaneously which on the face of it sounds much more difficult. The sideways display above though would only need to have the different columns written (as rows of eight bits) 40 or 48 times (as the display size requires) which sounds much easier.
 
Last edited:
As said in the memory_map.pdf there are only 8 pixels to update when we rotate 256...
So hardware optimisation is of little interest.
By the way, did you note that you can write any text any time, even varying numbers, time and date ?
See notes above about hardware optimisation.

I had noted that the text could be updated 'on the fly' thanks though I haven't tried it yet. It sounds extremely useful. I have used a lot of the very cheap (45p per pair 10 off) little 433MHz Tx/Rx boards in conjunction with the NKM2401 (or its equivalent in firmware in the larger PICAXE processors) to send data to and from PICAXEs and this could make a very useful and cost effective remote display for all sorts of things.

Thanks also for mentioning the memory_map.pdf which is very helpful - I hadn't looked at it previously.
 
Last edited:

techElder

Well-known member
I might have taken advantage of the opportunity to rotate each display to make control easier for the software
with the row addressing in the MAX7219 now forming the columns
Perhaps Hippy will expound (in a general manner) how this rotation makes "control easier for the software"?

PS. I think it was a mistake to move this discussion to finished projects section, Hairy Animal, because you clearly aren't "finished" with it yet! :D :D :D
 

BESQUEUT

Senior Member
Thanks also for mentioning the memory_map.pdf which is very helpful - I hadn't looked at it previously.
:giggle: it was made for that...
Code implement a variable length font for... 51 characters
A regular 8x5 font will occupy 51*5=255 bytes... (and will be easier to code.)
So variable length is only interresting if actuals characters lengths are very differents.
Also :
- the font is only 7 pixels height ; 8th is only used for comma...
- possible optimisation for white leading column and space.
 

techElder

Well-known member
A regular 8x5 font will occupy 51*5=255 bytes... (and will be easier to code.)
Why would you store the "dots" / font rather than store the ASCII characters? In the code I'm using/modifying, the "dots" / font information is stored in program memory as BASIC code.

I'm curious why you chose to store the "dots" / font?
 

BESQUEUT

Senior Member
Why would you store the "dots" / font rather than store the ASCII characters? In the code I'm using/modifying, the "dots" / font information is stored in program memory as BASIC code.
Please, publish your code (maybe not in finished projects...)
I'm curious why you chose to store the "dots" / font?
Only to save program space.
It's application dependant.
If you have lots of fixed texts, it may be better to store texts as ASCII.
But if code have many things to do and have to compose texts on the fly, it's a different thing...

The two can be combinated with a bitmap wich IHMO simplify things to rotate display.

Same bitmap can be used to show a varying value as an oscilloscope...
 
Last edited:

techElder

Well-known member
I'm not certain about the value of the decoupling capacitor as it's not marked, but 100nF would be a sensible value given the spikey nature of the current draw by the MAX7219.
Hairy Animal, the following quote is from the data sheet on the Max7219:
Supply Bypassing and Wiring
To minimize power-supply ripple due to the peak digit driver currents, connect a 10μF electrolytic and a 0.1μF ceramic capacitor between V+ and GND as close to the device as possible.
You might want to boost that "100nF" on each module to make sure you don't get random effects. I did on my modules.
 
PS. I think it was a mistake to move this discussion to finished projects section, Hairy Animal, because you clearly aren't "finished" with it yet! :D :D :D
Well, when I documented my project (the first entry in this thread), I had considered it to be a finished project. The simple hardware (& software thanks to Hippy) did exactly what I'd wanted to do which was to repeatedly scroll a fixed message across the 32 x 8 pixel display.

Since posting it, more sophisticated solutions to the software have been offered which are very interesting and useful and make the overall project far more versatile and capable of displaying more than just a fixed message.

I have no objection if a moderator would like to move the subsequent discussions to a new thread in the active forum. In due course maybe one of the contributors would like to post a revised version in the A/V projects forum?
 
You might want to boost that "100nF" on each module to make sure you don't get random effects. I did on my modules.
Indeed, the one MAX7219 module (the only ident I can find on it is www.icstation.com) I soldered together from scratch (including the SM components) does include a 10μF capacitor but the ready made ones (FC-16) don't include this nor do they have anywhere on the board to fit one.

The full 32 x 8 pixel displays though could easily have one or more extra decoupling caps added as there are plenty of unused VCC & GND holes available where headers would be on the individual displays:
23130

I haven't had any issues though since making sure my PSU isn't current limiting. Also, I'm running an 08M2 at 32 MHz so the update rate on the display isn't as fast as a 20X2 running at 64 MHz. It does seem like a good idea though so I'll be adding extra decoupling to these displays.
 

BESQUEUT

Senior Member
I haven't had any issues though since making sure my PSU isn't current limiting. Also, I'm running an 08M2 at 32 MHz so the update rate on the display isn't as fast as a 20X2 running at 64 MHz. It does seem like a good idea though so I'll be adding extra decoupling to these displays.
An also hspiout is faster than BitBanging...
 
Top