summaryrefslogtreecommitdiff
path: root/libhw/rp2040_hwspi.c
diff options
context:
space:
mode:
Diffstat (limited to 'libhw/rp2040_hwspi.c')
-rw-r--r--libhw/rp2040_hwspi.c21
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;
}