+#if DEBUG
+static struct {
+ uint8_t task;
+ uint8_t which;
+ AO_TICK_TYPE tick;
+ uint16_t len;
+} spi_tasks[64];
+static uint8_t spi_task_index;
+
+static void
+validate_spi(struct stm_spi *stm_spi, int which, uint16_t len)
+{
+ uint32_t sr = stm_spi->sr;
+
+ if (stm_spi != &stm_spi2)
+ return;
+ spi_tasks[spi_task_index].task = ao_cur_task ? ao_cur_task->task_id : 0;
+ spi_tasks[spi_task_index].which = which;
+ spi_tasks[spi_task_index].tick = ao_time();
+ spi_tasks[spi_task_index].len = len;
+ spi_task_index = (spi_task_index + 1) & (63);
+ if (sr & (1 << STM_SPI_SR_FRE))
+ ao_panic(0x40 | 1);
+ if (sr & (1 << STM_SPI_SR_BSY))
+ ao_panic(0x40 | 2);
+ if (sr & (1 << STM_SPI_SR_OVR))
+ ao_panic(0x40 | 3);
+ if (sr & (1 << STM_SPI_SR_MODF))
+ ao_panic(0x40 | 4);
+ if (sr & (1 << STM_SPI_SR_UDR))
+ ao_panic(0x40 | 5);
+ if ((sr & (1 << STM_SPI_SR_TXE)) == 0)
+ ao_panic(0x40 | 6);
+ if (sr & (1 << STM_SPI_SR_RXNE))
+ ao_panic(0x40 | 7);
+ if (which != 5 && which != 6 && which != 13)
+ if (ao_cur_task->task_id != ao_spi_mutex[1])
+ ao_panic(0x40 | 8);
+}
+#else
+#define validate_spi(stm_spi, which, len) do { (void) (which); (void) (len); } while (0)
+#endif
+
+static void
+ao_spi_run(uint8_t id, uint8_t which, uint16_t len)
+{
+ struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
+ uint8_t mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
+ uint8_t miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
+
+ validate_spi(stm_spi, which, len);
+
+ stm_spi->cr2 = SPI_CR2_DMA;
+
+ ao_dma_start(miso_dma_index);
+ ao_dma_start(mosi_dma_index);
+
+ ao_arch_critical(
+ while (!ao_dma_done[miso_dma_index])
+ ao_sleep(&ao_dma_done[miso_dma_index]);
+ );
+
+ while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0);
+ while (stm_spi->sr & (1 << STM_SPI_SR_BSY));
+
+ validate_spi(stm_spi, which+1, len);
+
+ stm_spi->cr2 = 0;
+
+ ao_dma_done_transfer(mosi_dma_index);
+ ao_dma_done_transfer(miso_dma_index);
+}
+