-
-
Save salkinium/3624a2c4ff73b2ec6892 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Copyright (c) 2013, Roboterclub Aachen e.V. | |
* All Rights Reserved. | |
* | |
* The file is part of the xpcc library and is released under the 3-clause BSD | |
* license. See the file `LICENSE` for the full license governing this code. | |
* ------------------------------------------------------------------------- */ | |
#ifndef XPCC_STM32_CLOCK_SINKS_HPP | |
#define XPCC_STM32_CLOCK_SINKS_HPP | |
#include <stdint.h> // uint32_t | |
#include "../../../device.hpp" | |
#include "../../../type_ids.hpp" | |
#include "../generic/common_clock.hpp" | |
using namespace xpcc::clock; | |
namespace xpcc | |
{ | |
namespace stm32 | |
{ | |
enum class | |
AhbPrescaler : uint8_t | |
{ | |
Div1 = 0, | |
Div2 = 1, | |
Div4 = 2, | |
Div8 = 3, | |
Div16 = 4, | |
Div64 = 5, | |
Div128 = 6, | |
Div256 = 7, | |
Div512 = 8, | |
}; | |
enum class | |
Apb1Prescaler : uint8_t | |
{ | |
Div1 = 0, | |
Div2 = 1, | |
Div4 = 2, | |
Div8 = 3, | |
Div16 = 4, | |
}; | |
enum class | |
Apb2Prescaler : uint8_t | |
{ | |
Div1 = 0, | |
Div2 = 1, | |
Div4 = 2, | |
Div8 = 3, | |
Div16 = 4, | |
}; | |
/// @cond | |
namespace detail | |
{ | |
// divisor constants for Ahb, must be sorted by < | |
static constexpr uint16_t SystemClockAhbDivisorCount = 9; | |
static constexpr uint16_t SystemClockAhbDivisors[SystemClockAhbDivisorCount] = { 1, 2, 4, 8, 16, 64, 128, 256, 512 }; | |
// divisor constants for Apb1, must be sorted by < | |
static constexpr uint16_t SystemClockApb1DivisorCount = 5; | |
static constexpr uint16_t SystemClockApb1Divisors[SystemClockApb1DivisorCount] = { 1, 2, 4, 8, 16 }; | |
// divisor constants for Apb2, must be sorted by < | |
static constexpr uint16_t SystemClockApb2DivisorCount = 5; | |
static constexpr uint16_t SystemClockApb2Divisors[SystemClockApb2DivisorCount] = { 1, 2, 4, 8, 16 }; | |
static constexpr uint16_t SystemClockApb1TimerMultipliers[SystemClockApb1DivisorCount] = { 1, 2, 2, 2, 2 }; | |
static constexpr uint16_t SystemClockApb2TimerMultipliers[SystemClockApb2DivisorCount] = { 1, 2, 2, 2, 2 }; | |
} // namespace detail | |
/// @endcond | |
template< class Input, AhbPrescaler AhbDivisor = AhbPrescaler(0), Apb1Prescaler Apb1Divisor = Apb1Prescaler(0), Apb2Prescaler Apb2Divisor = Apb2Prescaler(0) > | |
class | |
SystemClock | |
{ | |
static_assert( | |
(Input::Name == ClockName::InternalClock) or | |
(Input::Name == ClockName::ExternalClock) or | |
(Input::Name == ClockName::ExternalCrystal) or | |
(Input::Name == ClockName::Pll), | |
"The clock source is not a valid selection for SystemClock!"); | |
public: | |
static constexpr ClockControl::SystemClockSource | |
Source = ( | |
( Input::Name == ClockName::InternalClock )? ClockControl::SystemClockSource::InternalClock :( | |
( Input::Name == ClockName::ExternalClock )? ClockControl::SystemClockSource::ExternalClock :( | |
( Input::Name == ClockName::ExternalCrystal )? ClockControl::SystemClockSource::ExternalCrystal :( | |
ClockControl::SystemClockSource::Pll )))); | |
static constexpr uint16_t | |
getAhbDivisor() | |
{ | |
return detail::SystemClockAhbDivisors[int(AhbDivisor)]; | |
} | |
static constexpr ClockControl::AhbPrescaler | |
getAhbPrescaler() | |
{ | |
return ( | |
( AhbDivisor == AhbPrescaler::Div1 )? ClockControl::AhbPrescaler::Div1 :( | |
( AhbDivisor == AhbPrescaler::Div2 )? ClockControl::AhbPrescaler::Div2 :( | |
( AhbDivisor == AhbPrescaler::Div4 )? ClockControl::AhbPrescaler::Div4 :( | |
( AhbDivisor == AhbPrescaler::Div8 )? ClockControl::AhbPrescaler::Div8 :( | |
( AhbDivisor == AhbPrescaler::Div16 )? ClockControl::AhbPrescaler::Div16 :( | |
( AhbDivisor == AhbPrescaler::Div64 )? ClockControl::AhbPrescaler::Div64 :( | |
( AhbDivisor == AhbPrescaler::Div128 )? ClockControl::AhbPrescaler::Div128 :( | |
( AhbDivisor == AhbPrescaler::Div256 )? ClockControl::AhbPrescaler::Div256 :( | |
ClockControl::AhbPrescaler::Div512 ))))))))); | |
} | |
static constexpr uint16_t | |
getApb1Divisor() | |
{ | |
return detail::SystemClockApb1Divisors[int(Apb1Divisor)]; | |
} | |
static constexpr ClockControl::Apb1Prescaler | |
getApb1Prescaler() | |
{ | |
return ( | |
( Apb1Divisor == Apb1Prescaler::Div1 )? ClockControl::Apb1Prescaler::Div1 :( | |
( Apb1Divisor == Apb1Prescaler::Div2 )? ClockControl::Apb1Prescaler::Div2 :( | |
( Apb1Divisor == Apb1Prescaler::Div4 )? ClockControl::Apb1Prescaler::Div4 :( | |
( Apb1Divisor == Apb1Prescaler::Div8 )? ClockControl::Apb1Prescaler::Div8 :( | |
ClockControl::Apb1Prescaler::Div16 ))))); | |
} | |
static constexpr uint16_t | |
getApb2Divisor() | |
{ | |
return detail::SystemClockApb2Divisors[int(Apb2Divisor)]; | |
} | |
static constexpr ClockControl::Apb2Prescaler | |
getApb2Prescaler() | |
{ | |
return ( | |
( Apb2Divisor == Apb2Prescaler::Div1 )? ClockControl::Apb2Prescaler::Div1 :( | |
( Apb2Divisor == Apb2Prescaler::Div2 )? ClockControl::Apb2Prescaler::Div2 :( | |
( Apb2Divisor == Apb2Prescaler::Div4 )? ClockControl::Apb2Prescaler::Div4 :( | |
( Apb2Divisor == Apb2Prescaler::Div8 )? ClockControl::Apb2Prescaler::Div8 :( | |
ClockControl::Apb2Prescaler::Div16 ))))); | |
} | |
static constexpr uint16_t | |
getApb1TimerMultiplier() | |
{ | |
return detail::SystemClockApb1TimerMultipliers[int(Apb1Divisor)]; | |
} | |
static constexpr uint16_t | |
getApb2TimerMultiplier() | |
{ | |
return detail::SystemClockApb2TimerMultipliers[int(Apb2Divisor)]; | |
} | |
public: | |
static const TypeId::SystemClock Id; | |
static constexpr ClockName Name = ClockName::SystemClock; | |
static constexpr uint32_t InputFrequency = Input::OutputFrequency; | |
static constexpr uint32_t OutputFrequency = InputFrequency; | |
static StartupError | |
enable(const uint32_t waitCycles = 2048) | |
{ | |
// enable input | |
StartupError err = Input::enable(waitCycles); | |
// quit if failed | |
if (err != StartupError::None) return err; | |
if (not ClockControl::enableSystemClock( Source )) | |
return StartupError::SystemClock; | |
if (not ClockControl::setAhbPrescaler(getAhbPrescaler())) | |
return StartupError::SystemClock; | |
if (not ClockControl::setApb1Prescaler(getApb1Prescaler())) | |
return StartupError::SystemClock; | |
if (not ClockControl::setApb2Prescaler(getApb2Prescaler())) | |
return StartupError::SystemClock; | |
// copy the generated system clock frequency into the run-time variables for the delay functions | |
xpcc::clock::fcpu = Fclk; | |
xpcc::clock::fcpu_kHz = Fclk / 1000; | |
xpcc::clock::fcpu_MHz = Fclk / 1000000; | |
xpcc::clock::ns_per_loop = std::round(1000000000.f / Fclk * 3.f); | |
return StartupError::None; | |
} | |
public: | |
// sink outputs | |
static constexpr uint32_t Ahb = OutputFrequency / getAhbDivisor(); | |
static_assert((Ahb <= 72000000), | |
"The input frequency of Ahb needs to be less or equal to 72000000!"); | |
static constexpr uint32_t Hclk = Ahb; | |
static constexpr uint32_t SystemTimer = Ahb; | |
static constexpr uint32_t Fclk = Ahb; | |
static constexpr uint32_t Fcpu = Fclk; | |
static constexpr uint32_t Apb1 = Ahb / getApb1Divisor(); | |
static_assert((Apb1 <= 36000000), | |
"The input frequency of Apb1 needs to be less or equal to 36000000!"); | |
static constexpr uint32_t Usart2 = Apb1; | |
static constexpr uint32_t Usart3 = Apb1; | |
static constexpr uint32_t Uart4 = Apb1; | |
static constexpr uint32_t Uart5 = Apb1; | |
static constexpr uint32_t Spi2 = Apb1; | |
static constexpr uint32_t Spi3 = Apb1; | |
static constexpr uint32_t I2c1 = Apb1; | |
static constexpr uint32_t I2c2 = Apb1; | |
static constexpr uint32_t Apb1Timer = Apb1 * getApb1TimerMultiplier(); | |
static constexpr uint32_t Timer2 = Apb1Timer; | |
static constexpr uint32_t Timer3 = Apb1Timer; | |
static constexpr uint32_t Timer4 = Apb1Timer; | |
static constexpr uint32_t Timer5 = Apb1Timer; | |
static constexpr uint32_t Timer6 = Apb1Timer; | |
static constexpr uint32_t Timer7 = Apb1Timer; | |
static constexpr uint32_t Timer12 = Apb1Timer; | |
static constexpr uint32_t Timer13 = Apb1Timer; | |
static constexpr uint32_t Timer14 = Apb1Timer; | |
static constexpr uint32_t Apb2 = Ahb / getApb2Divisor(); | |
static_assert((Apb2 <= 72000000), | |
"The input frequency of Apb2 needs to be less or equal to 72000000!"); | |
static constexpr uint32_t Usart1 = Apb2; | |
static constexpr uint32_t Spi1 = Apb2; | |
static constexpr uint32_t Adc1 = Apb2; | |
static constexpr uint32_t Apb2Timer = Apb2 * getApb2TimerMultiplier(); | |
static constexpr uint32_t Timer1 = Apb2Timer; | |
static constexpr uint32_t Timer8 = Apb2Timer; | |
static constexpr uint32_t Timer9 = Apb2Timer; | |
static constexpr uint32_t Timer10 = Apb2Timer; | |
static constexpr uint32_t Timer11 = Apb2Timer; | |
static constexpr uint32_t Timer15 = Apb2Timer; | |
static constexpr uint32_t Timer16 = Apb2Timer; | |
static constexpr uint32_t Timer17 = Apb2Timer; | |
private: | |
// frequency constraints | |
static_assert((OutputFrequency <= 72000000), | |
"The output frequency of SystemClock needs to be less or equal to 72000000!"); | |
}; | |
template< class Input > | |
class | |
RealTimeClock | |
{ | |
static_assert( | |
(Input::Name == ClockName::ExternalClock) or | |
(Input::Name == ClockName::ExternalCrystal) or | |
(Input::Name == ClockName::LowSpeedExternalClock) or | |
(Input::Name == ClockName::LowSpeedExternalCrystal) or | |
(Input::Name == ClockName::LowSpeedInternalClock), | |
"The clock source is not a valid selection for RealTimeClock!"); | |
public: | |
static constexpr ClockControl::RealTimeClockSource | |
Source = ( | |
( Input::Name == ClockName::ExternalClock )? ClockControl::RealTimeClockSource::ExternalClock :( | |
( Input::Name == ClockName::ExternalCrystal )? ClockControl::RealTimeClockSource::ExternalCrystal :( | |
( Input::Name == ClockName::LowSpeedExternalClock )? ClockControl::RealTimeClockSource::LowSpeedExternalClock :( | |
( Input::Name == ClockName::LowSpeedExternalCrystal )? ClockControl::RealTimeClockSource::LowSpeedExternalCrystal :( | |
ClockControl::RealTimeClockSource::LowSpeedInternalClock ))))); | |
public: | |
static const TypeId::RealTimeClock Id; | |
static constexpr ClockName Name = ClockName::RealTimeClock; | |
static constexpr uint32_t InputFrequency = Input::OutputFrequency; | |
static constexpr uint32_t OutputFrequency = InputFrequency / ( | |
( Input::Name == ClockName::ExternalClock )? 128 :( | |
128 )); | |
static StartupError | |
enable(const uint32_t waitCycles = 2048) | |
{ | |
// enable input | |
StartupError err = Input::enable(waitCycles); | |
// quit if failed | |
if (err != StartupError::None) return err; | |
if (not ClockControl::enableRealTimeClock( Source )) | |
return StartupError::RealTimeClock; | |
return StartupError::None; | |
} | |
public: | |
// sink outputs | |
static constexpr uint32_t Rtc = OutputFrequency; | |
private: | |
// frequency constraints | |
}; | |
template< class Input > | |
class | |
WatchdogClock | |
{ | |
static_assert( | |
(Input::Name == ClockName::LowSpeedInternalClock), | |
"The clock source is not a valid selection for WatchdogClock!"); | |
public: | |
static constexpr ClockControl::WatchdogClockSource | |
Source = ( | |
ClockControl::WatchdogClockSource::LowSpeedInternalClock ); | |
public: | |
static const TypeId::WatchdogClock Id; | |
static constexpr ClockName Name = ClockName::WatchdogClock; | |
static constexpr uint32_t InputFrequency = Input::OutputFrequency; | |
static constexpr uint32_t OutputFrequency = InputFrequency; | |
static StartupError | |
enable(const uint32_t waitCycles = 2048) | |
{ | |
// enable input | |
StartupError err = Input::enable(waitCycles); | |
// quit if failed | |
if (err != StartupError::None) return err; | |
if (not ClockControl::enableWatchdogClock( Source )) | |
return StartupError::WatchdogClock; | |
return StartupError::None; | |
} | |
public: | |
// sink outputs | |
static constexpr uint32_t Wwdc = OutputFrequency; | |
private: | |
// frequency constraints | |
}; | |
template< class Input > | |
class | |
ClockOutput | |
{ | |
static_assert( | |
(Input::Name == ClockName::Pll) or | |
(Input::Name == ClockName::SystemClock) or | |
(Input::Name == ClockName::InternalClock) or | |
(Input::Name == ClockName::ExternalClock) or | |
(Input::Name == ClockName::ExternalCrystal), | |
"The clock source is not a valid selection for ClockOutput!"); | |
public: | |
static constexpr ClockControl::ClockOutputSource | |
Source = ( | |
( Input::Name == ClockName::Pll )? ClockControl::ClockOutputSource::Pll :( | |
( Input::Name == ClockName::SystemClock )? ClockControl::ClockOutputSource::SystemClock :( | |
( Input::Name == ClockName::InternalClock )? ClockControl::ClockOutputSource::InternalClock :( | |
( Input::Name == ClockName::ExternalClock )? ClockControl::ClockOutputSource::ExternalClock :( | |
ClockControl::ClockOutputSource::ExternalCrystal ))))); | |
public: | |
static const TypeId::ClockOutput Id; | |
static constexpr ClockName Name = ClockName::ClockOutput; | |
static constexpr uint32_t InputFrequency = Input::OutputFrequency; | |
static constexpr uint32_t OutputFrequency = InputFrequency / ( | |
2 ); | |
static StartupError | |
enable(const uint32_t waitCycles = 2048) | |
{ | |
// enable input | |
StartupError err = Input::enable(waitCycles); | |
// quit if failed | |
if (err != StartupError::None) return err; | |
if (not ClockControl::enableClockOutput( Source )) | |
return StartupError::ClockOutput; | |
return StartupError::None; | |
} | |
public: | |
// sink outputs | |
private: | |
// frequency constraints | |
}; | |
} // namespace stm32 | |
} // namespace xpcc | |
#endif // XPCC_STM32_CLOCK_SINKS_HPP |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment