diff --git a/linux/spi/SpiComIF.cpp b/linux/spi/SpiComIF.cpp index c39f397..9dc4429 100644 --- a/linux/spi/SpiComIF.cpp +++ b/linux/spi/SpiComIF.cpp @@ -47,7 +47,7 @@ ReturnValue_t SpiComIF::initializeInterface(CookieIF *cookie) { auto iter = spiDeviceMap.find(spiAddress); if(iter == spiDeviceMap.end()) { size_t bufferSize = spiCookie->getMaxBufferSize(); - SpiInstance spiInstance = {std::vector(bufferSize)}; + SpiInstance spiInstance(bufferSize); auto statusPair = spiDeviceMap.emplace(spiAddress, spiInstance); if (not statusPair.second) { #if FSFW_VERBOSE_LEVEL >= 1 diff --git a/linux/spi/SpiComIF.h b/linux/spi/SpiComIF.h index d1a583b..60b250e 100644 --- a/linux/spi/SpiComIF.h +++ b/linux/spi/SpiComIF.h @@ -67,6 +67,7 @@ public: private: struct SpiInstance { + SpiInstance(size_t maxRecvSize): replyBuffer(std::vector(maxRecvSize)) {} std::vector replyBuffer; }; diff --git a/stm32h7/devicetest/GyroL3GD20H.h b/stm32h7/devicetest/GyroL3GD20H.h index b96f203..4ebed1e 100644 --- a/stm32h7/devicetest/GyroL3GD20H.h +++ b/stm32h7/devicetest/GyroL3GD20H.h @@ -50,7 +50,6 @@ private: ReturnValue_t handlePollingSensorRead(); ReturnValue_t handleInterruptSensorRead(); - friend void spiTransferCompleteCallback(SPI_HandleTypeDef *hspi, void* args); static void spiTransferCompleteCallback(SPI_HandleTypeDef *hspi, void* args); static void spiTransferErrorCallback(SPI_HandleTypeDef *hspi, void* args); diff --git a/stm32h7/spi/SpiComIF.cpp b/stm32h7/spi/SpiComIF.cpp index bec47a6..5b1b7af 100644 --- a/stm32h7/spi/SpiComIF.cpp +++ b/stm32h7/spi/SpiComIF.cpp @@ -2,6 +2,7 @@ #include "SpiCookie.h" #include "fsfw/tasks/SemaphoreFactory.h" +#include "fsfw/osal/FreeRTOS/TaskManagement.h" #include "fsfw_hal/stm32h7/spi/spiCore.h" #include "stm32h7xx_hal_gpio.h" @@ -30,6 +31,11 @@ SpiComIF::SpiComIF(object_id_t objectId, SPI_TypeDef* spiInstance, SPI_HandleTyp // Recommended setting to avoid glitches spiHandle->Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; spiHandle->Init.Mode = SPI_MODE_MASTER; + + spi::assignTransferRxTxCompleteCallback(&spiTransferCompleteCallback, this); + spi::assignTransferRxCompleteCallback(&spiTransferRxCompleteCallback, this); + spi::assignTransferTxCompleteCallback(&spiTransferTxCompleteCallback, this); + spi::assignTransferErrorCallback(&spiTransferErrorCallback, this); } void SpiComIF::configureCacheMaintenanceOnTxBuffer(bool enable) { @@ -69,7 +75,8 @@ ReturnValue_t SpiComIF::initializeInterface(CookieIF *cookie) { } if(transferMode == spi::TransferModes::DMA or transferMode == spi::TransferModes::INTERRUPT) { - spiSemaphore = SemaphoreFactory::instance()->createBinarySemaphore(); + spiSemaphore = dynamic_cast( + SemaphoreFactory::instance()->createBinarySemaphore()); } else { spiMutex = MutexFactory::instance()->createMutex(); @@ -80,8 +87,7 @@ ReturnValue_t SpiComIF::initializeInterface(CookieIF *cookie) { auto iter = spiDeviceMap.find(spiAddress); if(iter == spiDeviceMap.end()) { size_t bufferSize = spiCookie->getMaxRecvSize(); - SpiInstance spiInstance = {std::vector(bufferSize)}; - auto statusPair = spiDeviceMap.emplace(spiAddress, spiInstance); + auto statusPair = spiDeviceMap.emplace(spiAddress, SpiInstance(bufferSize)); if (not statusPair.second) { #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 @@ -119,6 +125,8 @@ ReturnValue_t SpiComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, s if(iter == spiDeviceMap.end()) { return HasReturnvaluesIF::RETURN_FAILED; } + iter->second.currentTransferLen = sendLen; + switch(transferMode) { case(spi::TransferModes::POLLING): { return handlePollingSendOperation(iter->second.replyBuffer.data(), spiCookie, sendData, @@ -144,12 +152,22 @@ ReturnValue_t SpiComIF::requestReceiveMessage(CookieIF *cookie, size_t requestLe return HasReturnvaluesIF::RETURN_OK; } -void SpiComIF::setDefaultPollingTimeout(dur_millis_t timeout) { - this->defaultPollingTimeout = timeout; +ReturnValue_t SpiComIF::readReceivedMessage(CookieIF *cookie, uint8_t **buffer, size_t *size) { + SpiCookie* spiCookie = dynamic_cast(cookie); + if(spiCookie == nullptr) { + return NULLPOINTER; + } + auto iter = spiDeviceMap.find(spiCookie->getDeviceAddress()); + if(iter == spiDeviceMap.end()) { + return HasReturnvaluesIF::RETURN_FAILED; + } + *buffer = iter->second.replyBuffer.data(); + *size = iter->second.currentTransferLen; + return HasReturnvaluesIF::RETURN_OK; } -ReturnValue_t SpiComIF::readReceivedMessage(CookieIF *cookie, uint8_t **buffer, size_t *size) { - return HasReturnvaluesIF::RETURN_OK; +void SpiComIF::setDefaultPollingTimeout(dur_millis_t timeout) { + this->defaultPollingTimeout = timeout; } ReturnValue_t SpiComIF::handlePollingSendOperation(uint8_t* recvPtr, SpiCookie *spiCookie, @@ -197,14 +215,144 @@ ReturnValue_t SpiComIF::handlePollingSendOperation(uint8_t* recvPtr, SpiCookie * ReturnValue_t SpiComIF::handleInterruptSendOperation(uint8_t* recvPtr, SpiCookie* spiCookie, const uint8_t * sendData, size_t sendLen) { - auto gpioPort = spiCookie->getChipSelectGpioPort(); - auto gpioPin = spiCookie->getChipSelectGpioPin(); - spiMutex->lockMutex(timeoutType, timeoutMs); - HAL_GPIO_WritePin(gpioPort, gpioPin, GPIO_PIN_RESET); - return HasReturnvaluesIF::RETURN_OK; + return handleIrqSendOperation(recvPtr, spiCookie, sendData, sendLen); } ReturnValue_t SpiComIF::handleDmaSendOperation(uint8_t* recvPtr, SpiCookie* spiCookie, const uint8_t * sendData, size_t sendLen) { + return handleIrqSendOperation(recvPtr, spiCookie, sendData, sendLen); +} + +ReturnValue_t SpiComIF::handleIrqSendOperation(uint8_t *recvPtr, SpiCookie *spiCookie, + const uint8_t *sendData, size_t sendLen) { + ReturnValue_t result = genericIrqSendSetup(recvPtr, spiCookie, sendData, sendLen); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + // yet another HAL driver which is not const-correct.. + HAL_StatusTypeDef status = HAL_OK; + if(transferMode == spi::TransferModes::DMA) { + status = HAL_SPI_TransmitReceive_DMA(spiHandle, const_cast(sendData), + currentRecvPtr, sendLen); + } + else { + status = HAL_SPI_TransmitReceive_IT(spiHandle, const_cast(sendData), + currentRecvPtr, sendLen); + } + switch(status) { + case(HAL_OK): { + break; + } + default: { + return halErrorHandler(status); + } + } + return result; +} + +ReturnValue_t SpiComIF::halErrorHandler(HAL_StatusTypeDef status) { + char modeString[10]; + if(transferMode == spi::TransferModes::DMA) { + std::snprintf(modeString, sizeof(modeString), "Dma"); + } + else { + std::snprintf(modeString, sizeof(modeString), "Interrupt"); + } + sif::printWarning("SpiComIF::handle%sSendOperation: HAL error %d occured\n", modeString, + status); + switch(status) { + case(HAL_BUSY): { + return spi::HAL_BUSY_RETVAL; + } + case(HAL_ERROR): { + return spi::HAL_ERROR_RETVAL; + } + case(HAL_TIMEOUT): { + return spi::HAL_TIMEOUT_RETVAL; + } + default: { + return HasReturnvaluesIF::RETURN_FAILED; + } + } +} + + +ReturnValue_t SpiComIF::genericIrqSendSetup(uint8_t *recvPtr, SpiCookie *spiCookie, + const uint8_t *sendData, size_t sendLen) { + // These are required by the callback + currentGpioPort = spiCookie->getChipSelectGpioPort(); + currentGpioPin = spiCookie->getChipSelectGpioPin(); + currentRecvPtr = recvPtr; + currentRecvBuffSize = sendLen; + + // Take the semaphore which will be released by a callback when the transfer is complete + ReturnValue_t result = spiSemaphore->acquire(SemaphoreIF::TimeoutType::WAITING, timeoutMs); + if(result != HasReturnvaluesIF::RETURN_OK) { + // Configuration error + sif::printWarning("SpiComIF::handleInterruptSendOperation: Semaphore" + "could not be acquired after %d ms\n", timeoutMs); + return result; + } + HAL_GPIO_WritePin(currentGpioPort, currentGpioPin, GPIO_PIN_RESET); return HasReturnvaluesIF::RETURN_OK; } + +void SpiComIF::spiTransferTxCompleteCallback(SPI_HandleTypeDef *hspi, void *args) { + SpiComIF* spiComIF = reinterpret_cast(args); + if(spiComIF == nullptr) { + return; + } + genericIrqHandler(spiComIF, TransferStates::FAILURE); +} + +void SpiComIF::spiTransferRxCompleteCallback(SPI_HandleTypeDef *hspi, void *args) { + SpiComIF* spiComIF = reinterpret_cast(args); + if(spiComIF == nullptr) { + return; + } + genericIrqHandler(spiComIF, TransferStates::FAILURE); +} + +void SpiComIF::spiTransferCompleteCallback(SPI_HandleTypeDef *hspi, void *args) { + SpiComIF* spiComIF = reinterpret_cast(args); + if(spiComIF == nullptr) { + return; + } + genericIrqHandler(spiComIF, TransferStates::FAILURE); +} + +void SpiComIF::spiTransferErrorCallback(SPI_HandleTypeDef *hspi, void *args) { + SpiComIF* spiComIF = reinterpret_cast(args); + if(spiComIF == nullptr) { + return; + } + genericIrqHandler(spiComIF, TransferStates::FAILURE); +} + +void SpiComIF::genericIrqHandler(SpiComIF *spiComIF, TransferStates targetState) { + spiComIF->transferState = TransferStates::SUCCESS; + + // Pull CS pin high again + HAL_GPIO_WritePin(spiComIF->currentGpioPort, spiComIF->currentGpioPin, GPIO_PIN_SET); + + // Release the task semaphore + BaseType_t taskWoken = pdFALSE; + ReturnValue_t result = BinarySemaphore::releaseFromISR(spiComIF->spiSemaphore->getSemaphore(), + &taskWoken); + if(result != HasReturnvaluesIF::RETURN_FAILED) { + // Configuration error + printf("SpiComIF::genericIrqHandler: Failure releasing Semaphore!\n"); + } + + // Perform cache maintenance operation for DMA transfers + if(spiComIF->transferMode == spi::TransferModes::DMA) { + // Invalidate cache prior to access by CPU + SCB_InvalidateDCache_by_Addr ((uint32_t *) spiComIF->currentRecvPtr, + spiComIF->currentRecvBuffSize); + } + /* Request a context switch if the SPI ComIF task was woken up and has a higher priority + than the currently running task */ + if(taskWoken == pdTRUE) { + TaskManagement::requestContextSwitch(CallContext::ISR); + } +} diff --git a/stm32h7/spi/SpiComIF.h b/stm32h7/spi/SpiComIF.h index d166f49..909e742 100644 --- a/stm32h7/spi/SpiComIF.h +++ b/stm32h7/spi/SpiComIF.h @@ -2,10 +2,12 @@ #define FSFW_HAL_STM32H7_SPI_SPICOMIF_H_ + #include "fsfw/tasks/SemaphoreIF.h" #include "fsfw/devicehandlers/DeviceCommunicationIF.h" #include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/osal/FreeRTOS/BinarySemaphore.h" #include "fsfw_hal/stm32h7/spi/spiDefinitions.h" #include "stm32h7xx_hal_spi.h" #include "stm32h743xx.h" @@ -15,6 +17,13 @@ class SpiCookie; +enum class TransferStates { + IDLE, + WAIT, + SUCCESS, + FAILURE +}; + class SpiComIF: public SystemObject, public DeviceCommunicationIF { @@ -60,10 +69,15 @@ protected: virtual ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer, size_t *size) override; + private: + struct SpiInstance { + SpiInstance(size_t maxRecvSize): replyBuffer(std::vector(maxRecvSize)) {} std::vector replyBuffer; + size_t currentTransferLen = 0; }; + uint32_t defaultPollingTimeout = 50; spi::TransferModes transferMode; @@ -72,13 +86,19 @@ private: MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING; dur_millis_t timeoutMs = 20; - SemaphoreIF* spiSemaphore = nullptr; + BinarySemaphore* spiSemaphore = nullptr; MutexIF* spiMutex = nullptr; bool cacheMaintenanceOnTxBuffer = true; using SpiDeviceMap = std::map; using SpiDeviceMapIter = SpiDeviceMap::iterator; + GPIO_TypeDef* currentGpioPort = nullptr; + uint16_t currentGpioPin = 0; + uint8_t* currentRecvPtr = nullptr; + size_t currentRecvBuffSize = 0; + volatile TransferStates transferState = TransferStates::IDLE; + SpiDeviceMap spiDeviceMap; ReturnValue_t handlePollingSendOperation(uint8_t* recvPtr, SpiCookie* spiCookie, @@ -87,6 +107,20 @@ private: const uint8_t * sendData, size_t sendLen); ReturnValue_t handleDmaSendOperation(uint8_t* recvPtr, SpiCookie* spiCookie, const uint8_t * sendData, size_t sendLen); + ReturnValue_t handleIrqSendOperation(uint8_t* recvPtr, SpiCookie* spiCookie, + const uint8_t * sendData, size_t sendLen); + ReturnValue_t genericIrqSendSetup(uint8_t* recvPtr, SpiCookie* spiCookie, + const uint8_t * sendData, size_t sendLen); + ReturnValue_t halErrorHandler(HAL_StatusTypeDef status); + + static void spiTransferTxCompleteCallback(SPI_HandleTypeDef *hspi, void* args); + static void spiTransferRxCompleteCallback(SPI_HandleTypeDef *hspi, void* args); + static void spiTransferCompleteCallback(SPI_HandleTypeDef *hspi, void* args); + static void spiTransferErrorCallback(SPI_HandleTypeDef *hspi, void* args); + + static void genericIrqHandler(SpiComIF* comIF, TransferStates targetState); + + }; diff --git a/stm32h7/spi/spiDefinitions.h b/stm32h7/spi/spiDefinitions.h index db16df4..0ea83ac 100644 --- a/stm32h7/spi/spiDefinitions.h +++ b/stm32h7/spi/spiDefinitions.h @@ -13,7 +13,8 @@ namespace spi { static constexpr uint8_t HAL_SPI_ID = CLASS_ID::HAL_SPI; static constexpr ReturnValue_t HAL_TIMEOUT_RETVAL = HasReturnvaluesIF::makeReturnCode(HAL_SPI_ID, 0); -static constexpr ReturnValue_t HAL_ERROR_RETVAL = HasReturnvaluesIF::makeReturnCode(HAL_SPI_ID, 1); +static constexpr ReturnValue_t HAL_BUSY_RETVAL = HasReturnvaluesIF::makeReturnCode(HAL_SPI_ID, 1); +static constexpr ReturnValue_t HAL_ERROR_RETVAL = HasReturnvaluesIF::makeReturnCode(HAL_SPI_ID, 2); enum SpiBus { SPI_1,