Set Pins values synchroniously

All ESP32 boards running MicroPython.
Target audience: MicroPython users with an ESP32 board.
User avatar
pythoncoder
Posts: 3724
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Set Pins values synchroniously

Post by pythoncoder » Sat Nov 09, 2019 8:11 am

I'd think, when doing parallel I/O, it was more common to send a multi-bit data value to a list of pins as per the original version. Speed is also an issue here: if doing parallel I/O it's usually because you need performance.
Peter Hinch

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

Re: Set Pins values synchroniously

Post by Roberthh » Sat Nov 09, 2019 8:29 am

I made a variant which allows either a singe value or a list of bits, only that two lists o tuples are provided. One for the bits and one for the pins . Speed is the same in both cases, about 100µs per bit.

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
    if type(data) is int:
        for i in range(len(pin_list) - 1, -1, -1):
            pin = pin_list[i]
            if init:
                Pin(pin, Pin.OUT)
            mask |= 1 <<  pin
            value |= ((data & 1) << pin)
            data >>= 1
    else:
        for i in range(len(pin_list)):
            pin = pin_list[i]
            if init:
                Pin(pin, Pin.OUT)
            mask |= 1 <<  pin
            value |= ((data[i] & 1) << pin)
    mask = 0xffffffff - mask
    set_gpio(value, mask)

def run():
    init = True
    for n in range(8): # supplying a singe value
        write_multi(n, (14, 18, 4), init)
        init = False
    for n in range(8): # supplying a list of bits
        write_multi((n >> 2, n >> 1, n), (14, 18, 4), init)

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

Re: Set Pins values synchroniously

Post by Roberthh » Sat Nov 09, 2019 12:25 pm

Another variant, but just for the int value, using viper code. The init is outside the call. The first call takes 20µs, the following ones 8µs:

Code: Select all

from machine import Pin

@micropython.viper
def write_multi(data:int, pin_list:ptr8, plen:int):
    GPIO_OUT = ptr32(0x3FF44004) # GPIO Output register
    mask = 0
    value = 0
    i = plen - 1
    while i >= 0:
        pin = pin_list[i]
        mask |= 1 <<  pin
        value |= ((data & 1) << pin)
        data >>= 1
        i -= 1
    mask = int(0xffffffff) - mask
    GPIO_OUT[0] = (GPIO_OUT[0] & mask) | value

def run():
    pin_list = bytearray((14,18,4))
    for p in pin_list:
        Pin(p, Pin.OUT)
    pl = len(pin_list)
    for n in range(8):
        write_multi(n, pin_list, pl)
Viper does not like range(), so the loop is made in a basic mode. And it is very sensitive to the code size. If I add both variants (int and tuple for data), the call takes ~18µs.

Post Reply