diff options
Diffstat (limited to 'libhw/rp2040_hwspi.c')
-rw-r--r-- | libhw/rp2040_hwspi.c | 21 |
1 files changed, 13 insertions, 8 deletions
diff --git a/libhw/rp2040_hwspi.c b/libhw/rp2040_hwspi.c index 1c4e096..f747b1e 100644 --- a/libhw/rp2040_hwspi.c +++ b/libhw/rp2040_hwspi.c @@ -33,6 +33,12 @@ LO_IMPLEMENTATION_C(io_duplex_readwriter, struct rp2040_hwspi, rp2040_hwspi, static) LO_IMPLEMENTATION_C(spi, struct rp2040_hwspi, rp2040_hwspi, static) +static void rp2040_hwspi_intrhandler(void *_self, enum dmairq LM_UNUSED(irq), uint LM_UNUSED(channel)) { + struct rp2040_hwspi *self = _self; + gpio_put(self->pin_cs, 1); + cr_sema_signal_from_intrhandler(&self->sema); +} + #define assert_4distinct(a, b, c, d) \ assert(a != b); \ assert(a != c); \ @@ -124,6 +130,10 @@ void _rp2040_hwspi_init(struct rp2040_hwspi *self, self->dma_tx_data = dma3; self->dma_rx_data = dma4; self->dead_until_ns = 0; + self->sema = (cr_sema_t){0}; + + /* Initialize the interrupt handler. */ + dmairq_set_and_enable_exclusive_handler(DMAIRQ_0, self->dma_rx_data, rp2040_hwspi_intrhandler, self); } static void rp2040_hwspi_readwritev(struct rp2040_hwspi *self, const struct duplex_iovec *iov, int iovcnt) { @@ -225,15 +235,10 @@ static void rp2040_hwspi_readwritev(struct rp2040_hwspi *self, const struct dupl uint64_t now = LO_CALL(bootclock, get_time_ns); if (now < self->dead_until_ns) sleep_until_ns(self->dead_until_ns); - /* TODO: Use interrupts instead of busy-polling. */ + bool saved = cr_save_and_disable_interrupts(); gpio_put(self->pin_cs, 0); dma_hw->multi_channel_trigger = (1u<<self->dma_tx_ctrl) | (1u<<self->dma_rx_ctrl); - while (dma_channel_is_busy(self->dma_tx_ctrl) - || dma_channel_is_busy(self->dma_tx_data) - || dma_channel_is_busy(self->dma_rx_ctrl) - || dma_channel_is_busy(self->dma_rx_data)) - tight_loop_contents(); - __compiler_memory_barrier(); - gpio_put(self->pin_cs, 1); + cr_restore_interrupts(saved); + cr_sema_wait(&self->sema); self->dead_until_ns = LO_CALL(bootclock, get_time_ns) + self->min_delay_ns; } |