TinyTapeout / tt-micropython-firmware

TinyTapeout demo pcb's RP2040 functionality
GNU Lesser General Public License v2.1
4 stars 7 forks source link

Pulsing a pin for a single clock cycle #9

Open urish opened 4 months ago

urish commented 4 months ago

In some cases, like my TT04 USB CDC project, we need a way to pulse a pin for a single clock cycle, e.g. to latch some value into a register.

This can be achieved using the Pi Pico's PIO. The relevant PIO machine code is as follows:

import rp2

# We use the PIO as we need to generate a tx_valid pulse of a single clock cycle
@rp2.asm_pio(set_init=(rp2.PIO.OUT_LOW))
def pio_pin_pulse():
    wrap_target()
    pull(block)  # 0
    set(pins, 1)  # 1
    set(pins, 0)  # 2
    wrap()

Then, to use it, you need to set up the clock frequency to match your project clock frequency (48 MHz in the example below), and to set the pin you would like to pulse:

tx_valid_sm = rp2.StateMachine(
    0, pio_pin_pulse, freq=48_000_000, set_base=tt.bidirs[2].raw_pin
)
tx_valid_sm.active(1)

Finally, to pulse the pin, call to put method with any value, e.g.:

tx_valid_sm.put(1)

It would be great to have this functionality built into the SDK, e.g. as a utility class that takes a pin number and the tt object, and creates the PIO machines behind the scenes. Something along the following lines:

tx_pulser = PinPulser(tt, tt.bidirs[2].raw_pin)
tx_pulser.pulse() # Send a single-clock pulse
psychogenic commented 3 months ago

I like it and it'd be useful. Could include as is but this stuff involves some caveats... mainly that the pin becomes taken over by PIO, e.g.

Pin(GPIO21, mode=ALT, pull=PULL_DOWN, alt=PIO0)

and then all the uPython sdk stuff doesn't necessarily work as expected. So this is expertish mode. So, we add it as a util or side library in the SDK? Or start a side project set of libs for things like this?