move HAL and tests folder
This commit is contained in:
9
src/fsfw_hal/stm32h7/spi/CMakeLists.txt
Normal file
9
src/fsfw_hal/stm32h7/spi/CMakeLists.txt
Normal file
@ -0,0 +1,9 @@
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||
spiCore.cpp
|
||||
spiDefinitions.cpp
|
||||
spiInterrupts.cpp
|
||||
mspInit.cpp
|
||||
SpiCookie.cpp
|
||||
SpiComIF.cpp
|
||||
stm32h743zi.cpp
|
||||
)
|
474
src/fsfw_hal/stm32h7/spi/SpiComIF.cpp
Normal file
474
src/fsfw_hal/stm32h7/spi/SpiComIF.cpp
Normal file
@ -0,0 +1,474 @@
|
||||
#include "fsfw_hal/stm32h7/spi/SpiComIF.h"
|
||||
|
||||
#include "fsfw/tasks/SemaphoreFactory.h"
|
||||
#include "fsfw_hal/stm32h7/gpio/gpio.h"
|
||||
#include "fsfw_hal/stm32h7/spi/SpiCookie.h"
|
||||
#include "fsfw_hal/stm32h7/spi/mspInit.h"
|
||||
#include "fsfw_hal/stm32h7/spi/spiCore.h"
|
||||
#include "fsfw_hal/stm32h7/spi/spiInterrupts.h"
|
||||
|
||||
// FreeRTOS required special Semaphore handling from an ISR. Therefore, we use the concrete
|
||||
// instance here, because RTEMS and FreeRTOS are the only relevant OSALs currently
|
||||
// and it is not trivial to add a releaseFromISR to the SemaphoreIF
|
||||
#if defined FSFW_OSAL_RTEMS
|
||||
#include "fsfw/osal/rtems/BinarySemaphore.h"
|
||||
#elif defined FSFW_OSAL_FREERTOS
|
||||
#include "fsfw/osal/freertos/BinarySemaphore.h"
|
||||
#include "fsfw/osal/freertos/TaskManagement.h"
|
||||
#endif
|
||||
|
||||
#include "stm32h7xx_hal_gpio.h"
|
||||
|
||||
SpiComIF::SpiComIF(object_id_t objectId) : SystemObject(objectId) {
|
||||
void *irqArgsVoided = reinterpret_cast<void *>(&irqArgs);
|
||||
spi::assignTransferRxTxCompleteCallback(&spiTransferCompleteCallback, irqArgsVoided);
|
||||
spi::assignTransferRxCompleteCallback(&spiTransferRxCompleteCallback, irqArgsVoided);
|
||||
spi::assignTransferTxCompleteCallback(&spiTransferTxCompleteCallback, irqArgsVoided);
|
||||
spi::assignTransferErrorCallback(&spiTransferErrorCallback, irqArgsVoided);
|
||||
}
|
||||
|
||||
void SpiComIF::configureCacheMaintenanceOnTxBuffer(bool enable) {
|
||||
this->cacheMaintenanceOnTxBuffer = enable;
|
||||
}
|
||||
|
||||
void SpiComIF::addDmaHandles(DMA_HandleTypeDef *txHandle, DMA_HandleTypeDef *rxHandle) {
|
||||
spi::setDmaHandles(txHandle, rxHandle);
|
||||
}
|
||||
|
||||
ReturnValue_t SpiComIF::initialize() { return HasReturnvaluesIF::RETURN_OK; }
|
||||
|
||||
ReturnValue_t SpiComIF::initializeInterface(CookieIF *cookie) {
|
||||
SpiCookie *spiCookie = dynamic_cast<SpiCookie *>(cookie);
|
||||
if (spiCookie == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error < "SpiComIF::initializeInterface: Invalid cookie" << std::endl;
|
||||
#else
|
||||
sif::printError("SpiComIF::initializeInterface: Invalid cookie\n");
|
||||
#endif
|
||||
return NULLPOINTER;
|
||||
}
|
||||
auto transferMode = spiCookie->getTransferMode();
|
||||
|
||||
if (transferMode == spi::TransferModes::DMA) {
|
||||
DMA_HandleTypeDef *txHandle = nullptr;
|
||||
DMA_HandleTypeDef *rxHandle = nullptr;
|
||||
spi::getDmaHandles(&txHandle, &rxHandle);
|
||||
if (txHandle == nullptr or rxHandle == nullptr) {
|
||||
sif::printError("SpiComIF::initialize: DMA handles not set!\n");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
// This semaphore ensures thread-safety for a given bus
|
||||
spiSemaphore =
|
||||
dynamic_cast<BinarySemaphore *>(SemaphoreFactory::instance()->createBinarySemaphore());
|
||||
address_t spiAddress = spiCookie->getDeviceAddress();
|
||||
|
||||
auto iter = spiDeviceMap.find(spiAddress);
|
||||
if (iter == spiDeviceMap.end()) {
|
||||
size_t bufferSize = spiCookie->getMaxRecvSize();
|
||||
auto statusPair = spiDeviceMap.emplace(spiAddress, SpiInstance(bufferSize));
|
||||
if (not statusPair.second) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "SpiComIF::initializeInterface: Failed to insert device with address "
|
||||
<< spiAddress << "to SPI device map" << std::endl;
|
||||
#else
|
||||
sif::printError(
|
||||
"SpiComIF::initializeInterface: Failed to insert device with address "
|
||||
"%lu to SPI device map\n",
|
||||
static_cast<unsigned long>(spiAddress));
|
||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
auto gpioPin = spiCookie->getChipSelectGpioPin();
|
||||
auto gpioPort = spiCookie->getChipSelectGpioPort();
|
||||
|
||||
SPI_HandleTypeDef &spiHandle = spiCookie->getSpiHandle();
|
||||
|
||||
auto spiIdx = spiCookie->getSpiIdx();
|
||||
if (spiIdx == spi::SpiBus::SPI_1) {
|
||||
#ifdef SPI1
|
||||
spiHandle.Instance = SPI1;
|
||||
#endif
|
||||
} else if (spiIdx == spi::SpiBus::SPI_2) {
|
||||
#ifdef SPI2
|
||||
spiHandle.Instance = SPI2;
|
||||
#endif
|
||||
} else {
|
||||
printCfgError("SPI Bus Index");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
auto mspCfg = spiCookie->getMspCfg();
|
||||
|
||||
if (transferMode == spi::TransferModes::POLLING) {
|
||||
auto typedCfg = dynamic_cast<spi::MspPollingConfigStruct *>(mspCfg);
|
||||
if (typedCfg == nullptr) {
|
||||
printCfgError("Polling MSP");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
spi::setSpiPollingMspFunctions(typedCfg);
|
||||
} else if (transferMode == spi::TransferModes::INTERRUPT) {
|
||||
auto typedCfg = dynamic_cast<spi::MspIrqConfigStruct *>(mspCfg);
|
||||
if (typedCfg == nullptr) {
|
||||
printCfgError("IRQ MSP");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
spi::setSpiIrqMspFunctions(typedCfg);
|
||||
} else if (transferMode == spi::TransferModes::DMA) {
|
||||
auto typedCfg = dynamic_cast<spi::MspDmaConfigStruct *>(mspCfg);
|
||||
if (typedCfg == nullptr) {
|
||||
printCfgError("DMA MSP");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
// Check DMA handles
|
||||
DMA_HandleTypeDef *txHandle = nullptr;
|
||||
DMA_HandleTypeDef *rxHandle = nullptr;
|
||||
spi::getDmaHandles(&txHandle, &rxHandle);
|
||||
if (txHandle == nullptr or rxHandle == nullptr) {
|
||||
printCfgError("DMA Handle");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
spi::setSpiDmaMspFunctions(typedCfg);
|
||||
}
|
||||
|
||||
if (gpioPort != nullptr) {
|
||||
gpio::initializeGpioClock(gpioPort);
|
||||
GPIO_InitTypeDef chipSelect = {};
|
||||
chipSelect.Pin = gpioPin;
|
||||
chipSelect.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
HAL_GPIO_Init(gpioPort, &chipSelect);
|
||||
HAL_GPIO_WritePin(gpioPort, gpioPin, GPIO_PIN_SET);
|
||||
}
|
||||
|
||||
if (HAL_SPI_Init(&spiHandle) != HAL_OK) {
|
||||
sif::printWarning("SpiComIF::initialize: Error initializing SPI\n");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
// The MSP configuration struct is not required anymore
|
||||
spiCookie->deleteMspCfg();
|
||||
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t SpiComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, size_t sendLen) {
|
||||
SpiCookie *spiCookie = dynamic_cast<SpiCookie *>(cookie);
|
||||
if (spiCookie == nullptr) {
|
||||
return NULLPOINTER;
|
||||
}
|
||||
|
||||
SPI_HandleTypeDef &spiHandle = spiCookie->getSpiHandle();
|
||||
|
||||
auto iter = spiDeviceMap.find(spiCookie->getDeviceAddress());
|
||||
if (iter == spiDeviceMap.end()) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
iter->second.currentTransferLen = sendLen;
|
||||
|
||||
auto transferMode = spiCookie->getTransferMode();
|
||||
switch (spiCookie->getTransferState()) {
|
||||
case (spi::TransferStates::IDLE): {
|
||||
break;
|
||||
}
|
||||
case (spi::TransferStates::WAIT):
|
||||
case (spi::TransferStates::FAILURE):
|
||||
case (spi::TransferStates::SUCCESS):
|
||||
default: {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
switch (transferMode) {
|
||||
case (spi::TransferModes::POLLING): {
|
||||
return handlePollingSendOperation(iter->second.replyBuffer.data(), spiHandle, *spiCookie,
|
||||
sendData, sendLen);
|
||||
}
|
||||
case (spi::TransferModes::INTERRUPT): {
|
||||
return handleInterruptSendOperation(iter->second.replyBuffer.data(), spiHandle, *spiCookie,
|
||||
sendData, sendLen);
|
||||
}
|
||||
case (spi::TransferModes::DMA): {
|
||||
return handleDmaSendOperation(iter->second.replyBuffer.data(), spiHandle, *spiCookie,
|
||||
sendData, sendLen);
|
||||
}
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t SpiComIF::getSendSuccess(CookieIF *cookie) { return HasReturnvaluesIF::RETURN_OK; }
|
||||
|
||||
ReturnValue_t SpiComIF::requestReceiveMessage(CookieIF *cookie, size_t requestLen) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t SpiComIF::readReceivedMessage(CookieIF *cookie, uint8_t **buffer, size_t *size) {
|
||||
SpiCookie *spiCookie = dynamic_cast<SpiCookie *>(cookie);
|
||||
if (spiCookie == nullptr) {
|
||||
return NULLPOINTER;
|
||||
}
|
||||
switch (spiCookie->getTransferState()) {
|
||||
case (spi::TransferStates::SUCCESS): {
|
||||
auto iter = spiDeviceMap.find(spiCookie->getDeviceAddress());
|
||||
if (iter == spiDeviceMap.end()) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
*buffer = iter->second.replyBuffer.data();
|
||||
*size = iter->second.currentTransferLen;
|
||||
spiCookie->setTransferState(spi::TransferStates::IDLE);
|
||||
break;
|
||||
}
|
||||
case (spi::TransferStates::FAILURE): {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "SpiComIF::readReceivedMessage: Transfer failure" << std::endl;
|
||||
#else
|
||||
sif::printWarning("SpiComIF::readReceivedMessage: Transfer failure\n");
|
||||
#endif
|
||||
#endif
|
||||
spiCookie->setTransferState(spi::TransferStates::IDLE);
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
case (spi::TransferStates::WAIT):
|
||||
case (spi::TransferStates::IDLE): {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
void SpiComIF::setDefaultPollingTimeout(dur_millis_t timeout) {
|
||||
this->defaultPollingTimeout = timeout;
|
||||
}
|
||||
|
||||
ReturnValue_t SpiComIF::handlePollingSendOperation(uint8_t *recvPtr, SPI_HandleTypeDef &spiHandle,
|
||||
SpiCookie &spiCookie, const uint8_t *sendData,
|
||||
size_t sendLen) {
|
||||
auto gpioPort = spiCookie.getChipSelectGpioPort();
|
||||
auto gpioPin = spiCookie.getChipSelectGpioPin();
|
||||
auto returnval = spiSemaphore->acquire(timeoutType, timeoutMs);
|
||||
if (returnval != HasReturnvaluesIF::RETURN_OK) {
|
||||
return returnval;
|
||||
}
|
||||
spiCookie.setTransferState(spi::TransferStates::WAIT);
|
||||
if (gpioPort != nullptr) {
|
||||
HAL_GPIO_WritePin(gpioPort, gpioPin, GPIO_PIN_RESET);
|
||||
}
|
||||
|
||||
auto result = HAL_SPI_TransmitReceive(&spiHandle, const_cast<uint8_t *>(sendData), recvPtr,
|
||||
sendLen, defaultPollingTimeout);
|
||||
if (gpioPort != nullptr) {
|
||||
HAL_GPIO_WritePin(gpioPort, gpioPin, GPIO_PIN_SET);
|
||||
}
|
||||
spiSemaphore->release();
|
||||
switch (result) {
|
||||
case (HAL_OK): {
|
||||
spiCookie.setTransferState(spi::TransferStates::SUCCESS);
|
||||
break;
|
||||
}
|
||||
case (HAL_TIMEOUT): {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "SpiComIF::sendMessage: Polling Mode | Timeout for SPI device"
|
||||
<< spiCookie->getDeviceAddress() << std::endl;
|
||||
#else
|
||||
sif::printWarning("SpiComIF::sendMessage: Polling Mode | Timeout for SPI device %d\n",
|
||||
spiCookie.getDeviceAddress());
|
||||
#endif
|
||||
#endif
|
||||
spiCookie.setTransferState(spi::TransferStates::FAILURE);
|
||||
return spi::HAL_TIMEOUT_RETVAL;
|
||||
}
|
||||
case (HAL_ERROR):
|
||||
default: {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "SpiComIF::sendMessage: Polling Mode | HAL error for SPI device"
|
||||
<< spiCookie->getDeviceAddress() << std::endl;
|
||||
#else
|
||||
sif::printWarning("SpiComIF::sendMessage: Polling Mode | HAL error for SPI device %d\n",
|
||||
spiCookie.getDeviceAddress());
|
||||
#endif
|
||||
#endif
|
||||
spiCookie.setTransferState(spi::TransferStates::FAILURE);
|
||||
return spi::HAL_ERROR_RETVAL;
|
||||
}
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t SpiComIF::handleInterruptSendOperation(uint8_t *recvPtr, SPI_HandleTypeDef &spiHandle,
|
||||
SpiCookie &spiCookie, const uint8_t *sendData,
|
||||
size_t sendLen) {
|
||||
return handleIrqSendOperation(recvPtr, spiHandle, spiCookie, sendData, sendLen);
|
||||
}
|
||||
|
||||
ReturnValue_t SpiComIF::handleDmaSendOperation(uint8_t *recvPtr, SPI_HandleTypeDef &spiHandle,
|
||||
SpiCookie &spiCookie, const uint8_t *sendData,
|
||||
size_t sendLen) {
|
||||
return handleIrqSendOperation(recvPtr, spiHandle, spiCookie, sendData, sendLen);
|
||||
}
|
||||
|
||||
ReturnValue_t SpiComIF::handleIrqSendOperation(uint8_t *recvPtr, SPI_HandleTypeDef &spiHandle,
|
||||
SpiCookie &spiCookie, const uint8_t *sendData,
|
||||
size_t sendLen) {
|
||||
ReturnValue_t result = genericIrqSendSetup(recvPtr, spiHandle, spiCookie, sendData, sendLen);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
// yet another HAL driver which is not const-correct..
|
||||
HAL_StatusTypeDef status = HAL_OK;
|
||||
auto transferMode = spiCookie.getTransferMode();
|
||||
if (transferMode == spi::TransferModes::DMA) {
|
||||
if (cacheMaintenanceOnTxBuffer) {
|
||||
/* Clean D-cache. Make sure the address is 32-byte aligned and add 32-bytes to length,
|
||||
in case it overlaps cacheline */
|
||||
SCB_CleanDCache_by_Addr((uint32_t *)(((uint32_t)sendData) & ~(uint32_t)0x1F), sendLen + 32);
|
||||
}
|
||||
status = HAL_SPI_TransmitReceive_DMA(&spiHandle, const_cast<uint8_t *>(sendData),
|
||||
currentRecvPtr, sendLen);
|
||||
} else {
|
||||
status = HAL_SPI_TransmitReceive_IT(&spiHandle, const_cast<uint8_t *>(sendData), currentRecvPtr,
|
||||
sendLen);
|
||||
}
|
||||
switch (status) {
|
||||
case (HAL_OK): {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return halErrorHandler(status, transferMode);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t SpiComIF::halErrorHandler(HAL_StatusTypeDef status, spi::TransferModes transferMode) {
|
||||
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, SPI_HandleTypeDef &spiHandle,
|
||||
SpiCookie &spiCookie, const uint8_t *sendData,
|
||||
size_t sendLen) {
|
||||
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;
|
||||
}
|
||||
// Cache the current SPI handle in any case
|
||||
spi::setSpiHandle(&spiHandle);
|
||||
// Assign the IRQ arguments for the user callbacks
|
||||
irqArgs.comIF = this;
|
||||
irqArgs.spiCookie = &spiCookie;
|
||||
// The SPI handle is passed to the default SPI callback as a void argument. This callback
|
||||
// is different from the user callbacks specified above!
|
||||
spi::assignSpiUserArgs(spiCookie.getSpiIdx(), reinterpret_cast<void *>(&spiHandle));
|
||||
if (spiCookie.getChipSelectGpioPort() != nullptr) {
|
||||
HAL_GPIO_WritePin(spiCookie.getChipSelectGpioPort(), spiCookie.getChipSelectGpioPin(),
|
||||
GPIO_PIN_RESET);
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
void SpiComIF::spiTransferTxCompleteCallback(SPI_HandleTypeDef *hspi, void *args) {
|
||||
genericIrqHandler(args, spi::TransferStates::SUCCESS);
|
||||
}
|
||||
|
||||
void SpiComIF::spiTransferRxCompleteCallback(SPI_HandleTypeDef *hspi, void *args) {
|
||||
genericIrqHandler(args, spi::TransferStates::SUCCESS);
|
||||
}
|
||||
|
||||
void SpiComIF::spiTransferCompleteCallback(SPI_HandleTypeDef *hspi, void *args) {
|
||||
genericIrqHandler(args, spi::TransferStates::SUCCESS);
|
||||
}
|
||||
|
||||
void SpiComIF::spiTransferErrorCallback(SPI_HandleTypeDef *hspi, void *args) {
|
||||
genericIrqHandler(args, spi::TransferStates::FAILURE);
|
||||
}
|
||||
|
||||
void SpiComIF::genericIrqHandler(void *irqArgsVoid, spi::TransferStates targetState) {
|
||||
IrqArgs *irqArgs = reinterpret_cast<IrqArgs *>(irqArgsVoid);
|
||||
if (irqArgs == nullptr) {
|
||||
return;
|
||||
}
|
||||
SpiCookie *spiCookie = irqArgs->spiCookie;
|
||||
SpiComIF *comIF = irqArgs->comIF;
|
||||
if (spiCookie == nullptr or comIF == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
spiCookie->setTransferState(targetState);
|
||||
|
||||
if (spiCookie->getChipSelectGpioPort() != nullptr) {
|
||||
// Pull CS pin high again
|
||||
HAL_GPIO_WritePin(spiCookie->getChipSelectGpioPort(), spiCookie->getChipSelectGpioPin(),
|
||||
GPIO_PIN_SET);
|
||||
}
|
||||
|
||||
#if defined FSFW_OSAL_FREERTOS
|
||||
// Release the task semaphore
|
||||
BaseType_t taskWoken = pdFALSE;
|
||||
ReturnValue_t result =
|
||||
BinarySemaphore::releaseFromISR(comIF->spiSemaphore->getSemaphore(), &taskWoken);
|
||||
#elif defined FSFW_OSAL_RTEMS
|
||||
ReturnValue_t result = comIF->spiSemaphore->release();
|
||||
#endif
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
// Configuration error
|
||||
printf("SpiComIF::genericIrqHandler: Failure releasing Semaphore!\n");
|
||||
}
|
||||
|
||||
// Perform cache maintenance operation for DMA transfers
|
||||
if (spiCookie->getTransferMode() == spi::TransferModes::DMA) {
|
||||
// Invalidate cache prior to access by CPU
|
||||
SCB_InvalidateDCache_by_Addr((uint32_t *)comIF->currentRecvPtr, comIF->currentRecvBuffSize);
|
||||
}
|
||||
#if defined FSFW_OSAL_FREERTOS
|
||||
/* 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);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void SpiComIF::printCfgError(const char *const type) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "SpiComIF::initializeInterface: Invalid " << type << " configuration"
|
||||
<< std::endl;
|
||||
#else
|
||||
sif::printWarning("SpiComIF::initializeInterface: Invalid %s configuration\n", type);
|
||||
#endif
|
||||
}
|
126
src/fsfw_hal/stm32h7/spi/SpiComIF.h
Normal file
126
src/fsfw_hal/stm32h7/spi/SpiComIF.h
Normal file
@ -0,0 +1,126 @@
|
||||
#ifndef FSFW_HAL_STM32H7_SPI_SPICOMIF_H_
|
||||
#define FSFW_HAL_STM32H7_SPI_SPICOMIF_H_
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "fsfw/devicehandlers/DeviceCommunicationIF.h"
|
||||
#include "fsfw/objectmanager/SystemObject.h"
|
||||
#include "fsfw/tasks/SemaphoreIF.h"
|
||||
#include "fsfw_hal/stm32h7/spi/spiDefinitions.h"
|
||||
#include "stm32h743xx.h"
|
||||
#include "stm32h7xx_hal_spi.h"
|
||||
|
||||
class SpiCookie;
|
||||
class BinarySemaphore;
|
||||
|
||||
/**
|
||||
* @brief This communication interface allows using generic device handlers with using
|
||||
* the STM32H7 SPI peripherals
|
||||
* @details
|
||||
* This communication interface supports all three major communcation modes:
|
||||
* - Polling: Simple, but not recommended to real use-cases, blocks the CPU
|
||||
* - Interrupt: Good for small data only arriving occasionally
|
||||
* - DMA: Good for large data which also occur regularly. Please note that the number
|
||||
* of DMA channels in limited
|
||||
* The device specific information is usually kept in the SpiCookie class. The current
|
||||
* implementation limits the transfer mode for a given SPI bus.
|
||||
* @author R. Mueller
|
||||
*/
|
||||
class SpiComIF : public SystemObject, public DeviceCommunicationIF {
|
||||
public:
|
||||
/**
|
||||
* Create a SPI communication interface for the given SPI peripheral (spiInstance)
|
||||
* @param objectId
|
||||
* @param spiInstance
|
||||
* @param spiHandle
|
||||
* @param transferMode
|
||||
*/
|
||||
SpiComIF(object_id_t objectId);
|
||||
|
||||
/**
|
||||
* Allows the user to disable cache maintenance on the TX buffer. This can be done if the
|
||||
* TX buffers are places and MPU protected properly like specified in this link:
|
||||
* https://community.st.com/s/article/FAQ-DMA-is-not-working-on-STM32H7-devices
|
||||
* The cache maintenace is enabled by default.
|
||||
* @param enable
|
||||
*/
|
||||
void configureCacheMaintenanceOnTxBuffer(bool enable);
|
||||
|
||||
void setDefaultPollingTimeout(dur_millis_t timeout);
|
||||
|
||||
/**
|
||||
* Add the DMA handles. These need to be set in the DMA transfer mode is used.
|
||||
* @param txHandle
|
||||
* @param rxHandle
|
||||
*/
|
||||
void addDmaHandles(DMA_HandleTypeDef* txHandle, DMA_HandleTypeDef* rxHandle);
|
||||
|
||||
ReturnValue_t initialize() override;
|
||||
|
||||
// DeviceCommunicationIF overrides
|
||||
virtual ReturnValue_t initializeInterface(CookieIF* cookie) override;
|
||||
virtual ReturnValue_t sendMessage(CookieIF* cookie, const uint8_t* sendData,
|
||||
size_t sendLen) override;
|
||||
virtual ReturnValue_t getSendSuccess(CookieIF* cookie) override;
|
||||
virtual ReturnValue_t requestReceiveMessage(CookieIF* cookie, size_t requestLen) override;
|
||||
virtual ReturnValue_t readReceivedMessage(CookieIF* cookie, uint8_t** buffer,
|
||||
size_t* size) override;
|
||||
|
||||
protected:
|
||||
struct SpiInstance {
|
||||
SpiInstance(size_t maxRecvSize) : replyBuffer(std::vector<uint8_t>(maxRecvSize)) {}
|
||||
std::vector<uint8_t> replyBuffer;
|
||||
size_t currentTransferLen = 0;
|
||||
};
|
||||
|
||||
struct IrqArgs {
|
||||
SpiComIF* comIF = nullptr;
|
||||
SpiCookie* spiCookie = nullptr;
|
||||
};
|
||||
|
||||
IrqArgs irqArgs;
|
||||
|
||||
uint32_t defaultPollingTimeout = 50;
|
||||
|
||||
SemaphoreIF::TimeoutType timeoutType = SemaphoreIF::TimeoutType::WAITING;
|
||||
dur_millis_t timeoutMs = 20;
|
||||
|
||||
BinarySemaphore* spiSemaphore = nullptr;
|
||||
bool cacheMaintenanceOnTxBuffer = true;
|
||||
|
||||
using SpiDeviceMap = std::map<address_t, SpiInstance>;
|
||||
using SpiDeviceMapIter = SpiDeviceMap::iterator;
|
||||
|
||||
uint8_t* currentRecvPtr = nullptr;
|
||||
size_t currentRecvBuffSize = 0;
|
||||
|
||||
SpiDeviceMap spiDeviceMap;
|
||||
|
||||
ReturnValue_t handlePollingSendOperation(uint8_t* recvPtr, SPI_HandleTypeDef& spiHandle,
|
||||
SpiCookie& spiCookie, const uint8_t* sendData,
|
||||
size_t sendLen);
|
||||
ReturnValue_t handleInterruptSendOperation(uint8_t* recvPtr, SPI_HandleTypeDef& spiHandle,
|
||||
SpiCookie& spiCookie, const uint8_t* sendData,
|
||||
size_t sendLen);
|
||||
ReturnValue_t handleDmaSendOperation(uint8_t* recvPtr, SPI_HandleTypeDef& spiHandle,
|
||||
SpiCookie& spiCookie, const uint8_t* sendData,
|
||||
size_t sendLen);
|
||||
ReturnValue_t handleIrqSendOperation(uint8_t* recvPtr, SPI_HandleTypeDef& spiHandle,
|
||||
SpiCookie& spiCookie, const uint8_t* sendData,
|
||||
size_t sendLen);
|
||||
ReturnValue_t genericIrqSendSetup(uint8_t* recvPtr, SPI_HandleTypeDef& spiHandle,
|
||||
SpiCookie& spiCookie, const uint8_t* sendData, size_t sendLen);
|
||||
ReturnValue_t halErrorHandler(HAL_StatusTypeDef status, spi::TransferModes transferMode);
|
||||
|
||||
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(void* irqArgs, spi::TransferStates targetState);
|
||||
|
||||
void printCfgError(const char* const type);
|
||||
};
|
||||
|
||||
#endif /* FSFW_HAL_STM32H7_SPI_SPICOMIF_H_ */
|
60
src/fsfw_hal/stm32h7/spi/SpiCookie.cpp
Normal file
60
src/fsfw_hal/stm32h7/spi/SpiCookie.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
#include "fsfw_hal/stm32h7/spi/SpiCookie.h"
|
||||
|
||||
SpiCookie::SpiCookie(address_t deviceAddress, spi::SpiBus spiIdx, spi::TransferModes transferMode,
|
||||
spi::MspCfgBase* mspCfg, uint32_t spiSpeed, spi::SpiModes spiMode,
|
||||
size_t maxRecvSize, stm32h7::GpioCfg csGpio)
|
||||
: deviceAddress(deviceAddress),
|
||||
spiIdx(spiIdx),
|
||||
spiSpeed(spiSpeed),
|
||||
spiMode(spiMode),
|
||||
transferMode(transferMode),
|
||||
csGpio(csGpio),
|
||||
mspCfg(mspCfg),
|
||||
maxRecvSize(maxRecvSize) {
|
||||
spiHandle.Init.DataSize = SPI_DATASIZE_8BIT;
|
||||
spiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;
|
||||
spiHandle.Init.TIMode = SPI_TIMODE_DISABLE;
|
||||
spiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
|
||||
spiHandle.Init.CRCPolynomial = 7;
|
||||
spiHandle.Init.CRCLength = SPI_CRC_LENGTH_8BIT;
|
||||
spiHandle.Init.NSS = SPI_NSS_SOFT;
|
||||
spiHandle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
|
||||
spiHandle.Init.Direction = SPI_DIRECTION_2LINES;
|
||||
// Recommended setting to avoid glitches
|
||||
spiHandle.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;
|
||||
spiHandle.Init.Mode = SPI_MODE_MASTER;
|
||||
spi::assignSpiMode(spiMode, spiHandle);
|
||||
spiHandle.Init.BaudRatePrescaler = spi::getPrescaler(HAL_RCC_GetHCLKFreq(), spiSpeed);
|
||||
}
|
||||
|
||||
uint16_t SpiCookie::getChipSelectGpioPin() const { return csGpio.pin; }
|
||||
|
||||
GPIO_TypeDef* SpiCookie::getChipSelectGpioPort() { return csGpio.port; }
|
||||
|
||||
address_t SpiCookie::getDeviceAddress() const { return deviceAddress; }
|
||||
|
||||
spi::SpiBus SpiCookie::getSpiIdx() const { return spiIdx; }
|
||||
|
||||
spi::SpiModes SpiCookie::getSpiMode() const { return spiMode; }
|
||||
|
||||
uint32_t SpiCookie::getSpiSpeed() const { return spiSpeed; }
|
||||
|
||||
size_t SpiCookie::getMaxRecvSize() const { return maxRecvSize; }
|
||||
|
||||
SPI_HandleTypeDef& SpiCookie::getSpiHandle() { return spiHandle; }
|
||||
|
||||
spi::MspCfgBase* SpiCookie::getMspCfg() { return mspCfg; }
|
||||
|
||||
void SpiCookie::deleteMspCfg() {
|
||||
if (mspCfg != nullptr) {
|
||||
delete mspCfg;
|
||||
}
|
||||
}
|
||||
|
||||
spi::TransferModes SpiCookie::getTransferMode() const { return transferMode; }
|
||||
|
||||
void SpiCookie::setTransferState(spi::TransferStates transferState) {
|
||||
this->transferState = transferState;
|
||||
}
|
||||
|
||||
spi::TransferStates SpiCookie::getTransferState() const { return this->transferState; }
|
76
src/fsfw_hal/stm32h7/spi/SpiCookie.h
Normal file
76
src/fsfw_hal/stm32h7/spi/SpiCookie.h
Normal file
@ -0,0 +1,76 @@
|
||||
#ifndef FSFW_HAL_STM32H7_SPI_SPICOOKIE_H_
|
||||
#define FSFW_HAL_STM32H7_SPI_SPICOOKIE_H_
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "../definitions.h"
|
||||
#include "fsfw/devicehandlers/CookieIF.h"
|
||||
#include "mspInit.h"
|
||||
#include "spiDefinitions.h"
|
||||
#include "stm32h743xx.h"
|
||||
|
||||
/**
|
||||
* @brief SPI cookie implementation for the STM32H7 device family
|
||||
* @details
|
||||
* This cookie contains and caches device specific information to be used by the
|
||||
* SPI communication interface
|
||||
* @author R. Mueller
|
||||
*/
|
||||
class SpiCookie : public CookieIF {
|
||||
friend class SpiComIF;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Allows construction of a SPI cookie for a connected SPI device
|
||||
* @param deviceAddress
|
||||
* @param spiIdx SPI bus, e.g. SPI1 or SPI2
|
||||
* @param transferMode
|
||||
* @param mspCfg This is the MSP configuration. The user is expected to supply
|
||||
* a valid MSP configuration. See mspInit.h for functions
|
||||
* to create one.
|
||||
* @param spiSpeed
|
||||
* @param spiMode
|
||||
* @param chipSelectGpioPin GPIO port. Don't use a number here, use the 16 bit type
|
||||
* definitions supplied in the MCU header file! (e.g. GPIO_PIN_X)
|
||||
* @param chipSelectGpioPort GPIO port (e.g. GPIOA)
|
||||
* @param maxRecvSize Maximum expected receive size. Chose as small as possible.
|
||||
* @param csGpio Optional CS GPIO definition.
|
||||
*/
|
||||
SpiCookie(address_t deviceAddress, spi::SpiBus spiIdx, spi::TransferModes transferMode,
|
||||
spi::MspCfgBase* mspCfg, uint32_t spiSpeed, spi::SpiModes spiMode, size_t maxRecvSize,
|
||||
stm32h7::GpioCfg csGpio = stm32h7::GpioCfg(nullptr, 0, 0));
|
||||
|
||||
uint16_t getChipSelectGpioPin() const;
|
||||
GPIO_TypeDef* getChipSelectGpioPort();
|
||||
address_t getDeviceAddress() const;
|
||||
spi::SpiBus getSpiIdx() const;
|
||||
spi::SpiModes getSpiMode() const;
|
||||
spi::TransferModes getTransferMode() const;
|
||||
uint32_t getSpiSpeed() const;
|
||||
size_t getMaxRecvSize() const;
|
||||
SPI_HandleTypeDef& getSpiHandle();
|
||||
|
||||
private:
|
||||
address_t deviceAddress;
|
||||
SPI_HandleTypeDef spiHandle = {};
|
||||
spi::SpiBus spiIdx;
|
||||
uint32_t spiSpeed;
|
||||
spi::SpiModes spiMode;
|
||||
spi::TransferModes transferMode;
|
||||
volatile spi::TransferStates transferState = spi::TransferStates::IDLE;
|
||||
stm32h7::GpioCfg csGpio;
|
||||
|
||||
// The MSP configuration is cached here. Be careful when using this, it is automatically
|
||||
// deleted by the SPI communication interface if it is not required anymore!
|
||||
spi::MspCfgBase* mspCfg = nullptr;
|
||||
const size_t maxRecvSize;
|
||||
|
||||
// Only the SpiComIF is allowed to use this to prevent dangling pointers issues
|
||||
spi::MspCfgBase* getMspCfg();
|
||||
void deleteMspCfg();
|
||||
|
||||
void setTransferState(spi::TransferStates transferState);
|
||||
spi::TransferStates getTransferState() const;
|
||||
};
|
||||
|
||||
#endif /* FSFW_HAL_STM32H7_SPI_SPICOOKIE_H_ */
|
248
src/fsfw_hal/stm32h7/spi/mspInit.cpp
Normal file
248
src/fsfw_hal/stm32h7/spi/mspInit.cpp
Normal file
@ -0,0 +1,248 @@
|
||||
#include "fsfw_hal/stm32h7/spi/mspInit.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include "fsfw_hal/stm32h7/dma.h"
|
||||
#include "fsfw_hal/stm32h7/spi/spiCore.h"
|
||||
#include "fsfw_hal/stm32h7/spi/spiInterrupts.h"
|
||||
#include "stm32h743xx.h"
|
||||
#include "stm32h7xx_hal_def.h"
|
||||
#include "stm32h7xx_hal_dma.h"
|
||||
#include "stm32h7xx_hal_spi.h"
|
||||
|
||||
spi::msp_func_t mspInitFunc = nullptr;
|
||||
spi::MspCfgBase* mspInitArgs = nullptr;
|
||||
|
||||
spi::msp_func_t mspDeinitFunc = nullptr;
|
||||
spi::MspCfgBase* mspDeinitArgs = nullptr;
|
||||
|
||||
/**
|
||||
* @brief SPI MSP Initialization
|
||||
* This function configures the hardware resources used in this example:
|
||||
* - Peripheral's clock enable
|
||||
* - Peripheral's GPIO Configuration
|
||||
* - DMA configuration for transmission request by peripheral
|
||||
* - NVIC configuration for DMA interrupt request enable
|
||||
* @param hspi: SPI handle pointer
|
||||
* @retval None
|
||||
*/
|
||||
void spi::halMspInitDma(SPI_HandleTypeDef* hspi, MspCfgBase* cfgBase) {
|
||||
auto cfg = dynamic_cast<MspDmaConfigStruct*>(cfgBase);
|
||||
if (hspi == nullptr or cfg == nullptr) {
|
||||
return;
|
||||
}
|
||||
setSpiHandle(hspi);
|
||||
|
||||
DMA_HandleTypeDef* hdma_tx = nullptr;
|
||||
DMA_HandleTypeDef* hdma_rx = nullptr;
|
||||
spi::getDmaHandles(&hdma_tx, &hdma_rx);
|
||||
if (hdma_tx == nullptr or hdma_rx == nullptr) {
|
||||
printf("HAL_SPI_MspInit: Invalid DMA handles. Make sure to call setDmaHandles!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
spi::halMspInitInterrupt(hspi, cfg);
|
||||
|
||||
// DMA setup
|
||||
if (cfg->dmaClkEnableWrapper == nullptr) {
|
||||
mspErrorHandler("spi::halMspInitDma", "DMA Clock init invalid");
|
||||
}
|
||||
cfg->dmaClkEnableWrapper();
|
||||
|
||||
// Configure the DMA
|
||||
/* Configure the DMA handler for Transmission process */
|
||||
if (hdma_tx->Instance == nullptr) {
|
||||
// Assume it was not configured properly
|
||||
mspErrorHandler("spi::halMspInitDma", "DMA TX handle invalid");
|
||||
}
|
||||
|
||||
HAL_DMA_Init(hdma_tx);
|
||||
/* Associate the initialized DMA handle to the the SPI handle */
|
||||
__HAL_LINKDMA(hspi, hdmatx, *hdma_tx);
|
||||
|
||||
HAL_DMA_Init(hdma_rx);
|
||||
/* Associate the initialized DMA handle to the the SPI handle */
|
||||
__HAL_LINKDMA(hspi, hdmarx, *hdma_rx);
|
||||
|
||||
/*##-4- Configure the NVIC for DMA #########################################*/
|
||||
/* NVIC configuration for DMA transfer complete interrupt (SPI1_RX) */
|
||||
// Assign the interrupt handler
|
||||
dma::assignDmaUserHandler(cfg->rxDmaIndex, cfg->rxDmaStream, &spi::dmaRxIrqHandler, hdma_rx);
|
||||
HAL_NVIC_SetPriority(cfg->rxDmaIrqNumber, cfg->rxPreEmptPriority, cfg->rxSubpriority);
|
||||
HAL_NVIC_EnableIRQ(cfg->rxDmaIrqNumber);
|
||||
|
||||
/* NVIC configuration for DMA transfer complete interrupt (SPI1_TX) */
|
||||
// Assign the interrupt handler
|
||||
dma::assignDmaUserHandler(cfg->txDmaIndex, cfg->txDmaStream, &spi::dmaTxIrqHandler, hdma_tx);
|
||||
HAL_NVIC_SetPriority(cfg->txDmaIrqNumber, cfg->txPreEmptPriority, cfg->txSubpriority);
|
||||
HAL_NVIC_EnableIRQ(cfg->txDmaIrqNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SPI MSP De-Initialization
|
||||
* This function frees the hardware resources used in this example:
|
||||
* - Disable the Peripheral's clock
|
||||
* - Revert GPIO, DMA and NVIC configuration to their default state
|
||||
* @param hspi: SPI handle pointer
|
||||
* @retval None
|
||||
*/
|
||||
void spi::halMspDeinitDma(SPI_HandleTypeDef* hspi, MspCfgBase* cfgBase) {
|
||||
auto cfg = dynamic_cast<MspDmaConfigStruct*>(cfgBase);
|
||||
if (hspi == nullptr or cfg == nullptr) {
|
||||
return;
|
||||
}
|
||||
spi::halMspDeinitInterrupt(hspi, cfgBase);
|
||||
DMA_HandleTypeDef* hdma_tx = NULL;
|
||||
DMA_HandleTypeDef* hdma_rx = NULL;
|
||||
spi::getDmaHandles(&hdma_tx, &hdma_rx);
|
||||
if (hdma_tx == NULL || hdma_rx == NULL) {
|
||||
printf("HAL_SPI_MspInit: Invalid DMA handles. Make sure to call setDmaHandles!\n");
|
||||
} else {
|
||||
// Disable the DMA
|
||||
/* De-Initialize the DMA associated to transmission process */
|
||||
HAL_DMA_DeInit(hdma_tx);
|
||||
/* De-Initialize the DMA associated to reception process */
|
||||
HAL_DMA_DeInit(hdma_rx);
|
||||
}
|
||||
|
||||
// Disable the NVIC for DMA
|
||||
HAL_NVIC_DisableIRQ(cfg->txDmaIrqNumber);
|
||||
HAL_NVIC_DisableIRQ(cfg->rxDmaIrqNumber);
|
||||
}
|
||||
|
||||
void spi::halMspInitPolling(SPI_HandleTypeDef* hspi, MspCfgBase* cfgBase) {
|
||||
auto cfg = dynamic_cast<MspPollingConfigStruct*>(cfgBase);
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {};
|
||||
/*##-1- Enable peripherals and GPIO Clocks #################################*/
|
||||
/* Enable GPIO TX/RX clock */
|
||||
cfg->setupCb();
|
||||
|
||||
/*##-2- Configure peripheral GPIO ##########################################*/
|
||||
/* SPI SCK GPIO pin configuration */
|
||||
GPIO_InitStruct.Pin = cfg->sck.pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
|
||||
GPIO_InitStruct.Alternate = cfg->sck.altFnc;
|
||||
HAL_GPIO_Init(cfg->sck.port, &GPIO_InitStruct);
|
||||
|
||||
/* SPI MISO GPIO pin configuration */
|
||||
GPIO_InitStruct.Pin = cfg->miso.pin;
|
||||
GPIO_InitStruct.Alternate = cfg->miso.altFnc;
|
||||
HAL_GPIO_Init(cfg->miso.port, &GPIO_InitStruct);
|
||||
|
||||
/* SPI MOSI GPIO pin configuration */
|
||||
GPIO_InitStruct.Pin = cfg->mosi.pin;
|
||||
GPIO_InitStruct.Alternate = cfg->mosi.altFnc;
|
||||
HAL_GPIO_Init(cfg->mosi.port, &GPIO_InitStruct);
|
||||
}
|
||||
|
||||
void spi::halMspDeinitPolling(SPI_HandleTypeDef* hspi, MspCfgBase* cfgBase) {
|
||||
auto cfg = reinterpret_cast<MspPollingConfigStruct*>(cfgBase);
|
||||
// Reset peripherals
|
||||
cfg->cleanupCb();
|
||||
|
||||
// Disable peripherals and GPIO Clocks
|
||||
/* Configure SPI SCK as alternate function */
|
||||
HAL_GPIO_DeInit(cfg->sck.port, cfg->sck.pin);
|
||||
/* Configure SPI MISO as alternate function */
|
||||
HAL_GPIO_DeInit(cfg->miso.port, cfg->miso.pin);
|
||||
/* Configure SPI MOSI as alternate function */
|
||||
HAL_GPIO_DeInit(cfg->mosi.port, cfg->mosi.pin);
|
||||
}
|
||||
|
||||
void spi::halMspInitInterrupt(SPI_HandleTypeDef* hspi, MspCfgBase* cfgBase) {
|
||||
auto cfg = dynamic_cast<MspIrqConfigStruct*>(cfgBase);
|
||||
if (cfg == nullptr or hspi == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
spi::halMspInitPolling(hspi, cfg);
|
||||
// Configure the NVIC for SPI
|
||||
spi::assignSpiUserHandler(cfg->spiBus, cfg->spiIrqHandler, cfg->spiUserArgs);
|
||||
HAL_NVIC_SetPriority(cfg->spiIrqNumber, cfg->preEmptPriority, cfg->subpriority);
|
||||
HAL_NVIC_EnableIRQ(cfg->spiIrqNumber);
|
||||
}
|
||||
|
||||
void spi::halMspDeinitInterrupt(SPI_HandleTypeDef* hspi, MspCfgBase* cfgBase) {
|
||||
auto cfg = dynamic_cast<MspIrqConfigStruct*>(cfgBase);
|
||||
spi::halMspDeinitPolling(hspi, cfg);
|
||||
// Disable the NVIC for SPI
|
||||
HAL_NVIC_DisableIRQ(cfg->spiIrqNumber);
|
||||
}
|
||||
|
||||
void spi::getMspInitFunction(msp_func_t* init_func, MspCfgBase** args) {
|
||||
if (init_func != NULL && args != NULL) {
|
||||
*init_func = mspInitFunc;
|
||||
*args = mspInitArgs;
|
||||
}
|
||||
}
|
||||
|
||||
void spi::getMspDeinitFunction(msp_func_t* deinit_func, MspCfgBase** args) {
|
||||
if (deinit_func != NULL && args != NULL) {
|
||||
*deinit_func = mspDeinitFunc;
|
||||
*args = mspDeinitArgs;
|
||||
}
|
||||
}
|
||||
|
||||
void spi::setSpiDmaMspFunctions(MspDmaConfigStruct* cfg, msp_func_t initFunc,
|
||||
msp_func_t deinitFunc) {
|
||||
mspInitFunc = initFunc;
|
||||
mspDeinitFunc = deinitFunc;
|
||||
mspInitArgs = cfg;
|
||||
mspDeinitArgs = cfg;
|
||||
}
|
||||
|
||||
void spi::setSpiIrqMspFunctions(MspIrqConfigStruct* cfg, msp_func_t initFunc,
|
||||
msp_func_t deinitFunc) {
|
||||
mspInitFunc = initFunc;
|
||||
mspDeinitFunc = deinitFunc;
|
||||
mspInitArgs = cfg;
|
||||
mspDeinitArgs = cfg;
|
||||
}
|
||||
|
||||
void spi::setSpiPollingMspFunctions(MspPollingConfigStruct* cfg, msp_func_t initFunc,
|
||||
msp_func_t deinitFunc) {
|
||||
mspInitFunc = initFunc;
|
||||
mspDeinitFunc = deinitFunc;
|
||||
mspInitArgs = cfg;
|
||||
mspDeinitArgs = cfg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SPI MSP Initialization
|
||||
* This function configures the hardware resources used in this example:
|
||||
* - Peripheral's clock enable
|
||||
* - Peripheral's GPIO Configuration
|
||||
* - DMA configuration for transmission request by peripheral
|
||||
* - NVIC configuration for DMA interrupt request enable
|
||||
* @param hspi: SPI handle pointer
|
||||
* @retval None
|
||||
*/
|
||||
extern "C" void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi) {
|
||||
if (mspInitFunc != NULL) {
|
||||
mspInitFunc(hspi, mspInitArgs);
|
||||
} else {
|
||||
printf("HAL_SPI_MspInit: Please call set_msp_functions to assign SPI MSP functions\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SPI MSP De-Initialization
|
||||
* This function frees the hardware resources used in this example:
|
||||
* - Disable the Peripheral's clock
|
||||
* - Revert GPIO, DMA and NVIC configuration to their default state
|
||||
* @param hspi: SPI handle pointer
|
||||
* @retval None
|
||||
*/
|
||||
extern "C" void HAL_SPI_MspDeInit(SPI_HandleTypeDef* hspi) {
|
||||
if (mspDeinitFunc != NULL) {
|
||||
mspDeinitFunc(hspi, mspDeinitArgs);
|
||||
} else {
|
||||
printf("HAL_SPI_MspDeInit: Please call set_msp_functions to assign SPI MSP functions\n");
|
||||
}
|
||||
}
|
||||
|
||||
void spi::mspErrorHandler(const char* const function, const char* const message) {
|
||||
printf("%s failure: %s\n", function, message);
|
||||
}
|
123
src/fsfw_hal/stm32h7/spi/mspInit.h
Normal file
123
src/fsfw_hal/stm32h7/spi/mspInit.h
Normal file
@ -0,0 +1,123 @@
|
||||
#ifndef FSFW_HAL_STM32H7_SPI_MSPINIT_H_
|
||||
#define FSFW_HAL_STM32H7_SPI_MSPINIT_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "../definitions.h"
|
||||
#include "../dma.h"
|
||||
#include "spiDefinitions.h"
|
||||
#include "stm32h7xx_hal_spi.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
using mspCb = void (*)(void);
|
||||
|
||||
/**
|
||||
* @brief This file provides MSP implementation for DMA, IRQ and Polling mode for the
|
||||
* SPI peripheral. This configuration is required for the SPI communication to work.
|
||||
*/
|
||||
namespace spi {
|
||||
|
||||
struct MspCfgBase {
|
||||
MspCfgBase() {}
|
||||
MspCfgBase(stm32h7::GpioCfg sck, stm32h7::GpioCfg mosi, stm32h7::GpioCfg miso,
|
||||
mspCb cleanupCb = nullptr, mspCb setupCb = nullptr)
|
||||
: sck(sck), mosi(mosi), miso(miso), cleanupCb(cleanupCb), setupCb(setupCb) {}
|
||||
|
||||
virtual ~MspCfgBase() = default;
|
||||
|
||||
stm32h7::GpioCfg sck;
|
||||
stm32h7::GpioCfg mosi;
|
||||
stm32h7::GpioCfg miso;
|
||||
|
||||
mspCb cleanupCb = nullptr;
|
||||
mspCb setupCb = nullptr;
|
||||
};
|
||||
|
||||
struct MspPollingConfigStruct : public MspCfgBase {
|
||||
MspPollingConfigStruct() : MspCfgBase(){};
|
||||
MspPollingConfigStruct(stm32h7::GpioCfg sck, stm32h7::GpioCfg mosi, stm32h7::GpioCfg miso,
|
||||
mspCb cleanupCb = nullptr, mspCb setupCb = nullptr)
|
||||
: MspCfgBase(sck, mosi, miso, cleanupCb, setupCb) {}
|
||||
};
|
||||
|
||||
/* A valid instance of this struct must be passed to the MSP initialization function as a void*
|
||||
argument */
|
||||
struct MspIrqConfigStruct : public MspPollingConfigStruct {
|
||||
MspIrqConfigStruct() : MspPollingConfigStruct(){};
|
||||
MspIrqConfigStruct(stm32h7::GpioCfg sck, stm32h7::GpioCfg mosi, stm32h7::GpioCfg miso,
|
||||
mspCb cleanupCb = nullptr, mspCb setupCb = nullptr)
|
||||
: MspPollingConfigStruct(sck, mosi, miso, cleanupCb, setupCb) {}
|
||||
|
||||
SpiBus spiBus = SpiBus::SPI_1;
|
||||
user_handler_t spiIrqHandler = nullptr;
|
||||
user_args_t spiUserArgs = nullptr;
|
||||
IRQn_Type spiIrqNumber = SPI1_IRQn;
|
||||
// Priorities for NVIC
|
||||
// Pre-Empt priority ranging from 0 to 15. If FreeRTOS calls are used, only 5-15 are allowed
|
||||
IrqPriorities preEmptPriority = IrqPriorities::LOWEST;
|
||||
IrqPriorities subpriority = IrqPriorities::LOWEST;
|
||||
};
|
||||
|
||||
/* A valid instance of this struct must be passed to the MSP initialization function as a void*
|
||||
argument */
|
||||
struct MspDmaConfigStruct : public MspIrqConfigStruct {
|
||||
MspDmaConfigStruct() : MspIrqConfigStruct(){};
|
||||
MspDmaConfigStruct(stm32h7::GpioCfg sck, stm32h7::GpioCfg mosi, stm32h7::GpioCfg miso,
|
||||
mspCb cleanupCb = nullptr, mspCb setupCb = nullptr)
|
||||
: MspIrqConfigStruct(sck, mosi, miso, cleanupCb, setupCb) {}
|
||||
void (*dmaClkEnableWrapper)(void) = nullptr;
|
||||
|
||||
dma::DMAIndexes txDmaIndex = dma::DMAIndexes::DMA_1;
|
||||
dma::DMAIndexes rxDmaIndex = dma::DMAIndexes::DMA_1;
|
||||
dma::DMAStreams txDmaStream = dma::DMAStreams::STREAM_0;
|
||||
dma::DMAStreams rxDmaStream = dma::DMAStreams::STREAM_0;
|
||||
IRQn_Type txDmaIrqNumber = DMA1_Stream0_IRQn;
|
||||
IRQn_Type rxDmaIrqNumber = DMA1_Stream1_IRQn;
|
||||
// Priorities for NVIC
|
||||
IrqPriorities txPreEmptPriority = IrqPriorities::LOWEST;
|
||||
IrqPriorities rxPreEmptPriority = IrqPriorities::LOWEST;
|
||||
IrqPriorities txSubpriority = IrqPriorities::LOWEST;
|
||||
IrqPriorities rxSubpriority = IrqPriorities::LOWEST;
|
||||
};
|
||||
|
||||
using msp_func_t = void (*)(SPI_HandleTypeDef* hspi, MspCfgBase* cfg);
|
||||
|
||||
void getMspInitFunction(msp_func_t* init_func, MspCfgBase** args);
|
||||
void getMspDeinitFunction(msp_func_t* deinit_func, MspCfgBase** args);
|
||||
|
||||
void halMspInitDma(SPI_HandleTypeDef* hspi, MspCfgBase* cfg);
|
||||
void halMspDeinitDma(SPI_HandleTypeDef* hspi, MspCfgBase* cfg);
|
||||
|
||||
void halMspInitInterrupt(SPI_HandleTypeDef* hspi, MspCfgBase* cfg);
|
||||
void halMspDeinitInterrupt(SPI_HandleTypeDef* hspi, MspCfgBase* cfg);
|
||||
|
||||
void halMspInitPolling(SPI_HandleTypeDef* hspi, MspCfgBase* cfg);
|
||||
void halMspDeinitPolling(SPI_HandleTypeDef* hspi, MspCfgBase* cfg);
|
||||
|
||||
/**
|
||||
* Assign MSP init functions. Important for SPI configuration
|
||||
* @param init_func
|
||||
* @param init_args
|
||||
* @param deinit_func
|
||||
* @param deinit_args
|
||||
*/
|
||||
void setSpiDmaMspFunctions(MspDmaConfigStruct* cfg, msp_func_t initFunc = &spi::halMspInitDma,
|
||||
msp_func_t deinitFunc = &spi::halMspDeinitDma);
|
||||
void setSpiIrqMspFunctions(MspIrqConfigStruct* cfg, msp_func_t initFunc = &spi::halMspInitInterrupt,
|
||||
msp_func_t deinitFunc = &spi::halMspDeinitInterrupt);
|
||||
void setSpiPollingMspFunctions(MspPollingConfigStruct* cfg,
|
||||
msp_func_t initFunc = &spi::halMspInitPolling,
|
||||
msp_func_t deinitFunc = &spi::halMspDeinitPolling);
|
||||
|
||||
void mspErrorHandler(const char* const function, const char* const message);
|
||||
|
||||
} // namespace spi
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FSFW_HAL_STM32H7_SPI_MSPINIT_H_ */
|
329
src/fsfw_hal/stm32h7/spi/spiCore.cpp
Normal file
329
src/fsfw_hal/stm32h7/spi/spiCore.cpp
Normal file
@ -0,0 +1,329 @@
|
||||
#include "fsfw_hal/stm32h7/spi/spiCore.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include "fsfw_hal/stm32h7/spi/spiDefinitions.h"
|
||||
|
||||
SPI_HandleTypeDef* spiHandle = nullptr;
|
||||
DMA_HandleTypeDef* hdmaTx = nullptr;
|
||||
DMA_HandleTypeDef* hdmaRx = nullptr;
|
||||
|
||||
spi_transfer_cb_t rxTxCb = nullptr;
|
||||
void* rxTxArgs = nullptr;
|
||||
spi_transfer_cb_t txCb = nullptr;
|
||||
void* txArgs = nullptr;
|
||||
spi_transfer_cb_t rxCb = nullptr;
|
||||
void* rxArgs = nullptr;
|
||||
spi_transfer_cb_t errorCb = nullptr;
|
||||
void* errorArgs = nullptr;
|
||||
|
||||
void mapIndexAndStream(DMA_HandleTypeDef* handle, dma::DMAType dmaType, dma::DMAIndexes dmaIdx,
|
||||
dma::DMAStreams dmaStream, IRQn_Type* dmaIrqNumber);
|
||||
void mapSpiBus(DMA_HandleTypeDef* handle, dma::DMAType dmaType, spi::SpiBus spiBus);
|
||||
|
||||
void spi::configureDmaHandle(DMA_HandleTypeDef* handle, spi::SpiBus spiBus, dma::DMAType dmaType,
|
||||
dma::DMAIndexes dmaIdx, dma::DMAStreams dmaStream,
|
||||
IRQn_Type* dmaIrqNumber, uint32_t dmaMode, uint32_t dmaPriority) {
|
||||
using namespace dma;
|
||||
mapIndexAndStream(handle, dmaType, dmaIdx, dmaStream, dmaIrqNumber);
|
||||
mapSpiBus(handle, dmaType, spiBus);
|
||||
|
||||
if (dmaType == DMAType::TX) {
|
||||
handle->Init.Direction = DMA_MEMORY_TO_PERIPH;
|
||||
} else {
|
||||
handle->Init.Direction = DMA_PERIPH_TO_MEMORY;
|
||||
}
|
||||
|
||||
handle->Init.Priority = dmaPriority;
|
||||
handle->Init.Mode = dmaMode;
|
||||
|
||||
// Standard settings for the rest for now
|
||||
handle->Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||
handle->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
|
||||
handle->Init.MemBurst = DMA_MBURST_INC4;
|
||||
handle->Init.PeriphBurst = DMA_PBURST_INC4;
|
||||
handle->Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
handle->Init.MemInc = DMA_MINC_ENABLE;
|
||||
handle->Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
|
||||
handle->Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
|
||||
}
|
||||
|
||||
void spi::setDmaHandles(DMA_HandleTypeDef* txHandle, DMA_HandleTypeDef* rxHandle) {
|
||||
hdmaTx = txHandle;
|
||||
hdmaRx = rxHandle;
|
||||
}
|
||||
|
||||
void spi::getDmaHandles(DMA_HandleTypeDef** txHandle, DMA_HandleTypeDef** rxHandle) {
|
||||
*txHandle = hdmaTx;
|
||||
*rxHandle = hdmaRx;
|
||||
}
|
||||
|
||||
void spi::setSpiHandle(SPI_HandleTypeDef* spiHandle_) {
|
||||
if (spiHandle_ == NULL) {
|
||||
return;
|
||||
}
|
||||
spiHandle = spiHandle_;
|
||||
}
|
||||
|
||||
void spi::assignTransferRxTxCompleteCallback(spi_transfer_cb_t callback, void* userArgs) {
|
||||
rxTxCb = callback;
|
||||
rxTxArgs = userArgs;
|
||||
}
|
||||
|
||||
void spi::assignTransferRxCompleteCallback(spi_transfer_cb_t callback, void* userArgs) {
|
||||
rxCb = callback;
|
||||
rxArgs = userArgs;
|
||||
}
|
||||
|
||||
void spi::assignTransferTxCompleteCallback(spi_transfer_cb_t callback, void* userArgs) {
|
||||
txCb = callback;
|
||||
txArgs = userArgs;
|
||||
}
|
||||
|
||||
void spi::assignTransferErrorCallback(spi_transfer_cb_t callback, void* userArgs) {
|
||||
errorCb = callback;
|
||||
errorArgs = userArgs;
|
||||
}
|
||||
|
||||
SPI_HandleTypeDef* spi::getSpiHandle() { return spiHandle; }
|
||||
|
||||
/**
|
||||
* @brief TxRx Transfer completed callback.
|
||||
* @param hspi: SPI handle
|
||||
*/
|
||||
extern "C" void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef* hspi) {
|
||||
if (rxTxCb != NULL) {
|
||||
rxTxCb(hspi, rxTxArgs);
|
||||
} else {
|
||||
printf("HAL_SPI_TxRxCpltCallback: No user callback specified\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TxRx Transfer completed callback.
|
||||
* @param hspi: SPI handle
|
||||
*/
|
||||
extern "C" void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef* hspi) {
|
||||
if (txCb != NULL) {
|
||||
txCb(hspi, txArgs);
|
||||
} else {
|
||||
printf("HAL_SPI_TxCpltCallback: No user callback specified\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TxRx Transfer completed callback.
|
||||
* @param hspi: SPI handle
|
||||
*/
|
||||
extern "C" void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef* hspi) {
|
||||
if (rxCb != nullptr) {
|
||||
rxCb(hspi, rxArgs);
|
||||
} else {
|
||||
printf("HAL_SPI_RxCpltCallback: No user callback specified\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SPI error callbacks.
|
||||
* @param hspi: SPI handle
|
||||
* @note This example shows a simple way to report transfer error, and you can
|
||||
* add your own implementation.
|
||||
* @retval None
|
||||
*/
|
||||
extern "C" void HAL_SPI_ErrorCallback(SPI_HandleTypeDef* hspi) {
|
||||
if (errorCb != nullptr) {
|
||||
errorCb(hspi, rxArgs);
|
||||
} else {
|
||||
printf("HAL_SPI_ErrorCallback: No user callback specified\n");
|
||||
}
|
||||
}
|
||||
|
||||
void mapIndexAndStream(DMA_HandleTypeDef* handle, dma::DMAType dmaType, dma::DMAIndexes dmaIdx,
|
||||
dma::DMAStreams dmaStream, IRQn_Type* dmaIrqNumber) {
|
||||
using namespace dma;
|
||||
if (dmaIdx == DMAIndexes::DMA_1) {
|
||||
#ifdef DMA1
|
||||
switch (dmaStream) {
|
||||
case (DMAStreams::STREAM_0): {
|
||||
#ifdef DMA1_Stream0
|
||||
handle->Instance = DMA1_Stream0;
|
||||
if (dmaIrqNumber != nullptr) {
|
||||
*dmaIrqNumber = DMA1_Stream0_IRQn;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case (DMAStreams::STREAM_1): {
|
||||
#ifdef DMA1_Stream1
|
||||
handle->Instance = DMA1_Stream1;
|
||||
if (dmaIrqNumber != nullptr) {
|
||||
*dmaIrqNumber = DMA1_Stream1_IRQn;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case (DMAStreams::STREAM_2): {
|
||||
#ifdef DMA1_Stream2
|
||||
handle->Instance = DMA1_Stream2;
|
||||
if (dmaIrqNumber != nullptr) {
|
||||
*dmaIrqNumber = DMA1_Stream2_IRQn;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case (DMAStreams::STREAM_3): {
|
||||
#ifdef DMA1_Stream3
|
||||
handle->Instance = DMA1_Stream3;
|
||||
if (dmaIrqNumber != nullptr) {
|
||||
*dmaIrqNumber = DMA1_Stream3_IRQn;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case (DMAStreams::STREAM_4): {
|
||||
#ifdef DMA1_Stream4
|
||||
handle->Instance = DMA1_Stream4;
|
||||
if (dmaIrqNumber != nullptr) {
|
||||
*dmaIrqNumber = DMA1_Stream4_IRQn;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case (DMAStreams::STREAM_5): {
|
||||
#ifdef DMA1_Stream5
|
||||
handle->Instance = DMA1_Stream5;
|
||||
if (dmaIrqNumber != nullptr) {
|
||||
*dmaIrqNumber = DMA1_Stream5_IRQn;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case (DMAStreams::STREAM_6): {
|
||||
#ifdef DMA1_Stream6
|
||||
handle->Instance = DMA1_Stream6;
|
||||
if (dmaIrqNumber != nullptr) {
|
||||
*dmaIrqNumber = DMA1_Stream6_IRQn;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case (DMAStreams::STREAM_7): {
|
||||
#ifdef DMA1_Stream7
|
||||
handle->Instance = DMA1_Stream7;
|
||||
if (dmaIrqNumber != nullptr) {
|
||||
*dmaIrqNumber = DMA1_Stream7_IRQn;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dmaType == DMAType::TX) {
|
||||
handle->Init.Request = DMA_REQUEST_SPI1_TX;
|
||||
} else {
|
||||
handle->Init.Request = DMA_REQUEST_SPI1_RX;
|
||||
}
|
||||
#endif /* DMA1 */
|
||||
}
|
||||
if (dmaIdx == DMAIndexes::DMA_2) {
|
||||
#ifdef DMA2
|
||||
switch (dmaStream) {
|
||||
case (DMAStreams::STREAM_0): {
|
||||
#ifdef DMA2_Stream0
|
||||
handle->Instance = DMA2_Stream0;
|
||||
if (dmaIrqNumber != nullptr) {
|
||||
*dmaIrqNumber = DMA2_Stream0_IRQn;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case (DMAStreams::STREAM_1): {
|
||||
#ifdef DMA2_Stream1
|
||||
handle->Instance = DMA2_Stream1;
|
||||
if (dmaIrqNumber != nullptr) {
|
||||
*dmaIrqNumber = DMA2_Stream1_IRQn;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case (DMAStreams::STREAM_2): {
|
||||
#ifdef DMA2_Stream2
|
||||
handle->Instance = DMA2_Stream2;
|
||||
if (dmaIrqNumber != nullptr) {
|
||||
*dmaIrqNumber = DMA2_Stream2_IRQn;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case (DMAStreams::STREAM_3): {
|
||||
#ifdef DMA2_Stream3
|
||||
handle->Instance = DMA2_Stream3;
|
||||
if (dmaIrqNumber != nullptr) {
|
||||
*dmaIrqNumber = DMA2_Stream3_IRQn;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case (DMAStreams::STREAM_4): {
|
||||
#ifdef DMA2_Stream4
|
||||
handle->Instance = DMA2_Stream4;
|
||||
if (dmaIrqNumber != nullptr) {
|
||||
*dmaIrqNumber = DMA2_Stream4_IRQn;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case (DMAStreams::STREAM_5): {
|
||||
#ifdef DMA2_Stream5
|
||||
handle->Instance = DMA2_Stream5;
|
||||
if (dmaIrqNumber != nullptr) {
|
||||
*dmaIrqNumber = DMA2_Stream5_IRQn;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case (DMAStreams::STREAM_6): {
|
||||
#ifdef DMA2_Stream6
|
||||
handle->Instance = DMA2_Stream6;
|
||||
if (dmaIrqNumber != nullptr) {
|
||||
*dmaIrqNumber = DMA2_Stream6_IRQn;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case (DMAStreams::STREAM_7): {
|
||||
#ifdef DMA2_Stream7
|
||||
handle->Instance = DMA2_Stream7;
|
||||
if (dmaIrqNumber != nullptr) {
|
||||
*dmaIrqNumber = DMA2_Stream7_IRQn;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* DMA2 */
|
||||
}
|
||||
}
|
||||
|
||||
void mapSpiBus(DMA_HandleTypeDef* handle, dma::DMAType dmaType, spi::SpiBus spiBus) {
|
||||
if (dmaType == dma::DMAType::TX) {
|
||||
if (spiBus == spi::SpiBus::SPI_1) {
|
||||
#ifdef DMA_REQUEST_SPI1_TX
|
||||
handle->Init.Request = DMA_REQUEST_SPI1_TX;
|
||||
#endif
|
||||
} else if (spiBus == spi::SpiBus::SPI_2) {
|
||||
#ifdef DMA_REQUEST_SPI2_TX
|
||||
handle->Init.Request = DMA_REQUEST_SPI2_TX;
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
if (spiBus == spi::SpiBus::SPI_1) {
|
||||
#ifdef DMA_REQUEST_SPI1_RX
|
||||
handle->Init.Request = DMA_REQUEST_SPI1_RX;
|
||||
#endif
|
||||
} else if (spiBus == spi::SpiBus::SPI_2) {
|
||||
#ifdef DMA_REQUEST_SPI2_RX
|
||||
handle->Init.Request = DMA_REQUEST_SPI2_RX;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
52
src/fsfw_hal/stm32h7/spi/spiCore.h
Normal file
52
src/fsfw_hal/stm32h7/spi/spiCore.h
Normal file
@ -0,0 +1,52 @@
|
||||
#ifndef FSFW_HAL_STM32H7_SPI_SPICORE_H_
|
||||
#define FSFW_HAL_STM32H7_SPI_SPICORE_H_
|
||||
|
||||
#include "fsfw_hal/stm32h7/dma.h"
|
||||
#include "fsfw_hal/stm32h7/spi/spiDefinitions.h"
|
||||
#include "stm32h7xx_hal.h"
|
||||
#include "stm32h7xx_hal_dma.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
using spi_transfer_cb_t = void (*)(SPI_HandleTypeDef* hspi, void* userArgs);
|
||||
|
||||
namespace spi {
|
||||
|
||||
void configureDmaHandle(DMA_HandleTypeDef* handle, spi::SpiBus spiBus, dma::DMAType dmaType,
|
||||
dma::DMAIndexes dmaIdx, dma::DMAStreams dmaStream, IRQn_Type* dmaIrqNumber,
|
||||
uint32_t dmaMode = DMA_NORMAL, uint32_t dmaPriority = DMA_PRIORITY_LOW);
|
||||
|
||||
/**
|
||||
* Assign DMA handles. Required to use DMA for SPI transfers.
|
||||
* @param txHandle
|
||||
* @param rxHandle
|
||||
*/
|
||||
void setDmaHandles(DMA_HandleTypeDef* txHandle, DMA_HandleTypeDef* rxHandle);
|
||||
void getDmaHandles(DMA_HandleTypeDef** txHandle, DMA_HandleTypeDef** rxHandle);
|
||||
|
||||
/**
|
||||
* Assign SPI handle. Needs to be done before using the SPI
|
||||
* @param spiHandle
|
||||
*/
|
||||
void setSpiHandle(SPI_HandleTypeDef* spiHandle);
|
||||
|
||||
void assignTransferRxTxCompleteCallback(spi_transfer_cb_t callback, void* userArgs);
|
||||
void assignTransferRxCompleteCallback(spi_transfer_cb_t callback, void* userArgs);
|
||||
void assignTransferTxCompleteCallback(spi_transfer_cb_t callback, void* userArgs);
|
||||
void assignTransferErrorCallback(spi_transfer_cb_t callback, void* userArgs);
|
||||
|
||||
/**
|
||||
* Get the assigned SPI handle.
|
||||
* @return
|
||||
*/
|
||||
SPI_HandleTypeDef* getSpiHandle();
|
||||
|
||||
} // namespace spi
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FSFW_HAL_STM32H7_SPI_SPICORE_H_ */
|
46
src/fsfw_hal/stm32h7/spi/spiDefinitions.cpp
Normal file
46
src/fsfw_hal/stm32h7/spi/spiDefinitions.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
#include "fsfw_hal/stm32h7/spi/spiDefinitions.h"
|
||||
|
||||
void spi::assignSpiMode(SpiModes spiMode, SPI_HandleTypeDef& spiHandle) {
|
||||
switch (spiMode) {
|
||||
case (SpiModes::MODE_0): {
|
||||
spiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;
|
||||
spiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;
|
||||
break;
|
||||
}
|
||||
case (SpiModes::MODE_1): {
|
||||
spiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;
|
||||
spiHandle.Init.CLKPhase = SPI_PHASE_2EDGE;
|
||||
break;
|
||||
}
|
||||
case (SpiModes::MODE_2): {
|
||||
spiHandle.Init.CLKPolarity = SPI_POLARITY_HIGH;
|
||||
spiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;
|
||||
break;
|
||||
}
|
||||
case (SpiModes::MODE_3): {
|
||||
spiHandle.Init.CLKPolarity = SPI_POLARITY_HIGH;
|
||||
spiHandle.Init.CLKPhase = SPI_PHASE_2EDGE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t spi::getPrescaler(uint32_t clock_src_freq, uint32_t baudrate_mbps) {
|
||||
uint32_t divisor = 0;
|
||||
uint32_t spi_clk = clock_src_freq;
|
||||
uint32_t presc = 0;
|
||||
static const uint32_t baudrate[] = {
|
||||
SPI_BAUDRATEPRESCALER_2, SPI_BAUDRATEPRESCALER_4, SPI_BAUDRATEPRESCALER_8,
|
||||
SPI_BAUDRATEPRESCALER_16, SPI_BAUDRATEPRESCALER_32, SPI_BAUDRATEPRESCALER_64,
|
||||
SPI_BAUDRATEPRESCALER_128, SPI_BAUDRATEPRESCALER_256,
|
||||
};
|
||||
|
||||
while (spi_clk > baudrate_mbps) {
|
||||
presc = baudrate[divisor];
|
||||
if (++divisor > 7) break;
|
||||
|
||||
spi_clk = (spi_clk >> 1);
|
||||
}
|
||||
|
||||
return presc;
|
||||
}
|
36
src/fsfw_hal/stm32h7/spi/spiDefinitions.h
Normal file
36
src/fsfw_hal/stm32h7/spi/spiDefinitions.h
Normal file
@ -0,0 +1,36 @@
|
||||
#ifndef FSFW_HAL_STM32H7_SPI_SPIDEFINITIONS_H_
|
||||
#define FSFW_HAL_STM32H7_SPI_SPIDEFINITIONS_H_
|
||||
|
||||
#include "../../common/spi/spiCommon.h"
|
||||
#include "fsfw/returnvalues/FwClassIds.h"
|
||||
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
|
||||
#include "stm32h7xx_hal.h"
|
||||
#include "stm32h7xx_hal_spi.h"
|
||||
|
||||
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_BUSY_RETVAL = HasReturnvaluesIF::makeReturnCode(HAL_SPI_ID, 1);
|
||||
static constexpr ReturnValue_t HAL_ERROR_RETVAL = HasReturnvaluesIF::makeReturnCode(HAL_SPI_ID, 2);
|
||||
|
||||
enum class TransferStates { IDLE, WAIT, SUCCESS, FAILURE };
|
||||
|
||||
enum SpiBus { SPI_1, SPI_2 };
|
||||
|
||||
enum TransferModes { POLLING, INTERRUPT, DMA };
|
||||
|
||||
void assignSpiMode(SpiModes spiMode, SPI_HandleTypeDef& spiHandle);
|
||||
|
||||
/**
|
||||
* @brief Set SPI frequency to calculate correspondent baud-rate prescaler.
|
||||
* @param clock_src_freq Frequency of clock source
|
||||
* @param baudrate_mbps Baudrate to set to set
|
||||
* @retval Baudrate prescaler
|
||||
*/
|
||||
uint32_t getPrescaler(uint32_t clock_src_freq, uint32_t baudrate_mbps);
|
||||
|
||||
} // namespace spi
|
||||
|
||||
#endif /* FSFW_HAL_STM32H7_SPI_SPIDEFINITIONS_H_ */
|
103
src/fsfw_hal/stm32h7/spi/spiInterrupts.cpp
Normal file
103
src/fsfw_hal/stm32h7/spi/spiInterrupts.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
#include "fsfw_hal/stm32h7/spi/spiInterrupts.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "fsfw_hal/stm32h7/spi/spiCore.h"
|
||||
#include "stm32h7xx_hal.h"
|
||||
#include "stm32h7xx_hal_dma.h"
|
||||
#include "stm32h7xx_hal_spi.h"
|
||||
|
||||
user_handler_t spi1UserHandler = &spi::spiIrqHandler;
|
||||
user_args_t spi1UserArgs = nullptr;
|
||||
|
||||
user_handler_t spi2UserHandler = &spi::spiIrqHandler;
|
||||
user_args_t spi2UserArgs = nullptr;
|
||||
|
||||
/**
|
||||
* @brief This function handles DMA Rx interrupt request.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void spi::dmaRxIrqHandler(void *dmaHandle) {
|
||||
if (dmaHandle == nullptr) {
|
||||
return;
|
||||
}
|
||||
HAL_DMA_IRQHandler((DMA_HandleTypeDef *)dmaHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles DMA Rx interrupt request.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void spi::dmaTxIrqHandler(void *dmaHandle) {
|
||||
if (dmaHandle == nullptr) {
|
||||
return;
|
||||
}
|
||||
HAL_DMA_IRQHandler((DMA_HandleTypeDef *)dmaHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles SPIx interrupt request.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void spi::spiIrqHandler(void *spiHandle) {
|
||||
if (spiHandle == nullptr) {
|
||||
return;
|
||||
}
|
||||
// auto currentSpiHandle = spi::getSpiHandle();
|
||||
HAL_SPI_IRQHandler((SPI_HandleTypeDef *)spiHandle);
|
||||
}
|
||||
|
||||
void spi::assignSpiUserHandler(spi::SpiBus spiIdx, user_handler_t userHandler,
|
||||
user_args_t userArgs) {
|
||||
if (spiIdx == spi::SpiBus::SPI_1) {
|
||||
spi1UserHandler = userHandler;
|
||||
spi1UserArgs = userArgs;
|
||||
} else {
|
||||
spi2UserHandler = userHandler;
|
||||
spi2UserArgs = userArgs;
|
||||
}
|
||||
}
|
||||
|
||||
void spi::getSpiUserHandler(spi::SpiBus spiBus, user_handler_t *userHandler,
|
||||
user_args_t *userArgs) {
|
||||
if (userHandler == nullptr or userArgs == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (spiBus == spi::SpiBus::SPI_1) {
|
||||
*userArgs = spi1UserArgs;
|
||||
*userHandler = spi1UserHandler;
|
||||
} else {
|
||||
*userArgs = spi2UserArgs;
|
||||
*userHandler = spi2UserHandler;
|
||||
}
|
||||
}
|
||||
|
||||
void spi::assignSpiUserArgs(spi::SpiBus spiBus, user_args_t userArgs) {
|
||||
if (spiBus == spi::SpiBus::SPI_1) {
|
||||
spi1UserArgs = userArgs;
|
||||
} else {
|
||||
spi2UserArgs = userArgs;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do not change these function names! They need to be exactly equal to the name of the functions
|
||||
defined in the startup_stm32h743xx.s files! */
|
||||
|
||||
extern "C" void SPI1_IRQHandler() {
|
||||
if (spi1UserHandler != NULL) {
|
||||
spi1UserHandler(spi1UserArgs);
|
||||
return;
|
||||
}
|
||||
Default_Handler();
|
||||
}
|
||||
|
||||
extern "C" void SPI2_IRQHandler() {
|
||||
if (spi2UserHandler != nullptr) {
|
||||
spi2UserHandler(spi2UserArgs);
|
||||
return;
|
||||
}
|
||||
Default_Handler();
|
||||
}
|
39
src/fsfw_hal/stm32h7/spi/spiInterrupts.h
Normal file
39
src/fsfw_hal/stm32h7/spi/spiInterrupts.h
Normal file
@ -0,0 +1,39 @@
|
||||
#ifndef FSFW_HAL_STM32H7_SPI_INTERRUPTS_H_
|
||||
#define FSFW_HAL_STM32H7_SPI_INTERRUPTS_H_
|
||||
|
||||
#include "../interrupts.h"
|
||||
#include "spiDefinitions.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
namespace spi {
|
||||
|
||||
void assignSpiUserArgs(spi::SpiBus spiBus, user_args_t userArgs);
|
||||
|
||||
/**
|
||||
* Assign a user interrupt handler for SPI bus 1, allowing to pass an arbitrary argument as well.
|
||||
* Generally, this argument will be the related SPI handle.
|
||||
* @param user_handler
|
||||
* @param user_args
|
||||
*/
|
||||
void assignSpiUserHandler(spi::SpiBus spiBus, user_handler_t user_handler, user_args_t user_args);
|
||||
void getSpiUserHandler(spi::SpiBus spiBus, user_handler_t* user_handler, user_args_t* user_args);
|
||||
|
||||
/**
|
||||
* Generic interrupt handlers supplied for convenience. Do not call these directly! Set them
|
||||
* instead with assign_dma_user_handler and assign_spi_user_handler functions.
|
||||
* @param dma_handle
|
||||
*/
|
||||
void dmaRxIrqHandler(void* dma_handle);
|
||||
void dmaTxIrqHandler(void* dma_handle);
|
||||
void spiIrqHandler(void* spi_handle);
|
||||
|
||||
} // namespace spi
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FSFW_HAL_STM32H7_SPI_INTERRUPTS_H_ */
|
81
src/fsfw_hal/stm32h7/spi/stm32h743zi.cpp
Normal file
81
src/fsfw_hal/stm32h7/spi/stm32h743zi.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
#include "fsfw_hal/stm32h7/spi/stm32h743zi.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include "fsfw_hal/stm32h7/spi/spiCore.h"
|
||||
#include "fsfw_hal/stm32h7/spi/spiInterrupts.h"
|
||||
#include "stm32h7xx_hal.h"
|
||||
#include "stm32h7xx_hal_rcc.h"
|
||||
|
||||
void spiSetupWrapper() {
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||||
__HAL_RCC_SPI1_CLK_ENABLE();
|
||||
}
|
||||
|
||||
void spiCleanUpWrapper() {
|
||||
__HAL_RCC_SPI1_FORCE_RESET();
|
||||
__HAL_RCC_SPI1_RELEASE_RESET();
|
||||
}
|
||||
|
||||
void spiDmaClockEnableWrapper() { __HAL_RCC_DMA2_CLK_ENABLE(); }
|
||||
|
||||
void stm32h7::h743zi::standardPollingCfg(spi::MspPollingConfigStruct& cfg) {
|
||||
cfg.setupCb = &spiSetupWrapper;
|
||||
cfg.cleanupCb = &spiCleanUpWrapper;
|
||||
cfg.sck.port = GPIOA;
|
||||
cfg.sck.pin = GPIO_PIN_5;
|
||||
cfg.miso.port = GPIOA;
|
||||
cfg.miso.pin = GPIO_PIN_6;
|
||||
cfg.mosi.port = GPIOA;
|
||||
cfg.mosi.pin = GPIO_PIN_7;
|
||||
cfg.sck.altFnc = GPIO_AF5_SPI1;
|
||||
cfg.mosi.altFnc = GPIO_AF5_SPI1;
|
||||
cfg.miso.altFnc = GPIO_AF5_SPI1;
|
||||
}
|
||||
|
||||
void stm32h7::h743zi::standardInterruptCfg(spi::MspIrqConfigStruct& cfg, IrqPriorities spiIrqPrio,
|
||||
IrqPriorities spiSubprio) {
|
||||
// High, but works on FreeRTOS as well (priorities range from 0 to 15)
|
||||
cfg.preEmptPriority = spiIrqPrio;
|
||||
cfg.subpriority = spiSubprio;
|
||||
cfg.spiIrqNumber = SPI1_IRQn;
|
||||
cfg.spiBus = spi::SpiBus::SPI_1;
|
||||
user_handler_t spiUserHandler = nullptr;
|
||||
user_args_t spiUserArgs = nullptr;
|
||||
getSpiUserHandler(spi::SpiBus::SPI_1, &spiUserHandler, &spiUserArgs);
|
||||
if (spiUserHandler == nullptr) {
|
||||
printf("spi::h743zi::standardInterruptCfg: Invalid SPI user handlers\n");
|
||||
return;
|
||||
}
|
||||
cfg.spiUserArgs = spiUserArgs;
|
||||
cfg.spiIrqHandler = spiUserHandler;
|
||||
standardPollingCfg(cfg);
|
||||
}
|
||||
|
||||
void stm32h7::h743zi::standardDmaCfg(spi::MspDmaConfigStruct& cfg, IrqPriorities spiIrqPrio,
|
||||
IrqPriorities txIrqPrio, IrqPriorities rxIrqPrio,
|
||||
IrqPriorities spiSubprio, IrqPriorities txSubprio,
|
||||
IrqPriorities rxSubprio) {
|
||||
cfg.dmaClkEnableWrapper = &spiDmaClockEnableWrapper;
|
||||
cfg.rxDmaIndex = dma::DMAIndexes::DMA_2;
|
||||
cfg.txDmaIndex = dma::DMAIndexes::DMA_2;
|
||||
cfg.txDmaStream = dma::DMAStreams::STREAM_3;
|
||||
cfg.rxDmaStream = dma::DMAStreams::STREAM_2;
|
||||
DMA_HandleTypeDef* txHandle;
|
||||
DMA_HandleTypeDef* rxHandle;
|
||||
spi::getDmaHandles(&txHandle, &rxHandle);
|
||||
if (txHandle == nullptr or rxHandle == nullptr) {
|
||||
printf("spi::h743zi::standardDmaCfg: Invalid DMA handles\n");
|
||||
return;
|
||||
}
|
||||
spi::configureDmaHandle(txHandle, spi::SpiBus::SPI_1, dma::DMAType::TX, cfg.txDmaIndex,
|
||||
cfg.txDmaStream, &cfg.txDmaIrqNumber);
|
||||
spi::configureDmaHandle(rxHandle, spi::SpiBus::SPI_1, dma::DMAType::RX, cfg.rxDmaIndex,
|
||||
cfg.rxDmaStream, &cfg.rxDmaIrqNumber, DMA_NORMAL, DMA_PRIORITY_HIGH);
|
||||
cfg.txPreEmptPriority = txIrqPrio;
|
||||
cfg.rxPreEmptPriority = txSubprio;
|
||||
cfg.txSubpriority = rxIrqPrio;
|
||||
cfg.rxSubpriority = rxSubprio;
|
||||
standardInterruptCfg(cfg, spiIrqPrio, spiSubprio);
|
||||
}
|
20
src/fsfw_hal/stm32h7/spi/stm32h743zi.h
Normal file
20
src/fsfw_hal/stm32h7/spi/stm32h743zi.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef FSFW_HAL_STM32H7_SPI_STM32H743ZISPI_H_
|
||||
#define FSFW_HAL_STM32H7_SPI_STM32H743ZISPI_H_
|
||||
|
||||
#include "mspInit.h"
|
||||
|
||||
namespace stm32h7 {
|
||||
|
||||
namespace h743zi {
|
||||
|
||||
void standardPollingCfg(spi::MspPollingConfigStruct& cfg);
|
||||
void standardInterruptCfg(spi::MspIrqConfigStruct& cfg, IrqPriorities spiIrqPrio,
|
||||
IrqPriorities spiSubprio = HIGHEST);
|
||||
void standardDmaCfg(spi::MspDmaConfigStruct& cfg, IrqPriorities spiIrqPrio, IrqPriorities txIrqPrio,
|
||||
IrqPriorities rxIrqPrio, IrqPriorities spiSubprio = HIGHEST,
|
||||
IrqPriorities txSubPrio = HIGHEST, IrqPriorities rxSubprio = HIGHEST);
|
||||
|
||||
} // namespace h743zi
|
||||
} // namespace stm32h7
|
||||
|
||||
#endif /* FSFW_HAL_STM32H7_SPI_STM32H743ZISPI_H_ */
|
Reference in New Issue
Block a user