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