1

A very basic circuit uses MicroPython and the SPI interface to connect an ESP8266 MCU to a 74HC595 shift register. This is how I try to send the data:

from machine import Pin, SPI
hspi = SPI(-1, baudrate=50000, polarity=0, phase=0, sck=Pin(14), mosi=Pin(13), miso=Pin(12), bits=8)
latch_pin = Pin(15, Pin.OUT)
latch_pin.off()

def send(s):
    hspi.write(s)
    latch_pin.on()
    latch_pin.off()

For testing, I have put 8 leds between output pins and +5V (through a 100 Ohm resistor) to see what is happening, and tried to send data using this test function:

import time
def test_one(s):
    send(chr(int(s)))
    time.sleep(0.5) # only to be able to examine the leds after data was sent

def test():
    [test_one(s) for s in [
        '0b00000000',
        '0b10000000',
        '0b01000000',
        '0b00100000',
        '0b00010000',
        '0b00001000',
        '0b00000100',
        '0b00000010',
        '0b00000001',
        '0b01111111',
        '0b10111111',
        '0b11011111',
        '0b11101111',
        '0b11110111',
        '0b11111011',
        '0b11111101',
        '0b11111110',
        '0b11111111']]

test()

As you can see, there are moving ones and moving zeros in this test. The result is very interesting. The value 0000 0000 is transferred as 1100 0010. After that, all of the values with a single bit set are transferred correctly. Then 0111 1111 is correct again. After that, all values are wrong again. I have examined the output with a logic analyzer, and it seems that these values are sent in two bytes instead of one.

First good value is 1000 0000:

enter image description here

The last value with a single 1 bit 0000 0001 is also transmitted okay:

enter image description here

The last good value is 0111 1111:

enter image description here

The next one should be 1011 1111 but instead of that, 1100 0010 1011 1111 is transferred. E.g. instead of one byte, there are two bytes sent:

enter image description here

My very first thought was that maybe the SPI is using 7 bits instead of 8. But that is impossible, because in that case 1000 0000 should also be wrong. (Also, the SPI object was created with bits=8 parameter.) By the way, I have also tried the hardware SPI (id=1) but that had the very same problem. So it must be a problem in my program, and not the hardware, but I'm stuck and cannot figure this out.

The send() function uses chr() to create a single character. Can anyone explain how it is possible that some single characters are sent as two bytes, and others as a single byte?

nagylzs
  • 3,954
  • 6
  • 39
  • 70
  • 1
    I'm not sure if you should expect the SPI functions to directly drive a 74HC595, and I haven't tried this out on Micropython, but `chr` in Python 3.x returns a Unicode text string, not a byte array. What happens if you replace `send(chr(int(s)))` with `send(bytes([int(s)]))`? – nekomatic Jan 02 '19 at 11:02
  • I have done this with ESP8266 with Lua already. 74HC595 does work with simple SPI. So maybe really MicroPython implements unicode strings - which is VERY suprising for me. :-) I'll check this within 2 hours. – nagylzs Jan 02 '19 at 14:27
  • 1
    It checks out: chr() will create an UTF-8 string! If I replace it with bytes([int(s)]) then everything works as expected. It is unbelieveable that they have implemented UTF-8 strings on a tiny microcontroller. Please post an answer so I can accept it. – nagylzs Jan 02 '19 at 14:55

1 Answers1

2

MicroPython is based on Python 3...

MicroPython aims to implement the Python 3.4 standard (with selected features from later versions) with respect to language syntax, and most of the features of MicroPython are identical to those described by the “Language Reference” documentation at docs.python.org.

...so chr returns a Unicode string. To specify the exact byte(s) to be sent over SPI, you need to give the SPI write method a bytes object.

If you replace send(chr(int(s))) in your code with send(bytes([int(s)])), it should send the bit patterns you expect.

nekomatic
  • 5,988
  • 1
  • 20
  • 27