Skip to content

Rewrite SerialPIO receive path, ensure proper edge #2929

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions cores/rp2040/SerialPIO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ static PIOProgram *_getRxProgram(int bits) {
// ------------------------------------------------------------------------

// TODO - this works, but there must be a faster/better way...
static int _parity(int bits, int data) {
static int __not_in_flash_func(_parity)(int bits, int data) {
int p = 0;
for (int b = 0; b < bits; b++) {
p ^= (data & (1 << b)) ? 1 : 0;
Expand Down Expand Up @@ -98,11 +98,7 @@ void __not_in_flash_func(SerialPIO::_handleIRQ)() {
}
while (!pio_sm_is_rx_fifo_empty(_rxPIO, _rxSM)) {
uint32_t decode = _rxPIO->rxf[_rxSM];
decode >>= 33 - _rxBits;
uint32_t val = 0;
for (int b = 0; b < _bits + 1; b++) {
val |= (decode & (1 << (b * 2))) ? 1 << b : 0;
}
uint32_t val = decode >> (32 - _rxBits - 1);
if (_parity == UART_PARITY_EVEN) {
int p = ::_parity(_bits, val);
int r = (val & (1 << _bits)) ? 1 : 0;
Expand Down Expand Up @@ -234,7 +230,7 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
_writer = 0;
_reader = 0;

_rxBits = 2 * (_bits + _stop + (_parity != UART_PARITY_NONE ? 1 : 0) + 1) - 1;
_rxBits = _bits + (_parity != UART_PARITY_NONE ? 1 : 0);
_rxPgm = _getRxProgram(_rxBits);
int off;
if (!_rxPgm->prepare(&_rxPIO, &_rxSM, &off, _rx, 1)) {
Expand All @@ -249,7 +245,7 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
pio_sm_clear_fifos(_rxPIO, _rxSM); // Remove any existing data

// Put phase divider into OSR w/o using add'l program memory
pio_sm_put_blocking(_rxPIO, _rxSM, clock_get_hz(clk_sys) / (_baud * 2) - 7 /* insns in PIO halfbit loop */);
pio_sm_put_blocking(_rxPIO, _rxSM, clock_get_hz(clk_sys) / (_baud * 2) - 3);
pio_sm_exec(_rxPIO, _rxSM, pio_encode_pull(false, false));

// Join the TX FIFO to the RX one now that we don't need it
Expand Down
23 changes: 14 additions & 9 deletions cores/rp2040/pio_uart.pio
Original file line number Diff line number Diff line change
Expand Up @@ -73,20 +73,25 @@ static inline void pio_tx_program_init(PIO pio, uint sm, uint offset, uint pin_t
; IN pin 0 and JMP pin are both mapped to the GPIO used as UART RX.

start:
set x, 18 ; Preload bit counter...we'll shift in the start bit and stop bit, and each bit will be double-recorded (to be fixed by RP2040 code)
set x, 18 ; Preload bit counter...overwritten by the app
wait 0 pin 0 ; Stall until start bit is asserted

bitloop:
; Delay until 1/2 way into the bit time
mov y, osr
wait_half:
jmp y-- wait_half
wait_mid_start:
jmp y-- wait_mid_start

; Read in the bit
in pins, 1 ; Shift data bit into ISR
jmp x-- bitloop ; Loop all bits

push ; Stuff it and wait for next start
bitloop:
mov y, osr
bitloop1:
jmp y-- bitloop1
mov y, osr
bitloop2:
jmp y-- bitloop2

in pins, 1
jmp x-- bitloop
push

% c-sdk {
static inline void pio_rx_program_init(PIO pio, uint sm, uint offset, uint pin) {
Expand Down
14 changes: 9 additions & 5 deletions cores/rp2040/pio_uart.pio.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ static inline void pio_tx_program_init(PIO pio, uint sm, uint offset, uint pin_t
// ------ //

#define pio_rx_wrap_target 0
#define pio_rx_wrap 6
#define pio_rx_wrap 10
#define pio_rx_pio_version 0

static const uint16_t pio_rx_program_instructions[] = {
Expand All @@ -80,16 +80,20 @@ static const uint16_t pio_rx_program_instructions[] = {
0x2020, // 1: wait 0 pin, 0
0xa047, // 2: mov y, osr
0x0083, // 3: jmp y--, 3
0x4001, // 4: in pins, 1
0x0042, // 5: jmp x--, 2
0x8020, // 6: push block
0xa047, // 4: mov y, osr
0x0085, // 5: jmp y--, 5
0xa047, // 6: mov y, osr
0x0087, // 7: jmp y--, 7
0x4001, // 8: in pins, 1
0x0044, // 9: jmp x--, 4
0x8020, // 10: push block
// .wrap
};

#if !PICO_NO_HARDWARE
static const struct pio_program pio_rx_program = {
.instructions = pio_rx_program_instructions,
.length = 7,
.length = 11,
.origin = -1,
.pio_version = 0,
#if PICO_PIO_VERSION > 0
Expand Down