Running a C++ SPI library inside Micropython on ESP32

All ESP32 boards running MicroPython.
Target audience: MicroPython users with an ESP32 board.
Post Reply
Hallsand
Posts: 5
Joined: Thu Nov 07, 2019 2:30 pm

Running a C++ SPI library inside Micropython on ESP32

Post by Hallsand » Thu Nov 07, 2019 2:41 pm

Hello everyone,

I've been working with a MCP3909, a energy meter, along side a ESP32 board. Initially I tried to start the communication between my ESP32 and MCP3909 using the machine.SPI module. Turns out that wasn't possible because I needed to have a precision of 2 microseconds to enter the MCP board into "configuration mode". The faster response I got from the micropython was 20us.

I could create, though, a C++ code fast enough to communicate those boards.

My problem now is: I need to run micropython on that board because every single code my team made for this project is in that language.

I'm trying to make my C code a library I could call, but the "SPI.h" library I use can't just be easily imported into my ESP32 board.

Is there any way I could make my Arduino "SPI.h" library compatible with my ESP32 micropython board? Could I call the "machine.SPI" module from my C code and have it running faster?

Thank you.
Last edited by Hallsand on Fri Nov 08, 2019 1:17 pm, edited 2 times in total.

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Running a C SPI library inside Micropython on ESP32

Post by Roberthh » Thu Nov 07, 2019 4:00 pm

What kind of operation requires this 2µs max time? I see a tWINSET in the data sheet, with 1/MCLK minimum time. And a tWINDOW, which is 32/MCLK or ~9 µs. That is fast. If it's only for that first byte to configure the mode, you can do that with Viper code, direct port access and bit banging, controlling all four port bits for MCLR, F0, F1 and F2 by direct port access. Not beautiful, but doable.
After that initial burst you would then use normal SPI methods.
The short script below creates a 10 pulse burst of ~8 MHz, total time 1.25µs at a ESP32 clock of 240 MHz.

Code: Select all

def loop():
    import machine
    machine.Pin(4, machine.Pin.OUT, value=0)
    do_loop()
    print("Done")

@micropython.viper
def do_loop():

    GPIO_OUT_SET = ptr32(0x3FF44008) # GPIO Output set
    GPIO_OUT_CLR = ptr32(0x3FF4400C) # GPIO Output clear
    for i in range(10):
        GPIO_OUT_SET[0] = 0x10 # set bit 4
        GPIO_OUT_CLR[0] = 0x10 # clear bit 4

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Running a C SPI library inside Micropython on ESP32

Post by Roberthh » Thu Nov 07, 2019 5:34 pm

Update: I made a simulation, which toggles an I/O line and then shifts out a byte over two other GPIO lines emulating SPI CLK and MOSI using viper. Total time 2 µs.

Code: Select all

from machine import Pin, SPI

pin = Pin(4, Pin.OUT, value=1)
SCLK = Pin(14, Pin.OUT, value=0)
MOSI = Pin(13, Pin.OUT, value=0)

@micropython.viper
def reset_n_shift(value:int):
    GPIO_OUT_SET = ptr32(0x3FF44008) # GPIO Output set
    GPIO_OUT_CLR = ptr32(0x3FF4400C) # GPIO Output clear

    GPIO_OUT_CLR[0] = 0x10 # set bit 4
    for _ in range(2): pass  # short delay of 200 ns
    GPIO_OUT_SET[0] = 0x10 # clear bit 4

    for _ in range (8):
        GPIO_OUT_SET[0] = 1 << 14 # setclear bit 14
        if value & 1:
            GPIO_OUT_SET[0] = 1 << 13 # set bit 13
        else:
            GPIO_OUT_CLR[0] = 1 << 13 # set bit 13
        GPIO_OUT_CLR[0] = 1 << 14 # setclear bit 14
        value = value >> 1

    GPIO_OUT_CLR[0] = 1 << 14 # setclear bit 14

def run():
    reset_n_shift(0xaa)
Edit: Timing snapshot:
https://hidrive.ionos.com/lnk/XBYGqOGt

Hallsand
Posts: 5
Joined: Thu Nov 07, 2019 2:30 pm

Re: Running a C SPI library inside Micropython on ESP32

Post by Hallsand » Fri Nov 08, 2019 12:20 pm

Thank you for the answer!

I didn't know about the viper

I'm trying to run that code, but it's returning an error I've never seen:

"Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: incompatible .mpy arch"

I'm searching on the internet, but I couldn't find a solution yet.

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Running a C SPI library inside Micropython on ESP32

Post by Roberthh » Fri Nov 08, 2019 12:34 pm

You may have to update the firmware version. There were quite a few changes lately.
If you do put the code into frozen bytecode, there have been other inconsistencies, which have been fixed recently.
If you pre-compile with mpy-cross, you have to use the option:
-march=xtensa
into the mpy-cross call.

Hallsand
Posts: 5
Joined: Thu Nov 07, 2019 2:30 pm

Re: Running a C++ SPI library inside Micropython on ESP32

Post by Hallsand » Mon Nov 11, 2019 1:10 pm

I'm still receiving that one error.

I updated my firmware, as you said, and tried to use the "-march=xtensa", but I'm doing something wrong since the same error is still appearing.

Should I use "-march=xtensa" this way?
"/home/hallsand/micropython/mpy-cross/mpy-cross -march=xtensa /home/hallsand/Desktop/mpy/teste.py"?

Sorry if it sounds stupid. I'm quite new to MicroPython.

Thank you again!

-
Edit: I checked my Makefile and mpy-tool.py files and those are up to what dpgeorge commented 7 days ago:

https://github.com/micropython/micropython/issues/4607
Last edited by Hallsand on Mon Nov 11, 2019 1:20 pm, edited 1 time in total.

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Running a C++ SPI library inside Micropython on ESP32

Post by Roberthh » Mon Nov 11, 2019 1:19 pm

If you run your python code with the viper functions from the device itself as python file (extension .py), you do not need to precompile with mpy-cross. For mpy-cross, check the version with mpy-cross --version. It should be v5.
You may have to re-compile mpy-cross.

Hallsand
Posts: 5
Joined: Thu Nov 07, 2019 2:30 pm

Re: Running a C++ SPI library inside Micropython on ESP32

Post by Hallsand » Mon Nov 11, 2019 3:50 pm

That works! You must be a technomancer!

Thank you so much!

It wouldn't be possible without your help! :D

I'm still receiving the error when running the .mpy file, though. My mpy-cross version is 5. I'll keep searching a way to fix because I must use the machine.SPI library to read the information from the MCP.

Post Reply