Unverified Commit 355abd8c authored by Mykle's avatar Mykle Committed by GitHub

Add setInverted() options to SerialPIO (#1451)

Call `SerialPIO::setInverted(txinv, rxinv)` before `SerialPIO::begin()` to enable.

---------
Co-authored-by: default avatarMykle Hansen <mykle@mykle.com>
Co-authored-by: default avatarEarle F. Philhower, III <earlephilhower@yahoo.com>
parent b57ac668
...@@ -46,22 +46,24 @@ static pio_program_t *pio_make_uart_prog(int repl, const pio_program_t *pg) { ...@@ -46,22 +46,24 @@ static pio_program_t *pio_make_uart_prog(int repl, const pio_program_t *pg) {
return p; return p;
} }
static PIOProgram *_getTxProgram(int bits) { static PIOProgram *_getTxProgram(int bits, bool inverted) {
auto f = _txMap.find(bits); int key = inverted ? -bits : bits;
auto f = _txMap.find(key);
if (f == _txMap.end()) { if (f == _txMap.end()) {
pio_program_t * p = pio_make_uart_prog(bits, &pio_tx_program); pio_program_t * p = pio_make_uart_prog(bits, inverted ? &pio_tx_inv_program : &pio_tx_program);
_txMap.insert({bits, new PIOProgram(p)}); _txMap.insert({key, new PIOProgram(p)});
f = _txMap.find(bits); f = _txMap.find(key);
} }
return f->second; return f->second;
} }
static PIOProgram *_getRxProgram(int bits) { static PIOProgram *_getRxProgram(int bits, bool inverted) {
auto f = _rxMap.find(bits); int key = inverted ? -bits : bits;
auto f = _rxMap.find(key);
if (f == _rxMap.end()) { if (f == _rxMap.end()) {
pio_program_t * p = pio_make_uart_prog(bits, &pio_rx_program); pio_program_t * p = pio_make_uart_prog(bits, inverted ? &pio_rx_inv_program : &pio_rx_program);
_rxMap.insert({bits, new PIOProgram(p)}); _rxMap.insert({key, new PIOProgram(p)});
f = _rxMap.find(bits); f = _rxMap.find(key);
} }
return f->second; return f->second;
} }
...@@ -96,7 +98,7 @@ void __not_in_flash_func(SerialPIO::_handleIRQ)() { ...@@ -96,7 +98,7 @@ void __not_in_flash_func(SerialPIO::_handleIRQ)() {
return; return;
} }
while (!pio_sm_is_rx_fifo_empty(_rxPIO, _rxSM)) { while (!pio_sm_is_rx_fifo_empty(_rxPIO, _rxSM)) {
uint32_t decode = _rxPIO->rxf[_rxSM]; uint32_t decode = _rxPIO->rxf[_rxSM] ^ (_rxInverted ? 0xffffffff : 0);
decode >>= 33 - _rxBits; decode >>= 33 - _rxBits;
uint32_t val = 0; uint32_t val = 0;
for (int b = 0; b < _bits + 1; b++) { for (int b = 0; b < _bits + 1; b++) {
...@@ -189,7 +191,7 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) { ...@@ -189,7 +191,7 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
if (_tx != NOPIN) { if (_tx != NOPIN) {
_txBits = _bits + _stop + (_parity != UART_PARITY_NONE ? 1 : 0) + 1/*start bit*/; _txBits = _bits + _stop + (_parity != UART_PARITY_NONE ? 1 : 0) + 1/*start bit*/;
_txPgm = _getTxProgram(_txBits); _txPgm = _getTxProgram(_txBits, _txInverted);
int off; int off;
if (!_txPgm->prepare(&_txPIO, &_txSM, &off)) { if (!_txPgm->prepare(&_txPIO, &_txSM, &off)) {
DEBUGCORE("ERROR: Unable to allocate PIO TX UART, out of PIO resources\n"); 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) { ...@@ -216,7 +218,7 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
_reader = 0; _reader = 0;
_rxBits = 2 * (_bits + _stop + (_parity != UART_PARITY_NONE ? 1 : 0) + 1) - 1; _rxBits = 2 * (_bits + _stop + (_parity != UART_PARITY_NONE ? 1 : 0) + 1) - 1;
_rxPgm = _getRxProgram(_rxBits); _rxPgm = _getRxProgram(_rxBits, _rxInverted);
int off; int off;
if (!_rxPgm->prepare(&_rxPIO, &_rxSM, &off)) { if (!_rxPgm->prepare(&_rxPIO, &_rxSM, &off)) {
DEBUGCORE("ERROR: Unable to allocate PIO RX UART, out of PIO resources\n"); DEBUGCORE("ERROR: Unable to allocate PIO RX UART, out of PIO resources\n");
...@@ -346,6 +348,11 @@ void SerialPIO::flush() { ...@@ -346,6 +348,11 @@ void SerialPIO::flush() {
delay((1000 * (_txBits + 1)) / _baud); delay((1000 * (_txBits + 1)) / _baud);
} }
void SerialPIO::setInverted(bool invTx, bool invRx) {
_txInverted = invTx;
_rxInverted = invRx;
}
size_t SerialPIO::write(uint8_t c) { size_t SerialPIO::write(uint8_t c) {
CoreMutex m(&_mutex); CoreMutex m(&_mutex);
if (!_running || !m || (_tx == NOPIN)) { if (!_running || !m || (_tx == NOPIN)) {
...@@ -364,7 +371,7 @@ size_t SerialPIO::write(uint8_t c) { ...@@ -364,7 +371,7 @@ size_t SerialPIO::write(uint8_t c) {
} }
val <<= 1; // Start bit = low val <<= 1; // Start bit = low
pio_sm_put_blocking(_txPIO, _txSM, val); pio_sm_put_blocking(_txPIO, _txSM, _txInverted ? ~val : val);
return 1; return 1;
} }
......
...@@ -41,6 +41,8 @@ public: ...@@ -41,6 +41,8 @@ public:
void begin(unsigned long baud, uint16_t config) override; void begin(unsigned long baud, uint16_t config) override;
void end() override; void end() override;
void setInverted(bool invTx = true, bool invRx = true);
virtual int peek() override; virtual int peek() override;
virtual int read() override; virtual int read() override;
virtual int available() override; virtual int available() override;
...@@ -63,6 +65,8 @@ protected: ...@@ -63,6 +65,8 @@ protected:
int _stop; int _stop;
bool _overflow; bool _overflow;
mutex_t _mutex; mutex_t _mutex;
bool _txInverted = false;
bool _rxInverted = false;
PIOProgram *_txPgm; PIOProgram *_txPgm;
PIO _txPIO; PIO _txPIO;
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
; We shift out the start and stop bit as part of the FIFO ; We shift out the start and stop bit as part of the FIFO
set x, 9 set x, 9
pull side 1 ; Force stop bit pull side 1 ; Force stop bit high
; Send the bits ; Send the bits
bitloop: bitloop:
...@@ -41,6 +41,26 @@ wait_bit: ...@@ -41,6 +41,26 @@ wait_bit:
; inverted-logic version (inverts the stop bit)
.program pio_tx_inv
.side_set 1 opt
; We shift out the start and stop bit as part of the FIFO
set x, 9
pull side 0 ; Force stop bit low
; Send the bits
bitloop:
out pins, 1
mov y, isr ; ISR is loaded by the setup routine with the period-1 count
wait_bit:
jmp y-- wait_bit
jmp x-- bitloop
% c-sdk { % c-sdk {
static inline void pio_tx_program_init(PIO pio, uint sm, uint offset, uint pin_tx) { 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 ...@@ -68,7 +88,7 @@ static inline void pio_tx_program_init(PIO pio, uint sm, uint offset, uint pin_t
} }
%} %}
.program pio_rx .program pio_rx
...@@ -91,6 +111,27 @@ wait_half: ...@@ -91,6 +111,27 @@ wait_half:
push ; Stuff it and wait for next start push ; Stuff it and wait for next start
.program pio_rx_inv
; 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)
wait 1 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
; 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
% c-sdk { % c-sdk {
static inline void pio_rx_program_init(PIO pio, uint sm, uint offset, uint pin) { static inline void pio_rx_program_init(PIO pio, uint sm, uint offset, uint pin) {
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false); pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// This file is autogenerated by pioasm; do not edit! // // This file is autogenerated by pioasm; do not edit! //
// -------------------------------------------------- // // -------------------------------------------------- //
#pragma once
#if !PICO_NO_HARDWARE #if !PICO_NO_HARDWARE
#include "hardware/pio.h" #include "hardware/pio.h"
#endif #endif
...@@ -37,6 +39,39 @@ static inline pio_sm_config pio_tx_program_get_default_config(uint offset) { ...@@ -37,6 +39,39 @@ static inline pio_sm_config pio_tx_program_get_default_config(uint offset) {
sm_config_set_sideset(&c, 2, true, false); sm_config_set_sideset(&c, 2, true, false);
return c; return c;
} }
#endif
// ---------- //
// pio_tx_inv //
// ---------- //
#define pio_tx_inv_wrap_target 0
#define pio_tx_inv_wrap 5
static const uint16_t pio_tx_inv_program_instructions[] = {
// .wrap_target
0xe029, // 0: set x, 9
0x90a0, // 1: pull block side 0
0x6001, // 2: out pins, 1
0xa046, // 3: mov y, isr
0x0084, // 4: jmp y--, 4
0x0042, // 5: jmp x--, 2
// .wrap
};
#if !PICO_NO_HARDWARE
static const struct pio_program pio_tx_inv_program = {
.instructions = pio_tx_inv_program_instructions,
.length = 6,
.origin = -1,
};
static inline pio_sm_config pio_tx_inv_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + pio_tx_inv_wrap_target, offset + pio_tx_inv_wrap);
sm_config_set_sideset(&c, 2, true, false);
return c;
}
static inline void pio_tx_program_init(PIO pio, uint sm, uint offset, uint pin_tx) { static inline void pio_tx_program_init(PIO pio, uint sm, uint offset, uint pin_tx) {
// Tell PIO to initially drive output-high on the selected pin, then map PIO // 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) { ...@@ -90,6 +125,39 @@ static inline pio_sm_config pio_rx_program_get_default_config(uint offset) {
sm_config_set_wrap(&c, offset + pio_rx_wrap_target, offset + pio_rx_wrap); sm_config_set_wrap(&c, offset + pio_rx_wrap_target, offset + pio_rx_wrap);
return c; return c;
} }
#endif
// ---------- //
// pio_rx_inv //
// ---------- //
#define pio_rx_inv_wrap_target 0
#define pio_rx_inv_wrap 6
static const uint16_t pio_rx_inv_program_instructions[] = {
// .wrap_target
0xe032, // 0: set x, 18
0x20a0, // 1: wait 1 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
// .wrap
};
#if !PICO_NO_HARDWARE
static const struct pio_program pio_rx_inv_program = {
.instructions = pio_rx_inv_program_instructions,
.length = 7,
.origin = -1,
};
static inline pio_sm_config pio_rx_inv_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + pio_rx_inv_wrap_target, offset + pio_rx_inv_wrap);
return c;
}
static inline void pio_rx_program_init(PIO pio, uint sm, uint offset, uint pin) { static inline void pio_rx_program_init(PIO pio, uint sm, uint offset, uint pin) {
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false); pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment