memorymap: Convert to use memoryview internally.#11110
Conversation
506fa9c to
e8a23f3
Compare
|
Here's the code I use in my program to read & update GPIO pins as a group: SIO_BASE = const(0xd0000000)
SIO_LEN = const(0x1000)
GPIO_IN = const(4//4)
GPIO_OUT_XOR = const(0x1c//4)
sio = memorymap.AddressRange(start=SIO_BASE, length=SIO_LEN).cast('L')
def gpio_in():
"""Fetch the status of all GPIO inputs"""
return sio[GPIO_IN]
def gpio_out_xor(x):
"""Invert the given pins simultaneously"""
sio[GPIO_OUT_XOR] = x |
3b0b1dd to
db8b15f
Compare
|
Space Savings from this PR, raspberry_pi_pico:
|
db8b15f to
fd9766d
Compare
Importantly, a memoryview can be .cast(), and then accesses to it for 4 byte values don't require allocations or to/from_bytes. This does remove the existing protections enforcing aligned accesses to IO blocks on raspberrypi. However, the behavior in these cases is actually well defined: an 8 or 16 bit access is replicated across all 32 bits of the register. See RP2040 datasheet 2.1.4. Narrow IO Register Writes and RP2350 datasheet 2.1.5. Narrow IO register writes. Signed-off-by: Jeff Epler <jepler@unpythonic.net>
fd9766d to
e94f0f5
Compare
tannewt
left a comment
There was a problem hiding this comment.
Looks good overall. One question about the future API. Could we make cast() check alignment?
| //| the physical address space. | ||
| //| """ | ||
| //| | ||
| //| def AddressRange(start_address: int, length: int) -> memoryview: |
There was a problem hiding this comment.
I don't feel like we'll want this long term. I'm happy to have this be in 10.x alongside a new api. Maybe we just want an access name for this? So you do memorymap.access(start, length) instead of memorymap.AddressRange(start, length). (AddressRange looks likes a class still. Thoughts?
|
Thanks for the review.
As an alternative, what about an optional We could change what the core
I could add the name |
Yup, that works for me. I think I'd prefer
Sounds good! Thanks for doing this! |
Importantly, a memoryview can be .cast(), and then accesses to it for 4 byte values don't require allocations or to/from_bytes. (as long as the register values actually fit in CircuitPython "small integers")
This does remove the existing protections enforcing aligned accesses to IO blocks on raspberrypi. However, the behavior in these cases is actually well defined: an 8 or 16 bit write access is replicated across all 32 bits of the register. See RP2040 datasheet 2.1.4. Narrow IO Register Writes and RP2350 datasheet 2.1.5. Narrow IO register writes.
As discussed on Discord, this speeds up the keyboard scanner of my Unicomp Mini M firmware by nearly 10x compared to using DigitalInOut, mostly because 12 pins can be read by a single operation, allowing it to scan the full keyboard in under 1ms when overclocked. (https://adafruit-playground.com/u/jepler/pages/unicomp-mini-m-with-circuitpython currently details the original lower performance keyboard, which took about 6ms to scan the full keyboard when overclocked)
Currently tested only on rp2040.