summaryrefslogtreecommitdiffstatshomepage
path: root/examples/rp2/pio_uart_rx.py
blob: f46aaa6a5e38848793ae3f84a9b35496f62a34b1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# 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

# ruff: noqa: F821 - @asm_pio decorator adds names to function scope

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