Set Pins values synchroniously

All ESP32 boards running MicroPython.
Target audience: MicroPython users with an ESP32 board.
User avatar
Roberthh
Posts: 1718
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Set Pins values synchroniously

Post by Roberthh » Thu Nov 07, 2019 8:44 pm

You test code above would with viper and including masking for instance look like:

Code: Select all

from machine import Pin, mem16

p12=Pin(12, Pin.OUT)
p14=Pin(14, Pin.OUT)

@micropython.viper
def set_gpio(value:int, mask:int):
    GPIO_OUT = ptr32(0x3FF44004) # GPIO Output register
    GPIO_OUT[0] = (GPIO_OUT[0] & mask) | value

p12.value(0)
print(p12.value())

p14.value(0)
print(p14.value())

#esp32
set_gpio(0b00000000000000000101000000000000,
         0b11111111111111111010111111111111)

print(p12.value())
print(p14.value())

pidou46
Posts: 59
Joined: Sat May 28, 2016 7:01 pm

Re: Set Pins values synchroniously

Post by pidou46 » Thu Nov 07, 2019 9:16 pm

Nice, it works like a charm with the latest build.

Thank you
nodemcu V2 (amica)
micropython firmware Daily build 05/31/2016

pidou46
Posts: 59
Joined: Sat May 28, 2016 7:01 pm

Re: Set Pins values synchroniously

Post by pidou46 » Thu Nov 07, 2019 9:23 pm

Still, I think OutoftheBOTS_ is right it could be usefull to have synchro pin value setting build in micropython, it would bring easyness and portability, I will probably open an issue on git repository since I'm (still) not able to make a PR by myself...
nodemcu V2 (amica)
micropython firmware Daily build 05/31/2016

User avatar
pythoncoder
Posts: 3669
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Set Pins values synchroniously

Post by pythoncoder » Fri Nov 08, 2019 9:08 am

It could be difficult to achieve in machine since registers are platform dependent. A Pyboard-only solution could be implemented as a user module.
Peter Hinch

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

Re: Set Pins values synchroniously

Post by Roberthh » Fri Nov 08, 2019 10:13 am

A lot of the stuff in machine is platform dependent. machine is the API that hides it. I see more the problem on how the api should look like, in contrast to the simplicity of self implemented functions, which hardly are longer than a few lines, and, if implemented as viper code, are pretty fast.
P.S.: The API could be something like:
gpio_set(value, GPIO_number_list, init=False)
If init is true, the GPIO's would be configured to OUT mode. still easy to implement as Python function.

OutoftheBOTS_
Posts: 666
Joined: Mon Nov 20, 2017 10:18 am

Re: Set Pins values synchroniously

Post by OutoftheBOTS_ » Fri Nov 08, 2019 8:18 pm

It is correct that it isn't many lines of code but for a beginner python programmer (python mainly being a higher level language) it is a little confusing understanding viper code and masking and reset(&= ~) or set(|=)

It is true that working out just how the python implementation should look and work is the hardest part.

Sometimes people will want to do 4 bit parallel, sometimes 8 bit parallel and sometimes 16 bit.

A machine.write_mulit(number_bits, first_pin, data) method that takes the inputted bits e.g 8 bits then shifts it to the needed position to correspond to correct parallel pins e.g pin5 to pin12 then reads the ODR first sets the needed 8 bits to 0 then && the new bits in then writes it back to the ODR. Then also a similar function for reading in parallel

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

Re: Set Pins values synchroniously

Post by Roberthh » Fri Nov 08, 2019 8:29 pm

Yes, that is similar to what I sketched in my post. Only that I though of a list of pin numbers, to allow for non-consecutive port bits to be set. Looking at the various boards on my desk, there is no common set of bits which is available. Protoyping that in Python & Viper is easy - and maybe sufficient.

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

Re: Set Pins values synchroniously

Post by Roberthh » Fri Nov 08, 2019 9:15 pm

Here is a simple implementation of that. Whithin the limits of my cheap 10€ saleae clone, the bits are set simultaneously. The bits of value are in the same order as the pin list. Lowest order bit of the data goes to the last pin in the list. Using mem32 instead of the viper helper function works too, but is a little bit worse in timing consistency.

Code: Select all

from machine import Pin, mem32

@micropython.viper
def set_gpio(value:int, mask:int):

    GPIO_OUT = ptr32(0x3FF44004) # GPIO Output register
    GPIO_OUT[0] = (GPIO_OUT[0] & mask) | value

def write_multi(data, pin_list, init=False):
    mask = 0
    value = 0
    for pin in list[::-1]:
        if init:
            Pin(pin, Pin.OUT)
        mask |= 1 <<  pin
        value |= (data & 1) << pin
        data >>= 1
    mask = 0xffffffff - mask
    set_gpio(value, mask)
    # mem32[0x3FF44004] = (mem32[0x3FF44004] & mask) | value

def run():
    init = True
    for n in range(8):
        write_multi(n, [14, 18, 4], init)
        init = False
See: https://hidrive.ionos.com/lnk/naYGqITP

kevinkk525
Posts: 511
Joined: Sat Feb 03, 2018 7:02 pm

Re: Set Pins values synchroniously

Post by kevinkk525 » Sat Nov 09, 2019 6:55 am

Would it be possible to change the API to accept tuples of pin number and pin value?
So you could call it like:

Code: Select all

write_multi((14,0),(5,1),(0,1))
Or would that not feel more natural?
Kevin Köck
Micropython Smarthome Firmware: https://github.com/kevinkk525/pysmartnode

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

Re: Set Pins values synchroniously

Post by Roberthh » Sat Nov 09, 2019 7:52 am

That's obviously possible, the code would then e.g. look like the one below. But calling may be a little bit more effort, if the bits are in a single value at the callers side.

Code: Select all

from machine import Pin, mem32

@micropython.viper
def set_gpio(value:int, mask:int):

    GPIO_OUT = ptr32(0x3FF44004) # GPIO Output register
    GPIO_OUT[0] = (GPIO_OUT[0] & mask) | value

def write_multi(*pv_list, init=False):
    mask = 0
    value = 0
    for pin, bit in pv_list:
        if init:
            Pin(pin, Pin.OUT)
        mask |= 1 << pin
        value |= ((bit & 1) << pin)
    mask = 0xffffffff - mask
    set_gpio(value, mask)
    # mem32[0x3FF44004] = (mem32[0x3FF44004] & mask) | value

def run():
    init = True
    for n in range(8):
        write_multi((14, n >> 2), (18, n >> 1), (4, n), init=init)
        init = False


Post Reply