95 lines
3.4 KiB
Plaintext
95 lines
3.4 KiB
Plaintext
|
;
|
||
|
; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||
|
;
|
||
|
; SPDX-License-Identifier: BSD-3-Clause
|
||
|
;
|
||
|
|
||
|
.program uart_rx_mini
|
||
|
|
||
|
; Minimum viable 8n1 UART receiver. Wait for the start bit, then sample 8 bits
|
||
|
; with the correct timing.
|
||
|
; IN pin 0 is mapped to the GPIO used as UART RX.
|
||
|
; Autopush must be enabled, with a threshold of 8.
|
||
|
|
||
|
wait 0 pin 0 ; Wait for start bit
|
||
|
set x, 7 [10] ; Preload bit counter, delay until eye of first data bit
|
||
|
bitloop: ; Loop 8 times
|
||
|
in pins, 1 ; Sample data
|
||
|
jmp x-- bitloop [6] ; Each iteration is 8 cycles
|
||
|
|
||
|
% c-sdk {
|
||
|
#include "hardware/clocks.h"
|
||
|
#include "hardware/gpio.h"
|
||
|
|
||
|
static inline void uart_rx_mini_program_init(PIO pio, uint sm, uint offset, uint pin, uint baud) {
|
||
|
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
|
||
|
pio_gpio_init(pio, pin);
|
||
|
gpio_pull_up(pin);
|
||
|
|
||
|
pio_sm_config c = uart_rx_mini_program_get_default_config(offset);
|
||
|
sm_config_set_in_pins(&c, pin); // for WAIT, IN
|
||
|
// Shift to right, autopush enabled
|
||
|
sm_config_set_in_shift(&c, true, true, 8);
|
||
|
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
|
||
|
// SM transmits 1 bit per 8 execution cycles.
|
||
|
float div = (float)clock_get_hz(clk_sys) / (8 * baud);
|
||
|
sm_config_set_clkdiv(&c, div);
|
||
|
|
||
|
pio_sm_init(pio, sm, offset, &c);
|
||
|
pio_sm_set_enabled(pio, sm, true);
|
||
|
}
|
||
|
%}
|
||
|
|
||
|
.program uart_rx
|
||
|
|
||
|
; Slightly more fleshed-out 8n1 UART receiver which handles framing errors and
|
||
|
; break conditions more gracefully.
|
||
|
; IN pin 0 and JMP pin are both mapped to the GPIO used as UART RX.
|
||
|
|
||
|
start:
|
||
|
wait 0 pin 0 ; Stall until start bit is asserted
|
||
|
set x, 7 [10] ; Preload bit counter, then delay until halfway through
|
||
|
bitloop: ; the first data bit (12 cycles incl wait, set).
|
||
|
in pins, 1 ; Shift data bit into ISR
|
||
|
jmp x-- bitloop [6] ; Loop 8 times, each loop iteration is 8 cycles
|
||
|
jmp pin good_stop ; Check stop bit (should be high)
|
||
|
|
||
|
irq 4 rel ; Either a framing error or a break. Set a sticky flag,
|
||
|
wait 1 pin 0 ; and wait for line to return to idle state.
|
||
|
jmp start ; Don't push data if we didn't see good framing.
|
||
|
|
||
|
good_stop: ; No delay before returning to start; a little slack is
|
||
|
push ; important in case the TX clock is slightly too fast.
|
||
|
|
||
|
|
||
|
% c-sdk {
|
||
|
static inline void uart_rx_program_init(PIO pio, uint sm, uint offset, uint pin, uint baud) {
|
||
|
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
|
||
|
pio_gpio_init(pio, pin);
|
||
|
gpio_pull_up(pin);
|
||
|
|
||
|
pio_sm_config c = uart_rx_program_get_default_config(offset);
|
||
|
sm_config_set_in_pins(&c, pin); // for WAIT, IN
|
||
|
sm_config_set_jmp_pin(&c, pin); // for JMP
|
||
|
// Shift to right, autopush disabled
|
||
|
sm_config_set_in_shift(&c, true, false, 32);
|
||
|
// Deeper FIFO as we're not doing any TX
|
||
|
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
|
||
|
// SM transmits 1 bit per 8 execution cycles.
|
||
|
float div = (float)clock_get_hz(clk_sys) / (8 * baud);
|
||
|
sm_config_set_clkdiv(&c, div);
|
||
|
|
||
|
pio_sm_init(pio, sm, offset, &c);
|
||
|
pio_sm_set_enabled(pio, sm, true);
|
||
|
}
|
||
|
|
||
|
static inline char uart_rx_program_getc(PIO pio, uint sm) {
|
||
|
// 8-bit read from the uppermost byte of the FIFO, as data is left-justified
|
||
|
io_rw_8 *rxfifo_shift = (io_rw_8*)&pio->rxf[sm] + 3;
|
||
|
while (pio_sm_is_rx_fifo_empty(pio, sm))
|
||
|
tight_loop_contents();
|
||
|
return (char)*rxfifo_shift;
|
||
|
}
|
||
|
|
||
|
%}
|