Skip to content
Snippets Groups Projects
Verified Commit 151320fd authored by Jakub Vaněk's avatar Jakub Vaněk
Browse files

Handle-ize PIO UART

parent 5a7d81cb
No related branches found
No related tags found
No related merge requests found
......@@ -9,6 +9,7 @@
#include "sw_uart.pio.h"
#endif
// OK: PIO memory will survive a soft-reboot
static int rx_address[2] = {-1, -1};
static int tx_address[2] = {-1, -1};
......
......@@ -6,6 +6,7 @@
#include <hardware/gpio.h>
#include <hardware/pio.h>
#include <opencube_hw.h>
#include <shared_resource.h>
#include "sw_uart_rx.h"
#include "sw_uart_loader.h"
......@@ -18,27 +19,27 @@
#define BULK_IRQ_THRESHOLD 7
static float calc_uart_multiplier(uint32_t baud);
static void register_irq_handler(opencube_swu_rx *rx);
static void unregister_irq_handler(opencube_swu_rx *rx);
static void pio_irq_handler(void);
static void sm_irq_handler(opencube_swu_rx *rx);
static void isr_ll_insert(opencube_swu_rx *rx);
static void isr_ll_remove(opencube_swu_rx *rx);
static critical_section_t irq_lock;
static bool irq_lock_initialized = false;
static bool irq_enabled_on_any_core = false;
static opencube_swu_rx *irq_handlers = NULL;
typedef struct swu_irq_data {
shared_resource_base_t base;
critical_section_t lock;
opencube_swu_rx *handler_ll_head;
} swu_irq_data_t;
int opencube_swu_rx_open(opencube_swu_rx *rx, const opencube_swu_rx_config *config) {
if (!irq_lock_initialized) {
critical_section_init(&irq_lock);
irq_lock_initialized = true;
}
static void swu_irq_init(mp_obj_t obj);
static void swu_irq_deinit(mp_obj_t obj);
static void swu_irq_add_handler(opencube_swu_rx *rx);
static void swu_irq_remove_handler(opencube_swu_rx *rx);
DEFINE_SHARED_RESOURCE(swu_irq_data_t, swu_irq_data_obj, swu_irq_init, swu_irq_deinit);
int opencube_swu_rx_open(opencube_swu_rx *rx, const opencube_swu_rx_config *config) {
rx->irq = shared_resource_get_or_new(&swu_irq_data_obj);
rx->pio = config->pio;
rx->sm = config->sm;
rx->next_rx = NULL;
rx->next = NULL;
rx->baud = config->baud;
opencube_uart_ring_clear(&rx->ring);
......@@ -56,7 +57,7 @@ int opencube_swu_rx_open(opencube_swu_rx *rx, const opencube_swu_rx_config *conf
pio_sm_set_consecutive_pindirs(rx->pio, rx->sm, config->gpio_pin, 1, false);
pio_set_irq1_source_enabled(rx->pio, pis_interrupt0 + rx->sm, true);
register_irq_handler(rx);
swu_irq_add_handler(rx);
pio_sm_set_enabled(rx->pio, rx->sm, true);
return PICO_OK;
}
......@@ -64,28 +65,28 @@ int opencube_swu_rx_open(opencube_swu_rx *rx, const opencube_swu_rx_config *conf
void opencube_swu_rx_close(opencube_swu_rx *rx) {
pio_sm_set_enabled(rx->pio, rx->sm, false);
pio_sm_unclaim(rx->pio, rx->sm);
unregister_irq_handler(rx);
swu_irq_remove_handler(rx);
}
int opencube_swu_rx_read_one(opencube_swu_rx *rx) {
critical_section_enter_blocking(&irq_lock);
critical_section_enter_blocking(&rx->irq->lock);
// re-query FSM for queued data
sm_irq_handler(rx);
int result = opencube_uart_ring_pop(&rx->ring);
critical_section_exit(&irq_lock);
critical_section_exit(&rx->irq->lock);
return result;
}
bool opencube_swu_rx_read_many(opencube_swu_rx *rx, partial_message *win) {
critical_section_enter_blocking(&irq_lock);
critical_section_enter_blocking(&rx->irq->lock);
// re-query FSM for queued data
sm_irq_handler(rx);
// read data from the ring buffer
bool result = opencube_uart_ring_readmsg(&rx->ring, win);
critical_section_exit(&irq_lock);
critical_section_exit(&rx->irq->lock);
return result;
}
......@@ -96,7 +97,7 @@ void opencube_swu_rx_set_baud(opencube_swu_rx *rx, uint32_t new_rate) {
}
void opencube_swu_rx_clear(opencube_swu_rx *rx) {
critical_section_enter_blocking(&irq_lock);
critical_section_enter_blocking(&rx->irq->lock);
// drain hw fifo
while (!pio_sm_is_rx_fifo_empty(rx->pio, rx->sm)) {
......@@ -106,15 +107,15 @@ void opencube_swu_rx_clear(opencube_swu_rx *rx) {
// clear buffer & reset overrun flag
opencube_uart_ring_clear(&rx->ring);
rx->pio->fdebug &= ~(1 << (rx->sm + PIO_FDEBUG_RXSTALL_LSB));
critical_section_exit(&irq_lock);
critical_section_exit(&rx->irq->lock);
}
bool opencube_swu_rx_has_overrun(opencube_swu_rx *rx) {
bool result;
critical_section_enter_blocking(&irq_lock);
critical_section_enter_blocking(&rx->irq->lock);
uint rx_stall_mask = (1 << (rx->sm + PIO_FDEBUG_RXSTALL_LSB));
result = rx->ring.overrun || (rx->pio->fdebug & rx_stall_mask) != 0;
critical_section_exit(&irq_lock);
critical_section_exit(&rx->irq->lock);
return result;
}
......@@ -122,44 +123,25 @@ float calc_uart_multiplier(uint32_t baud) {
return (float) RP2040_CPU_FREQ / (float) (uart_rx_multiplier * baud);
}
void register_irq_handler(opencube_swu_rx *rx) {
bool enable_irqs_now = false;
critical_section_enter_blocking(&irq_lock);
enable_irqs_now = !irq_enabled_on_any_core;
irq_enabled_on_any_core = true;
isr_ll_insert(rx);
critical_section_exit(&irq_lock);
if (enable_irqs_now) {
// Shared handlers are scarce (only 4 per program!).
// To save them, here we claim the IRQ1 on PIO1.
// MicroPython only uses IRQ0 on both PIO cores.
irq_set_exclusive_handler(PIO1_IRQ_1, pio_irq_handler);
irq_set_enabled(PIO1_IRQ_1, true);
void pio_irq_handler(void) {
swu_irq_data_t *irq = shared_resource_try_acquire(&swu_irq_data_obj);
if (irq == NULL) {
// :( either a spurious IRQ, or the locking is sus
return;
}
}
void unregister_irq_handler(opencube_swu_rx *rx) {
critical_section_enter_blocking(&irq_lock);
isr_ll_remove(rx);
critical_section_exit(&irq_lock);
}
critical_section_enter_blocking(&irq->lock);
for (opencube_swu_rx *handler = irq->handler_ll_head;
handler != NULL;
handler = handler->next) {
void pio_irq_handler(void) {
critical_section_enter_blocking(&irq_lock);
for (opencube_swu_rx *rx = irq_handlers;
rx != NULL;
rx = rx->next_rx) {
if (pio_interrupt_get(rx->pio, rx->sm)) {
pio_interrupt_clear(rx->pio, rx->sm);
sm_irq_handler(rx);
if (pio_interrupt_get(handler->pio, handler->sm)) {
pio_interrupt_clear(handler->pio, handler->sm);
sm_irq_handler(handler);
}
}
critical_section_exit(&irq_lock);
critical_section_exit(&irq->lock);
shared_resource_release(irq);
}
void sm_irq_handler(opencube_swu_rx *rx) {
......@@ -169,19 +151,63 @@ void sm_irq_handler(opencube_swu_rx *rx) {
}
}
void isr_ll_insert(opencube_swu_rx *rx) {
rx->next_rx = irq_handlers;
irq_handlers = rx;
void swu_irq_init(mp_obj_t obj) {
swu_irq_data_t *ctx = MP_OBJ_TO_PTR(obj);
ctx->handler_ll_head = NULL;
critical_section_init(&ctx->lock);
// Shared handlers are scarce (only 4 per program!).
// To save them, here we claim the IRQ1 on PIO1.
// MicroPython only uses IRQ0 on both PIO cores.
irq_set_exclusive_handler(PIO1_IRQ_1, pio_irq_handler);
irq_set_enabled(PIO1_IRQ_1, true);
}
void isr_ll_remove(opencube_swu_rx *rx) {
for (opencube_swu_rx **chaining_ptr = &irq_handlers;
void swu_irq_deinit(mp_obj_t obj) {
swu_irq_data_t *irq = MP_OBJ_TO_PTR(obj);
// disable IRQs
irq_set_enabled(PIO1_IRQ_1, false);
irq_remove_handler(PIO1_IRQ_1, pio_irq_handler);
// unchain all handlers
critical_section_enter_blocking(&irq->lock);
opencube_swu_rx *modified_item = irq->handler_ll_head;
while (modified_item != NULL) {
opencube_swu_rx *next_item = modified_item->next;
modified_item->next = NULL;
modified_item = next_item;
}
irq->handler_ll_head = NULL;
critical_section_exit(&irq->lock);
// free critical section
critical_section_deinit(&irq->lock);
}
void swu_irq_add_handler(opencube_swu_rx *rx) {
swu_irq_data_t *irq = rx->irq;
critical_section_enter_blocking(&rx->irq->lock);
rx->next = irq->handler_ll_head;
irq->handler_ll_head = rx;
critical_section_exit(&rx->irq->lock);
}
void swu_irq_remove_handler(opencube_swu_rx *rx) {
swu_irq_data_t *irq = rx->irq;
critical_section_enter_blocking(&irq->lock);
for (opencube_swu_rx **chaining_ptr = &irq->handler_ll_head;
*chaining_ptr != NULL;
chaining_ptr = &(*chaining_ptr)->next_rx) {
chaining_ptr = &(*chaining_ptr)->next) {
if (*chaining_ptr == rx) {
*chaining_ptr = rx->next_rx;
rx->next_rx = NULL;
*chaining_ptr = rx->next;
rx->next = NULL;
break;
}
}
critical_section_exit(&irq->lock);
}
......@@ -11,6 +11,8 @@
#include <pico/critical_section.h>
#include "uart_ring.h"
typedef struct swu_irq_data swu_irq_data_t;
// Receiver configuration
typedef struct {
// Hardware PIO unit to use
......@@ -25,7 +27,8 @@ typedef struct {
// Receiver state
typedef struct opencube_swu_rx {
struct opencube_swu_rx *next_rx;
struct opencube_swu_rx *next;
swu_irq_data_t *irq;
pio_hw_t *pio;
uint baud;
uint sm;
......
......@@ -72,6 +72,7 @@ const struct {
},
};
// destructors will release UART ports on soft reboot
static bool port_claimed[NUM_SENSOR_PORTS];
static int opencube_swu_open(opencube_swu *uart, const opencube_swu_config *config);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment