23#include "hardware/gpio.h"
24#include "hardware/pio.h"
25#include "hardware/platform_defs.h"
26#include "hardware/regs/pio.h"
28#include "pico/types.h"
37#include "led_activity_mirror.pio.h"
38#include "rck_rxd.pio.h"
39#include "tck_txd.pio.h"
40#include "xck_txd.pio.h"
45#define V24_RTS_MIN_HOLDOFF 200U
51#define V24_RTS_HOLDOFF_MARGIN 41U
68 uint32_t events = gpio_get_irq_event_mask(
V24_CTS);
69 uint32_t mask = GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE;
72 gpio_acknowledge_irq(
V24_CTS, events & mask);
79 static bool initialized =
false;
86 gpio_set_irq_enabled(
V24_CTS, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE,
true);
87 irq_set_enabled(IO_IRQ_BANK0,
true);
97 return GPIO_FUNC_PIO0;
101 return GPIO_FUNC_PIO1;
103 return GPIO_FUNC_NULL;
112#define LED_MIRROR_PIO pio0
118 int pio_sm = pio_claim_unused_sm(pio,
false);
121 LOG_ERROR(
"LED mirror: no free SM on pio0\r\n");
124 LOG_INFO(
"LED Mirror: init pio%u sm%u \r\n", (
unsigned)pio_get_index(pio), (
unsigned)pio_sm);
126 if (!pio_can_add_program(pio, &led_mirror_program))
128 LOG_ERROR(
"LED mirror: no room for program on pio0\r\n");
129 pio_sm_unclaim(pio, (uint)pio_sm);
133 uint offset = pio_add_program(pio, &led_mirror_program);
135 pio_sm_config cfg = led_mirror_program_get_default_config(offset);
137 sm_config_set_jmp_pin(&cfg,
V24_TXD);
138 sm_config_set_in_pins(&cfg,
V24_RXD);
139 sm_config_set_in_shift(&cfg,
false,
false,
sizeof(uint32_t) * CHAR_BIT);
142 pio_sm_set_consecutive_pindirs(pio, (uint)pio_sm,
V24_STATUS_LED, 1,
true);
145 pio_sm_init(pio, (uint)pio_sm, offset, &cfg);
146 pio_sm_set_enabled(pio, (uint)pio_sm,
true);
148 LOG_INFO(
"LED mirror: enabled on pio%u sm%d offset=%u\r\n", (
unsigned)pio_get_index(pio),
149 pio_sm, (
unsigned)offset);
155 uint32_t t_bit_us = (
US_PER_SECOND + (uint32_t)baudrate - 1U) / (uint32_t)baudrate;
174 uint32_t rx_stall_mask = (1U << (PIO_FDEBUG_RXSTALL_LSB +
v24_runtime.
rx_sm));
203 polarities->
rxc_inverted ? GPIO_OVERRIDE_INVERT : GPIO_OVERRIDE_NORMAL);
205 polarities->
rxd_inverted ? GPIO_OVERRIDE_INVERT : GPIO_OVERRIDE_NORMAL);
207 polarities->
dcd_inverted ? GPIO_OVERRIDE_INVERT : GPIO_OVERRIDE_NORMAL);
227 LOG_INFO(
"RXC: init pio%u sm%u pin%u\r\n", (
unsigned)pio_get_index(pio), (
unsigned)pio_sm,
230 pio_sm_claim(pio, pio_sm);
234 uint offset = pio_add_program(pio, &rck_rxd_program);
235 LOG_INFO(
"RXC: program offset=%u\r\n", (
unsigned)offset);
239 pio_sm_set_consecutive_pindirs(pio, pio_sm,
V24_RXD, 1,
false);
241 pio_sm_set_consecutive_pindirs(pio, pio_sm,
V24_RXC, 1,
false);
244 pio_sm_config config = rck_rxd_program_get_default_config(offset);
245 sm_config_set_jmp_pin(&config,
V24_RXC);
246 sm_config_set_in_pins(&config,
V24_RXD);
247 sm_config_set_in_shift(&config,
true,
true, CHAR_BIT);
249 sm_config_set_fifo_join(&config, PIO_FIFO_JOIN_RX);
250 pio_sm_init(pio, pio_sm, offset, &config);
259 static bool deassert_pending =
false;
260 static uint64_t deassert_deadline_us = 0;
264 deassert_pending =
false;
271 bool ready_to_deassert = (fifo_empty || stalled);
273 uint64_t now_us = to_us_since_boot(get_absolute_time());
275 if (!ready_to_deassert)
277 deassert_pending =
false;
281 if (!deassert_pending)
283 deassert_pending =
true;
288 if (now_us < deassert_deadline_us)
295 deassert_pending =
false;
310 gpio_set_dir(
V24_RTS, GPIO_OUT);
349 polarities->
txc_inverted ? GPIO_OVERRIDE_INVERT : GPIO_OVERRIDE_NORMAL);
354 polarities->
txc_inverted ? GPIO_OVERRIDE_INVERT : GPIO_OVERRIDE_NORMAL);
357 polarities->
txd_inverted ? GPIO_OVERRIDE_INVERT : GPIO_OVERRIDE_NORMAL);
359 polarities->
dtr_inverted ? GPIO_OVERRIDE_INVERT : GPIO_OVERRIDE_NORMAL);
361 polarities->
rts_inverted ? GPIO_OVERRIDE_INVERT : GPIO_OVERRIDE_NORMAL);
363 polarities->
cts_inverted ? GPIO_OVERRIDE_INVERT : GPIO_OVERRIDE_NORMAL);
380 LOG_INFO(
"Initializing internal clock\r\n");
381 LOG_DEBUG(
"TXC: init pio%u sm%u pin%u baud=%u clkdiv=%.6f\r\n", (
unsigned)pio_get_index(pio),
384 pio_sm_claim(pio, pio_sm);
389 uint offset = pio_add_program(pio, &tck_txd_program);
390 LOG_DEBUG(
"TXC: program offset=%u\r\n", (
unsigned)offset);
394 pio_sm_set_consecutive_pindirs(pio, pio_sm,
V24_TXC_DTE, 1,
true);
396 pio_sm_set_consecutive_pindirs(pio, pio_sm,
V24_TXD, 1,
true);
398 pio_sm_set_consecutive_pindirs(pio, pio_sm,
V24_CTS, 1,
false);
401 pio_sm_config sm_config = tck_txd_program_get_default_config(offset);
402 sm_config_set_sideset_pins(&sm_config,
V24_TXC_DTE);
403 sm_config_set_out_pins(&sm_config,
V24_TXD, 1);
404 sm_config_set_jmp_pin(&sm_config,
V24_CTS);
405 sm_config_set_out_shift(&sm_config,
true,
true, CHAR_BIT);
407 pio_sm_init(pio, pio_sm, offset, &sm_config);
417 LOG_INFO(
"Initializing external clock\r\n");
418 LOG_DEBUG(
"TXC: init pio%u sm%u pin%u\r\n", (
unsigned)pio_get_index(pio), (
unsigned)pio_sm,
421 pio_sm_claim(pio, pio_sm);
426 uint offset = pio_add_program(pio, &xck_txd_program);
427 LOG_DEBUG(
"XCK: program offset=%u\r\n", (
unsigned)offset);
431 pio_sm_set_consecutive_pindirs(pio, pio_sm,
V24_TXC_DCE, 1,
false);
433 pio_sm_set_consecutive_pindirs(pio, pio_sm,
V24_TXD, 1,
true);
435 pio_sm_set_consecutive_pindirs(pio, pio_sm,
V24_CTS, 1,
false);
438 pio_sm_config sm_config = xck_txd_program_get_default_config(offset);
440 sm_config_set_out_pins(&sm_config,
V24_TXD, 1);
441 sm_config_set_jmp_pin(&sm_config,
V24_CTS);
443 sm_config_set_out_shift(&sm_config,
true,
false, CHAR_BIT);
445 pio_sm_init(pio, pio_sm, offset, &sm_config);
#define TX_PIO_CYCLES_PER_BIT
Number of TX PIO instructions executed per serialized bit.
#define RX_SHIFT_TO_LSB
Bit shift used to normalize RX byte ordering to LSB position.
#define US_PER_SECOND
The number of microseconds per second.
V24_POLARITIES_T init_polarities(void)
Build default V.24 polarity configuration.
bool tx_put(uint8_t data)
Queue one byte to the TX PIO FIFO.
void tx_clock_init(PIO pio, uint pio_sm, V24_CONFIG_T *config)
Initialize TX clock/data PIO state machine.
bool tx_poll(void)
Poll TX completion/holdoff state and manage RTS release.
static void cts_raw_irq_handler(void)
bool rx_get(uint8_t *data)
Read one received byte from RX PIO FIFO.
bool rx_clock_poll_stall(void)
Poll RX FIFO stall events and update the provided event counter.
void reinit_v24_config(V24_CONFIG_T *config, V24_BAUDRATE_T baudrate)
Reinitialize V.24 runtime configuration and derived timing values.
static float baud_to_clockdiv(V24_BAUDRATE_T baudrate)
void tx_clock_hard_reset(void)
Hard-reset TX SM state to discard queued/in-flight bytes.
const v24_runtime_t * get_v24_runtime(void)
Returns a pointer to the v24 runtime.
v24_runtime_t v24_runtime
uint32_t tx_clock_get_cts_toggle_seq(void)
Read current CTS edge sequence counter.
#define V24_RTS_HOLDOFF_MARGIN
RTS holdoff multiplier in bit-times. The final holdoff is: tx_rts_holdoff_us = margin * t_bit_us....
static void tx_clock_init_tck(PIO pio, uint pio_sm, V24_CONFIG_T *config)
static void tx_clock_init_xck(PIO pio, uint pio_sm, V24_CONFIG_T *config)
void led_mirror_init(void)
Initialize optional LED activity mirror PIO program.
void rx_clock_hard_reset(void)
Disable RX Path, clear fifos, restart SMs and CLKDIV and enable again.
void rx_clock_update_settings(V24_RX_POLARITIES_T *polarities)
Apply RX runtime settings to an already configured RX PIO SM. Take note that this function relies on ...
void tx_clock_update_settings(V24_CONFIG_T *config)
Apply TX runtime settings to an already configured TX PIO SM. Take note that this function relies on ...
void rx_clock_init(PIO pio, uint pio_sm, V24_RX_POLARITIES_T *polarities)
Initialize RX clock/data PIO state machine.
static gpio_function_t pio_gpio_func(PIO pio)
static void cts_irq_init(void)
void init_v24_config(V24_CONFIG_T *config, V24_BAUDRATE_T baudrate)
Initialize V.24 runtime configuration structure.
#define V24_RTS_MIN_HOLDOFF
Minimum RTS holdoff in microseconds used as a safety floor.
Runtime V.24 configuration and TX holdoff state.
V24_POLARITIES_T polarities
V24_TX_POLARITIES_T tx_polarities
RX/input polarity configuration.
TX/control output polarity configuration.
volatile uint32_t cts_toggle_seq
uint32_t tx_rts_holdoff_us
V24_BAUDRATE_T
Supported synchronous V.24 baudrates.