Help to drive a MAX7219 with ZBasic and a ESP8266

Discussion of issues related to writing ZBasic applications for targets other than ZX devices, i.e. generic targets.
Post Reply
memi205
Posts: 6
Joined: 03 May 2018, 16:41 PM

Help to drive a MAX7219 with ZBasic and a ESP8266

Post by memi205 »

Hi !
I need help to drive a MAX7219 with ZBasic and a Wemos D1 mini (ESP8266).

Any example for driving a MAX7219 with ZBasic for ESP8266 will be appreciated.

I did the same thing with success with BASCOM-AVR and a ATtiny85 and I used only Shiftout like this very short example in BASCOM-AVR :

Code: Select all

...
loadpin Alias Portb.2      ' load pin for display driver
Ser_clk Alias Portb.1      ' clk for display driver
Ser_data Alias Portb.0     ' data for display driver
...
Disp_num = &H0C
Disp_data = &H00
Shiftout Ser_data , Ser_clk , Disp_num , 1
Shiftout Ser_data , Ser_clk , Disp_data , 1
Set loadpin
Waitms 5
Reset loadpin
...
So, I try the same thing in ZBasic with a Wemos D1 mini (ESP8266) and it doesn't work.
I'm prettry sure that the connections between the Wemos D1 mini (ESP8266) and the MAX7219 are right.

Code: Select all

Const Ser_clk as Byte = A.14 
Const Ser_data as Byte = A.13 
Const loadpin as Byte = A.15 
Dim Disp_num as Byte
Dim Disp_data as Byte

Sub Main()

   Call Delay(1.0)

   'setup max7219 config. registers
   Disp_num = &H0C
   Disp_data = &H00
   Call Disp_write()
   Disp_num = &H09
   Disp_data = &H00
   Call Disp_write()
   Disp_num = &H0A
   Disp_data = &H05
   Call Disp_write()
   Disp_num = &H0B
   Disp_data = &H07
   Call Disp_write()
   Disp_num = &H0F
   Disp_data = &H00
   Call Disp_write()
   Disp_num = &H0C
   Disp_data = &H01
   Call Disp_write()

   Call Delay(1.0)

   Do
      'Display something in the Max7219 led matrix
      Disp_num = &H01
      Disp_data = &H01
      Call Disp_write()
      Disp_num = &H02
      Disp_data = &H03
      Call Disp_write()
      Disp_num = &H03
      Disp_data = &H07
      Call Disp_write()
      Disp_num = &H04
      Disp_data = &H0F
      Call Disp_write()
      Disp_num = &H05
      Disp_data = &H1F
      Call Disp_write()
      Disp_num = &H06
      Disp_data = &H3F
      Call Disp_write()
      Disp_num = &H07
      Disp_data = &H7F
      Call Disp_write()
      Disp_num = &H08
      Disp_data = &HFF
      Call Disp_write()

      Call Delay(60.0)

   Loop 

End Sub

Sub Disp_write()
   'Call ShiftOut(Ser_data,Ser_clk,8,Disp_num)
   'Call ShiftOut(Ser_data,Ser_clk,8,Disp_data)
   Call ShiftOutEx(Ser_data,Ser_clk,8,Disp_num,&H00)
   Call ShiftOutEx(Ser_data,Ser_clk,8,Disp_data,&H00)
   Call PutPin(loadpin,1)
   Call Delay(0.1)
   Call PutPin(loadpin, 0)
   Call Delay(0.1)
End Sub
What's wrong ?
Am I in the right way ?
Any working example to suggest me ?

Thank's a a lot !
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Re: Help to drive a MAX7219 with ZBasic and a ESP8266

Post by dkinzer »

memi205 wrote:I need help to drive a MAX7219 with ZBasic and a Wemos D1 mini (ESP8266).
Before looking at the code specifically for MAX7219 issues, I have a couple of comments.

Firstly, when you post code, use the code tags to set it off and preserve indentation. You can either use the Code button that appears below the subject line or just use code and /code in square brackets. I've already fixed your earlier posts.

Secondly, rather than using the global variables Disp_num and Disp_data to pass data to the subroutine Disp_write(), do it using parameters, e.g.

Code: Select all

Sub Disp_write(ByVal Disp_num as Byte, ByVal Disp_data as Byte)
...
End Sub
Thirdly, whenever you use ShiftOut() or ShiftOutEx() you should make a habit of configuring the clock and data pins as outputs and setting the state of the clock pin to the proper "idle" state for the device in your initialization. For example, if a device clocks data in on the rising edge the clock pin should idle low and for the falling edge the clock pin should idle high. You also need to check the datasheet for the device and determine what the minimum and maximum clocking speed is. Depending on the device, you may need to use the "throttling mode" of the shift out routines to slow down the clock.

Lastly, I don't see any code that initializes the state of the pin used for the MAX7219 chip select. From the datasheet it looks like the pin should be set low while clocking in the data and then set high during which time a rising edge on the clock is needed. Because of this unusual timing, you may need to implement the shifting out of the data manually rather than using ShiftOut().
Last edited by dkinzer on 07 May 2018, 14:40 PM, edited 1 time in total.
- Don Kinzer
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post by dkinzer »

Here is an attempt to implement a "bit-banged" interface to the MAX7219. It compiles but is otherwise untested. It is also incomplete in that there are no calls to the Disp_write() routine.

Code: Select all

Const Ser_clk as Byte = A.14
Const Ser_data as Byte = A.13
Const loadpin as Byte = A.15

Sub Main()
    ' initialize the pins
    Call PutPin(Ser_clk, 0)
    Call PutPin(Ser_data, 0)
    Call PutPin(loadpin, 1)

    ' other initialization code here
End Sub

Sub Disp_write(ByVal Disp_num as Byte, ByVal Disp_data as Byte)
    Dim i as Byte
    Dim data as UnsignedInteger

    ' set the chip select line low
    Call PutPin(loadPin, 0)

    ' combine the address and data values and output as 16 bits
    data = MakeWord(Disp_data, Disp_num)
    For i = 1 to 16
        ' output the next data bit
        Call PutPin&#40;Ser_data, IIF&#40;&#40;data And &H8000&#41; <> 0, 1, 0&#41;&#41;
        data = Shl&#40;data, 1&#41;

        ' pulse the clock pin - note that mode 5 of PutPin may work in place
        '   of these three instructions, i.e., Call PutPin&#40;Ser_clk, 5&#41;
        Call PutPin&#40;Ser_clk, 1&#41;
        Call DelayNanoseconds&#40;100&#41;
        Call PutPin&#40;Ser_clk, 0&#41;
    Next i

    ' set the chip select line back high 
    Call PutPin&#40;loadPin, 1&#41;
End Sub
On further reading of the MAX7219 datasheet, my earlier comments about a clock edge with the load pin high do not apply and, thus, the ShiftOutEx() routine might work. After you get the code above working you could try the alternate implementation of Disp_write() below.

Code: Select all

Sub Disp_write&#40;ByVal Disp_num as Byte, ByVal Disp_data as Byte&#41;
    Dim data as UnsignedInteger

    ' set the chip select line low
    Call PutPin&#40;loadPin, 0&#41;

    data = MakeWord&#40;Disp_data, Disp_num&#41;
    Call ShiftOutEx&#40;Ser_data, Ser_clk, 16, data, &H00&#41;

    ' set the chip select line back high 
    Call PutPin&#40;loadPin, 1&#41;
End Sub
- Don Kinzer
memi205
Posts: 6
Joined: 03 May 2018, 16:41 PM

Post by memi205 »

Thank you very much dkinzer !!!

Your last implementation of Disp_write works very well.

My code had 2 major problems:
1) The Ser_clk and Ser_data variables must be initialized at the beginning.
2) It seems that it is necessary to make a single shot of 16 bits in the ShiftOutEx

I am very sorry for the errors in my first message.

Thank you !!!
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post by dkinzer »

memi205 wrote:1) The Ser_clk and Ser_data variables must be initialized at the beginning.
Yes. It is always good practice to initialize all I/O pins to a "safe" state very early in your program. So too it is a good practice to design the hardware so that all I/O signals are held "inactive" by appropriate pullup or pulldown resistors. Doing so ensures that nothing happens during the time that the processor is resetting and the code is initializing.
memi205 wrote:2) It seems that it is necessary to make a single shot of 16 bits in the ShiftOutEx
I didn't see anything in the datasheet that would suggest that shifting out the two 8-bit values separately would be an issue. It is very easy to try it and see what happens. Just replace the one ShiftOutEx() call with these two.

Code: Select all

    Call ShiftOutEx&#40;Ser_data, Ser_clk, 8, Disp_num, &H00&#41;
    Call ShiftOutEx&#40;Ser_data, Ser_clk, 8, Disp_data, &H00&#41;
Experimentation like this can be done easily using the conditional compilation feature of ZBasic, e.g.

Code: Select all

#if 0
    Dim data as UnsignedInteger
    data = MakeWord&#40;Disp_data, Disp_num&#41;
    Call ShiftOutEx&#40;Ser_data, Ser_clk, 16, data, &H00&#41;
#else
    Call ShiftOutEx&#40;Ser_data, Ser_clk, 8, Disp_num, &H00&#41;
    Call ShiftOutEx&#40;Ser_data, Ser_clk, 8, Disp_data, &H00&#41;
#endif
With this you can easily switch between the two sequences of code by changing the #if 0 to #if 1 and back again. Then, when you're ready you can delete the code that is not needed.

One other issue in your original code is that you didn't set loadpin low before beginning the shifting. According to the datasheet the CS/load pin must be low while shifting and then taken high afterward.
- Don Kinzer
Post Reply