From ad1c5ab7950e35dcada7a0dfa3bb19a835163033 Mon Sep 17 00:00:00 2001 From: Daniel Fekete Date: Thu, 15 Jun 2017 07:26:43 +0200 Subject: [PATCH] spi: add nonblocking transfer() with callback --- STM32/libraries/SPI/src/SPI.cpp | 146 ++++++++++++------ STM32/libraries/SPI/src/SPI.h | 46 +++++- .../SdFat/src/SpiDriver/SdSpiSTM32.cpp | 13 +- 3 files changed, 154 insertions(+), 51 deletions(-) diff --git a/STM32/libraries/SPI/src/SPI.cpp b/STM32/libraries/SPI/src/SPI.cpp index 0a98a4a..e30af3b 100644 --- a/STM32/libraries/SPI/src/SPI.cpp +++ b/STM32/libraries/SPI/src/SPI.cpp @@ -4,6 +4,8 @@ #include "stm32_dma.h" +#include "stm32_HAL/stm32XXxx_ll_spi.h" + #if defined(MOSI) || defined(MISO) || defined(SCK) SPIClass SPI(SPI1, MOSI, MISO, SCK); #else @@ -11,6 +13,10 @@ #endif +int maxUsedCallback = 0; // This is set in SPI begin() +SPI_TypeDef *spiCallbackInstances[6]; +SPIClass *spiClass[6]; + void SPIClass::begin() { @@ -30,31 +36,55 @@ void SPIClass::begin() { #ifdef SPI1 if (spiHandle.Instance== SPI1) { __HAL_RCC_SPI1_CLK_ENABLE(); + + maxUsedCallback = max(maxUsedCallback, 1); + spiCallbackInstances[0] = spiHandle.Instance; + spiClass[0] = this; } #endif #ifdef SPI2 else if (spiHandle.Instance == SPI2) { __HAL_RCC_SPI2_CLK_ENABLE(); + + maxUsedCallback = max(maxUsedCallback, 2); + spiCallbackInstances[1] = spiHandle.Instance; + spiClass[1] = this; } #endif #ifdef SPI3 else if (spiHandle.Instance == SPI3) { __HAL_RCC_SPI3_CLK_ENABLE(); + + maxUsedCallback = max(maxUsedCallback, 3); + spiCallbackInstances[2] = spiHandle.Instance; + spiClass[2] = this; } #endif #ifdef SPI4 else if (spiHandle.Instance == SPI4) { __HAL_RCC_SPI4_CLK_ENABLE(); + + maxUsedCallback = max(maxUsedCallback, 4); + spiCallbackInstances[3] = spiHandle.Instance; + spiClass[3] = this; } #endif #ifdef SPI5 else if (spiHandle.Instance == SPI5) { __HAL_RCC_SPI5_CLK_ENABLE(); + + maxUsedCallback = max(maxUsedCallback, 5); + spiCallbackInstances[4] = spiHandle.Instance; + spiClass[4] = this; } #endif #ifdef SPI6 else if (spiHandle.Instance == SPI6) { __HAL_RCC_SPI6_CLK_ENABLE(); + + maxUsedCallback = max(maxUsedCallback, 6); + spiCallbackInstances[5] = spiHandle.Instance; + spiClass[5] = this; } #endif @@ -176,60 +206,88 @@ void SPIClass::stm32SetInstance(SPI_TypeDef *instance) { spiHandle.Instance = instance; } -#if defined(STM32F1) || defined(STM32F4) - -uint8_t SPIClass::dmaTransfer(uint8_t *transmitBuf, uint8_t *receiveBuf, uint16_t length) { - //HAL_SPI_TransmitReceive(&spiHandle, transmitBuf, receiveBuf, length, 1000); - // DMA handles configured in Begin. - if (length == 0) return 0; - - #ifdef STM32F1 - __HAL_DMA_DISABLE(&hdma_spi_tx); - __HAL_DMA_DISABLE(&hdma_spi_rx); - #endif - - if (!transmitBuf) { - transmitBuf = (uint8_t*)&repeatTransmitData; - hdma_spi_tx.Init.MemInc = DMA_MINC_DISABLE; - } else { - //Need to change the MINC mode since dmaSend with MINC 0 or Null transmitBuf may have been called last - hdma_spi_tx.Init.MemInc = DMA_MINC_ENABLE; - } - - HAL_DMA_Init(&hdma_spi_tx); - HAL_DMA_Init(&hdma_spi_rx); - - HAL_SPI_TransmitReceive_DMA(&spiHandle, transmitBuf, receiveBuf, length); - - while (spiHandle.State != HAL_SPI_STATE_READY); - - return 0; -} -uint8_t SPIClass::dmaSend(uint8_t *transmitBuf, uint16_t length, bool minc) { +bool SPIClass::transfer(uint8_t *txBuffer, uint8_t *rxBuffer, size_t count, spi_callback_type callback) { + this->callback = callback; #ifdef STM32F1 __HAL_DMA_DISABLE(&hdma_spi_tx); + __HAL_DMA_DISABLE(&hdma_spi_rx); #endif - //HAL_SPI_TransmitReceive(&spiHandle, transmitBuf, buf, length, 1000); - //Need to set TX DMA handle. - if (minc == 1){ - hdma_spi_tx.Init.MemInc = DMA_MINC_ENABLE; - } else { - hdma_spi_tx.Init.MemInc = DMA_MINC_DISABLE; - } + if (txBuffer != NULL) { + hdma_spi_tx.Init.MemInc = DMA_MINC_ENABLE; + } else { + txBuffer = (uint8_t*)&repeatTransmitData; + hdma_spi_tx.Init.MemInc = DMA_MINC_DISABLE; + } - HAL_DMA_Init(&hdma_spi_tx); + if (rxBuffer != NULL) { - HAL_SPI_Transmit_DMA(&spiHandle, transmitBuf, length); + if (HAL_DMA_Init(&hdma_spi_tx) != HAL_OK) { + return false; + } - while (spiHandle.State != HAL_SPI_STATE_READY); + if (HAL_DMA_Init(&hdma_spi_rx) != HAL_OK) { + return false; + } - return 0; + dmaDone = false; + if (HAL_SPI_TransmitReceive_DMA(&spiHandle, txBuffer, rxBuffer, count) != HAL_OK) { + return false; + } + } else { + if (HAL_DMA_Init(&hdma_spi_tx) != HAL_OK) { + return false; + } + + dmaDone = false; + if (HAL_SPI_Transmit_DMA(&spiHandle, txBuffer, count) != HAL_OK) { + return false; + } + } + + return true; +} + +void SPIClass::flush(void) { + while (!done()) { + yield(); + } +} +bool SPIClass::done(void) { + return dmaDone; +} + +uint8_t SPIClass::dmaTransfer(uint8_t *transmitBuf, uint8_t *receiveBuf, uint16_t length) { + return transfer(transmitBuf, receiveBuf, length); +} + +uint8_t SPIClass::dmaSend(uint8_t *transmitBuf, uint16_t length, bool minc) { + if (minc) { + return transfer(transmitBuf, NULL, length); + } else { + repeatTransmitData = transmitBuf[0]; + return transfer((uint8_t*)NULL, NULL, length); + } +} + +static void stm32SpiDmaFinished(SPI_HandleTypeDef *hspi) { + for(int i=0; iInstance) { + spiClass[i]->repeatTransmitData = 0xFFFF; + + if (spiClass[i]->callback != NULL) { + spiClass[i]->callback(); + } + spiClass[i]->dmaDone = true; + } + } +} + +extern "C" void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) { + stm32SpiDmaFinished(hspi); } extern "C" void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) { - // Called at the end of DMA + stm32SpiDmaFinished(hspi); } - -#endif diff --git a/STM32/libraries/SPI/src/SPI.h b/STM32/libraries/SPI/src/SPI.h index e792338..6118919 100644 --- a/STM32/libraries/SPI/src/SPI.h +++ b/STM32/libraries/SPI/src/SPI.h @@ -8,6 +8,17 @@ #define SPI_HAS_OLD_DMATRANSFER #endif +// SPI_HAS_EXTENDED_TRANSFER means SPI has +// - transfer(uint8_t data, uint8_t *rxBuffer, size_t count) +// - transfer(uint8_t *txBuffer, uint8_t *rxBuffer, size_t count) +#define SPI_HAS_EXTENDED_TRANSFER + +// SPI_HAS_EXTENDED_NONBLOCKING_TRANSFER means SPI has +// - implies SPI_HAS_EXTENDED_TRANSFER +// - transfer(uint8_t data, uint8_t *rxBuffer, size_t count, callback) +// - transfer(uint8_t *txBuffer, uint8_t *rxBuffer, size_t count, callback) +#define SPI_HAS_EXTENDED_NONBLOCKING_TRANSFER + // SPI_HAS_TRANSACTION means SPI has // - beginTransaction() // - endTransaction() @@ -64,7 +75,7 @@ class SPISettings { uint8_t dataMode; }; - +typedef void (*spi_callback_type)(); class SPIClass { public: @@ -97,13 +108,42 @@ class SPIClass { uint8_t transfer(uint8_t data); uint16_t transfer16(uint16_t data); void transfer(uint8_t *buf, size_t count); - uint8_t dmaTransfer(uint8_t *transmitBuf, uint8_t *receiveBuf, uint16_t length); - uint8_t dmaSend(uint8_t *transmitBuf, uint16_t length, bool minc = 1); + + + bool transfer(uint8_t data, uint8_t *rxBuffer, size_t count) { + repeatTransmitData = data; + if (transfer((uint8_t*) NULL, rxBuffer, count, NULL)) { + flush(); + return true; + } + return false; + } + bool transfer(uint8_t *txBuffer, uint8_t *rxBuffer, size_t count) { + if (transfer(txBuffer, rxBuffer, count, NULL)) { + flush(); + return true; + } + return false; + } + bool transfer(uint8_t data, uint8_t *rxBuffer, size_t count, spi_callback_type callback) { + repeatTransmitData = data; + return transfer((uint8_t*) NULL, rxBuffer, count, callback); + } + bool transfer(uint8_t *txBuffer, uint8_t *rxBuffer, size_t count, spi_callback_type callback); + + void flush(void); + bool done(void); + + uint8_t __attribute__ ((deprecated)) dmaTransfer(uint8_t *transmitBuf, uint8_t *receiveBuf, uint16_t length); + uint8_t __attribute__ ((deprecated)) dmaSend(uint8_t *transmitBuf, uint16_t length, bool minc = 1); SPI_HandleTypeDef spiHandle = {}; uint16_t repeatTransmitData = 0XFFFF; + spi_callback_type callback; + + volatile bool dmaDone = false; private: uint32_t apb_freq = 0; diff --git a/STM32/libraries/SdFat/src/SpiDriver/SdSpiSTM32.cpp b/STM32/libraries/SdFat/src/SpiDriver/SdSpiSTM32.cpp index a2d1512..75df0e1 100644 --- a/STM32/libraries/SdFat/src/SpiDriver/SdSpiSTM32.cpp +++ b/STM32/libraries/SdFat/src/SpiDriver/SdSpiSTM32.cpp @@ -19,6 +19,7 @@ */ #if defined(ARDUINO_ARCH_STM32) #include "SdSpiDriver.h" +#include "SdCard/SdInfo.h" //------------------------------------------------------------------------------ static SPIClass& pSpi = SPI; //------------------------------------------------------------------------------ @@ -65,8 +66,12 @@ uint8_t SdSpiAltDriver::receive() { */ uint8_t SdSpiAltDriver::receive(uint8_t* buf, size_t n) { int rtn = 0; -#ifdef SPI_HAS_OLD_DMATRANSFER - rtn = pSpi.dmaTransfer(0, buf, n); +#ifdef SPI_HAS_EXTENDED_TRANSFER + if (pSpi.transfer((uint8_t *)NULL, buf, n)) { + return 0; + } else { + return SD_CARD_ERROR_READ; + } #else // USE_STM32F1_DMAC // pSpi.read(buf, n); fails ?? use byte transfer for (size_t i = 0; i < n; i++) { @@ -90,8 +95,8 @@ void SdSpiAltDriver::send(uint8_t b) { * \param[in] n Number of bytes to send. */ void SdSpiAltDriver::send(const uint8_t* buf , size_t n) { -#ifdef SPI_HAS_OLD_DMATRANSFER - pSpi.dmaSend(const_cast(buf), n); +#ifdef SPI_HAS_EXTENDED_TRANSFER + pSpi.transfer((uint8_t*)buf, NULL, n); #else // #if USE_STM32F1_DMAC for (size_t i = 0; i < n; i++) { pSpi.transfer(buf[i]);