From 8e98de6f3cdb985065b1408dd871ebbd0b2bc3df Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Thu, 1 Jul 2021 10:53:50 +0200 Subject: [PATCH] added spi mux functionality to the rwSpiCallback --- bsp_q7s/ObjectFactory.cpp | 37 +++++++++------- bsp_q7s/spi/Q7sSpiComIF.cpp | 9 ++++ bsp_q7s/spi/Q7sSpiComIF.h | 33 +++++++++++++++ bsp_q7s/spiCallbacks/rwSpiCallback.cpp | 58 ++++++++++++++++---------- bsp_q7s/spiCallbacks/rwSpiCallback.h | 16 ++++++- linux/fsfwconfig/devices/gpioIds.h | 4 +- 6 files changed, 117 insertions(+), 40 deletions(-) create mode 100644 bsp_q7s/spi/Q7sSpiComIF.cpp create mode 100644 bsp_q7s/spi/Q7sSpiComIF.h diff --git a/bsp_q7s/ObjectFactory.cpp b/bsp_q7s/ObjectFactory.cpp index 936b1cd2..991cd8b2 100644 --- a/bsp_q7s/ObjectFactory.cpp +++ b/bsp_q7s/ObjectFactory.cpp @@ -521,12 +521,6 @@ void ObjectFactory::produce(void* args){ Max31865PT1000Handler* rtdIc16 = new Max31865PT1000Handler(objects::RTD_IC16, objects::SPI_COM_IF, spiRtdIc16, 0); Max31865PT1000Handler* rtdIc17 = new Max31865PT1000Handler(objects::RTD_IC17, objects::SPI_COM_IF, spiRtdIc17, 0); Max31865PT1000Handler* rtdIc18 = new Max31865PT1000Handler(objects::RTD_IC18, objects::SPI_COM_IF, spiRtdIc18, 0); -<<<<<<< HEAD - rtdIc3->setStartUpImmediately(); -======= - rtdIc17->setStartUpImmediately(); ->>>>>>> develop -// rtdIc4->setStartUpImmediately(); (void) rtdIc3; (void) rtdIc4; @@ -542,7 +536,7 @@ void ObjectFactory::produce(void* args){ (void) rtdIc14; (void) rtdIc15; (void) rtdIc16; -// (void) rtdIc17; + (void) rtdIc17; (void) rtdIc18; #endif /* Q7S_ADD_RTD_DEVICES == 1 */ @@ -582,16 +576,29 @@ void ObjectFactory::produce(void* args){ std::string("Enable reaction wheel 4"), gpio::OUT, 0); gpioCookieRw->addGpio(gpioIds::EN_RW4, enRw4); + /** + * This GPIO is only internally connected to the SPI MUX module and responsible to disconnect + * the PS SPI peripheral from the SPI interface and route out the SPI lines of the AXI SPI core. + * Per default the PS SPI is selected (EMIO = 0). + */ + GpiodRegular* spiMux = new GpiodRegular(std::string("gpiochip11"), 54, + std::string("EMIO 0 SPI Mux"), gpio::OUT, 0); + gpioCookieRw->addGpio(gpioIds::SPI_MUX, spiMux); + gpioComIF->addGpios(gpioCookieRw); - auto rw1SpiCookie = new SpiCookie(addresses::RW1, gpioIds::CS_RW1, "/dev/spidev2.0", - RwDefinitions::MAX_REPLY_SIZE, spi::RW_MODE, spi::RW_SPEED, &rwSpiCallback, nullptr); - auto rw2SpiCookie = new SpiCookie(addresses::RW2, gpioIds::CS_RW2, "/dev/spidev2.0", - RwDefinitions::MAX_REPLY_SIZE, spi::RW_MODE, spi::RW_SPEED, &rwSpiCallback, nullptr); - auto rw3SpiCookie = new SpiCookie(addresses::RW3, gpioIds::CS_RW3, "/dev/spidev2.0", - RwDefinitions::MAX_REPLY_SIZE, spi::RW_MODE, spi::RW_SPEED, &rwSpiCallback, nullptr); - auto rw4SpiCookie = new SpiCookie(addresses::RW4, gpioIds::CS_RW4, "/dev/spidev2.0", - RwDefinitions::MAX_REPLY_SIZE, spi::RW_MODE, spi::RW_SPEED, &rwSpiCallback, nullptr); + auto rw1SpiCookie = new SpiCookie(addresses::RW1, gpioIds::CS_RW1, "/dev/spidev3.0", + RwDefinitions::MAX_REPLY_SIZE, spi::RW_MODE, spi::RW_SPEED, &rwSpiCallback::spiCallback, + nullptr); + auto rw2SpiCookie = new SpiCookie(addresses::RW2, gpioIds::CS_RW2, "/dev/spidev3.0", + RwDefinitions::MAX_REPLY_SIZE, spi::RW_MODE, spi::RW_SPEED, &rwSpiCallback::spiCallback, + nullptr); + auto rw3SpiCookie = new SpiCookie(addresses::RW3, gpioIds::CS_RW3, "/dev/spidev3.0", + RwDefinitions::MAX_REPLY_SIZE, spi::RW_MODE, spi::RW_SPEED, &rwSpiCallback::spiCallback, + nullptr); + auto rw4SpiCookie = new SpiCookie(addresses::RW4, gpioIds::CS_RW4, "/dev/spidev3.0", + RwDefinitions::MAX_REPLY_SIZE, spi::RW_MODE, spi::RW_SPEED, &rwSpiCallback::spiCallback, + nullptr); auto rwHandler1 = new RwHandler(objects::RW1, objects::SPI_COM_IF, rw1SpiCookie, gpioComIF, gpioIds::EN_RW1); diff --git a/bsp_q7s/spi/Q7sSpiComIF.cpp b/bsp_q7s/spi/Q7sSpiComIF.cpp new file mode 100644 index 00000000..23dbe551 --- /dev/null +++ b/bsp_q7s/spi/Q7sSpiComIF.cpp @@ -0,0 +1,9 @@ +#include + +Q7sSpiComIF::Q7sSpiComIF(object_id_t objectId, GpioIF* gpioComIF) : + SpiComIF(objectId, gpioComIF) { +} + +Q7sSpiComIF::~Q7sSpiComIF() { +} + diff --git a/bsp_q7s/spi/Q7sSpiComIF.h b/bsp_q7s/spi/Q7sSpiComIF.h new file mode 100644 index 00000000..a10d63dd --- /dev/null +++ b/bsp_q7s/spi/Q7sSpiComIF.h @@ -0,0 +1,33 @@ +#ifndef BSP_Q7S_SPI_Q7SSPICOMIF_H_ +#define BSP_Q7S_SPI_Q7SSPICOMIF_H_ + +#include + + +/** + * @brief This additional communication interface is required because the SPI busses behind the + * devices "/dev/spi2.0" and "dev/spidev3.0" are multiplexed to one SPI interface. + * This was necessary because the processing system spi (/dev/spi2.0) does not support + * frequencies lower than 650 kHz. To reach lower frequencies also the CPU frequency must + * be reduced which leads to other effects compromising kernel drivers. + * The nano avionics reaction wheels require a spi frequency between 150 kHz and 300 kHz + * why an additional AXI SPI core has been implemented in the programmable logic. However, + * the spi frequency of the AXI SPI core is not configurable during runtime. Therefore, + * this communication interface multiplexes either the hard-wired SPI or the AXI SPI to + * the SPI interface. The multiplexing is performed via a GPIO connected to a VHDL + * module responsible for switching between the to SPI peripherals. + */ +class Q7sSpiComIF: public SpiComIF { +public: + /** + * @brief Constructor + * + * @param objectId + * @param gpioComIF + * @param gpioSwitchId The gpio ID of the GPIO connected to the SPI mux module in the PL. + */ + Q7sSpiComIF(object_id_t objectId, GpioIF* gpioComIF, gpioId_t gpioSwitchId); + virtual ~Q7sSpiComIF(); +}; + +#endif /* BSP_Q7S_SPI_Q7SSPICOMIF_H_ */ diff --git a/bsp_q7s/spiCallbacks/rwSpiCallback.cpp b/bsp_q7s/spiCallbacks/rwSpiCallback.cpp index bfb1892c..f05fbbdf 100644 --- a/bsp_q7s/spiCallbacks/rwSpiCallback.cpp +++ b/bsp_q7s/spiCallbacks/rwSpiCallback.cpp @@ -3,15 +3,18 @@ #include #include #include +#include "devices/gpioIds.h" -ReturnValue_t rwSpiCallback(SpiComIF* comIf, SpiCookie *cookie, const uint8_t *sendData, +namespace rwSpiCallback { + +ReturnValue_t spiCallback(SpiComIF* comIf, SpiCookie *cookie, const uint8_t *sendData, size_t sendLen, void* args) { ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; RwHandler* handler = reinterpret_cast(args); if(handler == nullptr) { - sif::error << "rwSpiCallback: Pointer to handler is invalid" + sif::error << "rwSpiCallback::spiCallback: Pointer to handler is invalid" << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } @@ -21,9 +24,9 @@ ReturnValue_t rwSpiCallback(SpiComIF* comIf, SpiCookie *cookie, const uint8_t *s int fileDescriptor = 0; std::string device = cookie->getSpiDevice(); - UnixFileGuard fileHelper(device, &fileDescriptor, O_RDWR, "rwSpiCallback: "); + UnixFileGuard fileHelper(device, &fileDescriptor, O_RDWR, "rwSpiCallback::spiCallback: "); if(fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) { - sif::error << "rwSpiCallback: Failed to open device file" << std::endl; + sif::error << "rwSpiCallback::spiCallback: Failed to open device file" << std::endl; return SpiComIF::OPENING_FILE_FAILED; } spi::SpiModes spiMode = spi::SpiModes::MODE_0; @@ -37,16 +40,19 @@ ReturnValue_t rwSpiCallback(SpiComIF* comIf, SpiCookie *cookie, const uint8_t *s uint32_t timeoutMs = 0; MutexIF* mutex = comIf->getMutex(&timeoutType, &timeoutMs); if(mutex == nullptr or gpioIF == nullptr) { - sif::debug << "rwSpiCallback: Mutex or GPIO interface invalid" << std::endl; + sif::debug << "rwSpiCallback::spiCallback: Mutex or GPIO interface invalid" << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } - if(gpioId != gpio::NO_GPIO) { - result = mutex->lockMutex(timeoutType, timeoutMs); - if (result != HasReturnvaluesIF::RETURN_OK) { - sif::debug << "rwSpiCallback: Failed to lock mutex" << std::endl; - return result; - } + result = mutex->lockMutex(timeoutType, timeoutMs); + if (result != HasReturnvaluesIF::RETURN_OK) { + sif::debug << "rwSpiCallback::spiCallback: Failed to lock mutex" << std::endl; + return result; + } + + /** Disconnect PS SPI peripheral and select AXI SPI core */ + if(gpioIF->pullHigh(gpioIds::SPI_MUX) != HasReturnvaluesIF::RETURN_OK) { + sif::error << "rwSpiCallback::spiCallback: Failed to pull spi mux gpio high" << std::endl; } /** Sending frame start sign */ @@ -56,12 +62,12 @@ ReturnValue_t rwSpiCallback(SpiComIF* comIf, SpiCookie *cookie, const uint8_t *s // Pull SPI CS low. For now, no support for active high given if(gpioId != gpio::NO_GPIO) { if(gpioIF->pullLow(gpioId) != HasReturnvaluesIF::RETURN_OK) { - sif::error << "rwSpiCallback: Failed to pull chip select low" << std::endl; + sif::error << "rwSpiCallback::spiCallback: Failed to pull chip select low" << std::endl; } } if (write(fileDescriptor, writeBuffer, writeSize) != static_cast(writeSize)) { - sif::error << "rwSpiCallback: Write failed!" << std::endl; + sif::error << "rwSpiCallback::spiCallback: Write failed!" << std::endl; closeSpi(gpioId, gpioIF, mutex); return RwHandler::SPI_WRITE_FAILURE; } @@ -86,7 +92,7 @@ ReturnValue_t rwSpiCallback(SpiComIF* comIf, SpiCookie *cookie, const uint8_t *s break; } if (write(fileDescriptor, writeBuffer, writeSize) != static_cast(writeSize)) { - sif::error << "rwSpiCallback: Write failed!" << std::endl; + sif::error << "rwSpiCallback::spiCallback: Write failed!" << std::endl; closeSpi(gpioId, gpioIF, mutex); return RwHandler::SPI_WRITE_FAILURE; } @@ -98,7 +104,7 @@ ReturnValue_t rwSpiCallback(SpiComIF* comIf, SpiCookie *cookie, const uint8_t *s writeSize = 1; if (write(fileDescriptor, writeBuffer, writeSize) != static_cast(writeSize)) { - sif::error << "rwSpiCallback: Write failed!" << std::endl; + sif::error << "rwSpiCallback::spiCallback: Write failed!" << std::endl; closeSpi(gpioId, gpioIF, mutex); return RwHandler::SPI_WRITE_FAILURE; } @@ -122,7 +128,7 @@ ReturnValue_t rwSpiCallback(SpiComIF* comIf, SpiCookie *cookie, const uint8_t *s uint8_t byteRead = 0; for (int idx = 0; idx < 10; idx++) { if(read(fileDescriptor, &byteRead, 1) != 1) { - sif::error << "rwSpiCallback: Read failed" << std::endl; + sif::error << "rwSpiCallback::spiCallback: Read failed" << std::endl; closeSpi(gpioId, gpioIF, mutex); return RwHandler::SPI_READ_FAILURE; } @@ -132,7 +138,7 @@ ReturnValue_t rwSpiCallback(SpiComIF* comIf, SpiCookie *cookie, const uint8_t *s } if (idx == 9) { - sif::error << "rwSpiCallback: Empty frame timeout" << std::endl; + sif::error << "rwSpiCallback::spiCallback: Empty frame timeout" << std::endl; closeSpi(gpioId, gpioIF, mutex); return RwHandler::NO_REPLY; } @@ -145,7 +151,7 @@ ReturnValue_t rwSpiCallback(SpiComIF* comIf, SpiCookie *cookie, const uint8_t *s if (decodedFrameLen != 0) { byteRead = 0; if(read(fileDescriptor, &byteRead, 1) != 1) { - sif::error << "rwSpiCallback: Read failed" << std::endl; + sif::error << "rwSpiCallback::spiCallback: Read failed" << std::endl; result = RwHandler::SPI_READ_FAILURE; break; } @@ -157,7 +163,7 @@ ReturnValue_t rwSpiCallback(SpiComIF* comIf, SpiCookie *cookie, const uint8_t *s } else if (byteRead == 0x7D) { if(read(fileDescriptor, &byteRead, 1) != 1) { - sif::error << "rwSpiCallback: Read failed" << std::endl; + sif::error << "rwSpiCallback::spiCallback: Read failed" << std::endl; result = RwHandler::SPI_READ_FAILURE; break; } @@ -172,7 +178,7 @@ ReturnValue_t rwSpiCallback(SpiComIF* comIf, SpiCookie *cookie, const uint8_t *s continue; } else { - sif::error << "rwSpiCallback: Invalid substitute" << std::endl; + sif::error << "rwSpiCallback::spiCallback: Invalid substitute" << std::endl; closeSpi(gpioId, gpioIF, mutex); result = RwHandler::INVALID_SUBSTITUTE; break; @@ -191,12 +197,12 @@ ReturnValue_t rwSpiCallback(SpiComIF* comIf, SpiCookie *cookie, const uint8_t *s */ if (decodedFrameLen == replyBufferSize) { if(read(fileDescriptor, &byteRead, 1) != 1) { - sif::error << "rwSpiCallback: Failed to read last byte" << std::endl; + sif::error << "rwSpiCallback::spiCallback: Failed to read last byte" << std::endl; result = RwHandler::SPI_READ_FAILURE; break; } if (byteRead != 0x7E) { - sif::error << "rwSpiCallback: Missing end sign 0x7E" << std::endl; + sif::error << "rwSpiCallback::spiCallback: Missing end sign 0x7E" << std::endl; decodedFrameLen--; result = RwHandler::MISSING_END_SIGN; break; @@ -219,6 +225,12 @@ void closeSpi (gpioId_t gpioId, GpioIF* gpioIF, MutexIF* mutex) { } } if(mutex->unlockMutex() != HasReturnvaluesIF::RETURN_OK) { - sif::error << "closeSpi: Failed to unlock mutex" << std::endl;; + sif::error << "rwSpiCallback::closeSpi: Failed to unlock mutex" << std::endl;; + } + + /** Route SPI interface again to PS SPI peripheral */ + if(gpioIF->pullLow(gpioIds::SPI_MUX) != HasReturnvaluesIF::RETURN_OK) { + sif::error << "rwSpiCallback::spiCallback: Failed to pull spi mux gpio low" << std::endl; } } +} diff --git a/bsp_q7s/spiCallbacks/rwSpiCallback.h b/bsp_q7s/spiCallbacks/rwSpiCallback.h index e684c1c1..e5a79e64 100644 --- a/bsp_q7s/spiCallbacks/rwSpiCallback.h +++ b/bsp_q7s/spiCallbacks/rwSpiCallback.h @@ -3,6 +3,10 @@ #include #include +#include + + +namespace rwSpiCallback { /** * @brief This is the callback function to send commands to the nano avionics reaction wheels and @@ -14,8 +18,17 @@ * Arbeitsdaten/08_Used%20Components/Nanoavionics_Reactionwheels&fileid=181622 * Each command entails exactly one reply which will also be read in and decoded by this * function. + * Because the reaction wheels require a spi clock frequency of maximum 300 kHZ and minimum + * 150 kHz which is not supported by the processing system SPI peripheral an AXI SPI core + * has been implemented in the programmable logic. This AXI SPI core works with a fixed + * frequency of 250 kHz. + * To allow the parallel usage of the same physical SPI bus, a VHDL module has been + * implemented which is able to disconnect the hard-wired SPI peripheral of the PS and + * route the AXI SPI to the SPI lines. + * To switch between the to SPI peripherals, an EMIO is used which will also be controlled + * by this function. */ -ReturnValue_t rwSpiCallback(SpiComIF* comIf, SpiCookie *cookie, const uint8_t *sendData, +ReturnValue_t spiCallback(SpiComIF* comIf, SpiCookie *cookie, const uint8_t *sendData, size_t sendLen, void* args); /** @@ -27,4 +40,5 @@ ReturnValue_t rwSpiCallback(SpiComIF* comIf, SpiCookie *cookie, const uint8_t *s */ void closeSpi(gpioId_t gpioId, GpioIF* gpioIF, MutexIF* mutex); +} #endif /* BSP_Q7S_RW_SPI_CALLBACK_H_ */ diff --git a/linux/fsfwconfig/devices/gpioIds.h b/linux/fsfwconfig/devices/gpioIds.h index 718bc9bf..aad06629 100644 --- a/linux/fsfwconfig/devices/gpioIds.h +++ b/linux/fsfwconfig/devices/gpioIds.h @@ -80,7 +80,9 @@ namespace gpioIds { CS_RW3, CS_RW4, - EN_RW_CS + EN_RW_CS, + + SPI_MUX }; }