Compare commits
38 Commits
1.0.0
...
895ba1b455
Author | SHA1 | Date | |
---|---|---|---|
895ba1b455 | |||
cf1d6bad19 | |||
cf8235cede | |||
20815c1d6b | |||
ff7421e1dd | |||
66a7a4dbbe | |||
863dfa68a0 | |||
a9390b145b | |||
abe62d807a | |||
78a66e1b67 | |||
21414c3594 | |||
dc6327b909 | |||
22384aec6a | |||
4c546820fd | |||
4ba4e45789 | |||
9e5e6da6f8 | |||
c69f314441 | |||
3c19e0f9eb | |||
836296b3af | |||
6487c88fc9 | |||
61d7c61852 | |||
c2b4231802 | |||
2893da047b | |||
bf8f3db41c | |||
73a427d7e0 | |||
f363d0fbd5 | |||
d801319c12 | |||
2fe1a66836 | |||
9203a30bcf | |||
a0f698fffa | |||
6341da2212 | |||
e5da8b194d | |||
c601e1dff7 | |||
d929352417 | |||
49da48dc0d | |||
99ba9d9346 | |||
425cfd2aba | |||
8a38c7958b |
17
common/spi/spiCommon.h
Normal file
17
common/spi/spiCommon.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef FSFW_HAL_COMMON_SPI_SPICOMMON_H_
|
||||
#define FSFW_HAL_COMMON_SPI_SPICOMMON_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace spi {
|
||||
|
||||
enum SpiModes: uint8_t {
|
||||
MODE_0,
|
||||
MODE_1,
|
||||
MODE_2,
|
||||
MODE_3
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* FSFW_HAL_COMMON_SPI_SPICOMMON_H_ */
|
@ -9,4 +9,5 @@ target_sources(${LIB_FSFW_HAL_NAME} PRIVATE
|
||||
|
||||
add_subdirectory(gpio)
|
||||
add_subdirectory(spi)
|
||||
add_subdirectory(i2c)
|
||||
add_subdirectory(i2c)
|
||||
add_subdirectory(uart)
|
@ -82,7 +82,7 @@ ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, GpiodRegular
|
||||
chipname = regularGpio->chipname;
|
||||
chip = gpiod_chip_open_by_name(chipname.c_str());
|
||||
if (!chip) {
|
||||
sif::warning << "LinuxLibgpioIF::configureGpios: Failed to open chip "
|
||||
sif::warning << "LinuxLibgpioIF::configureRegularGpio: Failed to open chip "
|
||||
<< chipname << ". Gpio ID: " << gpioId << std::endl;
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
@ -90,9 +90,10 @@ ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, GpiodRegular
|
||||
lineNum = regularGpio->lineNum;
|
||||
lineHandle = gpiod_chip_get_line(chip, lineNum);
|
||||
if (!lineHandle) {
|
||||
sif::warning << "LinuxLibgpioIF::configureGpios: Failed to open line for GPIO" << std::endl;
|
||||
sif::warning << "GPIO ID " << gpioId << "with line number " << lineNum <<
|
||||
" and chipname " << chipname << std::endl;
|
||||
sif::debug << "LinuxLibgpioIF::configureRegularGpio: Failed to open line " << std::endl;
|
||||
sif::debug << "GPIO ID: " << gpioId << ", line number: " << lineNum <<
|
||||
", chipname: " << chipname << std::endl;
|
||||
sif::debug << "Check if linux GPIO configuration has changed. " << std::endl;
|
||||
gpiod_chip_close(chip);
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
@ -105,7 +106,7 @@ ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, GpiodRegular
|
||||
result = gpiod_line_request_output(lineHandle, consumer.c_str(),
|
||||
regularGpio->initValue);
|
||||
if (result < 0) {
|
||||
sif::error << "LinuxLibgpioIF::configureGpios: Failed to request line " << lineNum <<
|
||||
sif::error << "LinuxLibgpioIF::configureRegularGpio: Failed to request line " << lineNum <<
|
||||
" from GPIO instance with ID: " << gpioId << std::endl;
|
||||
gpiod_line_release(lineHandle);
|
||||
return RETURN_FAILED;
|
||||
|
@ -2,10 +2,9 @@
|
||||
#include "SpiCookie.h"
|
||||
#include "../utility.h"
|
||||
#include "../UnixFileGuard.h"
|
||||
#include <FSFWConfig.h>
|
||||
#include "FSFWConfig.h"
|
||||
|
||||
#include <fsfw/ipc/MutexFactory.h>
|
||||
#include <fsfw/ipc/MutexGuard.h>
|
||||
#include <fsfw/globalfunctions/arrayprinter.h>
|
||||
|
||||
#include <linux/spi/spidev.h>
|
||||
@ -18,11 +17,11 @@
|
||||
|
||||
/* Can be used for low-level debugging of the SPI bus */
|
||||
#ifndef FSFW_HAL_LINUX_SPI_WIRETAPPING
|
||||
#define FSFW_HAL_LINUX_SPI_WIRETAPPING 1
|
||||
#define FSFW_HAL_LINUX_SPI_WIRETAPPING 0
|
||||
#endif
|
||||
|
||||
SpiComIF::SpiComIF(object_id_t objectId, GpioIF* gpioComIF): SystemObject(objectId),
|
||||
gpioComIF(gpioComIF) {
|
||||
SpiComIF::SpiComIF(object_id_t objectId, GpioIF* gpioComIF):
|
||||
SystemObject(objectId), gpioComIF(gpioComIF) {
|
||||
if(gpioComIF == nullptr) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
@ -139,7 +138,6 @@ ReturnValue_t SpiComIF::initializeInterface(CookieIF *cookie) {
|
||||
ReturnValue_t SpiComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, size_t sendLen) {
|
||||
SpiCookie* spiCookie = dynamic_cast<SpiCookie*>(cookie);
|
||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||
int retval = 0;
|
||||
|
||||
if(spiCookie == nullptr) {
|
||||
return NULLPOINTER;
|
||||
@ -159,12 +157,34 @@ ReturnValue_t SpiComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, s
|
||||
return DeviceCommunicationIF::TOO_MUCH_DATA;
|
||||
}
|
||||
|
||||
if(spiCookie->getComIfMode() == spi::SpiComIfModes::REGULAR) {
|
||||
result = performRegularSendOperation(spiCookie, sendData, sendLen);
|
||||
}
|
||||
else if(spiCookie->getComIfMode() == spi::SpiComIfModes::CALLBACK) {
|
||||
spi::send_callback_function_t sendFunc = nullptr;
|
||||
void* funcArgs = nullptr;
|
||||
spiCookie->getCallback(&sendFunc, &funcArgs);
|
||||
if(sendFunc != nullptr) {
|
||||
result = sendFunc(this, spiCookie, sendData, sendLen, funcArgs);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie *spiCookie, const uint8_t *sendData,
|
||||
size_t sendLen) {
|
||||
address_t spiAddress = spiCookie->getSpiAddress();
|
||||
auto iter = spiDeviceMap.find(spiAddress);
|
||||
if(iter != spiDeviceMap.end()) {
|
||||
spiCookie->assignReadBuffer(iter->second.replyBuffer.data());
|
||||
}
|
||||
|
||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||
int retval = 0;
|
||||
/* Prepare transfer */
|
||||
int fileDescriptor = 0;
|
||||
std::string device = spiCookie->getSpiDevice();
|
||||
UnixFileGuard fileHelper(device, &fileDescriptor, O_RDWR,
|
||||
"SpiComIF::sendMessage: ");
|
||||
UnixFileGuard fileHelper(device, &fileDescriptor, O_RDWR, "SpiComIF::sendMessage: ");
|
||||
if(fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) {
|
||||
return OPENING_FILE_FAILED;
|
||||
}
|
||||
@ -178,11 +198,15 @@ ReturnValue_t SpiComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, s
|
||||
bool fullDuplex = spiCookie->isFullDuplex();
|
||||
gpioId_t gpioId = spiCookie->getChipSelectPin();
|
||||
|
||||
/* GPIO access is mutex protected */
|
||||
MutexGuard(spiMutex, timeoutType, timeoutMs);
|
||||
|
||||
/* Pull SPI CS low. For now, no support for active high given */
|
||||
if(gpioId != gpio::NO_GPIO) {
|
||||
result = spiMutex->lockMutex(timeoutType, timeoutMs);
|
||||
if (result != RETURN_OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "SpiComIF::sendMessage: Failed to lock mutex" << std::endl;
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
gpioComIF->pullLow(gpioId);
|
||||
}
|
||||
|
||||
@ -195,19 +219,7 @@ ReturnValue_t SpiComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, s
|
||||
result = FULL_DUPLEX_TRANSFER_FAILED;
|
||||
}
|
||||
#if FSFW_HAL_LINUX_SPI_WIRETAPPING == 1
|
||||
size_t dataLen = spiCookie->getTransferStructHandle()->len;
|
||||
uint8_t* dataPtr = reinterpret_cast<uint8_t*>(spiCookie->getTransferStructHandle()->tx_buf);
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "Sent SPI data: " << std::endl;
|
||||
arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false);
|
||||
sif::info << "Received SPI data: " << std::endl;
|
||||
#else
|
||||
sif::printInfo("Sent SPI data: \n");
|
||||
arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false);
|
||||
sif::printInfo("Received SPI data: \n");
|
||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||
dataPtr = reinterpret_cast<uint8_t*>(spiCookie->getTransferStructHandle()->rx_buf);
|
||||
arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false);
|
||||
performSpiWiretapping(spiCookie);
|
||||
#endif /* FSFW_LINUX_SPI_WIRETAPPING == 1 */
|
||||
}
|
||||
else {
|
||||
@ -227,6 +239,13 @@ ReturnValue_t SpiComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, s
|
||||
|
||||
if(gpioId != gpio::NO_GPIO) {
|
||||
gpioComIF->pullHigh(gpioId);
|
||||
result = spiMutex->unlockMutex();
|
||||
if (result != RETURN_OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "SpiComIF::sendMessage: Failed to unlock mutex" << std::endl;
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -236,17 +255,21 @@ ReturnValue_t SpiComIF::getSendSuccess(CookieIF *cookie) {
|
||||
}
|
||||
|
||||
ReturnValue_t SpiComIF::requestReceiveMessage(CookieIF *cookie, size_t requestLen) {
|
||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||
SpiCookie* spiCookie = dynamic_cast<SpiCookie*>(cookie);
|
||||
if(spiCookie == nullptr) {
|
||||
return NULLPOINTER;
|
||||
}
|
||||
|
||||
bool fullDuplex = spiCookie->isFullDuplex();
|
||||
if(fullDuplex) {
|
||||
if(spiCookie->isFullDuplex()) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
return performHalfDuplexReception(spiCookie);
|
||||
}
|
||||
|
||||
|
||||
ReturnValue_t SpiComIF::performHalfDuplexReception(SpiCookie* spiCookie) {
|
||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||
std::string device = spiCookie->getSpiDevice();
|
||||
int fileDescriptor = 0;
|
||||
UnixFileGuard fileHelper(device, &fileDescriptor, O_RDWR,
|
||||
@ -263,8 +286,14 @@ ReturnValue_t SpiComIF::requestReceiveMessage(CookieIF *cookie, size_t requestLe
|
||||
}
|
||||
|
||||
gpioId_t gpioId = spiCookie->getChipSelectPin();
|
||||
MutexGuard(spiMutex, timeoutType, timeoutMs);
|
||||
if(gpioId != gpio::NO_GPIO) {
|
||||
result = spiMutex->lockMutex(timeoutType, timeoutMs);
|
||||
if (result != RETURN_OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "SpiComIF::getSendSuccess: Failed to lock mutex" << std::endl;
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
gpioComIF->pullLow(gpioId);
|
||||
}
|
||||
|
||||
@ -281,9 +310,16 @@ ReturnValue_t SpiComIF::requestReceiveMessage(CookieIF *cookie, size_t requestLe
|
||||
|
||||
if(gpioId != gpio::NO_GPIO) {
|
||||
gpioComIF->pullHigh(gpioId);
|
||||
result = spiMutex->unlockMutex();
|
||||
if (result != RETURN_OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "SpiComIF::getSendSuccess: Failed to unlock mutex" << std::endl;
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t SpiComIF::readReceivedMessage(CookieIF *cookie, uint8_t **buffer, size_t *size) {
|
||||
@ -302,6 +338,35 @@ ReturnValue_t SpiComIF::readReceivedMessage(CookieIF *cookie, uint8_t **buffer,
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
MutexIF* SpiComIF::getMutex(MutexIF::TimeoutType* timeoutType, uint32_t* timeoutMs) {
|
||||
if(timeoutType != nullptr) {
|
||||
*timeoutType = this->timeoutType;
|
||||
}
|
||||
if(timeoutMs != nullptr) {
|
||||
*timeoutMs = this->timeoutMs;
|
||||
}
|
||||
return spiMutex;
|
||||
}
|
||||
|
||||
void SpiComIF::performSpiWiretapping(SpiCookie* spiCookie) {
|
||||
if(spiCookie == nullptr) {
|
||||
return;
|
||||
}
|
||||
size_t dataLen = spiCookie->getTransferStructHandle()->len;
|
||||
uint8_t* dataPtr = reinterpret_cast<uint8_t*>(spiCookie->getTransferStructHandle()->tx_buf);
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "Sent SPI data: " << std::endl;
|
||||
arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false);
|
||||
sif::info << "Received SPI data: " << std::endl;
|
||||
#else
|
||||
sif::printInfo("Sent SPI data: \n");
|
||||
arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false);
|
||||
sif::printInfo("Received SPI data: \n");
|
||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||
dataPtr = reinterpret_cast<uint8_t*>(spiCookie->getTransferStructHandle()->rx_buf);
|
||||
arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false);
|
||||
}
|
||||
|
||||
ReturnValue_t SpiComIF::getReadBuffer(address_t spiAddress, uint8_t** buffer) {
|
||||
if(buffer == nullptr) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
@ -316,6 +381,10 @@ ReturnValue_t SpiComIF::getReadBuffer(address_t spiAddress, uint8_t** buffer) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
GpioIF* SpiComIF::getGpioInterface() {
|
||||
return gpioComIF;
|
||||
}
|
||||
|
||||
void SpiComIF::setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed) {
|
||||
int retval = ioctl(spiFd, SPI_IOC_WR_MODE, reinterpret_cast<uint8_t*>(&mode));
|
||||
if(retval != 0) {
|
||||
|
@ -2,8 +2,8 @@
|
||||
#define LINUX_SPI_SPICOMIF_H_
|
||||
|
||||
#include "spiDefinitions.h"
|
||||
#include <returnvalues/classIds.h>
|
||||
#include <fsfw_hal/common/gpio/GpioIF.h>
|
||||
#include "returnvalues/classIds.h"
|
||||
#include "../../common/gpio/GpioIF.h"
|
||||
|
||||
#include <fsfw/devicehandlers/DeviceCommunicationIF.h>
|
||||
#include <fsfw/objectmanager/SystemObject.h>
|
||||
@ -11,10 +11,13 @@
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
class SpiCookie;
|
||||
|
||||
/**
|
||||
* @brief Encapsulates access to linux SPI driver for FSFW objects
|
||||
* @details
|
||||
* Right now, only full-duplex SPI is supported.
|
||||
* Right now, only full-duplex SPI is supported. Most device specific transfer properties
|
||||
* are contained in the SPI cookie.
|
||||
* @author R. Mueller
|
||||
*/
|
||||
class SpiComIF: public DeviceCommunicationIF, public SystemObject {
|
||||
@ -39,6 +42,28 @@ public:
|
||||
size_t requestLen) override;
|
||||
ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer,
|
||||
size_t *size) override;
|
||||
|
||||
/**
|
||||
* @brief This function returns the mutex which can be used to protect the spi bus when
|
||||
* the chip select must be driven from outside of the com if.
|
||||
*/
|
||||
MutexIF* getMutex(MutexIF::TimeoutType* timeoutType = nullptr, uint32_t* timeoutMs = nullptr);
|
||||
|
||||
/**
|
||||
* Perform a regular send operation using Linux iotcl. This is public so it can be used
|
||||
* in functions like a user callback if special handling is only necessary for certain commands.
|
||||
* @param spiCookie
|
||||
* @param sendData
|
||||
* @param sendLen
|
||||
* @return
|
||||
*/
|
||||
ReturnValue_t performRegularSendOperation(SpiCookie* spiCookie, const uint8_t *sendData,
|
||||
size_t sendLen);
|
||||
|
||||
GpioIF* getGpioInterface();
|
||||
void setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed);
|
||||
void performSpiWiretapping(SpiCookie* spiCookie);
|
||||
|
||||
private:
|
||||
|
||||
struct SpiInstance {
|
||||
@ -56,9 +81,9 @@ private:
|
||||
|
||||
SpiDeviceMap spiDeviceMap;
|
||||
|
||||
ReturnValue_t performHalfDuplexReception(SpiCookie* spiCookie);
|
||||
|
||||
ReturnValue_t getReadBuffer(address_t spiAddress, uint8_t** buffer);
|
||||
void setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed);
|
||||
};
|
||||
|
||||
#endif /* LINUX_SPI_SPICOMIF_H_ */
|
||||
|
@ -1,14 +1,34 @@
|
||||
#include "SpiCookie.h"
|
||||
|
||||
SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev,
|
||||
const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed): spiAddress(spiAddress),
|
||||
chipSelectPin(chipSelect), spiDevice(spiDev), maxSize(maxSize), spiMode(spiMode),
|
||||
spiSpeed(spiSpeed) {
|
||||
const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed):
|
||||
SpiCookie(spi::SpiComIfModes::REGULAR, spiAddress, chipSelect, spiDev, maxSize, spiMode,
|
||||
spiSpeed, nullptr, nullptr) {
|
||||
|
||||
}
|
||||
|
||||
SpiCookie::SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxSize,
|
||||
spi::SpiModes spiMode, uint32_t spiSpeed):
|
||||
SpiCookie(spiAddress, gpio::NO_GPIO, spiDev, maxSize, spiMode, spiSpeed) {
|
||||
SpiCookie(spiAddress, gpio::NO_GPIO, spiDev, maxSize, spiMode, spiSpeed) {
|
||||
}
|
||||
|
||||
SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev,
|
||||
const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed,
|
||||
spi::send_callback_function_t callback, void *args):
|
||||
SpiCookie(spi::SpiComIfModes::CALLBACK, spiAddress, chipSelect, spiDev, maxSize,
|
||||
spiMode, spiSpeed, callback, args) {
|
||||
}
|
||||
|
||||
SpiCookie::SpiCookie(spi::SpiComIfModes comIfMode, address_t spiAddress, gpioId_t chipSelect,
|
||||
std::string spiDev, const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed,
|
||||
spi::send_callback_function_t callback, void* args):
|
||||
spiAddress(spiAddress), chipSelectPin(chipSelect), spiDevice(spiDev),
|
||||
comIfMode(comIfMode), maxSize(maxSize), spiMode(spiMode), spiSpeed(spiSpeed),
|
||||
sendCallback(callback), callbackArgs(args) {
|
||||
}
|
||||
|
||||
spi::SpiComIfModes SpiCookie::getComIfMode() const {
|
||||
return this->comIfMode;
|
||||
}
|
||||
|
||||
void SpiCookie::getSpiParameters(spi::SpiModes& spiMode, uint32_t& spiSpeed,
|
||||
@ -78,6 +98,13 @@ void SpiCookie::assignWriteBuffer(const uint8_t* tx) {
|
||||
}
|
||||
}
|
||||
|
||||
void SpiCookie::setCallbackMode(spi::send_callback_function_t callback,
|
||||
void *args) {
|
||||
this->comIfMode = spi::SpiComIfModes::CALLBACK;
|
||||
this->sendCallback = callback;
|
||||
this->callbackArgs = args;
|
||||
}
|
||||
|
||||
spi_ioc_transfer* SpiCookie::getTransferStructHandle() {
|
||||
return &spiTransferStruct;
|
||||
}
|
||||
@ -105,3 +132,9 @@ void SpiCookie::setSpiSpeed(uint32_t newSpeed) {
|
||||
void SpiCookie::setSpiMode(spi::SpiModes newMode) {
|
||||
this->spiMode = newMode;
|
||||
}
|
||||
|
||||
void SpiCookie::getCallback(spi::send_callback_function_t *callback,
|
||||
void **args) {
|
||||
*callback = this->sendCallback;
|
||||
*args = this->callbackArgs;
|
||||
}
|
||||
|
@ -2,13 +2,25 @@
|
||||
#define LINUX_SPI_SPICOOKIE_H_
|
||||
|
||||
#include "spiDefinitions.h"
|
||||
#include "../../common/gpio/gpioDefinitions.h"
|
||||
|
||||
#include <fsfw/devicehandlers/CookieIF.h>
|
||||
#include <fsfw_hal/common/gpio/gpioDefinitions.h>
|
||||
|
||||
#include <linux/spi/spidev.h>
|
||||
|
||||
/**
|
||||
* @brief This cookie class is passed to the SPI communication interface
|
||||
* @details
|
||||
* This cookie contains device specific properties like speed and SPI mode or the SPI transfer
|
||||
* struct required by the Linux SPI driver. It also contains a handle to a GPIO interface
|
||||
* to perform slave select switching when necessary.
|
||||
*
|
||||
* The user can specify gpio::NO_GPIO as the GPIO ID or use a custom send callback to meet
|
||||
* special requirements like expander slave select switching (e.g. GPIO or I2C expander)
|
||||
* or special timing related requirements.
|
||||
*/
|
||||
class SpiCookie: public CookieIF {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Each SPI device will have a corresponding cookie. The cookie is used by the communication
|
||||
* interface and contains device specific information like the largest expected size to be
|
||||
@ -19,7 +31,7 @@ public:
|
||||
* @param maxSize
|
||||
*/
|
||||
SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev,
|
||||
const size_t maxReplySize, spi::SpiModes spiMode, uint32_t spiSpeed);
|
||||
const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed);
|
||||
|
||||
/**
|
||||
* Like constructor above, but without a dedicated GPIO CS. Can be used for hardware
|
||||
@ -28,16 +40,41 @@ public:
|
||||
SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxReplySize,
|
||||
spi::SpiModes spiMode, uint32_t spiSpeed);
|
||||
|
||||
/**
|
||||
* Use the callback mode of the SPI communication interface. The user can pass the callback
|
||||
* function here or by using the setter function #setCallbackMode
|
||||
*/
|
||||
SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev, const size_t maxSize,
|
||||
spi::SpiModes spiMode, uint32_t spiSpeed, spi::send_callback_function_t callback,
|
||||
void *args);
|
||||
|
||||
/**
|
||||
* Get the callback function
|
||||
* @param callback
|
||||
* @param args
|
||||
*/
|
||||
void getCallback(spi::send_callback_function_t* callback, void** args);
|
||||
|
||||
address_t getSpiAddress() const;
|
||||
std::string getSpiDevice() const;
|
||||
gpioId_t getChipSelectPin() const;
|
||||
size_t getMaxBufferSize() const;
|
||||
|
||||
spi::SpiComIfModes getComIfMode() const;
|
||||
|
||||
/** Enables changing SPI speed at run-time */
|
||||
void setSpiSpeed(uint32_t newSpeed);
|
||||
/** Enables changing the SPI mode at run-time */
|
||||
void setSpiMode(spi::SpiModes newMode);
|
||||
|
||||
/**
|
||||
* Set the SPI to callback mode and assigns the user supplied callback and an argument
|
||||
* passed to the callback.
|
||||
* @param callback
|
||||
* @param args
|
||||
*/
|
||||
void setCallbackMode(spi::send_callback_function_t callback, void* args);
|
||||
|
||||
/**
|
||||
* True if SPI transfers should be performed in full duplex mode
|
||||
* @return
|
||||
@ -99,17 +136,40 @@ public:
|
||||
|
||||
spi_ioc_transfer* getTransferStructHandle();
|
||||
private:
|
||||
|
||||
/**
|
||||
* Internal constructor which initializes every field
|
||||
* @param spiAddress
|
||||
* @param chipSelect
|
||||
* @param spiDev
|
||||
* @param maxSize
|
||||
* @param spiMode
|
||||
* @param spiSpeed
|
||||
* @param callback
|
||||
* @param args
|
||||
*/
|
||||
SpiCookie(spi::SpiComIfModes comIfMode, address_t spiAddress, gpioId_t chipSelect,
|
||||
std::string spiDev, const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed,
|
||||
spi::send_callback_function_t callback, void* args);
|
||||
|
||||
size_t currentTransferSize = 0;
|
||||
|
||||
address_t spiAddress;
|
||||
gpioId_t chipSelectPin;
|
||||
std::string spiDevice;
|
||||
|
||||
spi::SpiComIfModes comIfMode;
|
||||
|
||||
// Required for regular mode
|
||||
const size_t maxSize;
|
||||
spi::SpiModes spiMode;
|
||||
uint32_t spiSpeed;
|
||||
bool halfDuplex = false;
|
||||
|
||||
// Required for callback mode
|
||||
spi::send_callback_function_t sendCallback = nullptr;
|
||||
void* callbackArgs = nullptr;
|
||||
|
||||
struct spi_ioc_transfer spiTransferStruct = {};
|
||||
UncommonParameters uncommonParameters;
|
||||
};
|
||||
|
@ -1,17 +1,28 @@
|
||||
#ifndef LINUX_SPI_SPIDEFINITONS_H_
|
||||
#define LINUX_SPI_SPIDEFINITONS_H_
|
||||
|
||||
#include "../../common/gpio/gpioDefinitions.h"
|
||||
#include "../../common/spi/spiCommon.h"
|
||||
|
||||
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
|
||||
#include <linux/spi/spidev.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
class SpiCookie;
|
||||
class SpiComIF;
|
||||
|
||||
namespace spi {
|
||||
|
||||
enum SpiModes: uint8_t {
|
||||
MODE_0,
|
||||
MODE_1,
|
||||
MODE_2,
|
||||
MODE_3
|
||||
enum SpiComIfModes {
|
||||
REGULAR,
|
||||
CALLBACK
|
||||
};
|
||||
|
||||
|
||||
using send_callback_function_t = ReturnValue_t (*) (SpiComIF* comIf, SpiCookie *cookie,
|
||||
const uint8_t *sendData, size_t sendLen, void* args);
|
||||
|
||||
}
|
||||
|
||||
#endif /* LINUX_SPI_SPIDEFINITONS_H_ */
|
||||
|
8
linux/uart/CMakeLists.txt
Normal file
8
linux/uart/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
target_sources(${TARGET_NAME} PUBLIC
|
||||
UartComIF.cpp
|
||||
UartCookie.cpp
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
370
linux/uart/UartComIF.cpp
Normal file
370
linux/uart/UartComIF.cpp
Normal file
@ -0,0 +1,370 @@
|
||||
#include "UartComIF.h"
|
||||
|
||||
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
UartComIF::UartComIF(object_id_t objectId): SystemObject(objectId){
|
||||
}
|
||||
|
||||
UartComIF::~UartComIF() {}
|
||||
|
||||
ReturnValue_t UartComIF::initializeInterface(CookieIF * cookie) {
|
||||
|
||||
std::string deviceFile;
|
||||
UartDeviceMapIter uartDeviceMapIter;
|
||||
|
||||
if(cookie == nullptr) {
|
||||
return NULLPOINTER;
|
||||
}
|
||||
|
||||
UartCookie* uartCookie = dynamic_cast<UartCookie*>(cookie);
|
||||
if (uartCookie == nullptr) {
|
||||
sif::error << "UartComIF::initializeInterface: Invalid UART Cookie!" << std::endl;
|
||||
return NULLPOINTER;
|
||||
}
|
||||
|
||||
deviceFile = uartCookie->getDeviceFile();
|
||||
|
||||
uartDeviceMapIter = uartDeviceMap.find(deviceFile);
|
||||
if(uartDeviceMapIter == uartDeviceMap.end()) {
|
||||
int fileDescriptor = configureUartPort(uartCookie);
|
||||
if (fileDescriptor < 0) {
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
size_t maxReplyLen = uartCookie->getMaxReplyLen();
|
||||
UartElements_t uartElements = {fileDescriptor, std::vector<uint8_t>(maxReplyLen), 0};
|
||||
std::pair status = uartDeviceMap.emplace(deviceFile, uartElements);
|
||||
if (status.second == false) {
|
||||
sif::debug << "UartComIF::initializeInterface: Failed to insert device " << deviceFile
|
||||
<< "to Uart device map" << std::endl;
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
else {
|
||||
sif::debug << "UartComIF::initializeInterface: Uart device " << deviceFile << "already in "
|
||||
<< "use" << std::endl;
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
int UartComIF::configureUartPort(UartCookie* uartCookie) {
|
||||
|
||||
struct termios options;
|
||||
|
||||
std::string deviceFile = uartCookie->getDeviceFile();
|
||||
int fd = open(deviceFile.c_str(), O_RDWR);
|
||||
|
||||
if (fd < 0) {
|
||||
sif::debug << "UartComIF::configureUartPort: Failed to open uart " << deviceFile << "with"
|
||||
<< " error code " << errno << strerror(errno) << std::endl;
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* Read in existing settings */
|
||||
if(tcgetattr(fd, &options) != 0) {
|
||||
sif::debug << "UartComIF::configureUartPort: Error " << errno << "from tcgetattr: "
|
||||
<< strerror(errno) << std::endl;
|
||||
return fd;
|
||||
}
|
||||
|
||||
setParityOptions(&options, uartCookie);
|
||||
setStopBitOptions(&options, uartCookie);
|
||||
setDatasizeOptions(&options, uartCookie);
|
||||
setFixedOptions(&options);
|
||||
|
||||
/* Sets uart to non-blocking mode. Read returns immediately when there are no data available */
|
||||
options.c_cc[VTIME] = 0;
|
||||
options.c_cc[VMIN] = 0;
|
||||
|
||||
configureBaudrate(&options, uartCookie);
|
||||
|
||||
/* Save option settings */
|
||||
if (tcsetattr(fd, TCSANOW, &options) != 0) {
|
||||
sif::debug << "UartComIF::configureUartPort: Failed to set options with error " << errno
|
||||
<< ": " << strerror(errno);
|
||||
return fd;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
void UartComIF::setParityOptions(struct termios* options, UartCookie* uartCookie) {
|
||||
/* Clear parity bit */
|
||||
options->c_cflag &= ~PARENB;
|
||||
switch (uartCookie->getParity()) {
|
||||
case Parity::EVEN:
|
||||
options->c_cflag |= PARENB;
|
||||
options->c_cflag &= ~PARODD;
|
||||
break;
|
||||
case Parity::ODD:
|
||||
options->c_cflag |= PARENB;
|
||||
options->c_cflag |= PARODD;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void UartComIF::setStopBitOptions(struct termios* options, UartCookie* uartCookie) {
|
||||
/* Clear stop field. Sets stop bit to one bit */
|
||||
options->c_cflag &= ~CSTOPB;
|
||||
switch (uartCookie->getStopBits()) {
|
||||
case StopBits::TWO_STOP_BITS:
|
||||
options->c_cflag |= CSTOPB;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void UartComIF::setDatasizeOptions(struct termios* options, UartCookie* uartCookie) {
|
||||
/* Clear size bits */
|
||||
options->c_cflag &= ~CSIZE;
|
||||
switch (uartCookie->getBitsPerWord()) {
|
||||
case 5:
|
||||
options->c_cflag |= CS5;
|
||||
break;
|
||||
case 6:
|
||||
options->c_cflag |= CS6;
|
||||
break;
|
||||
case 7:
|
||||
options->c_cflag |= CS7;
|
||||
break;
|
||||
case 8:
|
||||
options->c_cflag |= CS8;
|
||||
break;
|
||||
default:
|
||||
sif::debug << "UartComIF::setDatasizeOptions: Invalid size specified" << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void UartComIF::setFixedOptions(struct termios* options) {
|
||||
/* Disable RTS/CTS hardware flow control */
|
||||
options->c_cflag &= ~CRTSCTS;
|
||||
/* Turn on READ & ignore ctrl lines (CLOCAL = 1) */
|
||||
options->c_cflag |= CREAD | CLOCAL;
|
||||
/* Disable canonical mode */
|
||||
options->c_lflag &= ~ICANON;
|
||||
/* Disable echo */
|
||||
options->c_lflag &= ~ECHO;
|
||||
/* Disable erasure */
|
||||
options->c_lflag &= ~ECHOE;
|
||||
/* Disable new-line echo */
|
||||
options->c_lflag &= ~ECHONL;
|
||||
/* Disable interpretation of INTR, QUIT and SUSP */
|
||||
options->c_lflag &= ~ISIG;
|
||||
/* Turn off s/w flow ctrl */
|
||||
options->c_iflag &= ~(IXON | IXOFF | IXANY);
|
||||
/* Disable any special handling of received bytes */
|
||||
options->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL);
|
||||
/* Prevent special interpretation of output bytes (e.g. newline chars) */
|
||||
options->c_oflag &= ~OPOST;
|
||||
/* Prevent conversion of newline to carriage return/line feed */
|
||||
options->c_oflag &= ~ONLCR;
|
||||
}
|
||||
|
||||
void UartComIF::configureBaudrate(struct termios* options, UartCookie* uartCookie) {
|
||||
switch (uartCookie->getBaudrate()) {
|
||||
case 50:
|
||||
cfsetispeed(options, B50);
|
||||
cfsetospeed(options, B50);
|
||||
break;
|
||||
case 75:
|
||||
cfsetispeed(options, B75);
|
||||
cfsetospeed(options, B75);
|
||||
break;
|
||||
case 110:
|
||||
cfsetispeed(options, B110);
|
||||
cfsetospeed(options, B110);
|
||||
break;
|
||||
case 134:
|
||||
cfsetispeed(options, B134);
|
||||
cfsetospeed(options, B134);
|
||||
break;
|
||||
case 150:
|
||||
cfsetispeed(options, B150);
|
||||
cfsetospeed(options, B150);
|
||||
break;
|
||||
case 200:
|
||||
cfsetispeed(options, B200);
|
||||
cfsetospeed(options, B200);
|
||||
break;
|
||||
case 300:
|
||||
cfsetispeed(options, B300);
|
||||
cfsetospeed(options, B300);
|
||||
break;
|
||||
case 600:
|
||||
cfsetispeed(options, B600);
|
||||
cfsetospeed(options, B600);
|
||||
break;
|
||||
case 1200:
|
||||
cfsetispeed(options, B1200);
|
||||
cfsetospeed(options, B1200);
|
||||
break;
|
||||
case 1800:
|
||||
cfsetispeed(options, B1800);
|
||||
cfsetospeed(options, B1800);
|
||||
break;
|
||||
case 2400:
|
||||
cfsetispeed(options, B2400);
|
||||
cfsetospeed(options, B2400);
|
||||
break;
|
||||
case 4800:
|
||||
cfsetispeed(options, B4800);
|
||||
cfsetospeed(options, B4800);
|
||||
break;
|
||||
case 9600:
|
||||
cfsetispeed(options, B9600);
|
||||
cfsetospeed(options, B9600);
|
||||
break;
|
||||
case 19200:
|
||||
cfsetispeed(options, B19200);
|
||||
cfsetospeed(options, B19200);
|
||||
break;
|
||||
case 38400:
|
||||
cfsetispeed(options, B38400);
|
||||
cfsetospeed(options, B38400);
|
||||
break;
|
||||
case 57600:
|
||||
cfsetispeed(options, B57600);
|
||||
cfsetospeed(options, B57600);
|
||||
break;
|
||||
case 115200:
|
||||
cfsetispeed(options, B115200);
|
||||
cfsetospeed(options, B115200);
|
||||
break;
|
||||
case 230400:
|
||||
cfsetispeed(options, B230400);
|
||||
cfsetospeed(options, B230400);
|
||||
break;
|
||||
case 460800:
|
||||
cfsetispeed(options, B460800);
|
||||
cfsetospeed(options, B460800);
|
||||
break;
|
||||
default:
|
||||
sif::warning << "UartComIF::configureBaudrate: Baudrate not supported" << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t UartComIF::sendMessage(CookieIF *cookie,
|
||||
const uint8_t *sendData, size_t sendLen) {
|
||||
|
||||
int fd = 0;
|
||||
std::string deviceFile;
|
||||
UartDeviceMapIter uartDeviceMapIter;
|
||||
|
||||
if(sendData == nullptr) {
|
||||
sif::debug << "UartComIF::sendMessage: Send Data is nullptr" << std::endl;
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
|
||||
if(sendLen == 0) {
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
UartCookie* uartCookie = dynamic_cast<UartCookie*>(cookie);
|
||||
if(uartCookie == nullptr) {
|
||||
sif::debug << "UartComIF::sendMessasge: Invalid Uart Cookie!" << std::endl;
|
||||
return NULLPOINTER;
|
||||
}
|
||||
|
||||
deviceFile = uartCookie->getDeviceFile();
|
||||
uartDeviceMapIter = uartDeviceMap.find(deviceFile);
|
||||
if (uartDeviceMapIter == uartDeviceMap.end()) {
|
||||
sif::debug << "UartComIF::sendMessage: Device file " << deviceFile << "not in uart map"
|
||||
<< std::endl;
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
|
||||
fd = uartDeviceMapIter->second.fileDescriptor;
|
||||
|
||||
if (write(fd, sendData, sendLen) != (int)sendLen) {
|
||||
sif::error << "UartComIF::sendMessage: Failed to send data with error code " << errno
|
||||
<< ": Error description: " << strerror(errno) << std::endl;
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t UartComIF::getSendSuccess(CookieIF *cookie) {
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t UartComIF::requestReceiveMessage(CookieIF *cookie,
|
||||
size_t requestLen) {
|
||||
|
||||
int fd = 0;
|
||||
std::string deviceFile;
|
||||
UartDeviceMapIter uartDeviceMapIter;
|
||||
uint8_t* bufferPtr;
|
||||
|
||||
if(requestLen == 0) {
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
UartCookie* uartCookie = dynamic_cast<UartCookie*>(cookie);
|
||||
if(uartCookie == nullptr) {
|
||||
sif::debug << "UartComIF::requestReceiveMessage: Invalid Uart Cookie!" << std::endl;
|
||||
return NULLPOINTER;
|
||||
}
|
||||
|
||||
deviceFile = uartCookie->getDeviceFile();
|
||||
uartDeviceMapIter = uartDeviceMap.find(deviceFile);
|
||||
if (uartDeviceMapIter == uartDeviceMap.end()) {
|
||||
sif::debug << "UartComIF::requestReceiveMessage: Device file " << deviceFile
|
||||
<< " not in uart map" << std::endl;
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
|
||||
fd = uartDeviceMapIter->second.fileDescriptor;
|
||||
bufferPtr = uartDeviceMapIter->second.replyBuffer.data();
|
||||
int bytesRead = read(fd, bufferPtr, requestLen);
|
||||
if (bytesRead != static_cast<int>(requestLen)) {
|
||||
sif::debug << "UartComIF::requestReceiveMessage: Only read " << bytesRead
|
||||
<< " of " << requestLen << " bytes" << std::endl;
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
else {
|
||||
uartDeviceMapIter->second.replyLen = bytesRead;
|
||||
}
|
||||
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t UartComIF::readReceivedMessage(CookieIF *cookie,
|
||||
uint8_t **buffer, size_t* size) {
|
||||
|
||||
std::string deviceFile;
|
||||
UartDeviceMapIter uartDeviceMapIter;
|
||||
|
||||
UartCookie* uartCookie = dynamic_cast<UartCookie*>(cookie);
|
||||
if(uartCookie == nullptr) {
|
||||
sif::debug << "UartComIF::readReceivedMessage: Invalid uart cookie!" << std::endl;
|
||||
return NULLPOINTER;
|
||||
}
|
||||
|
||||
deviceFile = uartCookie->getDeviceFile();
|
||||
uartDeviceMapIter = uartDeviceMap.find(deviceFile);
|
||||
if (uartDeviceMapIter == uartDeviceMap.end()) {
|
||||
sif::debug << "UartComIF::readReceivedMessage: Device file " << deviceFile
|
||||
<< " not in uart map" << std::endl;
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
|
||||
*buffer = uartDeviceMapIter->second.replyBuffer.data();
|
||||
*size = uartDeviceMapIter->second.replyLen;
|
||||
|
||||
/* Length is reset to 0 to prevent reading the same data twice */
|
||||
uartDeviceMapIter->second.replyLen = 0;
|
||||
|
||||
return RETURN_OK;
|
||||
}
|
94
linux/uart/UartComIF.h
Normal file
94
linux/uart/UartComIF.h
Normal file
@ -0,0 +1,94 @@
|
||||
#ifndef BSP_Q7S_COMIF_UARTCOMIF_H_
|
||||
#define BSP_Q7S_COMIF_UARTCOMIF_H_
|
||||
|
||||
#include <fsfw/objectmanager/SystemObject.h>
|
||||
#include <fsfw/devicehandlers/DeviceCommunicationIF.h>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "UartCookie.h"
|
||||
|
||||
/**
|
||||
* @brief This is the communication interface to access serial ports on linux based operating
|
||||
* systems.
|
||||
*
|
||||
* @details The implementation follows the instructions from https://blog.mbedded.ninja/programming/
|
||||
* operating-systems/linux/linux-serial-ports-using-c-cpp/#disabling-canonical-mode
|
||||
*
|
||||
* @author J. Meier
|
||||
*/
|
||||
class UartComIF: public DeviceCommunicationIF, public SystemObject {
|
||||
public:
|
||||
UartComIF(object_id_t objectId);
|
||||
|
||||
virtual ~UartComIF();
|
||||
|
||||
ReturnValue_t initializeInterface(CookieIF * cookie) override;
|
||||
ReturnValue_t sendMessage(CookieIF *cookie,const uint8_t *sendData,
|
||||
size_t sendLen) override;
|
||||
ReturnValue_t getSendSuccess(CookieIF *cookie) override;
|
||||
ReturnValue_t requestReceiveMessage(CookieIF *cookie,
|
||||
size_t requestLen) override;
|
||||
ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer,
|
||||
size_t *size) override;
|
||||
|
||||
private:
|
||||
|
||||
using UartDeviceFile_t = std::string;
|
||||
|
||||
typedef struct UartElements {
|
||||
int fileDescriptor;
|
||||
std::vector<uint8_t> replyBuffer;
|
||||
/** Number of bytes read will be written to this variable */
|
||||
size_t replyLen;
|
||||
} UartElements_t;
|
||||
|
||||
using UartDeviceMap = std::unordered_map<UartDeviceFile_t, UartElements_t>;
|
||||
using UartDeviceMapIter = UartDeviceMap::iterator;
|
||||
|
||||
/**
|
||||
* The uart devie map stores informations of initialized uart ports.
|
||||
*/
|
||||
UartDeviceMap uartDeviceMap;
|
||||
|
||||
/**
|
||||
* @brief This function opens and configures a uart device by using the information stored
|
||||
* in the uart cookie.
|
||||
* @param uartCookie Pointer to uart cookie with information about the uart. Contains the
|
||||
* uart device file, baudrate, parity, stopbits etc.
|
||||
* @return The file descriptor of the configured uart.
|
||||
*/
|
||||
int configureUartPort(UartCookie* uartCookie);
|
||||
|
||||
/**
|
||||
* @brief This function adds the parity settings to the termios options struct.
|
||||
*
|
||||
* @param options Pointer to termios options struct which will be modified to enable or disable
|
||||
* parity checking.
|
||||
* @param uartCookie Pointer to uart cookie containing the information about the desired
|
||||
* parity settings.
|
||||
*
|
||||
*/
|
||||
void setParityOptions(struct termios* options, UartCookie* uartCookie);
|
||||
|
||||
void setStopBitOptions(struct termios* options, UartCookie* uartCookie);
|
||||
|
||||
/**
|
||||
* @brief This function sets options which are not configurable by the uartCookie.
|
||||
*/
|
||||
void setFixedOptions(struct termios* options);
|
||||
|
||||
/**
|
||||
* @brief With this function the datasize settings are added to the termios options struct.
|
||||
*/
|
||||
void setDatasizeOptions(struct termios* options, UartCookie* uartCookie);
|
||||
|
||||
/**
|
||||
* @brief This functions adds the baudrate specified in the uartCookie to the termios options
|
||||
* struct.
|
||||
*/
|
||||
void configureBaudrate(struct termios* options, UartCookie* uartCookie);
|
||||
};
|
||||
|
||||
#endif /* BSP_Q7S_COMIF_UARTCOMIF_H_ */
|
63
linux/uart/UartCookie.cpp
Normal file
63
linux/uart/UartCookie.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
#include "UartCookie.h"
|
||||
|
||||
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||
|
||||
UartCookie::UartCookie(std::string deviceFile, uint32_t baudrate, size_t maxReplyLen) :
|
||||
deviceFile(deviceFile), baudrate(baudrate), maxReplyLen(maxReplyLen) {
|
||||
}
|
||||
|
||||
UartCookie::~UartCookie() {}
|
||||
|
||||
uint32_t UartCookie::getBaudrate() const {
|
||||
return baudrate;
|
||||
}
|
||||
|
||||
size_t UartCookie::getMaxReplyLen() const {
|
||||
return maxReplyLen;
|
||||
}
|
||||
|
||||
std::string UartCookie::getDeviceFile() const {
|
||||
return deviceFile;
|
||||
}
|
||||
|
||||
void UartCookie::setParityOdd() {
|
||||
parity = Parity::ODD;
|
||||
}
|
||||
|
||||
void UartCookie::setParityEven() {
|
||||
parity = Parity::EVEN;
|
||||
}
|
||||
|
||||
Parity UartCookie::getParity() const {
|
||||
return parity;
|
||||
}
|
||||
|
||||
void UartCookie::setBitsPerWord(uint8_t bitsPerWord_) {
|
||||
switch(bitsPerWord_) {
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
break;
|
||||
default:
|
||||
sif::debug << "UartCookie::setBitsPerWord: Invalid bits per word specified" << std::endl;
|
||||
return;
|
||||
}
|
||||
bitsPerWord = bitsPerWord_;
|
||||
}
|
||||
|
||||
uint8_t UartCookie::getBitsPerWord() const {
|
||||
return bitsPerWord;
|
||||
}
|
||||
|
||||
StopBits UartCookie::getStopBits() const {
|
||||
return stopBits;
|
||||
}
|
||||
|
||||
void UartCookie::setTwoStopBits() {
|
||||
stopBits = StopBits::TWO_STOP_BITS;
|
||||
}
|
||||
|
||||
void UartCookie::setOneStopBit() {
|
||||
stopBits = StopBits::ONE_STOP_BIT;
|
||||
}
|
81
linux/uart/UartCookie.h
Normal file
81
linux/uart/UartCookie.h
Normal file
@ -0,0 +1,81 @@
|
||||
#ifndef SAM9G20_COMIF_COOKIES_UART_COOKIE_H_
|
||||
#define SAM9G20_COMIF_COOKIES_UART_COOKIE_H_
|
||||
|
||||
#include <fsfw/devicehandlers/CookieIF.h>
|
||||
#include <string>
|
||||
|
||||
enum class Parity {
|
||||
NONE,
|
||||
EVEN,
|
||||
ODD
|
||||
};
|
||||
|
||||
enum class StopBits {
|
||||
ONE_STOP_BIT,
|
||||
TWO_STOP_BITS
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Cookie for the UartComIF. There are many options available to configure the uart driver.
|
||||
* The constructor only requests for common options like the baudrate. Other options can
|
||||
* be set by member functions.
|
||||
*
|
||||
* @author J. Meier
|
||||
*/
|
||||
class UartCookie: public CookieIF {
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Constructor for the uart cookie.
|
||||
* @param deviceFile The device file specifying the uart to use. E.g. "/dev/ttyPS1".
|
||||
* @param baudrate The baudrate to use for input and output. Possible Baudrates are: 50,
|
||||
* 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, B19200,
|
||||
* 38400, 57600, 115200, 230400, 460800
|
||||
* @param maxReplyLen The maximum size an object using this cookie expects.
|
||||
*
|
||||
* @details Default configuration: No parity
|
||||
* 8 databits (number of bits transfered with one uart frame)
|
||||
* One stop bit
|
||||
*
|
||||
*
|
||||
*/
|
||||
UartCookie(std::string deviceFile, uint32_t baudrate, size_t maxReplyLen);
|
||||
|
||||
virtual ~UartCookie();
|
||||
|
||||
uint32_t getBaudrate() const;
|
||||
size_t getMaxReplyLen() const;
|
||||
std::string getDeviceFile() const;
|
||||
Parity getParity() const;
|
||||
uint8_t getBitsPerWord() const;
|
||||
StopBits getStopBits() const;
|
||||
|
||||
/**
|
||||
* Functions two enable parity checking.
|
||||
*/
|
||||
void setParityOdd();
|
||||
void setParityEven();
|
||||
|
||||
/**
|
||||
* Function two set number of bits per UART frame.
|
||||
*/
|
||||
void setBitsPerWord(uint8_t bitsPerWord_);
|
||||
|
||||
/**
|
||||
* Function to specify the number of stopbits.
|
||||
*/
|
||||
void setTwoStopBits();
|
||||
void setOneStopBit();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
std::string deviceFile;
|
||||
uint32_t baudrate;
|
||||
size_t maxReplyLen = 0;
|
||||
Parity parity = Parity::NONE;
|
||||
uint8_t bitsPerWord = 8;
|
||||
StopBits stopBits = StopBits::ONE_STOP_BIT;
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,7 @@
|
||||
add_subdirectory(spi)
|
||||
add_subdirectory(devicetest)
|
||||
|
||||
target_sources(${TARGET_NAME} PRIVATE
|
||||
interrupts.c
|
||||
dma_interrupts.c
|
||||
)
|
||||
|
3
stm32h7/devicetest/CMakeLists.txt
Normal file
3
stm32h7/devicetest/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
target_sources(${TARGET_NAME} PRIVATE
|
||||
GyroL3GD20H.cpp
|
||||
)
|
531
stm32h7/devicetest/GyroL3GD20H.cpp
Normal file
531
stm32h7/devicetest/GyroL3GD20H.cpp
Normal file
@ -0,0 +1,531 @@
|
||||
#include "GyroL3GD20H.h"
|
||||
#include "spiConf.h"
|
||||
#include "../spi/mspInit.h"
|
||||
#include "../spi/spiDefinitions.h"
|
||||
#include "../spi/spiCore.h"
|
||||
|
||||
#include "fsfw/tasks/TaskFactory.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
#include "stm32h7xx_nucleo.h"
|
||||
#include "stm32h7xx_hal_spi.h"
|
||||
#include "stm32h7xx_hal_rcc.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
alignas(32) std::array<uint8_t, GyroL3GD20H::recvBufferSize> GyroL3GD20H::rxBuffer;
|
||||
alignas(32) std::array<uint8_t, GyroL3GD20H::txBufferSize>
|
||||
GyroL3GD20H::txBuffer __attribute__((section(".dma_buffer")));
|
||||
|
||||
TransferStates transferState = TransferStates::IDLE;
|
||||
spi::TransferModes GyroL3GD20H::transferMode = spi::TransferModes::POLLING;
|
||||
|
||||
DMA_HandleTypeDef txDmaHandle;
|
||||
DMA_HandleTypeDef rxDmaHandle;
|
||||
|
||||
GyroL3GD20H::GyroL3GD20H(SPI_HandleTypeDef *spiHandle, spi::TransferModes transferMode_):
|
||||
spiHandle(spiHandle) {
|
||||
transferMode = transferMode_;
|
||||
if(transferMode == spi::TransferModes::DMA) {
|
||||
set_dma_handles(&txDmaHandle, &rxDmaHandle);
|
||||
set_spi_msp_functions(&hal_spi_msp_init_dma, spiHandle, &hal_spi_msp_deinit_dma, spiHandle);
|
||||
}
|
||||
else if(transferMode == spi::TransferModes::INTERRUPT) {
|
||||
set_spi_msp_functions(&hal_spi_msp_init_interrupt, spiHandle,
|
||||
&hal_spi_msp_deinit_interrupt, spiHandle);
|
||||
}
|
||||
else if(transferMode == spi::TransferModes::POLLING) {
|
||||
set_spi_msp_functions(&hal_spi_msp_init_polling, spiHandle,
|
||||
&hal_spi_msp_deinit_polling, spiHandle);
|
||||
}
|
||||
|
||||
GPIO_InitTypeDef chipSelect = {};
|
||||
__HAL_RCC_GPIOD_CLK_ENABLE();
|
||||
chipSelect.Pin = GPIO_PIN_14;
|
||||
chipSelect.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
HAL_GPIO_Init(GPIOD, &chipSelect);
|
||||
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET);
|
||||
}
|
||||
|
||||
ReturnValue_t GyroL3GD20H::initialize() {
|
||||
// Configure the SPI peripheral
|
||||
spiHandle->Instance = SPI1;
|
||||
spiHandle->Init.BaudRatePrescaler = spi::getPrescaler(HAL_RCC_GetHCLKFreq(), 3900000);
|
||||
spiHandle->Init.Direction = SPI_DIRECTION_2LINES;
|
||||
spi::assignSpiMode(spi::SpiModes::MODE_3, spiHandle);
|
||||
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;
|
||||
// Recommended setting to avoid glitches
|
||||
spiHandle->Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;
|
||||
spiHandle->Init.Mode = SPI_MODE_MASTER;
|
||||
if(HAL_SPI_Init(spiHandle) != HAL_OK) {
|
||||
sif::printWarning("Error initializing SPI\n");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
transferState = TransferStates::WAIT;
|
||||
|
||||
sif::printInfo("GyroL3GD20H::performOperation: Reading WHO AM I register\n");
|
||||
|
||||
txBuffer[0] = WHO_AM_I_REG | STM_READ_MASK;
|
||||
txBuffer[1] = 0;
|
||||
|
||||
switch(transferMode) {
|
||||
case(spi::TransferModes::DMA): {
|
||||
return handleDmaTransferInit();
|
||||
}
|
||||
case(spi::TransferModes::INTERRUPT): {
|
||||
return handleInterruptTransferInit();
|
||||
}
|
||||
case(spi::TransferModes::POLLING): {
|
||||
return handlePollingTransferInit();
|
||||
}
|
||||
default: {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t GyroL3GD20H::performOperation() {
|
||||
switch(transferMode) {
|
||||
case(spi::TransferModes::DMA): {
|
||||
return handleDmaSensorRead();
|
||||
}
|
||||
case(spi::TransferModes::POLLING): {
|
||||
return handlePollingSensorRead();
|
||||
}
|
||||
case(spi::TransferModes::INTERRUPT): {
|
||||
return handleInterruptSensorRead();
|
||||
}
|
||||
default: {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t GyroL3GD20H::handleDmaTransferInit() {
|
||||
/* Clean D-cache */
|
||||
/* Make sure the address is 32-byte aligned and add 32-bytes to length,
|
||||
in case it overlaps cacheline */
|
||||
// See https://community.st.com/s/article/FAQ-DMA-is-not-working-on-STM32H7-devices
|
||||
HAL_StatusTypeDef result = performDmaTransfer(2);
|
||||
if(result != HAL_OK) {
|
||||
// Transfer error in transmission process
|
||||
sif::printWarning("GyroL3GD20H::initialize: Error transmitting SPI with DMA\n");
|
||||
}
|
||||
|
||||
// Wait for the transfer to complete
|
||||
while (transferState == TransferStates::WAIT) {
|
||||
TaskFactory::delayTask(1);
|
||||
}
|
||||
|
||||
switch(transferState) {
|
||||
case(TransferStates::SUCCESS): {
|
||||
uint8_t whoAmIVal = rxBuffer[1];
|
||||
if(whoAmIVal != EXPECTED_WHO_AM_I_VAL) {
|
||||
sif::printDebug("GyroL3GD20H::initialize: "
|
||||
"Read WHO AM I value %d not equal to expected value!\n", whoAmIVal);
|
||||
}
|
||||
transferState = TransferStates::IDLE;
|
||||
break;
|
||||
}
|
||||
case(TransferStates::FAILURE): {
|
||||
sif::printWarning("Transfer failure\n");
|
||||
transferState = TransferStates::FAILURE;
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
default: {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
sif::printInfo("GyroL3GD20H::initialize: Configuring device\n");
|
||||
// Configure the 5 configuration registers
|
||||
uint8_t configRegs[5];
|
||||
prepareConfigRegs(configRegs);
|
||||
|
||||
result = performDmaTransfer(6);
|
||||
if(result != HAL_OK) {
|
||||
// Transfer error in transmission process
|
||||
sif::printWarning("Error transmitting SPI with DMA\n");
|
||||
}
|
||||
|
||||
// Wait for the transfer to complete
|
||||
while (transferState == TransferStates::WAIT) {
|
||||
TaskFactory::delayTask(1);
|
||||
}
|
||||
|
||||
switch(transferState) {
|
||||
case(TransferStates::SUCCESS): {
|
||||
sif::printInfo("GyroL3GD20H::initialize: Configuration transfer success\n");
|
||||
transferState = TransferStates::IDLE;
|
||||
break;
|
||||
}
|
||||
case(TransferStates::FAILURE): {
|
||||
sif::printWarning("GyroL3GD20H::initialize: Configuration transfer failure\n");
|
||||
transferState = TransferStates::FAILURE;
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
default: {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
txBuffer[0] = CTRL_REG_1 | STM_AUTO_INCREMENT_MASK | STM_READ_MASK;
|
||||
std::memset(txBuffer.data() + 1, 0 , 5);
|
||||
result = performDmaTransfer(6);
|
||||
if(result != HAL_OK) {
|
||||
// Transfer error in transmission process
|
||||
sif::printWarning("Error transmitting SPI with DMA\n");
|
||||
}
|
||||
// Wait for the transfer to complete
|
||||
while (transferState == TransferStates::WAIT) {
|
||||
TaskFactory::delayTask(1);
|
||||
}
|
||||
|
||||
switch(transferState) {
|
||||
case(TransferStates::SUCCESS): {
|
||||
if(rxBuffer[1] != configRegs[0] or rxBuffer[2] != configRegs[1] or
|
||||
rxBuffer[3] != configRegs[2] or rxBuffer[4] != configRegs[3] or
|
||||
rxBuffer[5] != configRegs[4]) {
|
||||
sif::printWarning("GyroL3GD20H::initialize: Configuration failure\n");
|
||||
}
|
||||
else {
|
||||
sif::printInfo("GyroL3GD20H::initialize: Configuration success\n");
|
||||
}
|
||||
transferState = TransferStates::IDLE;
|
||||
break;
|
||||
}
|
||||
case(TransferStates::FAILURE): {
|
||||
sif::printWarning("GyroL3GD20H::initialize: Configuration transfer failure\n");
|
||||
transferState = TransferStates::FAILURE;
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
default: {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t GyroL3GD20H::handleDmaSensorRead() {
|
||||
txBuffer[0] = CTRL_REG_1 | STM_AUTO_INCREMENT_MASK | STM_READ_MASK;
|
||||
std::memset(txBuffer.data() + 1, 0 , 14);
|
||||
|
||||
HAL_StatusTypeDef result = performDmaTransfer(15);
|
||||
if(result != HAL_OK) {
|
||||
// Transfer error in transmission process
|
||||
sif::printDebug("GyroL3GD20H::handleDmaSensorRead: Error transmitting SPI with DMA\n");
|
||||
}
|
||||
// Wait for the transfer to complete
|
||||
while (transferState == TransferStates::WAIT) {
|
||||
TaskFactory::delayTask(1);
|
||||
}
|
||||
|
||||
switch(transferState) {
|
||||
case(TransferStates::SUCCESS): {
|
||||
handleSensorReadout();
|
||||
break;
|
||||
}
|
||||
case(TransferStates::FAILURE): {
|
||||
sif::printWarning("GyroL3GD20H::handleDmaSensorRead: Sensor read failure\n");
|
||||
transferState = TransferStates::FAILURE;
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
default: {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef GyroL3GD20H::performDmaTransfer(size_t sendSize) {
|
||||
transferState = TransferStates::WAIT;
|
||||
#if STM_USE_PERIPHERAL_TX_BUFFER_MPU_PROTECTION == 0
|
||||
SCB_CleanDCache_by_Addr((uint32_t*)(((uint32_t)txBuffer.data()) & ~(uint32_t)0x1F),
|
||||
txBuffer.size()+32);
|
||||
#endif
|
||||
|
||||
// Start SPI transfer via DMA
|
||||
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET);
|
||||
return HAL_SPI_TransmitReceive_DMA(spiHandle, txBuffer.data(), rxBuffer.data(), sendSize);
|
||||
}
|
||||
|
||||
ReturnValue_t GyroL3GD20H::handlePollingTransferInit() {
|
||||
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET);
|
||||
auto result = HAL_SPI_TransmitReceive(spiHandle, txBuffer.data(), rxBuffer.data(), 2, 1000);
|
||||
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET);
|
||||
switch(result) {
|
||||
case(HAL_OK): {
|
||||
sif::printInfo("GyroL3GD20H::initialize: Polling transfer success\n");
|
||||
uint8_t whoAmIVal = rxBuffer[1];
|
||||
if(whoAmIVal != EXPECTED_WHO_AM_I_VAL) {
|
||||
sif::printDebug("GyroL3GD20H::performOperation: "
|
||||
"Read WHO AM I value %d not equal to expected value!\n", whoAmIVal);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case(HAL_TIMEOUT): {
|
||||
sif::printDebug("GyroL3GD20H::initialize: Polling transfer timeout\n");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
case(HAL_ERROR): {
|
||||
sif::printDebug("GyroL3GD20H::initialize: Polling transfer failure\n");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
default: {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
|
||||
sif::printInfo("GyroL3GD20H::initialize: Configuring device\n");
|
||||
// Configure the 5 configuration registers
|
||||
uint8_t configRegs[5];
|
||||
prepareConfigRegs(configRegs);
|
||||
|
||||
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET);
|
||||
result = HAL_SPI_TransmitReceive(spiHandle, txBuffer.data(), rxBuffer.data(), 6, 1000);
|
||||
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET);
|
||||
switch(result) {
|
||||
case(HAL_OK): {
|
||||
break;
|
||||
}
|
||||
case(HAL_TIMEOUT): {
|
||||
sif::printDebug("GyroL3GD20H::initialize: Polling transfer timeout\n");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
case(HAL_ERROR): {
|
||||
sif::printDebug("GyroL3GD20H::initialize: Polling transfer failure\n");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
default: {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
|
||||
txBuffer[0] = CTRL_REG_1 | STM_AUTO_INCREMENT_MASK | STM_READ_MASK;
|
||||
std::memset(txBuffer.data() + 1, 0 , 5);
|
||||
|
||||
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET);
|
||||
result = HAL_SPI_TransmitReceive(spiHandle, txBuffer.data(), rxBuffer.data(), 6, 1000);
|
||||
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET);
|
||||
switch(result) {
|
||||
case(HAL_OK): {
|
||||
if(rxBuffer[1] != configRegs[0] or rxBuffer[2] != configRegs[1] or
|
||||
rxBuffer[3] != configRegs[2] or rxBuffer[4] != configRegs[3] or
|
||||
rxBuffer[5] != configRegs[4]) {
|
||||
sif::printWarning("GyroL3GD20H::initialize: Configuration failure\n");
|
||||
}
|
||||
else {
|
||||
sif::printInfo("GyroL3GD20H::initialize: Configuration success\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case(HAL_TIMEOUT): {
|
||||
sif::printDebug("GyroL3GD20H::initialize: Polling transfer timeout\n");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
case(HAL_ERROR): {
|
||||
sif::printDebug("GyroL3GD20H::initialize: Polling transfer failure\n");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
default: {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t GyroL3GD20H::handlePollingSensorRead() {
|
||||
txBuffer[0] = CTRL_REG_1 | STM_AUTO_INCREMENT_MASK | STM_READ_MASK;
|
||||
std::memset(txBuffer.data() + 1, 0 , 14);
|
||||
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET);
|
||||
auto result = HAL_SPI_TransmitReceive(spiHandle, txBuffer.data(), rxBuffer.data(), 15, 1000);
|
||||
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET);
|
||||
switch(result) {
|
||||
case(HAL_OK): {
|
||||
handleSensorReadout();
|
||||
break;
|
||||
}
|
||||
case(HAL_TIMEOUT): {
|
||||
sif::printDebug("GyroL3GD20H::initialize: Polling transfer timeout\n");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
case(HAL_ERROR): {
|
||||
sif::printDebug("GyroL3GD20H::initialize: Polling transfer failure\n");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
default: {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t GyroL3GD20H::handleInterruptTransferInit() {
|
||||
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET);
|
||||
switch(HAL_SPI_TransmitReceive_IT(spiHandle, txBuffer.data(), rxBuffer.data(), 2)) {
|
||||
case(HAL_OK): {
|
||||
sif::printInfo("GyroL3GD20H::initialize: Interrupt transfer success\n");
|
||||
// Wait for the transfer to complete
|
||||
while (transferState == TransferStates::WAIT) {
|
||||
TaskFactory::delayTask(1);
|
||||
}
|
||||
|
||||
uint8_t whoAmIVal = rxBuffer[1];
|
||||
if(whoAmIVal != EXPECTED_WHO_AM_I_VAL) {
|
||||
sif::printDebug("GyroL3GD20H::initialize: "
|
||||
"Read WHO AM I value %d not equal to expected value!\n", whoAmIVal);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case(HAL_BUSY):
|
||||
case(HAL_ERROR):
|
||||
case(HAL_TIMEOUT): {
|
||||
sif::printDebug("GyroL3GD20H::initialize: Initialization failure using interrupts\n");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
sif::printInfo("GyroL3GD20H::initialize: Configuring device\n");
|
||||
transferState = TransferStates::WAIT;
|
||||
// Configure the 5 configuration registers
|
||||
uint8_t configRegs[5];
|
||||
prepareConfigRegs(configRegs);
|
||||
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET);
|
||||
switch(HAL_SPI_TransmitReceive_IT(spiHandle, txBuffer.data(), rxBuffer.data(), 6)) {
|
||||
case(HAL_OK): {
|
||||
// Wait for the transfer to complete
|
||||
while (transferState == TransferStates::WAIT) {
|
||||
TaskFactory::delayTask(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case(HAL_BUSY):
|
||||
case(HAL_ERROR):
|
||||
case(HAL_TIMEOUT): {
|
||||
sif::printDebug("GyroL3GD20H::initialize: Initialization failure using interrupts\n");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
txBuffer[0] = CTRL_REG_1 | STM_AUTO_INCREMENT_MASK | STM_READ_MASK;
|
||||
std::memset(txBuffer.data() + 1, 0 , 5);
|
||||
transferState = TransferStates::WAIT;
|
||||
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET);
|
||||
switch(HAL_SPI_TransmitReceive_IT(spiHandle, txBuffer.data(), rxBuffer.data(), 6)) {
|
||||
case(HAL_OK): {
|
||||
// Wait for the transfer to complete
|
||||
while (transferState == TransferStates::WAIT) {
|
||||
TaskFactory::delayTask(1);
|
||||
}
|
||||
if(rxBuffer[1] != configRegs[0] or rxBuffer[2] != configRegs[1] or
|
||||
rxBuffer[3] != configRegs[2] or rxBuffer[4] != configRegs[3] or
|
||||
rxBuffer[5] != configRegs[4]) {
|
||||
sif::printWarning("GyroL3GD20H::initialize: Configuration failure\n");
|
||||
}
|
||||
else {
|
||||
sif::printInfo("GyroL3GD20H::initialize: Configuration success\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case(HAL_BUSY):
|
||||
case(HAL_ERROR):
|
||||
case(HAL_TIMEOUT): {
|
||||
sif::printDebug("GyroL3GD20H::initialize: Initialization failure using interrupts\n");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t GyroL3GD20H::handleInterruptSensorRead() {
|
||||
transferState = TransferStates::WAIT;
|
||||
txBuffer[0] = CTRL_REG_1 | STM_AUTO_INCREMENT_MASK | STM_READ_MASK;
|
||||
std::memset(txBuffer.data() + 1, 0 , 14);
|
||||
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET);
|
||||
switch(HAL_SPI_TransmitReceive_IT(spiHandle, txBuffer.data(), rxBuffer.data(), 15)) {
|
||||
case(HAL_OK): {
|
||||
// Wait for the transfer to complete
|
||||
while (transferState == TransferStates::WAIT) {
|
||||
TaskFactory::delayTask(1);
|
||||
}
|
||||
handleSensorReadout();
|
||||
break;
|
||||
}
|
||||
case(HAL_BUSY):
|
||||
case(HAL_ERROR):
|
||||
case(HAL_TIMEOUT): {
|
||||
sif::printDebug("GyroL3GD20H::initialize: Sensor read failure using interrupts\n");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
void GyroL3GD20H::prepareConfigRegs(uint8_t* configRegs) {
|
||||
// Enable sensor
|
||||
configRegs[0] = 0b00001111;
|
||||
configRegs[1] = 0b00000000;
|
||||
configRegs[2] = 0b00000000;
|
||||
configRegs[3] = 0b01000000;
|
||||
// Big endian select
|
||||
configRegs[4] = 0b00000000;
|
||||
|
||||
txBuffer[0] = CTRL_REG_1 | STM_AUTO_INCREMENT_MASK;
|
||||
std::memcpy(txBuffer.data() + 1, configRegs, 5);
|
||||
}
|
||||
|
||||
void GyroL3GD20H::handleSensorReadout() {
|
||||
uint8_t statusReg = rxBuffer[8];
|
||||
int16_t gyroXRaw = rxBuffer[9] << 8 | rxBuffer[10];
|
||||
float gyroX = static_cast<float>(gyroXRaw) / INT16_MAX * L3G_RANGE;
|
||||
int16_t gyroYRaw = rxBuffer[11] << 8 | rxBuffer[12];
|
||||
float gyroY = static_cast<float>(gyroYRaw) / INT16_MAX * L3G_RANGE;
|
||||
int16_t gyroZRaw = rxBuffer[13] << 8 | rxBuffer[14];
|
||||
float gyroZ = static_cast<float>(gyroZRaw) / INT16_MAX * L3G_RANGE;
|
||||
sif::printInfo("Status register: 0b" BYTE_TO_BINARY_PATTERN "\n", BYTE_TO_BINARY(statusReg));
|
||||
sif::printInfo("Gyro X: %f\n", gyroX);
|
||||
sif::printInfo("Gyro Y: %f\n", gyroY);
|
||||
sif::printInfo("Gyro Z: %f\n", gyroZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TxRx Transfer completed callback.
|
||||
* @param hspi: SPI handle
|
||||
* @note This example shows a simple way to report end of DMA TxRx transfer, and
|
||||
* you can add your own implementation.
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) {
|
||||
transferState = TransferStates::SUCCESS;
|
||||
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET);
|
||||
if(GyroL3GD20H::transferMode == spi::TransferModes::DMA) {
|
||||
// Invalidate cache prior to access by CPU
|
||||
SCB_InvalidateDCache_by_Addr ((uint32_t *)GyroL3GD20H::rxBuffer.data(),
|
||||
GyroL3GD20H::recvBufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi) {
|
||||
transferState = TransferStates::FAILURE;
|
||||
}
|
58
stm32h7/devicetest/GyroL3GD20H.h
Normal file
58
stm32h7/devicetest/GyroL3GD20H.h
Normal file
@ -0,0 +1,58 @@
|
||||
#ifndef FSFW_HAL_STM32H7_DEVICETEST_GYRO_L3GD20H_H_
|
||||
#define FSFW_HAL_STM32H7_DEVICETEST_GYRO_L3GD20H_H_
|
||||
|
||||
#include "stm32h7xx_hal.h"
|
||||
#include "stm32h7xx_hal_spi.h"
|
||||
|
||||
#include "../spi/spiDefinitions.h"
|
||||
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
|
||||
enum class TransferStates {
|
||||
IDLE,
|
||||
WAIT,
|
||||
SUCCESS,
|
||||
FAILURE
|
||||
};
|
||||
|
||||
class GyroL3GD20H {
|
||||
friend void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi);
|
||||
public:
|
||||
GyroL3GD20H(SPI_HandleTypeDef* spiHandle, spi::TransferModes transferMode);
|
||||
|
||||
ReturnValue_t initialize();
|
||||
ReturnValue_t performOperation();
|
||||
|
||||
private:
|
||||
|
||||
const uint8_t WHO_AM_I_REG = 0b00001111;
|
||||
const uint8_t STM_READ_MASK = 0b10000000;
|
||||
const uint8_t STM_AUTO_INCREMENT_MASK = 0b01000000;
|
||||
const uint8_t EXPECTED_WHO_AM_I_VAL = 0b11010111;
|
||||
const uint8_t CTRL_REG_1 = 0b00100000;
|
||||
const uint32_t L3G_RANGE = 245;
|
||||
|
||||
SPI_HandleTypeDef* spiHandle;
|
||||
|
||||
static spi::TransferModes transferMode;
|
||||
static constexpr size_t recvBufferSize = 32 * 10;
|
||||
static std::array<uint8_t, recvBufferSize> rxBuffer;
|
||||
static constexpr size_t txBufferSize = 32;
|
||||
static std::array<uint8_t, txBufferSize> txBuffer;
|
||||
|
||||
ReturnValue_t handleDmaTransferInit();
|
||||
ReturnValue_t handlePollingTransferInit();
|
||||
ReturnValue_t handleInterruptTransferInit();
|
||||
|
||||
ReturnValue_t handleDmaSensorRead();
|
||||
HAL_StatusTypeDef performDmaTransfer(size_t sendSize);
|
||||
ReturnValue_t handlePollingSensorRead();
|
||||
ReturnValue_t handleInterruptSensorRead();
|
||||
|
||||
void prepareConfigRegs(uint8_t* configRegs);
|
||||
void handleSensorReadout();
|
||||
};
|
||||
|
||||
#endif /* FSFW_HAL_STM32H7_DEVICETEST_GYRO_L3GD20H_H_ */
|
84
stm32h7/dma_interrupts.c
Normal file
84
stm32h7/dma_interrupts.c
Normal file
@ -0,0 +1,84 @@
|
||||
#include "dma_interrupts.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
user_handler_t DMA_1_USER_HANDLERS[8];
|
||||
user_args_t DMA_1_USER_ARGS[8];
|
||||
|
||||
user_handler_t DMA_2_USER_HANDLERS[8];
|
||||
user_args_t DMA_2_USER_ARGS[8];
|
||||
|
||||
void assign_dma_user_handler(DMAIndexes dma_idx, DMAStreams stream_idx,
|
||||
user_handler_t user_handler, user_args_t user_args) {
|
||||
if(dma_idx == DMA_1) {
|
||||
DMA_1_USER_HANDLERS[stream_idx] = user_handler;
|
||||
DMA_1_USER_ARGS[stream_idx] = user_args;
|
||||
}
|
||||
else if(dma_idx == DMA_2) {
|
||||
DMA_2_USER_HANDLERS[stream_idx] = user_handler;
|
||||
DMA_2_USER_ARGS[stream_idx] = user_args;
|
||||
}
|
||||
}
|
||||
|
||||
// The interrupt handlers in the format required for the IRQ vector table
|
||||
|
||||
/* 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! */
|
||||
|
||||
#define GENERIC_DMA_IRQ_HANDLER(DMA_IDX, STREAM_IDX) \
|
||||
if(DMA_##DMA_IDX##_USER_HANDLERS[STREAM_IDX] != NULL) { \
|
||||
DMA_##DMA_IDX##_USER_HANDLERS[STREAM_IDX](DMA_##DMA_IDX##_USER_ARGS[STREAM_IDX]); \
|
||||
return; \
|
||||
} \
|
||||
Default_Handler() \
|
||||
|
||||
void DMA1_Stream0_IRQHandler() {
|
||||
GENERIC_DMA_IRQ_HANDLER(1, 0);
|
||||
}
|
||||
void DMA1_Stream1_IRQHandler() {
|
||||
GENERIC_DMA_IRQ_HANDLER(1, 1);
|
||||
}
|
||||
void DMA1_Stream2_IRQHandler() {
|
||||
GENERIC_DMA_IRQ_HANDLER(1, 2);
|
||||
}
|
||||
void DMA1_Stream3_IRQHandler() {
|
||||
GENERIC_DMA_IRQ_HANDLER(1, 3);
|
||||
}
|
||||
void DMA1_Stream4_IRQHandler() {
|
||||
GENERIC_DMA_IRQ_HANDLER(1, 4);
|
||||
}
|
||||
void DMA1_Stream5_IRQHandler() {
|
||||
GENERIC_DMA_IRQ_HANDLER(1, 5);
|
||||
}
|
||||
void DMA1_Stream6_IRQHandler() {
|
||||
GENERIC_DMA_IRQ_HANDLER(1, 6);
|
||||
}
|
||||
void DMA1_Stream7_IRQHandler() {
|
||||
GENERIC_DMA_IRQ_HANDLER(1, 7);
|
||||
}
|
||||
|
||||
void DMA2_Stream0_IRQHandler() {
|
||||
GENERIC_DMA_IRQ_HANDLER(2, 0);
|
||||
}
|
||||
void DMA2_Stream1_IRQHandler() {
|
||||
GENERIC_DMA_IRQ_HANDLER(2, 1);
|
||||
}
|
||||
void DMA2_Stream2_IRQHandler() {
|
||||
GENERIC_DMA_IRQ_HANDLER(2, 2);
|
||||
}
|
||||
void DMA2_Stream3_IRQHandler() {
|
||||
GENERIC_DMA_IRQ_HANDLER(2, 3);
|
||||
}
|
||||
void DMA2_Stream4_IRQHandler() {
|
||||
GENERIC_DMA_IRQ_HANDLER(2, 4);
|
||||
}
|
||||
void DMA2_Stream5_IRQHandler() {
|
||||
GENERIC_DMA_IRQ_HANDLER(2, 5);
|
||||
}
|
||||
void DMA2_Stream6_IRQHandler() {
|
||||
GENERIC_DMA_IRQ_HANDLER(2, 6);
|
||||
}
|
||||
void DMA2_Stream7_IRQHandler() {
|
||||
GENERIC_DMA_IRQ_HANDLER(2, 7);
|
||||
}
|
39
stm32h7/dma_interrupts.h
Normal file
39
stm32h7/dma_interrupts.h
Normal file
@ -0,0 +1,39 @@
|
||||
#ifndef FSFW_HAL_STM32H7_DMA_INTERRUPTS_H_
|
||||
#define FSFW_HAL_STM32H7_DMA_INTERRUPTS_H_
|
||||
|
||||
#include "interrupts.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
DMA_1 = 0,
|
||||
DMA_2 = 1
|
||||
} DMAIndexes;
|
||||
|
||||
typedef enum {
|
||||
STREAM_0 = 0,
|
||||
STREAM_1 = 1,
|
||||
STREAM_2 = 2,
|
||||
STREAM_3 = 3,
|
||||
STREAM_4 = 4,
|
||||
STREAM_5 = 5,
|
||||
STREAM_6 = 6,
|
||||
STREAM_7 = 7,
|
||||
} DMAStreams;
|
||||
|
||||
/**
|
||||
* Assign user interrupt handlers for DMA streams, allowing to pass an
|
||||
* arbitrary argument as well. Generally, this argument will be the related DMA handle.
|
||||
* @param user_handler
|
||||
* @param user_args
|
||||
*/
|
||||
void assign_dma_user_handler(DMAIndexes dma_idx, DMAStreams stream_idx,
|
||||
user_handler_t user_handler, user_args_t user_args);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FSFW_HAL_STM32H7_DMA_INTERRUPTS_H_ */
|
2
stm32h7/interrupts.c
Normal file
2
stm32h7/interrupts.c
Normal file
@ -0,0 +1,2 @@
|
||||
#include "interrupts.h"
|
||||
#include <stddef.h>
|
20
stm32h7/interrupts.h
Normal file
20
stm32h7/interrupts.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef FSFW_HAL_STM32H7_INTERRUPTS_H_
|
||||
#define FSFW_HAL_STM32H7_INTERRUPTS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Default handler which is defined in startup file as assembly code.
|
||||
*/
|
||||
extern void Default_Handler();
|
||||
|
||||
typedef void (*user_handler_t) (void*);
|
||||
typedef void* user_args_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FSFW_HAL_STM32H7_INTERRUPTS_H_ */
|
6
stm32h7/spi/CMakeLists.txt
Normal file
6
stm32h7/spi/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
target_sources(${TARGET_NAME} PRIVATE
|
||||
spiCore.c
|
||||
spiDefinitions.cpp
|
||||
interrupts.c
|
||||
mspInit.c
|
||||
)
|
73
stm32h7/spi/interrupts.c
Normal file
73
stm32h7/spi/interrupts.c
Normal file
@ -0,0 +1,73 @@
|
||||
#include "interrupts.h"
|
||||
|
||||
#include "stm32h7xx_hal.h"
|
||||
#include "stm32h7xx_hal_dma.h"
|
||||
#include "stm32h7xx_hal_spi.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
void (*spi1_user_handler) (void* args) = NULL;
|
||||
void * spi1_user_args = NULL;
|
||||
|
||||
void (*spi2_user_handler) (void* args) = NULL;
|
||||
void * spi2_user_args = NULL;
|
||||
|
||||
void assign_spi_user_handler(SpiBus spi_idx, user_handler_t user_handler, user_args_t user_args) {
|
||||
if(spi_idx == SPI_1) {
|
||||
spi1_user_handler = user_handler;
|
||||
spi1_user_args = user_args;
|
||||
}
|
||||
else {
|
||||
spi2_user_handler = user_handler;
|
||||
spi2_user_args = user_args;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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! */
|
||||
|
||||
void SPI1_IRQHandler() {
|
||||
if(spi1_user_handler != NULL) {
|
||||
spi1_user_handler(spi1_user_args);
|
||||
return;
|
||||
}
|
||||
Default_Handler();
|
||||
}
|
||||
|
||||
void SPI2_IRQHandler() {
|
||||
if(spi2_user_handler != NULL) {
|
||||
spi2_user_handler(spi2_user_args);
|
||||
return;
|
||||
}
|
||||
Default_Handler();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles DMA Rx interrupt request.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void dma_rx_irq_handler(void* dma_handle) {
|
||||
HAL_DMA_IRQHandler((DMA_HandleTypeDef *) dma_handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles DMA Rx interrupt request.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void dma_tx_irq_handler(void* dma_handle) {
|
||||
HAL_DMA_IRQHandler((DMA_HandleTypeDef *) dma_handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles SPIx interrupt request.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void spi1_irq_handler(void* spi_handle)
|
||||
{
|
||||
HAL_SPI_IRQHandler((SPI_HandleTypeDef *) spi_handle);
|
||||
}
|
||||
|
36
stm32h7/spi/interrupts.h
Normal file
36
stm32h7/spi/interrupts.h
Normal file
@ -0,0 +1,36 @@
|
||||
#ifndef FSFW_HAL_STM32H7_SPI_INTERRUPTS_H_
|
||||
#define FSFW_HAL_STM32H7_SPI_INTERRUPTS_H_
|
||||
|
||||
#include "../interrupts.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
SPI_1,
|
||||
SPI_2
|
||||
} SpiBus;
|
||||
|
||||
/**
|
||||
* 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 assign_spi_user_handler(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 dma_rx_irq_handler(void* dma_handle);
|
||||
void dma_tx_irq_handler(void* dma_handle);
|
||||
void spi1_irq_handler(void* spi_handle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FSFW_HAL_STM32H7_SPI_INTERRUPTS_H_ */
|
207
stm32h7/spi/mspInit.c
Normal file
207
stm32h7/spi/mspInit.c
Normal file
@ -0,0 +1,207 @@
|
||||
#include "mspInit.h"
|
||||
#include "spiConf.h"
|
||||
#include "spiCore.h"
|
||||
#include "../dma_interrupts.h"
|
||||
#include "interrupts.h"
|
||||
|
||||
#include "stm32h743xx.h"
|
||||
#include "stm32h7xx_hal_spi.h"
|
||||
#include "stm32h7xx_hal_dma.h"
|
||||
#include "stm32h7xx_hal_def.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/**
|
||||
* @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 hal_spi_msp_init_dma(void *spi_handle) {
|
||||
SPI_HandleTypeDef* hspi = (SPI_HandleTypeDef*) spi_handle;
|
||||
if(hspi == NULL) {
|
||||
return;
|
||||
}
|
||||
if(hspi == NULL) {
|
||||
printf("HAL_SPI_MspInit: Invalid SPI handle!\n");
|
||||
return;
|
||||
}
|
||||
assign_spi_handle(hspi);
|
||||
|
||||
DMA_HandleTypeDef* hdma_tx = NULL;
|
||||
DMA_HandleTypeDef* hdma_rx = NULL;
|
||||
get_dma_handles(&hdma_tx, &hdma_rx);
|
||||
if(hdma_tx == NULL || hdma_rx == NULL) {
|
||||
printf("HAL_SPI_MspInit: Invalid DMA handles. Make sure to call setDmaHandles!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hal_spi_msp_init_polling(spi_handle);
|
||||
if (hspi->Instance == SPI1) {
|
||||
// DMA setup
|
||||
DMAx_CLK_ENABLE();
|
||||
|
||||
// Configure the DMA
|
||||
/* Configure the DMA handler for Transmission process */
|
||||
hdma_tx->Instance = SPIx_TX_DMA_STREAM;
|
||||
hdma_tx->Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||
hdma_tx->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
|
||||
hdma_tx->Init.MemBurst = DMA_MBURST_INC4;
|
||||
hdma_tx->Init.PeriphBurst = DMA_PBURST_INC4;
|
||||
hdma_tx->Init.Request = SPIx_TX_DMA_REQUEST;
|
||||
hdma_tx->Init.Direction = DMA_MEMORY_TO_PERIPH;
|
||||
hdma_tx->Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
hdma_tx->Init.MemInc = DMA_MINC_ENABLE;
|
||||
hdma_tx->Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
|
||||
hdma_tx->Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
|
||||
hdma_tx->Init.Mode = DMA_NORMAL;
|
||||
hdma_tx->Init.Priority = DMA_PRIORITY_LOW;
|
||||
|
||||
HAL_DMA_Init(hdma_tx);
|
||||
|
||||
/* Associate the initialized DMA handle to the the SPI handle */
|
||||
__HAL_LINKDMA(hspi, hdmatx, *hdma_tx);
|
||||
|
||||
/* Configure the DMA handler for Transmission process */
|
||||
hdma_rx->Instance = SPIx_RX_DMA_STREAM;
|
||||
|
||||
hdma_rx->Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||
hdma_rx->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
|
||||
hdma_rx->Init.MemBurst = DMA_MBURST_INC4;
|
||||
hdma_rx->Init.PeriphBurst = DMA_PBURST_INC4;
|
||||
hdma_rx->Init.Request = SPIx_RX_DMA_REQUEST;
|
||||
hdma_rx->Init.Direction = DMA_PERIPH_TO_MEMORY;
|
||||
hdma_rx->Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
hdma_rx->Init.MemInc = DMA_MINC_ENABLE;
|
||||
hdma_rx->Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
|
||||
hdma_rx->Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
|
||||
hdma_rx->Init.Mode = DMA_NORMAL;
|
||||
hdma_rx->Init.Priority = DMA_PRIORITY_HIGH;
|
||||
|
||||
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
|
||||
assign_dma_user_handler(DMA_2, 2, &dma_rx_irq_handler, hdma_rx);
|
||||
HAL_NVIC_SetPriority(SPIx_DMA_RX_IRQn, 1, 0);
|
||||
HAL_NVIC_EnableIRQ(SPIx_DMA_RX_IRQn);
|
||||
|
||||
/* NVIC configuration for DMA transfer complete interrupt (SPI1_TX) */
|
||||
// Assign the interrupt handler
|
||||
assign_dma_user_handler(DMA_2, 3, &dma_tx_irq_handler, hdma_tx);
|
||||
HAL_NVIC_SetPriority(SPIx_DMA_TX_IRQn, 1, 1);
|
||||
HAL_NVIC_EnableIRQ(SPIx_DMA_TX_IRQn);
|
||||
|
||||
/*##-5- Configure the NVIC for SPI #########################################*/
|
||||
/* NVIC configuration for SPI transfer complete interrupt (SPI1) */
|
||||
// Assign the interrupt handler
|
||||
assign_spi_user_handler(SPI_1, &spi1_irq_handler, hspi);
|
||||
HAL_NVIC_SetPriority(SPIx_IRQn, 1, 0);
|
||||
HAL_NVIC_EnableIRQ(SPIx_IRQn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 hal_spi_msp_deinit_dma(void *spi_handle)
|
||||
{
|
||||
SPI_HandleTypeDef* hspi = (SPI_HandleTypeDef*) spi_handle;
|
||||
if(hspi == NULL) {
|
||||
return;
|
||||
}
|
||||
hal_spi_msp_deinit_polling(spi_handle);
|
||||
if(hspi->Instance == SPIx) {
|
||||
DMA_HandleTypeDef* hdma_tx = NULL;
|
||||
DMA_HandleTypeDef* hdma_rx = NULL;
|
||||
get_dma_handles(&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 {
|
||||
/*##-3- 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);
|
||||
}
|
||||
|
||||
/*##-4- Disable the NVIC for DMA ###########################################*/
|
||||
HAL_NVIC_DisableIRQ(SPIx_DMA_TX_IRQn);
|
||||
HAL_NVIC_DisableIRQ(SPIx_DMA_RX_IRQn);
|
||||
|
||||
/*##-5- Disable the NVIC for SPI ###########################################*/
|
||||
HAL_NVIC_EnableIRQ(SPIx_IRQn);
|
||||
}
|
||||
}
|
||||
|
||||
void hal_spi_msp_init_polling(void *hspi) {
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {};
|
||||
/*##-1- Enable peripherals and GPIO Clocks #################################*/
|
||||
/* Enable GPIO TX/RX clock */
|
||||
SPIx_SCK_GPIO_CLK_ENABLE();
|
||||
SPIx_MISO_GPIO_CLK_ENABLE();
|
||||
SPIx_MOSI_GPIO_CLK_ENABLE();
|
||||
/* Enable SPI clock */
|
||||
SPIx_CLK_ENABLE();
|
||||
|
||||
/*##-2- Configure peripheral GPIO ##########################################*/
|
||||
/* SPI SCK GPIO pin configuration */
|
||||
GPIO_InitStruct.Pin = SPIx_SCK_PIN;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
|
||||
GPIO_InitStruct.Alternate = SPIx_SCK_AF;
|
||||
HAL_GPIO_Init(SPIx_SCK_GPIO_PORT, &GPIO_InitStruct);
|
||||
|
||||
/* SPI MISO GPIO pin configuration */
|
||||
GPIO_InitStruct.Pin = SPIx_MISO_PIN;
|
||||
GPIO_InitStruct.Alternate = SPIx_MISO_AF;
|
||||
HAL_GPIO_Init(SPIx_MISO_GPIO_PORT, &GPIO_InitStruct);
|
||||
|
||||
/* SPI MOSI GPIO pin configuration */
|
||||
GPIO_InitStruct.Pin = SPIx_MOSI_PIN;
|
||||
GPIO_InitStruct.Alternate = SPIx_MOSI_AF;
|
||||
HAL_GPIO_Init(SPIx_MOSI_GPIO_PORT, &GPIO_InitStruct);
|
||||
}
|
||||
|
||||
void hal_spi_msp_deinit_polling(void *hspi) {
|
||||
/*##-1- Reset peripherals ##################################################*/
|
||||
SPIx_FORCE_RESET();
|
||||
SPIx_RELEASE_RESET();
|
||||
|
||||
/*##-2- Disable peripherals and GPIO Clocks ################################*/
|
||||
/* Configure SPI SCK as alternate function */
|
||||
HAL_GPIO_DeInit(SPIx_SCK_GPIO_PORT, SPIx_SCK_PIN);
|
||||
/* Configure SPI MISO as alternate function */
|
||||
HAL_GPIO_DeInit(SPIx_MISO_GPIO_PORT, SPIx_MISO_PIN);
|
||||
/* Configure SPI MOSI as alternate function */
|
||||
HAL_GPIO_DeInit(SPIx_MOSI_GPIO_PORT, SPIx_MOSI_PIN);
|
||||
}
|
||||
|
||||
void hal_spi_msp_init_interrupt(void *hspi) {
|
||||
hal_spi_msp_init_polling(hspi);
|
||||
// Configure the NVIC for SPI
|
||||
assign_spi_user_handler(SPI_1, &spi1_irq_handler, hspi);
|
||||
HAL_NVIC_SetPriority(SPIx_IRQn, 1, 0);
|
||||
HAL_NVIC_EnableIRQ(SPIx_IRQn);
|
||||
}
|
||||
|
||||
void hal_spi_msp_deinit_interrupt(void *hspi) {
|
||||
hal_spi_msp_deinit_polling(hspi);
|
||||
// Disable the NVIC for SPI
|
||||
HAL_NVIC_DisableIRQ(SPIx_IRQn);
|
||||
}
|
21
stm32h7/spi/mspInit.h
Normal file
21
stm32h7/spi/mspInit.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef FSFW_HAL_STM32H7_SPI_MSPINIT_H_
|
||||
#define FSFW_HAL_STM32H7_SPI_MSPINIT_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void hal_spi_msp_init_dma(void *hspi);
|
||||
void hal_spi_msp_deinit_dma(void *hspi);
|
||||
|
||||
void hal_spi_msp_init_polling(void *hspi);
|
||||
void hal_spi_msp_deinit_polling(void *hspi);
|
||||
|
||||
void hal_spi_msp_init_interrupt(void *hspi);
|
||||
void hal_spi_msp_deinit_interrupt(void *hspi);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FSFW_HAL_STM32H7_SPI_MSPINIT_H_ */
|
91
stm32h7/spi/spiCore.c
Normal file
91
stm32h7/spi/spiCore.c
Normal file
@ -0,0 +1,91 @@
|
||||
#include "spiCore.h"
|
||||
#include <stdio.h>
|
||||
|
||||
SPI_HandleTypeDef* spiHandle = NULL;
|
||||
DMA_HandleTypeDef* hdma_tx = NULL;
|
||||
DMA_HandleTypeDef* hdma_rx = NULL;
|
||||
|
||||
msp_func_t msp_init_func = NULL;
|
||||
void* msp_init_args = NULL;
|
||||
|
||||
msp_func_t msp_deinit_func = NULL;
|
||||
void* msp_deinit_args = NULL;
|
||||
|
||||
void set_dma_handles(DMA_HandleTypeDef* txHandle, DMA_HandleTypeDef* rxHandle) {
|
||||
hdma_tx = txHandle;
|
||||
hdma_rx = rxHandle;
|
||||
}
|
||||
|
||||
void get_dma_handles(DMA_HandleTypeDef** txHandle, DMA_HandleTypeDef** rxHandle) {
|
||||
*txHandle = hdma_tx;
|
||||
*rxHandle = hdma_rx;
|
||||
}
|
||||
|
||||
void assign_spi_handle(SPI_HandleTypeDef *spiHandle_) {
|
||||
if(spiHandle_ == NULL) {
|
||||
return;
|
||||
}
|
||||
spiHandle = spiHandle_;
|
||||
}
|
||||
|
||||
SPI_HandleTypeDef* get_spi_handle() {
|
||||
return spiHandle;
|
||||
}
|
||||
|
||||
void set_spi_msp_functions(msp_func_t init_func, void* init_args, msp_func_t deinit_func,
|
||||
void* deinit_args) {
|
||||
msp_init_func = init_func;
|
||||
msp_init_args = init_args;
|
||||
msp_deinit_func = deinit_func;
|
||||
msp_deinit_args = deinit_args;
|
||||
}
|
||||
|
||||
void get_msp_init_function(msp_func_t* init_func, void **args) {
|
||||
if(init_func != NULL && args != NULL) {
|
||||
*init_func = msp_init_func;
|
||||
*args = msp_init_args;
|
||||
}
|
||||
}
|
||||
|
||||
void get_msp_deinit_function(msp_func_t* deinit_func, void **args) {
|
||||
if(deinit_func != NULL && args != NULL) {
|
||||
*deinit_func = msp_deinit_func;
|
||||
*args = msp_deinit_args;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 HAL_SPI_MspInit(SPI_HandleTypeDef *hspi) {
|
||||
if(msp_init_func != NULL) {
|
||||
msp_init_func(msp_init_args);
|
||||
}
|
||||
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
|
||||
*/
|
||||
void HAL_SPI_MspDeInit(SPI_HandleTypeDef *hspi) {
|
||||
if(msp_deinit_func != NULL) {
|
||||
msp_deinit_func(msp_deinit_args);
|
||||
}
|
||||
else {
|
||||
printf("HAL_SPI_MspDeInit: Please call set_msp_functions to assign SPI MSP functions\n");
|
||||
}
|
||||
}
|
50
stm32h7/spi/spiCore.h
Normal file
50
stm32h7/spi/spiCore.h
Normal file
@ -0,0 +1,50 @@
|
||||
#ifndef FSFW_HAL_STM32H7_SPI_SPICORE_H_
|
||||
#define FSFW_HAL_STM32H7_SPI_SPICORE_H_
|
||||
|
||||
#include "stm32h7xx_hal.h"
|
||||
#include "stm32h7xx_hal_dma.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*msp_func_t) (void* args);
|
||||
|
||||
/**
|
||||
* Assign MSP init functions. Important for SPI configuration
|
||||
* @param init_func
|
||||
* @param init_args
|
||||
* @param deinit_func
|
||||
* @param deinit_args
|
||||
*/
|
||||
void set_spi_msp_functions(msp_func_t init_func, void* init_args, msp_func_t deinit_func,
|
||||
void* deinit_args);
|
||||
|
||||
/**
|
||||
* Assign DMA handles. Required to use DMA for SPI transfers.
|
||||
* @param txHandle
|
||||
* @param rxHandle
|
||||
*/
|
||||
void set_dma_handles(DMA_HandleTypeDef* txHandle, DMA_HandleTypeDef* rxHandle);
|
||||
|
||||
void get_dma_handles(DMA_HandleTypeDef** txHandle, DMA_HandleTypeDef** rxHandle);
|
||||
void get_msp_init_function(msp_func_t* init_func, void **args);
|
||||
void get_msp_deinit_function(msp_func_t* deinit_func, void **args);
|
||||
|
||||
/**
|
||||
* Assign SPI handle. Needs to be done before using the SPI
|
||||
* @param spiHandle
|
||||
*/
|
||||
void assign_spi_handle(SPI_HandleTypeDef *spiHandle);
|
||||
|
||||
/**
|
||||
* Get the assigned SPI handle.
|
||||
* @return
|
||||
*/
|
||||
SPI_HandleTypeDef* get_spi_handle();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FSFW_HAL_STM32H7_SPI_SPICORE_H_ */
|
52
stm32h7/spi/spiDefinitions.cpp
Normal file
52
stm32h7/spi/spiDefinitions.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
#include "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;
|
||||
}
|
30
stm32h7/spi/spiDefinitions.h
Normal file
30
stm32h7/spi/spiDefinitions.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef FSFW_HAL_STM32H7_SPI_SPIDEFINITIONS_H_
|
||||
#define FSFW_HAL_STM32H7_SPI_SPIDEFINITIONS_H_
|
||||
|
||||
#include "../../common/spi/spiCommon.h"
|
||||
|
||||
#include "stm32h7xx_hal.h"
|
||||
#include "stm32h7xx_hal_spi.h"
|
||||
|
||||
namespace spi {
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif /* FSFW_HAL_STM32H7_SPI_SPIDEFINITIONS_H_ */
|
Reference in New Issue
Block a user