# Example using PIO to create a UART TX interface
# From https://github.com/micropython/micropython/blob/master/examples/rp2/pio_uart_tx.py
# Todo :
# - check stop bit instead of "waiting for it"
# - delay in detecting start bit in read mode : look for a solution
# - instruction can be sparse : sync with a loop
# - check PIO mov(x,osr); jmp(not_x) can be shortened in jmp(not_osre)
from machine import UART, Pin, freq
from rp2 import PIO, StateMachine, asm_pio
import time
UART_BAUD = 115200
PIN_BASE = 18
NUM_UARTS = 2
#freq(48000000)
@asm_pio(
sideset_init=PIO.OUT_HIGH,
out_init=PIO.OUT_HIGH,
out_shiftdir=PIO.SHIFT_RIGHT,
in_shiftdir=PIO.SHIFT_RIGHT,
autopush=True,
push_thresh=8)
def uart_tx():
# fmt: off
label("start")
# Block with TX deasserted until data available
pull()
# Check if the pulled value is zero #todo : jmp(not_osre) not equivalent?
mov(x,osr)
jmp(x_dec, "isRead")
# If pulled value ==0, set x (bit counter) to break length
# Otherwise, send normal character
set(x, 15) .side(0) [6]
set(y, 1)
jmp("bitloop")
label("isRead")
# If pulled value ==1, go to read mode
# Otherwise (value > 1), go to normal write mode
jmp(x_dec,"normal_write")
jmp("read")
label("normal_write")
set(x, 7) .side(0) [6]
set(y, 0)
# 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
nop() .side(1) [4]
# if normal byte was sent, go to start
jmp(not_y, "start")
# if BRK signal was sent, send SYNC = 0b01010101
set(x,4) [2] # complete previous stop bit
# Send SYNC (start + 0b01010101 + stop = 0b0101010101)
label("send_sync")
nop() .side(0) [7]
jmp(x_dec, "send_sync") .side(1) [7]
jmp("start")
label("read")
#wait(0, pin, 0) # wait for start bit
# equivalent to wait(0, pin, 0) but with OSR polling?
# issue : may cause a very slight delay (1/8 bit)
# to detect start bit
# todo : check if this can be done with sm.exec() to force jump
#jmp(not_osre, "start")
jmp(pin, "read")
# hello world toggle to debug (check that point was reached)
nop() .side(0)
jmp("read") .side(1)
set(x, 7) [7] # prepare counter
nop() [2] # set measurement at middle of the bit
label("readLoop")
in_(pins, 1) # get one bit
jmp(x_dec, "readLoop") [6] # repeat 7 times
wait(1, pin, 0) # wait for stop bit
push() # push read value
irq(block, rel(0))
#jmp(not_osre, "start") # if osr not empty, go to start
jmp("read") # otherwise wait for the next read
# fmt: on
def handler(stateMachine):
value = chr(stateMachine.get() >> 24)
print(f"Got char: {value}")
uarts = []
for i in range(NUM_UARTS):
sm = StateMachine(
i,
uart_tx,
freq=8 * UART_BAUD,
sideset_base=Pin(PIN_BASE + 2*i),
out_base=Pin(PIN_BASE + 2*i),
in_base=Pin(PIN_BASE + 2*i + 1),
jmp_pin=Pin(PIN_BASE + 2*i + 1)
)
sm.active(1)
sm.irq(handler)
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))
#uart1 = UART(1, baudrate=9600, tx=Pin(4), rx=Pin(5))
# Print a different message from each UART
#for i, u in enumerate(uarts):
# u.put(0) # send start BRK + SYNC
# pio_uart_print(u, "Hello {}!\n".format(i)) # print something
# u.put(1) # go to read mode
uarts[0].put(0)
pio_uart_print(uarts[0], "Hello {}!\n".format(i))
while uarts[0].tx_fifo() != 0:
time.sleep_ms(1)
uarts[0].put(1)
while uarts[0].tx_fifo() != 0:
time.sleep_ms(1)
uarts[1].put("U")