micropython: add micropython component

This commit is contained in:
KY-zhang-X
2022-09-29 12:10:37 +08:00
parent 1514f1cb9b
commit dd76146324
2679 changed files with 354110 additions and 0 deletions

View File

@@ -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)

View File

@@ -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)")

View File

@@ -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.

View File

@@ -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)

View File

@@ -0,0 +1,105 @@
# Example using PIO to create a UART RX interface.
#
# To make it work you'll need a wire connecting GPIO4 and GPIO3.
#
# Demonstrates:
# - PIO shifting in data on a pin
# - PIO jmp(pin) instruction
# - PIO irq handler
# - using the second core via _thread
import _thread
from machine import Pin, UART
from rp2 import PIO, StateMachine, asm_pio
UART_BAUD = 9600
HARD_UART_TX_PIN = Pin(4, Pin.OUT)
PIO_RX_PIN = Pin(3, Pin.IN, Pin.PULL_UP)
@asm_pio(
autopush=True,
push_thresh=8,
in_shiftdir=rp2.PIO.SHIFT_RIGHT,
fifo_join=PIO.JOIN_RX,
)
def uart_rx_mini():
# fmt: off
# Wait for start bit
wait(0, pin, 0)
# Preload bit counter, delay until eye of first data bit
set(x, 7) [10]
# Loop 8 times
label("bitloop")
# Sample data
in_(pins, 1)
# Each iteration is 8 cycles
jmp(x_dec, "bitloop") [6]
# fmt: on
@asm_pio(
in_shiftdir=rp2.PIO.SHIFT_RIGHT,
)
def uart_rx():
# fmt: off
label("start")
# Stall until start bit is asserted
wait(0, pin, 0)
# Preload bit counter, then delay until halfway through
# the first data bit (12 cycles incl wait, set).
set(x, 7) [10]
label("bitloop")
# Shift data bit into ISR
in_(pins, 1)
# Loop 8 times, each loop iteration is 8 cycles
jmp(x_dec, "bitloop") [6]
# Check stop bit (should be high)
jmp(pin, "good_stop")
# Either a framing error or a break. Set a sticky flag
# and wait for line to return to idle state.
irq(block, 4)
wait(1, pin, 0)
# Don't push data if we didn't see good framing.
jmp("start")
# No delay before returning to start; a little slack is
# important in case the TX clock is slightly too fast.
label("good_stop")
push(block)
# fmt: on
# The handler for a UART break detected by the PIO.
def handler(sm):
print("break", time.ticks_ms(), end=" ")
# Function for core1 to execute to write to the given UART.
def core1_task(uart, text):
uart.write(text)
# Set up the hard UART we're going to use to print characters.
uart = UART(1, UART_BAUD, tx=HARD_UART_TX_PIN)
for pio_prog in ("uart_rx_mini", "uart_rx"):
# Set up the state machine we're going to use to receive the characters.
sm = StateMachine(
0,
globals()[pio_prog],
freq=8 * UART_BAUD,
in_base=PIO_RX_PIN, # For WAIT, IN
jmp_pin=PIO_RX_PIN, # For JMP
)
sm.irq(handler)
sm.active(1)
# Tell core 1 to print some text to UART 1
text = "Hello, world from PIO, using {}!".format(pio_prog)
_thread.start_new_thread(core1_task, (uart, text))
# Echo characters received from PIO to the console.
for i in range(len(text)):
print(chr(sm.get() >> 24), end="")
print()

View File

@@ -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))

View File

@@ -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)

View File

@@ -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)