Repository: incubator-mynewt-core
Updated Branches:
  refs/heads/develop e238713aa -> d0df2fbd4


stm32f4 hal spi; fix race when slave saw CS; sometimes was sending
first byte twice.


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/d0df2fbd
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/d0df2fbd
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/d0df2fbd

Branch: refs/heads/develop
Commit: d0df2fbd41454f76408c5ab7637e38099714b015
Parents: d3ed09c
Author: Marko Kiiskila <ma...@runtime.io>
Authored: Tue Oct 18 13:14:32 2016 -0700
Committer: Marko Kiiskila <ma...@runtime.io>
Committed: Tue Oct 18 13:15:41 2016 -0700

----------------------------------------------------------------------
 hw/mcu/stm/stm32f4xx/src/hal_spi.c | 103 ++++++++++++++++++++++----------
 1 file changed, 73 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/d0df2fbd/hw/mcu/stm/stm32f4xx/src/hal_spi.c
----------------------------------------------------------------------
diff --git a/hw/mcu/stm/stm32f4xx/src/hal_spi.c 
b/hw/mcu/stm/stm32f4xx/src/hal_spi.c
index c52fae9..4ed3bc0 100644
--- a/hw/mcu/stm/stm32f4xx/src/hal_spi.c
+++ b/hw/mcu/stm/stm32f4xx/src/hal_spi.c
@@ -42,10 +42,10 @@
 
 struct stm32f4_hal_spi {
     SPI_HandleTypeDef handle;
-    uint8_t slave:1;
-    uint8_t tx_in_prog:1;
-    uint8_t selected:1;
-    uint8_t def_char[4];
+    uint8_t slave:1;                   /* slave or master */
+    uint8_t tx_in_prog:1;              /* slave: tx'ing user data not def */
+    uint8_t selected:1;                        /* slave: if we see SS */
+    uint8_t def_char[4];               /* slave: default data to tx */
     struct stm32f4_hal_spi_cfg *cfg;
     /* Callback and arguments */
     hal_spi_txrx_cb txrx_cb_func;
@@ -155,6 +155,9 @@ stm32f4_resolve_spi_irq(SPI_HandleTypeDef *hspi)
     }
 }
 
+/*
+ * SPI master IRQ handler.
+ */
 static void
 spim_irq_handler(struct stm32f4_hal_spi *spi)
 {
@@ -165,11 +168,17 @@ spim_irq_handler(struct stm32f4_hal_spi *spi)
     }
 }
 
+/*
+ * SPI slave IRQ handler.
+ */
 static void
 spis_irq_handler(struct stm32f4_hal_spi *spi)
 {
     if (spi->tx_in_prog) {
         if (spi->handle.TxXferCount == 0 && spi->handle.RxXferCount == 0) {
+            /*
+             * If finished with data tx, start transmitting default char
+             */
             spi->tx_in_prog = 0;
 
             HAL_SPI_Transmit_IT(&spi->handle, spi->def_char, 2);
@@ -179,11 +188,17 @@ spis_irq_handler(struct stm32f4_hal_spi *spi)
             }
         }
     } else {
+        /*
+         * Reset TX pointer within default data.
+         */
         spi->handle.pTxBuffPtr = spi->def_char;
         spi->handle.TxXferCount = 2;
     }
 }
 
+/*
+ * Common IRQ handler for both master and slave.
+ */
 static void
 spi_irq_handler(struct stm32f4_hal_spi *spi)
 {
@@ -212,51 +227,71 @@ spi_irq_handler(struct stm32f4_hal_spi *spi)
     }
 }
 
+/*
+ * GPIO interrupt when slave gets selected/deselected.
+ */
 static void
 spi_ss_isr(void *arg)
 {
     struct stm32f4_hal_spi *spi = (struct stm32f4_hal_spi *)arg;
     int ss;
     int len;
-    int rc;
     uint16_t reg;
 
     spi_stat.ss_irq++;
     ss = hal_gpio_read(spi->cfg->ss_pin);
     if (ss == 0 && !spi->selected) {
-        reg = spi->handle.Instance->CR1;
-        reg &= ~SPI_CR1_SSI;
-        spi->handle.Instance->CR1 = reg;
+        /*
+         * We're now seeing chip select. Enable SPI, SPI interrupts.
+         */
         if (spi->tx_in_prog) {
-            rc = HAL_SPI_TransmitReceive_IT(&spi->handle,
-              spi->handle.pTxBuffPtr, spi->handle.pRxBuffPtr,
-              spi->handle.TxXferSize);
+            __HAL_SPI_ENABLE_IT(&spi->handle,
+              SPI_IT_RXNE | SPI_IT_TXE | SPI_IT_ERR);
         } else {
-            rc = HAL_SPI_Transmit_IT(&spi->handle, spi->def_char, 2);
+            __HAL_SPI_ENABLE_IT(&spi->handle, SPI_IT_TXE | SPI_IT_ERR);
         }
-        assert(rc == 0);
+        reg = spi->handle.Instance->CR1;
+        reg &= ~SPI_CR1_SSI;
+        reg |= SPI_CR1_SPE;
+        spi->handle.Instance->CR1 = reg;
         spi->selected = 1;
     }
     if (ss == 1 && spi->selected) {
+        /*
+         * Chip select done. Check whether there's pending data to RX.
+         */
         if (spi->handle.Instance->SR & SPI_SR_RXNE && spi->handle.RxISR) {
             spi->handle.RxISR(&spi->handle);
         }
+
+        /*
+         * Disable SPI.
+         */
         reg = spi->handle.Instance->CR1;
         reg &= ~SPI_CR1_SPE;
         reg |= SPI_CR1_SSI;
+        spi->handle.Instance->CR1 = reg;
 
         __HAL_SPI_DISABLE_IT(&spi->handle, SPI_IT_RXNE|SPI_IT_TXE|SPI_IT_ERR);
 
-        spi->handle.Instance->CR1 = reg;
         len = spi->handle.RxXferSize - spi->handle.RxXferCount;
-        if (spi->tx_in_prog && len) {
-            spi->tx_in_prog = 0;
+        if (len) {
+            /*
+             * If some data was clocked out, reset to start sending
+             * default data and call callback, if user was waiting for
+             * data.
+             */
+            spi->handle.State = HAL_SPI_STATE_READY;
+            HAL_SPI_QueueTransmit(&spi->handle, spi->def_char, 2);
 
-            if (spi->txrx_cb_func) {
-                spi->txrx_cb_func(spi->txrx_cb_arg, len);
+            if (spi->tx_in_prog) {
+                spi->tx_in_prog = 0;
+
+                if (spi->txrx_cb_func) {
+                    spi->txrx_cb_func(spi->txrx_cb_arg, len);
+                }
             }
         }
-        spi->handle.State = HAL_SPI_STATE_READY;
         spi->selected = 0;
     }
 }
@@ -660,7 +695,7 @@ hal_spi_config(int spi_num, struct hal_spi_settings 
*settings)
         goto err;
     }
     if (spi->slave) {
-        spi->handle.Instance->CR1 &= ~SPI_CR1_SSI;
+        hal_spi_slave_set_def_tx_val(spi_num, 0);
         rc = hal_gpio_irq_init(cfg->ss_pin, spi_ss_isr, spi, GPIO_TRIG_BOTH,
           GPIO_PULL_UP);
         spi_ss_isr(spi);
@@ -681,22 +716,25 @@ hal_spi_txrx_noblock(int spi_num, void *txbuf, void 
*rxbuf, int len)
 
     STM32F4_HAL_SPI_RESOLVE(spi_num, spi);
 
-    __HAL_DISABLE_INTERRUPTS(sr);
     spi_stat.tx++;
     rc = -1;
+    __HAL_DISABLE_INTERRUPTS(sr);
     if (!spi->slave) {
         rc = HAL_SPI_TransmitReceive_IT(&spi->handle, txbuf, rxbuf, len);
     } else {
-        spi->tx_in_prog = 1;
+        /*
+         * Slave: if selected, start transmitting new data.
+         * If not selected, queue it for transmission.
+         */
+        spi->handle.State = HAL_SPI_STATE_READY;
         if (spi->selected) {
-            spi->handle.State = HAL_SPI_STATE_READY;
             rc = HAL_SPI_TransmitReceive_IT(&spi->handle, txbuf, rxbuf, len);
         } else {
-            rc = 0;
-            spi->handle.pTxBuffPtr = txbuf;
-            spi->handle.TxXferSize = len;
-            spi->handle.pRxBuffPtr = rxbuf;
-            spi->handle.RxXferSize = len;
+            rc = HAL_SPI_Slave_Queue_TransmitReceive(&spi->handle, txbuf, 
rxbuf,
+              len);
+        }
+        if (rc == 0) {
+            spi->tx_in_prog = 1;
         }
     }
     __HAL_ENABLE_INTERRUPTS(sr);
@@ -732,8 +770,13 @@ hal_spi_slave_set_def_tx_val(int spi_num, uint16_t val)
                 ((uint16_t *)spi->def_char)[i] = val;
             }
         }
-        if (!spi->tx_in_prog && spi->selected) {
-            spi->handle.Instance->DR = val;
+        if (!spi->tx_in_prog) {
+            /*
+             * Replaces the current default char in tx buffer register.
+             */
+            spi->handle.State = HAL_SPI_STATE_READY;
+            rc = HAL_SPI_QueueTransmit(&spi->handle, spi->def_char, 2);
+            assert(rc == 0);
         }
         __HAL_ENABLE_INTERRUPTS(sr);
     } else {

Reply via email to