Skip to content

Commit 355abd8

Browse files
myklemykleMykle Hansenearlephilhower
authored
Add setInverted() options to SerialPIO (#1451)
Call `SerialPIO::setInverted(txinv, rxinv)` before `SerialPIO::begin()` to enable. --------- Co-authored-by: Mykle Hansen <[email protected]> Co-authored-by: Earle F. Philhower, III <[email protected]>
1 parent b57ac66 commit 355abd8

File tree

4 files changed

+136
-16
lines changed

4 files changed

+136
-16
lines changed

cores/rp2040/SerialPIO.cpp

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -46,22 +46,24 @@ static pio_program_t *pio_make_uart_prog(int repl, const pio_program_t *pg) {
4646
return p;
4747
}
4848

49-
static PIOProgram *_getTxProgram(int bits) {
50-
auto f = _txMap.find(bits);
49+
static PIOProgram *_getTxProgram(int bits, bool inverted) {
50+
int key = inverted ? -bits : bits;
51+
auto f = _txMap.find(key);
5152
if (f == _txMap.end()) {
52-
pio_program_t * p = pio_make_uart_prog(bits, &pio_tx_program);
53-
_txMap.insert({bits, new PIOProgram(p)});
54-
f = _txMap.find(bits);
53+
pio_program_t * p = pio_make_uart_prog(bits, inverted ? &pio_tx_inv_program : &pio_tx_program);
54+
_txMap.insert({key, new PIOProgram(p)});
55+
f = _txMap.find(key);
5556
}
5657
return f->second;
5758
}
5859

59-
static PIOProgram *_getRxProgram(int bits) {
60-
auto f = _rxMap.find(bits);
60+
static PIOProgram *_getRxProgram(int bits, bool inverted) {
61+
int key = inverted ? -bits : bits;
62+
auto f = _rxMap.find(key);
6163
if (f == _rxMap.end()) {
62-
pio_program_t * p = pio_make_uart_prog(bits, &pio_rx_program);
63-
_rxMap.insert({bits, new PIOProgram(p)});
64-
f = _rxMap.find(bits);
64+
pio_program_t * p = pio_make_uart_prog(bits, inverted ? &pio_rx_inv_program : &pio_rx_program);
65+
_rxMap.insert({key, new PIOProgram(p)});
66+
f = _rxMap.find(key);
6567
}
6668
return f->second;
6769
}
@@ -96,7 +98,7 @@ void __not_in_flash_func(SerialPIO::_handleIRQ)() {
9698
return;
9799
}
98100
while (!pio_sm_is_rx_fifo_empty(_rxPIO, _rxSM)) {
99-
uint32_t decode = _rxPIO->rxf[_rxSM];
101+
uint32_t decode = _rxPIO->rxf[_rxSM] ^ (_rxInverted ? 0xffffffff : 0);
100102
decode >>= 33 - _rxBits;
101103
uint32_t val = 0;
102104
for (int b = 0; b < _bits + 1; b++) {
@@ -189,7 +191,7 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
189191

190192
if (_tx != NOPIN) {
191193
_txBits = _bits + _stop + (_parity != UART_PARITY_NONE ? 1 : 0) + 1/*start bit*/;
192-
_txPgm = _getTxProgram(_txBits);
194+
_txPgm = _getTxProgram(_txBits, _txInverted);
193195
int off;
194196
if (!_txPgm->prepare(&_txPIO, &_txSM, &off)) {
195197
DEBUGCORE("ERROR: Unable to allocate PIO TX UART, out of PIO resources\n");
@@ -216,7 +218,7 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
216218
_reader = 0;
217219

218220
_rxBits = 2 * (_bits + _stop + (_parity != UART_PARITY_NONE ? 1 : 0) + 1) - 1;
219-
_rxPgm = _getRxProgram(_rxBits);
221+
_rxPgm = _getRxProgram(_rxBits, _rxInverted);
220222
int off;
221223
if (!_rxPgm->prepare(&_rxPIO, &_rxSM, &off)) {
222224
DEBUGCORE("ERROR: Unable to allocate PIO RX UART, out of PIO resources\n");
@@ -346,6 +348,11 @@ void SerialPIO::flush() {
346348
delay((1000 * (_txBits + 1)) / _baud);
347349
}
348350

351+
void SerialPIO::setInverted(bool invTx, bool invRx) {
352+
_txInverted = invTx;
353+
_rxInverted = invRx;
354+
}
355+
349356
size_t SerialPIO::write(uint8_t c) {
350357
CoreMutex m(&_mutex);
351358
if (!_running || !m || (_tx == NOPIN)) {
@@ -364,7 +371,7 @@ size_t SerialPIO::write(uint8_t c) {
364371
}
365372
val <<= 1; // Start bit = low
366373

367-
pio_sm_put_blocking(_txPIO, _txSM, val);
374+
pio_sm_put_blocking(_txPIO, _txSM, _txInverted ? ~val : val);
368375

369376
return 1;
370377
}

cores/rp2040/SerialPIO.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ class SerialPIO : public HardwareSerial {
4141
void begin(unsigned long baud, uint16_t config) override;
4242
void end() override;
4343

44+
void setInverted(bool invTx = true, bool invRx = true);
45+
4446
virtual int peek() override;
4547
virtual int read() override;
4648
virtual int available() override;
@@ -63,6 +65,8 @@ class SerialPIO : public HardwareSerial {
6365
int _stop;
6466
bool _overflow;
6567
mutex_t _mutex;
68+
bool _txInverted = false;
69+
bool _rxInverted = false;
6670

6771
PIOProgram *_txPgm;
6872
PIO _txPIO;

cores/rp2040/pio_uart.pio

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
; We shift out the start and stop bit as part of the FIFO
3030
set x, 9
3131

32-
pull side 1 ; Force stop bit
32+
pull side 1 ; Force stop bit high
3333

3434
; Send the bits
3535
bitloop:
@@ -41,6 +41,26 @@ wait_bit:
4141

4242

4343

44+
; inverted-logic version (inverts the stop bit)
45+
46+
.program pio_tx_inv
47+
.side_set 1 opt
48+
49+
50+
; We shift out the start and stop bit as part of the FIFO
51+
set x, 9
52+
53+
pull side 0 ; Force stop bit low
54+
55+
; Send the bits
56+
bitloop:
57+
out pins, 1
58+
mov y, isr ; ISR is loaded by the setup routine with the period-1 count
59+
wait_bit:
60+
jmp y-- wait_bit
61+
jmp x-- bitloop
62+
63+
4464
% c-sdk {
4565

4666
static inline void pio_tx_program_init(PIO pio, uint sm, uint offset, uint pin_tx) {
@@ -68,7 +88,7 @@ static inline void pio_tx_program_init(PIO pio, uint sm, uint offset, uint pin_t
6888
}
6989

7090
%}
71-
91+
7292

7393
.program pio_rx
7494

@@ -91,6 +111,27 @@ wait_half:
91111
push ; Stuff it and wait for next start
92112

93113

114+
.program pio_rx_inv
115+
116+
; IN pin 0 and JMP pin are both mapped to the GPIO used as UART RX.
117+
118+
start:
119+
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)
120+
wait 1 pin 0 ; Stall until start bit is asserted
121+
122+
bitloop:
123+
; Delay until 1/2 way into the bit time
124+
mov y, osr
125+
wait_half:
126+
jmp y-- wait_half
127+
128+
; Read in the bit
129+
in pins, 1 ; Shift data bit into ISR
130+
jmp x-- bitloop ; Loop all bits
131+
132+
push ; Stuff it and wait for next start
133+
134+
94135
% c-sdk {
95136
static inline void pio_rx_program_init(PIO pio, uint sm, uint offset, uint pin) {
96137
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);

cores/rp2040/pio_uart.pio.h

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// This file is autogenerated by pioasm; do not edit! //
33
// -------------------------------------------------- //
44

5+
#pragma once
6+
57
#if !PICO_NO_HARDWARE
68
#include "hardware/pio.h"
79
#endif
@@ -37,6 +39,39 @@ static inline pio_sm_config pio_tx_program_get_default_config(uint offset) {
3739
sm_config_set_sideset(&c, 2, true, false);
3840
return c;
3941
}
42+
#endif
43+
44+
// ---------- //
45+
// pio_tx_inv //
46+
// ---------- //
47+
48+
#define pio_tx_inv_wrap_target 0
49+
#define pio_tx_inv_wrap 5
50+
51+
static const uint16_t pio_tx_inv_program_instructions[] = {
52+
// .wrap_target
53+
0xe029, // 0: set x, 9
54+
0x90a0, // 1: pull block side 0
55+
0x6001, // 2: out pins, 1
56+
0xa046, // 3: mov y, isr
57+
0x0084, // 4: jmp y--, 4
58+
0x0042, // 5: jmp x--, 2
59+
// .wrap
60+
};
61+
62+
#if !PICO_NO_HARDWARE
63+
static const struct pio_program pio_tx_inv_program = {
64+
.instructions = pio_tx_inv_program_instructions,
65+
.length = 6,
66+
.origin = -1,
67+
};
68+
69+
static inline pio_sm_config pio_tx_inv_program_get_default_config(uint offset) {
70+
pio_sm_config c = pio_get_default_sm_config();
71+
sm_config_set_wrap(&c, offset + pio_tx_inv_wrap_target, offset + pio_tx_inv_wrap);
72+
sm_config_set_sideset(&c, 2, true, false);
73+
return c;
74+
}
4075

4176
static inline void pio_tx_program_init(PIO pio, uint sm, uint offset, uint pin_tx) {
4277
// Tell PIO to initially drive output-high on the selected pin, then map PIO
@@ -90,6 +125,39 @@ static inline pio_sm_config pio_rx_program_get_default_config(uint offset) {
90125
sm_config_set_wrap(&c, offset + pio_rx_wrap_target, offset + pio_rx_wrap);
91126
return c;
92127
}
128+
#endif
129+
130+
// ---------- //
131+
// pio_rx_inv //
132+
// ---------- //
133+
134+
#define pio_rx_inv_wrap_target 0
135+
#define pio_rx_inv_wrap 6
136+
137+
static const uint16_t pio_rx_inv_program_instructions[] = {
138+
// .wrap_target
139+
0xe032, // 0: set x, 18
140+
0x20a0, // 1: wait 1 pin, 0
141+
0xa047, // 2: mov y, osr
142+
0x0083, // 3: jmp y--, 3
143+
0x4001, // 4: in pins, 1
144+
0x0042, // 5: jmp x--, 2
145+
0x8020, // 6: push block
146+
// .wrap
147+
};
148+
149+
#if !PICO_NO_HARDWARE
150+
static const struct pio_program pio_rx_inv_program = {
151+
.instructions = pio_rx_inv_program_instructions,
152+
.length = 7,
153+
.origin = -1,
154+
};
155+
156+
static inline pio_sm_config pio_rx_inv_program_get_default_config(uint offset) {
157+
pio_sm_config c = pio_get_default_sm_config();
158+
sm_config_set_wrap(&c, offset + pio_rx_inv_wrap_target, offset + pio_rx_inv_wrap);
159+
return c;
160+
}
93161

94162
static inline void pio_rx_program_init(PIO pio, uint sm, uint offset, uint pin) {
95163
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);

0 commit comments

Comments
 (0)