Shop OBEX P1 Docs P2 Docs Learn Events
Eight Digit Seven-Segment Display based on MX7219 — Parallax Forums

Eight Digit Seven-Segment Display based on MX7219

tomcrawfordtomcrawford Posts: 1,126
edited 2014-09-24 00:19 in General Discussion
Here is an eight digit Seven-segment display based on MX7219 that recently appeared on eBay. They mostly come from China/Hong Kong and cost from $4.00 up, a little less in fives or tens. You can find plenty of them by searching “MAX7219 Digital Tube” (don’t know where the tube part came from).

http://www.ebay.com/itm/New-MAX7219-8-Digit-Red-LED-Digital-Tube-Display-Module-Green-Board-For-Arduino-/281347153969?pt=LH_DefaultDomain_0&hash=item418198e031

It is based on the Maxim MX7219; here is a pointer to their data sheet.

http://www.maximintegrated.com/en/datasheet/index.mvp/id/1339

This module is different from the Seven-segment module discussed in some detail in this tread. That module used just shift registers and requires constant refreshing.

http://forums.parallax.com/showthread.php/157074-7-Segement-DisplayHelp-Needed

Here is a sample driver that generates random numbers in the range +-9,999,999, and calls a PASM cog to convert to BCD and write onto a single module.
{Demo MX7219 Seven-segment display: Single stick}

CON

        _clkmode = xtal1 + pll16x    'Standard clock mode 
        _xinfreq = 5_000_000         '* crystal frequency = 80 MHz

        CS = 0, CLK = 1, DI = 2              'Mx7219 Pins

VAR

  long  BinValue, BCDValue, random            'input, result, randomizer
  byte  Flag                                  'value input available
  long  MyParm[5]                             'passing addresses to display driver
  byte  Cog

  

OBJ
  pst      : "parallax serial terminal"

PUB main
    pst.Start (115_200)                                   'start up ser terminal
    pst.str(String("hello, world   "))                    'runs in cog 1
    pst.NewLine
    waitcnt(clkfreq/10 + cnt)


    MyParm[0] := @BinValue            'argument to driver cog
    MyParm[1] := @BCDValue            'value displayed    
    MyParm[2] := @Flag                'valid inpiut available
    MyParm[3] := Constant((CS << 16) | (CLK << 8) | DI)   'the pins                                           
    cog := cognew(@PCog, @MyParm)       'start up the output cog
    pst.str(String("Panel Cog: "))             '
    pst.hex(Cog,1)
    pst.NewLine
    waitcnt(clkfreq/10 + cnt)

    repeat                             'forever  
      binvalue := random? // 9_999_999 'new argumwent in rangw -9,999,999..9,999,999   
      Flag := 1                        'tell cog to convert
      repeat while flag <> 0           'tis he gets done     
      pst.dec(BinValue)                'display input in decimal
      pst.str(string("   "))           
      pst.hex(BCDValue,8)              'display my result  
      pst.Newline
      waitcnt(clkfreq*5+cnt)

DAT
PCog    org   0                'This PASM cog converts bin2BCD, displays on a 7 segment panel
        mov AdPar,Par          'get the address of input parameters
        rdlong AdBin, AdPar    'Address in main memory of input argument
        add AdPar, #4          
        rdlong AdBCD, AdPar    'result
        add AdPar, #4          
        rdlong AdFlag, AdPar     'run flag
        add AdPar ,#4
        rdlong APins, AdPar      'get the pins             
        mov Work1, APins         'copy of pins
        shr Work1, #16           'scale chip select pin number
        and Work1, #$1F          'extract just pin number
        mov CSMask, #1           'single bit mask
        shl CSMask, Work1         'scaled
        or outa, CSMask           'CS starts out high
        or dira, CSMask           'enabled
        mov Work1, APins          'clk mask is just the same
        shr Work1, #8
        and Work1, #$1F
        mov ClkMask, #1
        shl ClkMask, Work1
        or dira, ClkMask
        mov Work1, APins           'and data pin
        and Work1, #$1F
        mov DMask, #1
        shl DMask, Work1
        or dira, DMask   
                                        'start up the Mx7219 Array
        mov Shifter, StDown             'shut down: get initial control
        call #Commo
        mov Shifter, Decode             'decode all digits
        call #Commo
        mov Shifter, Intens             'medium intensity  
        call #Commo
        mov Shifter, ScanAll              'scan all digits
        call #Commo
        mov Shifter, Normal              'normal operation
        call #Commo

Wait    rdbyte Work1, AdFlag wz      'get the flag
        if_Z jmp #Wait               'no bits set, wait here
        rdlong BinIn, AdBin          'get input argument
        mov Accum, BinIn             'copy in case it is positive
        mov BCDOut, #$F              'decodes to blank.  Positive result  
        test BinIn, SignBit wz       'see if it is negative
        if_Z jmp #L1                 'jump if positive
        mov accum, #0                 'negative input
        sub Accum, BinIn              'covert to pos
        mov BCDOut, #$A               'decodes as minus sign
L1      mov CSI, CSub                  'get nice fresh copy of cmpsub instruction
        mov DigCnt, #7                'will do seven digits
L2      shl BCDOut, #4                 'shift the current results        
CSI      nop                           'becomes compare/sub instruction
        if_NC jmp #L3                 'subtract was impossible
        add BCDOut, #1                'subtract took place, increment result         
        'if_Z jmp #L4                  'special case of exactly done
                                       'try uncommenting to see why this won't work
        jmp #CSI                       'continue with same subtractor   
L3      add CSI, #1                    'go on to next power of 10
        djnz DigCnt, #L2              'for all seven powers of 10

'ok the conversion is complete
L4      wrlong BCDOut, AdBCD           'stash result in hub memory
        call #OneModule                'write one eight-digit module
        wrbyte zero, AdFlag            'indicate done
        jmp #Wait

OneModule mov Work1, #8                 'we will do eight registers
         mov work2, #$100                'this will be the register address in MX7219
OneML    mov Shifter, BCDOut             'into shifter
         and Shifter, #$F                'just four bits
         or Shifter, Work2               'register number
         'or shifter, #$80                'for decimal point
         andn outa, CSMask               'chip select active
         shl shifter, #16                'scale for shift
         call #Shift
         ror BCDOut, #4                  'next four bits into D3..0
                                         'MX is wired with digit 0 on the right         
         or outa, CSMask                 'take away chip select (LOAD)
         add Work2, #$100                'to next register
         djnz work1,#OneML               'eight times for eight registers (digits)
OneModule_ret ret          

Commo   andn outa, CSMask          'chip select: send contents of command[31..16] eight times
CommoLp Call #Shift                 'always shifts left 16 bits
        or outa, CSMask             'turn off CS 
Commo_Ret   ret                                                   

Shift   mov BitC, #16                'serialize shifter[31..16] to left for 16 bits
SLoop   rol shifter, #1 wc           'get next bit into carry
        if_C or outa,DMask           'set data bit if needful
        if_NC andn outa, DMask       'or reset it
        mov MyCnt, cnt               'initialize timing for this bit
        add MyCnt, #70              'this will be data setup
        waitcnt MyCnt, #80           'data setup time, set clock high time
        or outa, ClkMask              'clock hi
        waitcnt MyCnt, #150            'clock hi period, set data hold from clock down
        andn outa, ClkMask            'clock goes low
        waitcnt MyCnt, #50             'data hold from clock low
        djnz BitC, #SLoop              'for however many bits
        andn outa, DMask              'force data low 
Shift_Ret  ret                        'and return                                            



StDown  long $0C00_0000          'shutdown  Note prescaled for shift routine
Decode  long $09FF_0000          'decode all digits
Intens  long $0A02_0000          'modest brightness
ScanAll long $0B07_0000          'scan all digits
Normal  long $0C01_0000          'normal operation



Ten6    long 1000000
Ten5    long 100000
Ten4    long 10000
Ten3    long 1000
Ten2    long 100
Ten1    long 10
Ten0    long 1

SignBit long $8000_0000
Zero    long 0 

CSub    cmpsub Accum, Ten6 wc, wz    'fresh copy of compare, subtract

BinIN   res                      'input in Binary
BCDOut  res                      'Output in signed BCD

AdPar   res                      'address of parameter list        
AdBCD   res                      'result
AdFlag  res                      'run flag
AdBin   res                      'input
Accum   res                      'running remainder

APins   res
CSMask  res                       'pin masks
ClkMask res
DMask   res
Work1   res                     'couple of COG general working registers
Work2   res
BitC    res                     '16 bits in each register
Command res                     'used for global commands
Shifter res                      'variable being shifted
MyCnt   res                      'used to time shifters
DigCnt  res                      'counts the digits
        fit 150                                                          

Here are a couple of photos. The eBay ads all shown the module next to a metric scale but I'm enough native U.S. to not really get a good feeling for the actual size. One picture shows a module next to a good ol' USA quarter. The other shows how the LEDs are socketed. Don't know why they did that.

I will do some fiddling to drive multiple modules and post results in this thread. tc

PS: I think I now understand why the comsub instruction happened.
1024 x 768 - 68K
1024 x 768 - 140K

Comments

  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-09-14 13:50
    Wow! Perfect timing Tom. I just received six of these displays.

    Thanks for posting your code.
  • tomcrawfordtomcrawford Posts: 1,126
    edited 2014-09-15 10:01
    Here is a driver for hexadecimal display. I used the typical lower case "b" and "d", and fiddled the "6" to not look like "b". I put a bottom on the "9" to match the "6"
    1024 x 768 - 78K
  • tomcrawfordtomcrawford Posts: 1,126
    edited 2014-09-16 13:36
    Here is a simulation of a Difference Engine finding cubes.


    http://youtu.be/JH0_inuzoO4

    I had tried "daisy-chaining" the sticks, but there was way too much VCC drop to do more than a couple. So I connected them in parallel, so to speak, with common clock and data, separate chip selects.
    1024 x 768 - 129K
  • JonnyMacJonnyMac Posts: 9,105
    edited 2014-09-17 08:52
    Thanks for the tip on those displays; I'm going to order a few for a book project.

    You can use the MUXC instruction to replace these two lines of code:
    if_c            or      outa, dmask
            if_nc           andn    outa, dmask
    


    with...
    muxc    outa, dmask
    
  • tomcrawfordtomcrawford Posts: 1,126
    edited 2014-09-17 10:18
    JonnyMac is correct about the muxc instruction, of course. It forces the bit(s) in the destination corresponding to the bit(s) in the mask to the state of the carry latch. In this case, it would be just the single bit corresponding to the data bit.

    Perhaps my wife was right about reading the Prop Manual in bed after all.

    I should point out that pull-ups on the CS pin(s) are really really Good. I think the MX7219 gets very confused if CS is undefined when power comes on and goes into some odd state a lot like lamp test except it ignores anything you tell it. Seems to me that Duane Degn and I found this during the MX7219 8x8 module days. I use 20K to +5V and that seems to work. Also 20K to +5V shouldn't fry the prop pin.
  • JonnyMacJonnyMac Posts: 9,105
    edited 2014-09-17 15:36
    As a matter of habit I put pull-ups on all active-low chip select lines in my designs. Not sure why the board vendor decided not to do this.
  • CuriousOneCuriousOne Posts: 931
    edited 2014-09-18 02:29
    Anyone got BS2 code for this?
    All BS2 examples use 4 digits with MAX7219, had no luck running 8 digits on it.
  • tomcrawfordtomcrawford Posts: 1,126
    edited 2014-09-18 09:16
    CuriousOne wrote: »
    Anyone got BS2 code for this?
    All BS2 examples use 4 digits with MAX7219, had no luck running 8 digits on it.

    This should get you started. Remember, DIG is your friend.
    ' {$STAMP BS2}
    ' {$PBASIC 2.5}
    ' {$PORT COM14}
    
    
    
    Clk   PIN 10
    DIN   PIN 12
    CS    PIN 11
    
    
    
    SWord VAR Word         'word which is shifted out to 7219
    SWHi  VAR SWord.HIGHBYTE
    SWLo  VAR SWord.LOWBYTE
    Digit    VAR Word
    
    begin:
    HIGH  CS               'normally not selected
    LOW   CLK              'make these outputs
    LOW   DIN
    
    SWord = $0C01                'shutdown register, normal operation
    GOSUB DMX7219
    SWord = $09FF                'decode register,  decode
    GOSUB DMX7219
    SWord = $0B07                'scan limit, all rows
    GOSUB DMX7219
    SWord = $0A08                'intensity register, medium
    GOSUB DMX7219
    
    
    Drive:                      'display seven thru zero
    FOR Digit = 0 TO 7           'go from right to left
      SWHi = (Digit +1)
      SWLo = Digit
      GOSUB DMX7219
      NEXT
    
      END
    
    
    DMX7219:                     'drive MX 7219
    LOW   CS                                           'enable
    SHIFTOUT DIN, CLK, MSBFIRST, [SWord \16]           'shift out 16 bits
    HIGH  CS                                           'it loads and executes
    RETURN
    
    
    1024 x 768 - 98K
  • CuriousOneCuriousOne Posts: 931
    edited 2014-09-23 04:10
    Thanks a lot, any idea how to display custom chars using BS2 there?

    I've set decide register to 0X00 and now assigning varios data to Sword variable displays various segments lit, however, it is hard to determine,which digit does what.
  • tomcrawfordtomcrawford Posts: 1,126
    edited 2014-09-23 08:59
    CuriousOne wrote: »
    Thanks a lot, any idea how to display custom chars using BS2 there?

    I've set decide register to 0X00 and now assigning varios data to Sword variable displays various segments lit, however, it is hard to determine,which digit does what.

    The high order byte of SWORD specifies which digit is written (1..8) and the low order byte specifies which segments are lit. Be systematic and write values with a single bit set in the SWLO field, one at a time, and write down on a piece of paper which bit controls which segment. Then decide which combinations are pleasing.

    Or you could look at the data sheet, Table 6 on page 8.

    tc
  • CuriousOneCuriousOne Posts: 931
    edited 2014-09-24 00:19
    Added the code below, after the "Drive" label code in sample provided:
    PAUSE 1000
    SWord = $0C00                'shutdown register, shutdown
    GOSUB DMX7219
    PAUSE 100
    SWord = $0C01                'shutdown register, normal operation
    GOSUB DMX7219
    SWord = $0900                'decode register,  no decode
    GOSUB DMX7219
    
    SWHI = $03
    SWLO = %11111111 'segments A, B, F, G, E
    GOSUB DMX7219
    END
    

    The "Drive" portion works fine, I see "0 1 2 3 " on display (using 4 digit right now)
    but the code below works not as planned. Even if SWLO=%00000001, 4 segments lit up - G segments in char 2,3,4 and B segment in char 4. If the wiring was incorrect, then "0 1 2 3" should not be displayed, right?
Sign In or Register to comment.