0

I am trying to send serial data to a MAX7219 8 Digit Seven Segment Display Module from a Pico W. I can blank the display or make every last LED light up but nothing else. I cannot currently see what I have done wrong.

Details

I went the Python route and downloaded Thonny. Then I looked up a datasheet which I found here.

What I am trying to do is create a loop that will take an array of bits (not necessarily efficiently) that will display digits with whatever LEDs I choose.

Connections

I put power on VBus and ground on ground. Yes, that is enough power, it seems. GP14 to DIN (Data in) GP15 to CS/Load GP18 to CLK

The code

This is my not especially well-written python. It is the result of fiddling about until I figured things out.

I've assumed a baud rate that should fit within 10Mhz and divided 1 second by it. I use that for a sleep call before stepping the clock forwards.

If I send a reset command 16 bits of all zeros, that works like a dream - display blanks out.

Anything else either does nothing or lights up all the LEDs.

The expected outcome is that the array my_rnd_bits should give me an 8 on segment 0 (possibly with a decimal point). I have yet to activate the display in any meaningful way. The actual outcome is everything on or nothing.

UPDATE: I have reordered my code a little bit. I have listed (almost) all the commands and registers and such so my bad typing does not cause bugs. This has not got me any further.

from machine import Pin
from time import sleep

junk = [0,0,0,0]

register = dict()
register['no-op']=junk+[0,0,0,0]
register['digit0']=junk+[0,0,0,1]
register['digit1']=junk+[0,0,1,0]
register['digit2']=junk+[0,0,1,1]
register['digit3']=junk+[0,1,0,0]
register['digit4']=junk+[0,1,0,1]
register['digit5']=junk+[0,1,1,0]
register['digit6']=junk+[0,1,1,1]
register['digit7']=junk+[1,0,0,0]
register['decode mode']=junk+[1,0,0,1]
register['intensity']=junk+[1,0,1,0]
register['scan limit']=junk+[1,0,1,1]
register['shutdown']=junk+[1,1,0,0]
register['test']=junk+[1,1,1,1]

command = dict()
command['shutdown'] = register['shutdown'] + junk + [0,0,0,0] # shutdown mode
command['normal'] = register['shutdown'] + junk + [0,0,0,1]   # Normal Opperation
command['reset'] = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]
# Mode B for digits
command['none'] = register['decode mode'] + [0,0,0,0,0,0,0,0]   # Normal Opperation
# others in here if I can be bothered later
command['all'] = register['decode mode'] + [1,1,1,1,1,1,1,1]   # Normal Opperation

codeBFont = dict()
codeBFont['0'] = junk+[0,0,0,0]
codeBFont['1'] = junk+[0,0,0,1]
codeBFont['2'] = junk+[0,0,1,0]
codeBFont['3'] = junk+[0,0,1,1]
codeBFont['4'] = junk+[0,1,0,0]
codeBFont['5'] = junk+[0,1,0,1]
codeBFont['6'] = junk+[0,1,1,0]
codeBFont['7'] = junk+[0,1,1,1]
codeBFont['8'] = junk+[1,0,0,0]
codeBFont['9'] = junk+[1,0,0,1]
codeBFont['-'] = junk+[1,0,1,0]
codeBFont['E'] = junk+[1,0,1,1]
codeBFont['H'] = junk+[1,1,0,0]
codeBFont['L'] = junk+[1,1,0,1]
codeBFont['P'] = junk+[1,1,1,0]
codeBFont[' '] = junk+[1,1,1,1]
codeBFont['blank'] = codeBFont[' ']

intensity = dict()
intensity[0] = junk+[0,0,0,0]
intensity[1] = junk+[0,0,0,1]
intensity[2] = junk+[0,0,1,0]
intensity[3] = junk+[0,0,1,1]
intensity[4] = junk+[0,1,0,0]
intensity[5] = junk+[0,1,0,1]
intensity[6] = junk+[0,1,1,0]
intensity[7] = junk+[0,1,1,1]
intensity[8] = junk+[1,0,0,0]
intensity[9] = junk+[1,0,0,1]
intensity[10] = junk+[1,0,1,0]
intensity[11] = junk+[1,0,1,1]
intensity[12] = junk+[1,1,0,0]
intensity[13] = junk+[1,1,0,1]
intensity[14] = junk+[1,1,1,0]
intensity[15] = junk+[1,1,1,1]

scanlimit = dict()
scanlimit[0] = junk+[0,0,0,0] # 0 only
scanlimit[1] = junk+[0,0,0,1] # 0 - 1
scanlimit[2] = junk+[0,0,1,0] # 0 - 2
scanlimit[3] = junk+[0,0,1,1] # 0 - 3
scanlimit[4] = junk+[0,1,0,0] # 0 - 4
scanlimit[5] = junk+[0,1,0,1] # 0 - 5
scanlimit[6] = junk+[0,1,1,0] # 0 - 6
scanlimit[7] = junk+[0,1,1,1] # 0 - 7

testmode = dict()
testmode['normal'] = junk+[0,0,0,0]
testmode['display'] = junk+[0,0,0,1]
def Seg7Send(bits):
    #baudr = (1/9600)*1 #multiplier is to slow the clk rate
    baudr = 5*(10^-8)
    p_cs = Pin(15,Pin.OUT) #CS/LOAD
    p_din = Pin(14,Pin.OUT) #DIN
    p_clk = Pin(18,Pin.OUT) #CLK
    hilo = 0
    counter = 0
    for bit in bits:
        counter += 1
        hilo = 1-hilo
        p_clk.value(hilo) #clock pulse
        p_din.value(bit) # send bit
        #print(f"bit: {bit}"); #debug
        if(counter>15):
            #print(f"clk: {hilo}"); #debug
            p_cs.value(1) # load
            counter = 0
        sleep(baudr) #Regulate clock
    p_cs.value(0) # reset
    p_din.value(0) # reset


mycommand = command['reset']+command['normal'] # not sure if this is necessary
mycommand = mycommand + register['scan limit']+scanlimit[7] # scan limit - show all digits
mycommand = mycommand + command['all']+register['digit0'] # decode mode B all digits
mycommand = mycommand + codeBFont['H']

print(f"Command: {command}")
Seg7Send(mycommand)

This has left me wondering if there is a handshake or prefix I need to send; if I have just missed a step; or if I have totally misunderstood something.

As might be obvious from all the commented-out stuff, I have experimented with going faster and slower. I have tried a bunch of stuff and then (in desperation) experimented with random data (no a great move).

Have I misunderstood how the clock should work? Missed a protocol header? Been an idiot (always a possibility), or just got something wrong?

5
  • You never send bit0. Oct 1, 2022 at 8:17
  • @KennethAndersen is that I don't send it or I do but shouldn't? Oct 1, 2022 at 10:36
  • 1
    You should. First you set counter to 0, but as soon as you enter the for bit in bits , counter is incremented. Oct 1, 2022 at 16:02
  • That's right - so at the 16th (counter>15) we can also set the CS/LOAD pin high. Is that a mistake? Oct 1, 2022 at 16:17
  • I think I have cracked it. I send data only on CLK-high. I am now getting some sensible output. Not perfect but closer than I was. Oct 1, 2022 at 16:50

1 Answer 1

0

Solution

The fault was not with the loop (as such) but with my reading of the chip details. The breakthrough was to do the following:

  1. Set CS-high on the same clock pulse as the 16th bit. For my chip, that might have been optional.

  2. Send data only on CLK-high and nothing on CLK-low

Special thanks

Kenneth Andersen's comment about checking how many bits I was sending forced me to look closer at when CS/LOAD should be set which made me look at the Timing Diagram.

code

from machine import Pin
from time import sleep
from picozero import pico_led

junk = [0,0,0,0]

register = dict()
register['no-op']=junk+[0,0,0,0]
register['digit0']=junk+[0,0,0,1]
register['digit1']=junk+[0,0,1,0]
register['digit2']=junk+[0,0,1,1]
register['digit3']=junk+[0,1,0,0]
register['digit4']=junk+[0,1,0,1]
register['digit5']=junk+[0,1,1,0]
register['digit6']=junk+[0,1,1,1]
register['digit7']=junk+[1,0,0,0]
register['decode mode']=junk+[1,0,0,1]
register['intensity']=junk+[1,0,1,0]
register['scan limit']=junk+[1,0,1,1]
register['shutdown']=junk+[1,1,0,0]
register['test']=junk+[1,1,1,1]

command = dict()
command['shutdown'] = register['shutdown'] + junk + [0,0,0,0] # shutdown mode
command['normal'] = register['shutdown'] + junk + [0,0,0,1]   # Normal Opperation
command['reset'] = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]
# Mode B for digits
command['none'] = register['decode mode'] + [0,0,0,0,0,0,0,0]   
# others in here if I can be bothered later
command['all'] = register['decode mode'] + [1,1,1,1,1,1,1,1]   

codeBFont = dict()
codeBFont['0'] = junk+[0,0,0,0]
codeBFont['1'] = junk+[0,0,0,1]
codeBFont['2'] = junk+[0,0,1,0]
codeBFont['3'] = junk+[0,0,1,1]
codeBFont['4'] = junk+[0,1,0,0]
codeBFont['5'] = junk+[0,1,0,1]
codeBFont['6'] = junk+[0,1,1,0]
codeBFont['7'] = junk+[0,1,1,1]
codeBFont['8'] = junk+[1,0,0,0]
codeBFont['9'] = junk+[1,0,0,1]
codeBFont['-'] = junk+[1,0,1,0]
codeBFont['E'] = junk+[1,0,1,1]
codeBFont['H'] = junk+[1,1,0,0]
codeBFont['L'] = junk+[1,1,0,1]
codeBFont['P'] = junk+[1,1,1,0]
codeBFont[' '] = junk+[1,1,1,1]
codeBFont['blank'] = codeBFont[' ']

intensity = dict()
intensity[0] = junk+[0,0,0,0]
intensity[1] = junk+[0,0,0,1]
intensity[2] = junk+[0,0,1,0]
intensity[3] = junk+[0,0,1,1]
intensity[4] = junk+[0,1,0,0]
intensity[5] = junk+[0,1,0,1]
intensity[6] = junk+[0,1,1,0]
intensity[7] = junk+[0,1,1,1]
intensity[8] = junk+[1,0,0,0]
intensity[9] = junk+[1,0,0,1]
intensity[10] = junk+[1,0,1,0]
intensity[11] = junk+[1,0,1,1]
intensity[12] = junk+[1,1,0,0]
intensity[13] = junk+[1,1,0,1]
intensity[14] = junk+[1,1,1,0]
intensity[15] = junk+[1,1,1,1]

scanlimit = dict()
scanlimit[0] = junk+[0,0,0,0] # 0 only
scanlimit[1] = junk+[0,0,0,1] # 0 - 1
scanlimit[2] = junk+[0,0,1,0] # 0 - 2
scanlimit[3] = junk+[0,0,1,1] # 0 - 3
scanlimit[4] = junk+[0,1,0,0] # 0 - 4
scanlimit[5] = junk+[0,1,0,1] # 0 - 5
scanlimit[6] = junk+[0,1,1,0] # 0 - 6
scanlimit[7] = junk+[0,1,1,1] # 0 - 7

testmode = dict()
testmode['normal'] = junk+[0,0,0,0]
testmode['display'] = junk+[0,0,0,1]
def Seg7Send(bits):
    #baudr = (1/9600)*1 #multiplier is to slow the clk rate
    baudr = 5*(10^-8)
    p_cs = Pin(15,Pin.OUT) #CS/LOAD
    p_din = Pin(14,Pin.OUT) #DIN
    p_clk = Pin(18,Pin.OUT) #CLK
    p_clk.value(0)
    sleep(baudr)
    counter = 0
    for bit in bits:
        counter += 1
        p_clk.value(0) #clock low
        pico_led.off()
        p_cs.value(0) # CS low
        sleep(baudr) #Regulate clock
        p_din.value(bit) # send bit
        p_clk.value(1) #clock pulse
        pico_led.on()
        if(counter>15): # CS high on 16th rising edge
            p_cs.value(1) # load
            counter = 0
        sleep(baudr) #Regulate clock
    p_cs.value(0) # reset
    p_din.value(0) # reset





mycommand = []
mycommand = command['shutdown'] 
mycommand = mycommand + register['scan limit']+scanlimit[7] # scan limit - show all digits
mycommand = mycommand + command['all'] # decode mode B all digits
mycommand = mycommand + register['digit0'] + codeBFont['H']
mycommand = mycommand + register['digit1'] + codeBFont['0']
mycommand = mycommand + register['digit2'] + codeBFont['2']
mycommand = mycommand + register['digit3'] + codeBFont['4']
mycommand = mycommand + register['digit4'] + codeBFont['6']
mycommand = mycommand + register['digit5'] + codeBFont['8']
mycommand = mycommand + register['digit6'] + codeBFont['1']
mycommand = mycommand + register['digit7'] + codeBFont['0']
mycommand = mycommand + command['normal'] + register['no-op']


#print(f"Command: {mycommand}")
Seg7Send(mycommand)

TL;DR:

Make sure to send data on but not between clock signals.

Bonus tip

I had some trouble with digit-0 resetting to zero after the display loop was done. This was due to junk code from my earlier testing. Always clean up your debug and testing code.

1
  • Please accept your own answer. This closes the question so that it doesn't keep reappearing periodically.
    – NomadMaker
    Oct 31, 2022 at 19:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.