Skip to content
Snippets Groups Projects
Commit 486fcc69 authored by Alberto Nidasio's avatar Alberto Nidasio
Browse files

[SPI] Implemented computeDivider function and removed constructor to SPIBusConfig

parent 55083e36
No related branches found
No related tags found
No related merge requests found
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <interfaces-impl/gpio_impl.h> #include <interfaces-impl/gpio_impl.h>
#include <stddef.h> #include <stddef.h>
#include <utils/ClockUtils.h>
#include "SPIDefs.h" #include "SPIDefs.h"
...@@ -45,13 +46,13 @@ namespace Boardcore ...@@ -45,13 +46,13 @@ namespace Boardcore
struct SPIBusConfig struct SPIBusConfig
{ {
///< Peripheral clock division ///< Peripheral clock division
SPI::ClockDivider clockDivider; SPI::ClockDivider clockDivider = SPI::ClockDivider::DIV_256;
///< Clock polarity and phase configuration ///< Clock polarity and phase configuration
SPI::Mode mode; SPI::Mode mode = SPI::Mode::MODE_0;
///< MSBit or LSBit first ///< MSBit or LSBit first
SPI::Order bitOrder; SPI::Order bitOrder = SPI::Order::MSB_FIRST;
/** /**
* @brief MSByte or LSByte first * @brief MSByte or LSByte first
...@@ -74,28 +75,16 @@ struct SPIBusConfig ...@@ -74,28 +75,16 @@ struct SPIBusConfig
* @warning This driver does not support devices which decrements registers * @warning This driver does not support devices which decrements registers
* address during multiple registers accesses. * address during multiple registers accesses.
*/ */
SPI::Order byteOrder; SPI::Order byteOrder = SPI::Order::MSB_FIRST;
///< Write bit behaviour, default high when reading ///< Write bit behaviour, default high when reading
SPI::WriteBit writeBit; SPI::WriteBit writeBit = SPI::WriteBit::NORMAL;
///< How long to wait before starting a tranmission after CS is set (us) ///< How long to wait before starting a tranmission after CS is set (us)
unsigned int csSetupTimeUs; unsigned int csSetupTimeUs = 0;
///< How long to hold cs after the end of a tranmission (us) ///< How long to hold cs after the end of a tranmission (us)
unsigned int csHoldTimeUs; unsigned int csHoldTimeUs = 0;
SPIBusConfig(SPI::ClockDivider clockDivider = SPI::ClockDivider::DIV_256,
SPI::Mode mode = SPI::Mode::MODE_0,
SPI::Order bitOrder = SPI::Order::MSB_FIRST,
SPI::Order byteOrder = SPI::Order::MSB_FIRST,
SPI::WriteBit writeBit = SPI::WriteBit::NORMAL,
unsigned int csSetupTimeUs = 0, unsigned int csHoldTimeUs = 0)
: clockDivider(clockDivider), mode(mode), bitOrder(bitOrder),
byteOrder(byteOrder), writeBit(writeBit),
csSetupTimeUs(csSetupTimeUs), csHoldTimeUs(csHoldTimeUs)
{
}
bool operator==(const SPIBusConfig& other) const bool operator==(const SPIBusConfig& other) const
{ {
...@@ -109,6 +98,40 @@ struct SPIBusConfig ...@@ -109,6 +98,40 @@ struct SPIBusConfig
{ {
return !(*this == other); return !(*this == other);
} }
/**
* @brief Computes the clock divider for the provided maximum frequency.
*
* The computed divider has the lowest possible value which generates a
* frequency not higher than the provided one.
* The spi peripheral is needed to get the source clock frequency, which
* depends on which APB bus the spi is connected to.
*/
static SPI::ClockDivider computeDivider(SPI_TypeDef* spi, uint32_t maxFreq)
{
ClockUtils::APB apb;
ClockUtils::getPeripheralBus(spi, apb);
uint32_t sourceFreq = ClockUtils::getAPBPeripheralsClock(apb);
uint32_t idealDivider = sourceFreq / maxFreq;
if (idealDivider <= 2)
return SPI::ClockDivider::DIV_2;
else if (idealDivider <= 4)
return SPI::ClockDivider::DIV_4;
else if (idealDivider <= 8)
return SPI::ClockDivider::DIV_8;
else if (idealDivider <= 16)
return SPI::ClockDivider::DIV_16;
else if (idealDivider <= 32)
return SPI::ClockDivider::DIV_32;
else if (idealDivider <= 64)
return SPI::ClockDivider::DIV_64;
else if (idealDivider <= 128)
return SPI::ClockDivider::DIV_128;
else
return SPI::ClockDivider::DIV_256;
}
}; };
/** /**
......
...@@ -68,6 +68,11 @@ bool enablePeripheralClock(void* peripheral); ...@@ -68,6 +68,11 @@ bool enablePeripheralClock(void* peripheral);
*/ */
bool disablePeripheralClock(void* peripheral); bool disablePeripheralClock(void* peripheral);
/**
* @brief Returns the APB bus to which the peripheral is connected.
*/
bool getPeripheralBus(void* peripheral, APB apb);
} // namespace ClockUtils } // namespace ClockUtils
inline uint32_t ClockUtils::getAPBPeripheralsClock(APB bus) inline uint32_t ClockUtils::getAPBPeripheralsClock(APB bus)
...@@ -912,4 +917,200 @@ inline bool ClockUtils::disablePeripheralClock(void* peripheral) ...@@ -912,4 +917,200 @@ inline bool ClockUtils::disablePeripheralClock(void* peripheral)
return true; return true;
} }
inline bool ClockUtils::getPeripheralBus(void* peripheral, APB apb)
{
switch (reinterpret_cast<uint32_t>(peripheral))
{
// APB1 peripherals
{
#ifdef TIM2_BASE
case TIM2_BASE:
apb = APB::APB1;
#endif
#ifdef TIM3_BASE
case TIM3_BASE:
apb = APB::APB1;
#endif
#ifdef TIM4_BASE
case TIM4_BASE:
apb = APB::APB1;
#endif
#ifdef TIM5_BASE
case TIM5_BASE:
apb = APB::APB1;
#endif
#ifdef TIM6_BASE
case TIM6_BASE:
apb = APB::APB1;
#endif
#ifdef TIM7_BASE
case TIM7_BASE:
apb = APB::APB1;
#endif
#ifdef TIM12_BASE
case TIM12_BASE:
apb = APB::APB1;
#endif
#ifdef TIM13_BASE
case TIM13_BASE:
apb = APB::APB1;
#endif
#ifdef TIM14_BASE
case TIM14_BASE:
apb = APB::APB1;
#endif
// RTC register interface gate only on stm32f7 micro controllers
#if defined(RTC_BASE) && defined(_ARCH_CORTEXM7_STM32F7)
case RTC_BASE:
apb = APB::APB1;
#endif
#ifdef WWDG_BASE
case WWDG_BASE:
apb = APB::APB1;
#endif
#ifdef SPI2_BASE
case SPI2_BASE:
apb = APB::APB1;
#endif
#ifdef SPI3_BASE
case SPI3_BASE:
apb = APB::APB1;
#endif
#ifdef USART2_BASE
case USART2_BASE:
apb = APB::APB1;
#endif
#ifdef USART3_BASE
case USART3_BASE:
apb = APB::APB1;
#endif
#ifdef UART4_BASE
case UART4_BASE:
apb = APB::APB1;
#endif
#ifdef UART5_BASE
case UART5_BASE:
apb = APB::APB1;
#endif
#ifdef I2C1_BASE
case I2C1_BASE:
apb = APB::APB1;
#endif
#ifdef I2C2_BASE
case I2C2_BASE:
apb = APB::APB1;
#endif
#ifdef I2C3_BASE
case I2C3_BASE:
apb = APB::APB1;
#endif
#ifdef CAN1_BASE
case CAN1_BASE:
apb = APB::APB1;
#endif
#ifdef CAN2_BASE
case CAN2_BASE:
apb = APB::APB1;
#endif
#ifdef PWR_BASE
case PWR_BASE:
apb = APB::APB1;
#endif
#ifdef DAC_BASE
case DAC_BASE:
apb = APB::APB1;
#endif
#ifdef UART7_BASE
case UART7_BASE:
apb = APB::APB1;
#endif
#ifdef UART8_BASE
case UART8_BASE:
apb = APB::APB1;
#endif
}
// APB2 peripherals
{
#ifdef TIM1_BASE
case TIM1_BASE:
apb = APB::APB2;
#endif
#ifdef TIM8_BASE
case TIM8_BASE:
apb = APB::APB2;
#endif
#ifdef USART1_BASE
case USART1_BASE:
apb = APB::APB2;
#endif
#ifdef USART6_BASE
case USART6_BASE:
apb = APB::APB2;
#endif
#ifdef ADC1_BASE
case ADC1_BASE:
apb = APB::APB2;
#endif
#ifdef ADC2_BASE
case ADC2_BASE:
apb = APB::APB2;
#endif
#ifdef ADC3_BASE
case ADC3_BASE:
apb = APB::APB2;
#endif
#ifdef SDIO_BASE
case SDIO_BASE:
apb = APB::APB2;
#endif
#ifdef SPI1_BASE
case SPI1_BASE:
apb = APB::APB2;
#endif
#ifdef SPI4_BASE
case SPI4_BASE:
apb = APB::APB2;
#endif
#ifdef SYSCFG_BASE
case SYSCFG_BASE:
apb = APB::APB2;
#endif
#ifdef TIM9_BASE
case TIM9_BASE:
apb = APB::APB2;
#endif
#ifdef TIM10_BASE
case TIM10_BASE:
apb = APB::APB2;
#endif
#ifdef TIM11_BASE
case TIM11_BASE:
apb = APB::APB2;
#endif
#ifdef SPI5_BASE
case SPI5_BASE:
apb = APB::APB2;
#endif
#ifdef SPI6_BASE
case SPI6_BASE:
apb = APB::APB2;
#endif
#ifdef SAI1_BASE
case SAI1_BASE:
apb = APB::APB2;
#endif
#ifdef LTDC_BASE
case LTDC_BASE:
apb = APB::APB2;
#endif
}
default:
return false;
}
return true;
}
} // namespace Boardcore } // namespace Boardcore
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment