From 41b6e6501a7dc5b190608b45a1a626ea90afb0bd Mon Sep 17 00:00:00 2001 From: Federico Terraneo <fede.tft@miosix.org> Date: Sun, 30 Apr 2017 16:36:38 +0200 Subject: [PATCH] Set the SPI1 frequency considering the sensor requirements, added comments about CS timings, fixed bug in BusTemplate not disabling interrupts when it should --- src/shared/BusTemplate.h | 27 ++++++++++++++++++++------- src/shared/DMA/DMA.cpp | 39 +++++++++++++++++++++++++++++---------- 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/src/shared/BusTemplate.h b/src/shared/BusTemplate.h index 482c8812e..47e6df14a 100644 --- a/src/shared/BusTemplate.h +++ b/src/shared/BusTemplate.h @@ -91,6 +91,8 @@ private: } BusSPI() { + //FIXME: this code is duplicated here and in the DMA driver, + //and both of them initialize SPI1 GpioMosi::mode(Mode::ALTERNATE); GpioMosi::alternateFunction(GetAlternativeFunctionNumber(N)); GpioMiso::mode(Mode::ALTERNATE); @@ -99,13 +101,21 @@ private: GpioSclk::alternateFunction(GetAlternativeFunctionNumber(N)); usleep(CS_DELAY); enableSPIBus(getSPIAddr(N)); - getSPIAddr(N)->CR1 = SPI_CR1_SSM - | SPI_CR1_SSI - | SPI_CR1_MSTR - // | SPI_CR1_BR_0 - // | SPI_CR1_BR_1 - | SPI_CR1_BR_2 - | SPI_CR1_SPE; + if(getSPIAddr(N) == SPI1) + { + getSPIAddr(N)->CR1 = SPI_CR1_SSM //Software cs + | SPI_CR1_SSI //Hardware cs internally tied high + | SPI_CR1_MSTR //Master mode + | SPI_CR1_BR_1 + | SPI_CR1_BR_2 // SPI FREQ=90MHz / 128 = 703KHz + | SPI_CR1_SPE; //SPI enabled + } else { + getSPIAddr(N)->CR1 = SPI_CR1_SSM //Software cs + | SPI_CR1_SSI //Hardware cs internally tied high + | SPI_CR1_MSTR //Master mode + | SPI_CR1_BR_2 // SPI clock divided by 32 + | SPI_CR1_SPE; //SPI enabled + } } inline static constexpr int GetAlternativeFunctionNumber(int n_spi) { @@ -118,6 +128,9 @@ private: } static inline void enableSPIBus(SPI_TypeDef* spi) { + //Interrupts are disabled to prevent bugs if more than one threads does + //a read-modify-write to RCC registers at the same time + FastInterruptDisableLock dLock; if(spi == SPI1) RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; else if(spi == SPI2) diff --git a/src/shared/DMA/DMA.cpp b/src/shared/DMA/DMA.cpp index 7e53eab19..2f14f41d1 100644 --- a/src/shared/DMA/DMA.cpp +++ b/src/shared/DMA/DMA.cpp @@ -31,6 +31,11 @@ typedef Gpio<GPIOA_BASE,5> sck; typedef Gpio<GPIOA_BASE,6> miso; typedef Gpio<GPIOA_BASE,7> mosi; +static Thread *waiting = nullptr; +static vector<SPIRequest> *requestVector = nullptr; +static size_t requestIndex = 0; +static bool error = false; + /** * DMA RX end of transfer */ @@ -41,11 +46,6 @@ void __attribute__((naked)) DMA2_Stream0_IRQHandler() restoreContext(); } -static Thread *waiting = nullptr; -static vector<SPIRequest> *requestVector = nullptr; -static size_t requestIndex = 0; -static bool error = false; - /** * DMA RX end of transfer actual implementation */ @@ -55,6 +55,7 @@ void __attribute__((used)) SPI1rxDmaHandlerImpl() error = true; if(DMA2->HISR & (DMA_HISR_TEIF5 | DMA_HISR_DMEIF5)) error = true; + DMA2->LIFCR = DMA_LIFCR_CTCIF0 | DMA_LIFCR_CTEIF0 | DMA_LIFCR_CDMEIF0; @@ -131,6 +132,8 @@ SPIDriver::SPIDriver() { pthread_mutex_init(&mutex,0); { + //Interrupts are disabled to prevent bugs if more than one threads does + //a read-modify-write to RCC or GPIO->MODER registers at the same time FastInterruptDisableLock dLock; mosi::mode(Mode::ALTERNATE); mosi::alternateFunction(5); @@ -141,14 +144,24 @@ SPIDriver::SPIDriver() RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN; RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; + + /* + * Table of the maximum speed of each sensor, used to set SPI speed + * LSM9DS0 IMU SPI <10MHz + * MPU9250 IMU SPI < 1MHz + * MAX21105 IMU SPI <10MHz + * FXAS21002 gyro SPI < 2MHz + * MS5803 baro SPI <20MHz + * LPS331 baro SPI FIXME: unknown! + * MAX31856 thermocouple SPI < 5MHz + */ disableDMA(); SPI1->CR1 = SPI_CR1_SSM //Software cs | SPI_CR1_SSI //Hardware cs internally tied high | SPI_CR1_MSTR //Master mode -// | SPI_CR1_BR_0 -// | SPI_CR1_BR_1 //Less than 10MHz - | SPI_CR1_BR_2 // fClock / 32 + | SPI_CR1_BR_1 + | SPI_CR1_BR_2 // SPI FREQ=90MHz / 128 = 703KHz | SPI_CR1_SPE; //SPI enabled NVIC_SetPriority(DMA2_Stream0_IRQn,10);//Low priority for DMA NVIC_EnableIRQ(DMA2_Stream0_IRQn); @@ -190,11 +203,17 @@ void SPIRequest::IRQbeginTransaction() | DMA_SxCR_TEIE //Interrupt on transfer error | DMA_SxCR_DMEIE //Interrupt on direct mode error | DMA_SxCR_EN; //Start DMA - // FIXME: handle DMA_SxCR_TEIE } void SPIRequest::IRQendTransaction() { chipSelect.high(); - delayUs(10); //FIXME: properly size the delay + /* + * NOTE: this code has no explicit delays and relies on the code execution + * timings to add the requred minimum delays between data CS toggling. + * When running at 180MHz with data in external RAM, the delay are as follow + * From last clock pulse till CS high : ~1.5us + * From CS high to CS low : ~2 us + * From CS low to first clock pulse : ~3.5us + */ } -- GitLab