altos: Add STM32F0 beep and SPI byte API.
[fw/altos] / src / stmf0 / ao_spi_stm.c
index 4eb4a2d94b0312ab84a1a56e80c2fc31c77360f2..0448ad8c375407167b1eeff93e04597a6dd07f75 100644 (file)
@@ -42,8 +42,6 @@ static const struct ao_spi_stm_info ao_spi_stm_info[STM_NUM_SPI] = {
 
 static uint8_t spi_dev_null;
 
-
-
 #define SPI_CR2        ((0 << STM_SPI_CR2_LDMA_TX) |                           \
                 (0 << STM_SPI_CR2_LDMA_RX) |                           \
                 (1 << STM_SPI_CR2_FRXTH) |                             \
@@ -63,12 +61,86 @@ static uint8_t      spi_dev_null;
                         (0 << STM_SPI_CR2_TXDMAEN) |   \
                         (0 << STM_SPI_CR2_RXDMAEN))
 
+#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);
+}
+
 void
 ao_spi_send(const void *block, uint16_t len, uint8_t spi_index)
 {
-       struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
-       uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
-       uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
+       uint8_t         id = AO_SPI_INDEX(spi_index);
+       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;
 
        /* Set up the transmit DMA to deliver data */
        ao_dma_set_transfer(mosi_dma_index,
@@ -85,9 +157,6 @@ ao_spi_send(const void *block, uint16_t len, uint8_t spi_index)
                            (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
                            (0 << STM_DMA_CCR_TCIE));
 
-       /* Clear RXNE */
-       (void) stm_spi->dr;
-
        /* Set up the receive DMA -- when this is done, we know the SPI unit
         * is idle. Without this, we'd have to poll waiting for the BSY bit to
         * be cleared
@@ -106,24 +175,16 @@ ao_spi_send(const void *block, uint16_t len, uint8_t spi_index)
                            (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
                            (1 << STM_DMA_CCR_TCIE));
 
-       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]);
-               );
-       ao_dma_done_transfer(mosi_dma_index);
-       ao_dma_done_transfer(miso_dma_index);
+       ao_spi_run(id, 1, len);
 }
 
 void
 ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
 {
-       struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
-       uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
-       uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
+       uint8_t         id = AO_SPI_INDEX(spi_index);
+       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;
 
        /* Set up the transmit DMA to deliver data */
        ao_dma_set_transfer(mosi_dma_index,
@@ -140,9 +201,6 @@ ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
                            (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
                            (0 << STM_DMA_CCR_TCIE));
 
-       /* Clear RXNE */
-       (void) stm_spi->dr;
-
        /* Set up the receive DMA -- when this is done, we know the SPI unit
         * is idle. Without this, we'd have to poll waiting for the BSY bit to
         * be cleared
@@ -161,40 +219,67 @@ ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
                            (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
                            (1 << STM_DMA_CCR_TCIE));
 
-       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]);
-               );
-       ao_dma_done_transfer(mosi_dma_index);
-       ao_dma_done_transfer(miso_dma_index);
+       ao_spi_run(id, 3, len);
 }
 
 void
-ao_spi_send_sync(void *block, uint16_t len, uint8_t spi_index)
+ao_spi_start_bytes(uint8_t spi_index)
 {
-       uint8_t         *b = block;
-       struct stm_spi  *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
+       uint8_t         id = AO_SPI_INDEX(spi_index);
+       struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
 
        stm_spi->cr2 = SPI_CR2_SYNC;
+       validate_spi(stm_spi, 5, 0xffff);
+}
 
-       /* Clear RXNE */
+void
+ao_spi_stop_bytes(uint8_t spi_index)
+{
+       uint8_t         id = AO_SPI_INDEX(spi_index);
+       struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
+
+       while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0)
+               ;
+       while (stm_spi->sr & (1 << STM_SPI_SR_BSY))
+               ;
+       /* Clear the OVR flag */
        (void) stm_spi->dr;
+       (void) stm_spi->sr;
+       validate_spi(stm_spi, 6, 0xffff);
+       stm_spi->cr2 = 0;
+}
 
+void
+ao_spi_send_sync(const void *block, uint16_t len, uint8_t spi_index)
+{
+       uint8_t         id = AO_SPI_INDEX(spi_index);
+       const uint8_t   *b = block;
+       struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
+
+       stm_spi->cr2 = SPI_CR2_SYNC;
+
+       validate_spi(stm_spi, 7, len);
        while (len--) {
                while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE)));
                stm_spi->dr = *b++;
        }
+       while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0)
+               ;
+       while (stm_spi->sr & (1 << STM_SPI_SR_BSY))
+               ;
+       /* Clear the OVR flag */
+       (void) stm_spi->dr;
+       (void) stm_spi->sr;
+       validate_spi(stm_spi, 8, len);
 }
 
 void
 ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
 {
-       struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
-       uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
-       uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
+       uint8_t         id = AO_SPI_INDEX(spi_index);
+       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;
 
        spi_dev_null = 0xff;
 
@@ -213,9 +298,6 @@ ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
                            (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
                            (0 << STM_DMA_CCR_TCIE));
 
-       /* Clear RXNE */
-       (void) stm_spi->dr;
-
        /* Set up the receive DMA to capture data */
        ao_dma_set_transfer(miso_dma_index,
                            &stm_spi->dr,
@@ -231,26 +313,16 @@ ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
                            (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
                            (1 << STM_DMA_CCR_TCIE));
 
-       stm_spi->cr2 = SPI_CR2_DMA;
-       ao_dma_start(miso_dma_index);
-       ao_dma_start(mosi_dma_index);
-
-       /* Wait until the SPI unit is done */
-       ao_arch_critical(
-               while (!ao_dma_done[miso_dma_index])
-                       ao_sleep(&ao_dma_done[miso_dma_index]);
-               );
-
-       ao_dma_done_transfer(mosi_dma_index);
-       ao_dma_done_transfer(miso_dma_index);
+       ao_spi_run(id, 9, len);
 }
 
 void
 ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index)
 {
-       struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
-       uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
-       uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
+       uint8_t         id = AO_SPI_INDEX(spi_index);
+       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;
 
        /* Set up transmit DMA to send data */
        ao_dma_set_transfer(mosi_dma_index,
@@ -267,9 +339,6 @@ ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index)
                            (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
                            (0 << STM_DMA_CCR_TCIE));
 
-       /* Clear RXNE */
-       (void) stm_spi->dr;
-
        /* Set up the receive DMA to capture data */
        ao_dma_set_transfer(miso_dma_index,
                            &stm_spi->dr,
@@ -285,18 +354,7 @@ ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index)
                            (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
                            (1 << STM_DMA_CCR_TCIE));
 
-       stm_spi->cr2 = SPI_CR2_DMA;
-       ao_dma_start(miso_dma_index);
-       ao_dma_start(mosi_dma_index);
-
-       /* Wait until the SPI unit is done */
-       ao_arch_critical(
-               while (!ao_dma_done[miso_dma_index])
-                       ao_sleep(&ao_dma_done[miso_dma_index]);
-               );
-
-       ao_dma_done_transfer(mosi_dma_index);
-       ao_dma_done_transfer(miso_dma_index);
+       ao_spi_run(id, 11, len);
 }
 
 static void
@@ -304,32 +362,24 @@ ao_spi_disable_index(uint8_t spi_index)
 {
        /* Disable current config
         */
-       switch (AO_SPI_INDEX(spi_index)) {
-       case STM_SPI_INDEX(1):
-               switch (spi_index) {
-               case AO_SPI_1_PA5_PA6_PA7:
-                       stm_gpio_set(&stm_gpioa, 5, 1);
-                       stm_moder_set(&stm_gpioa, 5, STM_MODER_OUTPUT);
-                       stm_moder_set(&stm_gpioa, 6, STM_MODER_INPUT);
-                       stm_moder_set(&stm_gpioa, 7, STM_MODER_OUTPUT);
-                       break;
-               case AO_SPI_1_PB3_PB4_PB5:
-                       stm_gpio_set(&stm_gpiob, 3, 1);
-                       stm_moder_set(&stm_gpiob, 3, STM_MODER_OUTPUT);
-                       stm_moder_set(&stm_gpiob, 4, STM_MODER_INPUT);
-                       stm_moder_set(&stm_gpiob, 5, STM_MODER_OUTPUT);
-                       break;
-               }
+       switch (spi_index) {
+       case AO_SPI_1_PA5_PA6_PA7:
+               stm_gpio_set(&stm_gpioa, 5, 1);
+               stm_moder_set(&stm_gpioa, 5, STM_MODER_OUTPUT);
+               stm_moder_set(&stm_gpioa, 6, STM_MODER_INPUT);
+               stm_moder_set(&stm_gpioa, 7, STM_MODER_OUTPUT);
                break;
-       case STM_SPI_INDEX(2):
-               switch (spi_index) {
-               case AO_SPI_2_PB13_PB14_PB15:
-                       stm_gpio_set(&stm_gpiob, 13, 1);
-                       stm_moder_set(&stm_gpiob, 13, STM_MODER_OUTPUT);
-                       stm_moder_set(&stm_gpiob, 14, STM_MODER_INPUT);
-                       stm_moder_set(&stm_gpiob, 15, STM_MODER_OUTPUT);
-                       break;
-               }
+       case AO_SPI_1_PB3_PB4_PB5:
+               stm_gpio_set(&stm_gpiob, 3, 1);
+               stm_moder_set(&stm_gpiob, 3, STM_MODER_OUTPUT);
+               stm_moder_set(&stm_gpiob, 4, STM_MODER_INPUT);
+               stm_moder_set(&stm_gpiob, 5, STM_MODER_OUTPUT);
+               break;
+       case AO_SPI_2_PB13_PB14_PB15:
+               stm_gpio_set(&stm_gpiob, 13, 1);
+               stm_moder_set(&stm_gpiob, 13, STM_MODER_OUTPUT);
+               stm_moder_set(&stm_gpiob, 14, STM_MODER_INPUT);
+               stm_moder_set(&stm_gpiob, 15, STM_MODER_OUTPUT);
                break;
        }
 }
@@ -337,29 +387,21 @@ ao_spi_disable_index(uint8_t spi_index)
 static void
 ao_spi_enable_index(uint8_t spi_index)
 {
-       switch (AO_SPI_INDEX(spi_index)) {
-       case STM_SPI_INDEX(1):
-               switch (spi_index) {
-               case AO_SPI_1_PA5_PA6_PA7:
-                       stm_afr_set(&stm_gpioa, 5, STM_AFR_AF0);
-                       stm_afr_set(&stm_gpioa, 6, STM_AFR_AF0);
-                       stm_afr_set(&stm_gpioa, 7, STM_AFR_AF0);
-                       break;
-               case AO_SPI_1_PB3_PB4_PB5:
-                       stm_afr_set(&stm_gpiob, 3, STM_AFR_AF0);
-                       stm_afr_set(&stm_gpiob, 4, STM_AFR_AF0);
-                       stm_afr_set(&stm_gpiob, 5, STM_AFR_AF0);
-                       break;
-               }
+       switch (spi_index) {
+       case AO_SPI_1_PA5_PA6_PA7:
+               stm_afr_set(&stm_gpioa, 5, STM_AFR_AF0);
+               stm_afr_set(&stm_gpioa, 6, STM_AFR_AF0);
+               stm_afr_set(&stm_gpioa, 7, STM_AFR_AF0);
                break;
-       case STM_SPI_INDEX(2):
-               switch (spi_index) {
-               case AO_SPI_2_PB13_PB14_PB15:
-                       stm_afr_set(&stm_gpiob, 13, STM_AFR_AF0);
-                       stm_afr_set(&stm_gpiob, 14, STM_AFR_AF0);
-                       stm_afr_set(&stm_gpiob, 15, STM_AFR_AF0);
-                       break;
-               }
+       case AO_SPI_1_PB3_PB4_PB5:
+               stm_afr_set(&stm_gpiob, 3, STM_AFR_AF0);
+               stm_afr_set(&stm_gpiob, 4, STM_AFR_AF0);
+               stm_afr_set(&stm_gpiob, 5, STM_AFR_AF0);
+               break;
+       case AO_SPI_2_PB13_PB14_PB15:
+               stm_afr_set(&stm_gpiob, 13, STM_AFR_AF0);
+               stm_afr_set(&stm_gpiob, 14, STM_AFR_AF0);
+               stm_afr_set(&stm_gpiob, 15, STM_AFR_AF0);
                break;
        }
 }
@@ -370,6 +412,20 @@ ao_spi_config(uint8_t spi_index, uint32_t speed)
        uint8_t         id = AO_SPI_INDEX(spi_index);
        struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
 
+       if (spi_index != ao_spi_index[id]) {
+
+               /* Disable old config
+                */
+               ao_spi_disable_index(ao_spi_index[id]);
+
+               /* Enable new config
+                */
+               ao_spi_enable_index(spi_index);
+
+               /* Remember current config
+                */
+               ao_spi_index[id] = spi_index;
+       }
        stm_spi->cr2 = SPI_CR2;
        stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) |                   /* Three wire mode */
                        (0 << STM_SPI_CR1_BIDIOE) |
@@ -385,21 +441,6 @@ ao_spi_config(uint8_t spi_index, uint32_t speed)
                        (1 << STM_SPI_CR1_MSTR) |
                        (0 << STM_SPI_CR1_CPOL) |                       /* Format 0 */
                        (0 << STM_SPI_CR1_CPHA));
-
-       if (spi_index != ao_spi_index[id]) {
-
-               /* Disable old config
-                */
-               ao_spi_disable_index(ao_spi_index[id]);
-
-               /* Enable new config
-                */
-               ao_spi_enable_index(spi_index);
-
-               /* Remember current config
-                */
-               ao_spi_index[id] = spi_index;
-       }
 }
 
 uint8_t
@@ -440,10 +481,57 @@ ao_spi_channel_init(uint8_t spi_index)
        ao_spi_disable_index(spi_index);
 
        stm_spi->cr1 = 0;
-       (void) stm_spi->sr;
        stm_spi->cr2 = SPI_CR2_SYNC;
+
+       /* Clear any pending data and error flags */
+       (void) stm_spi->dr;
+       (void) stm_spi->sr;
 }
 
+#if DEBUG
+void
+ao_spi_dump_cmd(void)
+{
+       int s;
+
+       for (s = 0; s < 64; s++) {
+               int i = (spi_task_index + s) & 63;
+               if (spi_tasks[i].which) {
+                       int t;
+                       const char *name = "(none)";
+                       for (t = 0; t < ao_num_tasks; t++)
+                               if (ao_tasks[t]->task_id == spi_tasks[i].task) {
+                                       name = ao_tasks[t]->name;
+                                       break;
+                               }
+                       printf("%2d: %5d task %2d which %2d len %5d %s\n",
+                              s,
+                              spi_tasks[i].tick,
+                              spi_tasks[i].task,
+                              spi_tasks[i].which,
+                              spi_tasks[i].len,
+                              name);
+               }
+       }
+       for (s = 0; s < STM_NUM_SPI; s++) {
+               struct stm_spi *spi = ao_spi_stm_info[s].stm_spi;
+
+               printf("%1d: mutex %2d index %3d miso dma %3d mosi dma %3d",
+                      s, ao_spi_mutex[s], ao_spi_index[s],
+                      ao_spi_stm_info[s].miso_dma_index,
+                      ao_spi_stm_info[s].mosi_dma_index);
+               printf(" cr1 %04x cr2 %02x sr %03x\n",
+                      spi->cr1, spi->cr2, spi->sr);
+       }
+
+}
+
+static const struct ao_cmds ao_spi_cmds[] = {
+       { ao_spi_dump_cmd,      "S\0Dump SPI status" },
+       { 0, NULL }
+};
+#endif
+
 void
 ao_spi_init(void)
 {
@@ -476,4 +564,7 @@ ao_spi_init(void)
        ao_spi_index[1] = AO_SPI_CONFIG_NONE;
        ao_spi_channel_init(STM_SPI_INDEX(2));
 #endif
+#if DEBUG
+       ao_cmd_register(&ao_spi_cmds[0]);
+#endif
 }