aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorDamien George2021-01-21 00:34:08 +1100
committerDamien George2021-01-30 00:42:29 +1100
commit469345e7285128739e2934e7934e107ffda79fc1 (patch)
treea410ce2d427770a01d5b6f4d1b3ff2fb342cd94b /examples
parentef3ee7aa1005cd1f15c2144d4b46feb792ab3185 (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.py35
-rw-r--r--examples/rp2/pio_exec.py27
-rw-r--r--examples/rp2/pio_pinchange.py46
-rw-r--r--examples/rp2/pio_pwm.py45
-rw-r--r--examples/rp2/pio_uart_tx.py44
-rw-r--r--examples/rp2/pio_ws2812.py59
-rw-r--r--examples/rp2/pwm_fade.py25
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)