MAX7219 multi-display output for TAQOZ
Peter Jakacki
Posts: 10,193
Here's a character output module for the MAX7219 display which can be cascaded to form much larger displays (default is 8 displays of 8 digits = 64 characters). This was adapted from an earlier Tachyon version and works as a normal character output device in TAQOZ. Just divert to this device and print text and numbers as normal and control characters are handled as you would expect them to. ^N enables the display and ^O blanks it btw.
Usage: MAX7219 PRINT" HELLO WORLD! " 1234 1000 * PRINT
I don't have any displays to test this with although I may scope the timing to make sure it is under the 10MHz limit of the chip.
This is the code complete with the full alpha-numeric look-up tables in around 500 bytes.
TAQOZ
pub *MAX7219* PRINT" MAX7219/7221 Multiple 8-digit LED Driver by PBJ 160409-0000 " ;
{
Handles strings of MAX7219 LED displays as one character output device.
Simply switch to the output and print as normal
Displays can be cascaded with up to 8 displays or 64 digits or increase buffer sizes
MAX7219 PRINT" NUMERIC DISPLAY " 1234567 100 * PRINT CON
210130 Convert to TAQOZ from Tachyon V3
}
pub displays 4 ; --- Use "<n> AT displays C!" to change
pri ledsz displays 3 << ;
9 bytes ledwr
64 bytes ledbuf
--- write to control register but duplicate for every display
pub CLED! ( val reg -- ) displays FOR SPIWB SWAP SPIWB SWAP NEXT 2DROP SPICE ;
--- Talk to the register in the specified cascaded chip by issuing dummy nops as necessary
pub DLED! ( val dreg chip -- )
-ROT SPIWB DROP SPIWB DROP
?DUP IF 0 SWAP FOR SPIWL NEXT DROP THEN
SPICE
;
--- refresh the display by copying the ledbuf to the chip - <182us
pub REFRESH ledsz FOR ledbuf I + C@ I 7 AND 7 XOR 1+ I 3 >> DLED! NEXT ;
( ASCII to 7-segment LED decode table - all characters and symbols )
\ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
0 TABLE 7segs
$00 | $86 | $42 | $49 | $2D | $52 | $5B | $02 | --- $20..$27 !"#$%&'
$39 | $0F | $C9 | $46 | $04 | $40 | $80 | $52 | --- $28..$2F ()*+,-./
$3F | $06 | $5B | $4F | $66 | $6D | $7D | $07 | --- $30..$37 01234567
$7F | $6F | $41 | $45 | $70 | $48 | $46 | $D3 | --- $38..$3F 89:;<=>?
$7B | $77 | $7C | $39 | $5E | $79 | $71 | $3D | --- $40..$47 @ABCDEFG
$76 | $30 | $0E | $72 | $38 | $23 | $54 | $5C | --- $48..$4F HIJKLMNO
$73 | $7B | $50 | $6D | $46 | $3E | $62 | $1D | --- $50..$57 PQRSTUVW
$52 | $6E | $5B | $39 | $64 | $0F | $01 | $08 | --- $58..$5F XYZ[\]^_
$20 | $77 | $7C | $39 | $5E | $79 | $71 | $3D | --- $60..$67 `abcdefg
$76 | $30 | $0E | $72 | $38 | $23 | $54 | $5C | --- $68..$6F hijklmno
$73 | $79 | $50 | $6D | $46 | $3E | $62 | $1D | --- $70..$77 pqrstuvw
$52 | $6E | $5B | $39 | $36 | $0F | $52 | $00 | --- $78..$7F xyz{|}~
--- Fix table to suit hardware as segments are flipped (except decimal)
7segs 96 ADO I C@ REV 25 >> I C@ $80 AND OR I C! LOOP
pub (LED) ( char -- )
SWITCH --- use the ASCII value as a switch in the case statement
^M CASE ledwr C~ BREAK --- on CR reset display pos
^J CASE ledbuf ledsz ERASE BREAK --- erase line but don't update yet
^L CASE ledwr ledsz 1+ ERASE REFRESH BREAK --- reset and blank
^N CASE 1 12 CLED! BREAK --- enable display (unblank)
^O CASE 0 12 CLED! BREAK --- disable display (blank)
"." CASE $80 ledwr C@ 1- ledsz >> ledbuf + C+! REFRESH BREAK --- add in DP to previous character (or first)
CASE@ $10 < IF BREAK --- ignore any other controls <$10
CASE@ $20 < IF CASE@ >N 10 CLED! BREAK --- set 4-bit brightness $10..$1F
( char is printable )
ledwr C@ ledsz =>
IF ledbuf 1+ ledbuf ledsz 1- CMOVE ledwr C-- 50 ms THEN --- scroll if at end but slowly so it can be read
CASE@ $20 - 7segs + C@ --- decode character to 8 segments
ledwr C@ ledsz // ledbuf + C! --- display it as a character
ledwr C++ --- increment position
REFRESH
;
pri !LEDPINS
&14.12.13.15 SPIPINS --- setup pins used by SPI instructions
SPICE 2 COG@ LOW --- MAX7219 likes to work with clock low to high
;
pub MAXPINS AT !LEDPINS 2+ ! ;
--- Switch character output to the MAX7219 LED display
pub MAX7219
EMIT:
pub >LED ( char -- )
ledbuf @ 0= --- initialise the display if necessary (all zeros on startup)
IF
!LEDPINS
$FD64401F $1AE COG! --- slow down the SPI output to a max of 10MHz (TBD) --- slow down the SPI output to a max of 10MHz (TBD)
7 11 CLED! --- scan limit for 8 digits
0 9 CLED! --- no decode, use table
0 15 CLED! --- don't forget to reset TEST mode
$18 (LED) --- SET BRIGHTNESS
^L (LED) --- clear the display
^N (LED) --- enable display
THEN
(LED)
;
END
edit: patched the delay for <10MHz
