Skip to content

Instantly share code, notes, and snippets.

@salkinium
Created February 5, 2016 00:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save salkinium/3624a2c4ff73b2ec6892 to your computer and use it in GitHub Desktop.
Save salkinium/3624a2c4ff73b2ec6892 to your computer and use it in GitHub Desktop.
/* 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