diff options
| author | Damien George | 2021-01-21 00:34:08 +1100 |
|---|---|---|
| committer | Damien George | 2021-01-30 00:42:29 +1100 |
| commit | 469345e7285128739e2934e7934e107ffda79fc1 (patch) | |
| tree | a410ce2d427770a01d5b6f4d1b3ff2fb342cd94b /examples | |
| parent | ef3ee7aa1005cd1f15c2144d4b46feb792ab3185 (diff) | |
rp2: Add new port to Raspberry Pi RP2 microcontroller.
This commit adds a new port "rp2" which targets the new Raspberry Pi RP2040
microcontroller.
The build system uses pure cmake (with a small Makefile wrapper for
convenience). The USB driver is TinyUSB, and there is a machine module
with most of the standard classes implemented. Some examples are provided
in the examples/rp2/ directory.
Work done in collaboration with Graham Sanderson.
Signed-off-by: Damien George <damien@micropython.org>
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/rp2/pio_1hz.py | 35 | ||||
| -rw-r--r-- | examples/rp2/pio_exec.py | 27 | ||||
| -rw-r--r-- | examples/rp2/pio_pinchange.py | 46 | ||||
| -rw-r--r-- | examples/rp2/pio_pwm.py | 45 | ||||
| -rw-r--r-- | examples/rp2/pio_uart_tx.py | 44 | ||||
| -rw-r--r-- | examples/rp2/pio_ws2812.py | 59 | ||||
| -rw-r--r-- | examples/rp2/pwm_fade.py | 25 |
7 files changed, 281 insertions, 0 deletions
diff --git a/examples/rp2/pio_1hz.py b/examples/rp2/pio_1hz.py new file mode 100644 index 000000000..c18aa22fc --- /dev/null +++ b/examples/rp2/pio_1hz.py @@ -0,0 +1,35 @@ +# Example using PIO to blink an LED and raise an IRQ at 1Hz. + +import time +from machine import Pin +import rp2 + + +@rp2.asm_pio(set_init=rp2.PIO.OUT_LOW) +def blink_1hz(): + # fmt: off + # Cycles: 1 + 1 + 6 + 32 * (30 + 1) = 1000 + irq(rel(0)) + set(pins, 1) + set(x, 31) [5] + label("delay_high") + nop() [29] + jmp(x_dec, "delay_high") + + # Cycles: 1 + 7 + 32 * (30 + 1) = 1000 + set(pins, 0) + set(x, 31) [6] + label("delay_low") + nop() [29] + jmp(x_dec, "delay_low") + # fmt: on + + +# Create the StateMachine with the blink_1hz program, outputting on Pin(25). +sm = rp2.StateMachine(0, blink_1hz, freq=2000, set_base=Pin(25)) + +# Set the IRQ handler to print the millisecond timestamp. +sm.irq(lambda p: print(time.ticks_ms())) + +# Start the StateMachine. +sm.active(1) diff --git a/examples/rp2/pio_exec.py b/examples/rp2/pio_exec.py new file mode 100644 index 000000000..d8cbc33ef --- /dev/null +++ b/examples/rp2/pio_exec.py @@ -0,0 +1,27 @@ +# Example using PIO to turn on an LED via an explicit exec. +# +# Demonstrates: +# - using set_init and set_base +# - using StateMachine.exec + +import time +from machine import Pin +import rp2 + +# Define an empty program that uses a single set pin. +@rp2.asm_pio(set_init=rp2.PIO.OUT_LOW) +def prog(): + pass + + +# Construct the StateMachine, binding Pin(25) to the set pin. +sm = rp2.StateMachine(0, prog, set_base=Pin(25)) + +# Turn on the set pin via an exec instruction. +sm.exec("set(pins, 1)") + +# Sleep for 500ms. +time.sleep(0.5) + +# Turn off the set pin via an exec instruction. +sm.exec("set(pins, 0)") diff --git a/examples/rp2/pio_pinchange.py b/examples/rp2/pio_pinchange.py new file mode 100644 index 000000000..767c8e78c --- /dev/null +++ b/examples/rp2/pio_pinchange.py @@ -0,0 +1,46 @@ +# Example using PIO to wait for a pin change and raise an IRQ. +# +# Demonstrates: +# - PIO wrapping +# - PIO wait instruction, waiting on an input pin +# - PIO irq instruction, in blocking mode with relative IRQ number +# - setting the in_base pin for a StateMachine +# - setting an irq handler for a StateMachine +# - instantiating 2x StateMachine's with the same program and different pins + +import time +from machine import Pin +import rp2 + + +@rp2.asm_pio() +def wait_pin_low(): + wrap_target() + + wait(0, pin, 0) + irq(block, rel(0)) + wait(1, pin, 0) + + wrap() + + +def handler(sm): + # Print a (wrapping) timestamp, and the state machine object. + print(time.ticks_ms(), sm) + + +# Instantiate StateMachine(0) with wait_pin_low program on Pin(16). +pin16 = Pin(16, Pin.IN, Pin.PULL_UP) +sm0 = rp2.StateMachine(0, wait_pin_low, in_base=pin16) +sm0.irq(handler) + +# Instantiate StateMachine(1) with wait_pin_low program on Pin(17). +pin17 = Pin(17, Pin.IN, Pin.PULL_UP) +sm1 = rp2.StateMachine(1, wait_pin_low, in_base=pin17) +sm1.irq(handler) + +# Start the StateMachine's running. +sm0.active(1) +sm1.active(1) + +# Now, when Pin(16) or Pin(17) is pulled low a message will be printed to the REPL. diff --git a/examples/rp2/pio_pwm.py b/examples/rp2/pio_pwm.py new file mode 100644 index 000000000..8e87448ca --- /dev/null +++ b/examples/rp2/pio_pwm.py @@ -0,0 +1,45 @@ +# Example of using PIO for PWM, and fading the brightness of an LED + +from machine import Pin +from rp2 import PIO, StateMachine, asm_pio +from time import sleep + + +@asm_pio(sideset_init=PIO.OUT_LOW) +def pwm_prog(): + # fmt: off + pull(noblock) .side(0) + mov(x, osr) # Keep most recent pull data stashed in X, for recycling by noblock + mov(y, isr) # ISR must be preloaded with PWM count max + label("pwmloop") + jmp(x_not_y, "skip") + nop() .side(1) + label("skip") + jmp(y_dec, "pwmloop") + # fmt: on + + +class PIOPWM: + def __init__(self, sm_id, pin, max_count, count_freq): + self._sm = StateMachine(sm_id, pwm_prog, freq=2 * count_freq, sideset_base=Pin(pin)) + # Use exec() to load max count into ISR + self._sm.put(max_count) + self._sm.exec("pull()") + self._sm.exec("mov(isr, osr)") + self._sm.active(1) + self._max_count = max_count + + def set(self, value): + # Minimum value is -1 (completely turn off), 0 actually still produces narrow pulse + value = max(value, -1) + value = min(value, self._max_count) + self._sm.put(value) + + +# Pin 25 is LED on Pico boards +pwm = PIOPWM(0, 25, max_count=(1 << 16) - 1, count_freq=10_000_000) + +while True: + for i in range(256): + pwm.set(i ** 2) + sleep(0.01) diff --git a/examples/rp2/pio_uart_tx.py b/examples/rp2/pio_uart_tx.py new file mode 100644 index 000000000..0f8c1260b --- /dev/null +++ b/examples/rp2/pio_uart_tx.py @@ -0,0 +1,44 @@ +# Example using PIO to create a UART TX interface + +from machine import Pin +from rp2 import PIO, StateMachine, asm_pio + +UART_BAUD = 115200 +PIN_BASE = 10 +NUM_UARTS = 8 + + +@asm_pio(sideset_init=PIO.OUT_HIGH, out_init=PIO.OUT_HIGH, out_shiftdir=PIO.SHIFT_RIGHT) +def uart_tx(): + # fmt: off + # Block with TX deasserted until data available + pull() + # Initialise bit counter, assert start bit for 8 cycles + set(x, 7) .side(0) [7] + # Shift out 8 data bits, 8 execution cycles per bit + label("bitloop") + out(pins, 1) [6] + jmp(x_dec, "bitloop") + # Assert stop bit for 8 cycles total (incl 1 for pull()) + nop() .side(1) [6] + # fmt: on + + +# Now we add 8 UART TXs, on pins 10 to 17. Use the same baud rate for all of them. +uarts = [] +for i in range(NUM_UARTS): + sm = StateMachine( + i, uart_tx, freq=8 * UART_BAUD, sideset_base=Pin(PIN_BASE + i), out_base=Pin(PIN_BASE + i) + ) + sm.active(1) + uarts.append(sm) + +# We can print characters from each UART by pushing them to the TX FIFO +def pio_uart_print(sm, s): + for c in s: + sm.put(ord(c)) + + +# Print a different message from each UART +for i, u in enumerate(uarts): + pio_uart_print(u, "Hello from UART {}!\n".format(i)) diff --git a/examples/rp2/pio_ws2812.py b/examples/rp2/pio_ws2812.py new file mode 100644 index 000000000..dd021a9d5 --- /dev/null +++ b/examples/rp2/pio_ws2812.py @@ -0,0 +1,59 @@ +# Example using PIO to drive a set of WS2812 LEDs. + +import array, time +from machine import Pin +import rp2 + +# Configure the number of WS2812 LEDs. +NUM_LEDS = 8 + + +@rp2.asm_pio( + sideset_init=rp2.PIO.OUT_LOW, + out_shiftdir=rp2.PIO.SHIFT_LEFT, + autopull=True, + pull_thresh=24, +) +def ws2812(): + # fmt: off + T1 = 2 + T2 = 5 + T3 = 3 + wrap_target() + label("bitloop") + out(x, 1) .side(0) [T3 - 1] + jmp(not_x, "do_zero") .side(1) [T1 - 1] + jmp("bitloop") .side(1) [T2 - 1] + label("do_zero") + nop() .side(0) [T2 - 1] + wrap() + # fmt: on + + +# Create the StateMachine with the ws2812 program, outputting on Pin(22). +sm = rp2.StateMachine(0, ws2812, freq=8_000_000, sideset_base=Pin(22)) + +# Start the StateMachine, it will wait for data on its FIFO. +sm.active(1) + +# Display a pattern on the LEDs via an array of LED RGB values. +ar = array.array("I", [0 for _ in range(NUM_LEDS)]) + +# Cycle colours. +for i in range(4 * NUM_LEDS): + for j in range(NUM_LEDS): + r = j * 100 // (NUM_LEDS - 1) + b = 100 - j * 100 // (NUM_LEDS - 1) + if j != i % NUM_LEDS: + r >>= 3 + b >>= 3 + ar[j] = r << 16 | b + sm.put(ar, 8) + time.sleep_ms(50) + +# Fade out. +for i in range(24): + for j in range(NUM_LEDS): + ar[j] = ar[j] >> 1 & 0x7F7F7F + sm.put(ar, 8) + time.sleep_ms(50) diff --git a/examples/rp2/pwm_fade.py b/examples/rp2/pwm_fade.py new file mode 100644 index 000000000..7264edaa2 --- /dev/null +++ b/examples/rp2/pwm_fade.py @@ -0,0 +1,25 @@ +# Example using PWM to fade an LED. + +import time +from machine import Pin, PWM + + +# Construct PWM object, with LED on Pin(25). +pwm = PWM(Pin(25)) + +# Set the PWM frequency. +pwm.freq(1000) + +# Fade the LED in and out a few times. +duty = 0 +direction = 1 +for _ in range(8 * 256): + duty += direction + if duty > 255: + duty = 255 + direction = -1 + elif duty < 0: + duty = 0 + direction = 1 + pwm.duty_u16(duty * duty) + time.sleep(0.001) |
