RP2040 PIO - set(pins, 1) works fine, but mov(pins, x) or out(pins, 1) does not #17268
-
Hello, sorry for the very fundamental question. I've started writing an I2C/I3C library using PIO for my own learning (and testing) purposes. I'm using GPIO2 (SDA) and GPIO3 (SCL) - both declared as outputs for the time being. I found that I can "set" the pin states high or low, however I can't assign the pin state to scratch register x or shift a bit in from the OSR. This command works fine: This command DOES NOT work: I suspect my error is related to the setup/config of the PIO block? Other information:
Here's my full code: from machine import Pin
import rp2
from time import sleep_ms
# PIO Examples:
# Micropython - https://github.com/raspberrypi/pico-micropython-examples/tree/master/pio
# C++ - https://github.com/raspberrypi/pico-examples/tree/master/pio
# Reference:
# https://docs.micropython.org/en/latest/library/rp2.html#module-rp2
# https://docs.micropython.org/en/latest/library/rp2.StateMachine.html#rp2.StateMachine
@rp2.asm_pio(set_init=rp2.PIO.OUT_HIGH, sideset_init=rp2.PIO.OUT_HIGH)
def i2c_test():
pull(block) # Pull 32-bit from the TX FIFO into OSR.. or wait forever!
set(y, 7) # prepare to loop n+1 times
set(pins, 0) .side(1)
label("transmit_addr")
nop() .side(1)
nop() .side(0)
out(pins, 1) .side(0)
jmp(y_dec, "transmit_addr") .side(1)
set(pins, 1) .side(1)
def generate_sm_i2c(F_clk_target, PIN_SCL, PIN_SDA):
sm_i2c = rp2.StateMachine(0)
sm_i2c.init(i2c_test, freq=F_clk_target*4,
in_base=PIN_SDA, # in command not used yet
out_base=PIN_SDA,
set_base=PIN_SDA,
sideset_base=PIN_SCL,
out_shiftdir=rp2.PIO.SHIFT_RIGHT,
in_shiftdir=rp2.PIO.SHIFT_RIGHT)
return sm_i2c
if __name__ == "__main__":
# https://docs.micropython.org/en/latest/library/machine.Pin.html
PIN_SCL = Pin(3, Pin.OUT) # RP2040 GPIO3, SCL
PIN_SDA = Pin(2, Pin.OUT) # RP2040 GPIO2, SDA
sm_i2c = generate_sm_i2c(100000, PIN_SCL, PIN_SDA)
sm_i2c.restart()
sleep_ms(200)
# (works) test that all pins toggle as expected
sm_i2c.exec("set(pins, 0).side(0)") # both pins low
sm_i2c.exec("set(pins, 1).side(0)") # SDA low
sm_i2c.exec("set(pins, 0).side(1)") # SCL low
sm_i2c.exec("set(pins, 1).side(1)")
# (works) Check if PIO can be sent a value, and return the same value
# TX FIFO --> OSR --> ISR --> RX FIFO
sm_i2c.put(0xAAAAAAAA)
sm_i2c.exec("pull(block)") # TX FIFO --> OSR
sm_i2c.exec("out(isr, 32)") # OSR --> ISR
sm_i2c.exec("push(block)") # ISR --> RX FIFO
print(hex(sm_i2c.get())) # output is 0xaaaaaaaa
# (doesn't work!!) Transmit a number, one bit at a time, on SDA
# TX FIFO --> OSR --> repeat(1-bit to pins)
sm_i2c.put(0xAAAAAAAA)
sm_i2c.exec("pull(block)")
for i in range(4):
sleep_ms(250)
sm_i2c.exec("out(pins, 1).side(0)") # output 1-bit from OSR --> SDA
sleep_ms(250)
sm_i2c.exec("out(pins, 1).side(1)") # output another 1-bit from OSR --> SDA
sm_i2c.exec("out(isr, 32)") # shift whatever remains in OSR --> ISR
sm_i2c.exec("push(block)") # push ISR --> RX_FIFO
print(hex(sm_i2c.get())) # print remainder of RX_FIFO, expected to be 8-bits shorter than what we input (measured: 0xaaaaaa)
sleep_ms(1000)
# (doesn't work!!) Transmit a number, one bit at a time, on SDA
# TX FIFO --> OSR --> X --> pins
sm_i2c.put(0xAAAAAAAA)
sm_i2c.exec("pull(block)")
for i in range(4):
sleep_ms(250)
sm_i2c.exec("out(x, 1).side(0)")
sm_i2c.exec("mov(pins, x).side(0)")
sleep_ms(250)
sm_i2c.exec("out(x, 1).side(1)")
sm_i2c.exec("mov(pins, x).side(1)")
sm_i2c.exec("out(isr, 32)") # shift whatever remains in OSR --> ISR
sm_i2c.exec("push(block)") # push ISR --> RX_FIFO
print(hex(sm_i2c.get())) # print remainder of RX_FIFO, expected to be 8-bits shorter than what we input (measured: 0xaaaaaa)
sleep_ms(1000)
# (doesn't work!!) See if pins can be set to value of x
# value 0 or 1 --> x --> pins
for i in range(4):
sleep_ms(250)
sm_i2c.exec("set(x, 1).side(0)")
sm_i2c.exec("mov(pins, x).side(0)")
sleep_ms(250)
sm_i2c.exec("set(x, 1).side(1)")
sm_i2c.exec("mov(pins, x).side(1)") |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
Could be that the StateMachine need to be active to handle out(): |
Beta Was this translation helpful? Give feedback.
-
Thanks for taking a look Norbert. It appears I didn't configure the PIO properly... I needed to set
Without that line, the PIO |
Beta Was this translation helpful? Give feedback.
Thanks for taking a look Norbert. It appears I didn't configure the PIO properly... I needed to set
out_init=rp2.PIO.OUT_HIGH
in my @rp2.asm_pio decorator:@rp2.asm_pio(out_init=rp2.PIO.OUT_HIGH, set_init=rp2.PIO.OUT_HIGH, sideset_init=rp2.PIO.OUT_HIGH)
Without that line, the PIO
out(pins, 1)
instruction didn't work. With that line,out(pins, 1)
appears to work as expected. I will update this ticket once my code is working properly