Skip to content

Instantly share code, notes, and snippets.

@salkinium
Created February 5, 2016 01:22
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/7113bb72c1f33ee6677d to your computer and use it in GitHub Desktop.
Save salkinium/7113bb72c1f33ee6677d to your computer and use it in GitHub Desktop.
// coding: utf-8
/* Copyright (c) 2011, 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.
*/
// ----------------------------------------------------------------------------
#include "../../../device.hpp"
#include "clock.hpp"
// ----------------------------------------------------------------------------
bool
xpcc::stm32::ClockControl::enableInternalClock(uint32_t waitCycles)
{
bool retval;
RCC->CR |= RCC_CR_HSION;
while (not (retval = (RCC->CR & RCC_CR_HSIRDY)) and --waitCycles)
;
return retval;
}
bool
xpcc::stm32::ClockControl::enableExternalClock(uint32_t waitCycles)
{
bool retval;
RCC->CR |= RCC_CR_HSEBYP | RCC_CR_HSEON;
while (not (retval = (RCC->CR & RCC_CR_HSERDY)) and --waitCycles)
;
return retval;
}
bool
xpcc::stm32::ClockControl::enableExternalCrystal(uint32_t waitCycles)
{
bool retval;
RCC->CR = (RCC->CR & ~RCC_CR_HSEBYP) | RCC_CR_HSEON;
while (not (retval = (RCC->CR & RCC_CR_HSERDY)) and --waitCycles)
;
return retval;
}
bool
xpcc::stm32::ClockControl::enableLowSpeedInternalClock(uint32_t waitCycles)
{
bool retval;
RCC->CSR |= RCC_CSR_LSION;
while (not (retval = (RCC->CSR & RCC_CSR_LSIRDY)) and --waitCycles)
;
return retval;
}
bool
xpcc::stm32::ClockControl::enableLowSpeedExternalClock(uint32_t waitCycles)
{
bool retval;
RCC->BDCR |= RCC_BDCR_LSEBYP | RCC_BDCR_LSEON;
while (not (retval = (RCC->BDCR & RCC_BDCR_LSERDY)) and --waitCycles)
;
return retval;
}
bool
xpcc::stm32::ClockControl::enableLowSpeedExternalCrystal(uint32_t waitCycles)
{
bool retval;
RCC->BDCR = (RCC->BDCR & ~RCC_BDCR_LSEBYP) | RCC_BDCR_LSEON;
while (not (retval = (RCC->BDCR & RCC_BDCR_LSERDY)) and --waitCycles)
;
return retval;
}
// ----------------------------------------------------------------------------
bool
xpcc::stm32::ClockControl::enablePll(PllSource source,
UsbPrescaler usb,
uint8_t pllMul, uint8_t pllPrediv, uint32_t waitCycles)
{
// Read reserved values and clear all other values
uint32_t tmp = RCC->CFGR & ~(RCC_CFGR_USBPRE | RCC_CFGR_PLLMULL | RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE);
// Divide Output for USB Clock by 1.5?
tmp |= static_cast<uint32_t>(usb);
// PLLSRC source for pll
tmp |= static_cast<uint32_t>(source);
// Pll multiplication factor
tmp |= (static_cast<uint32_t>(pllMul - 2) << 18) & RCC_CFGR_PLLMULL;
#ifdef RCC_CFGR2_PREDIV1
// HSE PREDIV division factor
RCC->CFGR2 = (RCC->CFGR2 & ~(RCC_CFGR2_PREDIV1)) | (uint32_t(pllPrediv - 1) & RCC_CFGR2_PREDIV1);
#else
if (uint32_t(pllPrediv - 1) & 0x1) tmp |= RCC_CFGR_PLLXTPRE;
#endif
RCC->CFGR = tmp;
// enable pll
RCC->CR |= RCC_CR_PLLON;
while (not (tmp = (RCC->CR & RCC_CR_PLLRDY)) and --waitCycles)
;
return tmp;
}
// ----------------------------------------------------------------------------
bool
xpcc::stm32::ClockControl::enableSystemClock(SystemClockSource src, uint32_t waitCycles)
{
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_SW) | uint32_t(src);
// Wait till the main PLL is used as system clock source
src = SystemClockSource(uint32_t(src) << 2);
while ((RCC->CFGR & RCC_CFGR_SWS) != uint32_t(src))
{
if (not --waitCycles)
return false;
}
return true;
}
// coding: utf-8
/* Copyright (c) 2011, 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_HPP
#define XPCC_STM32_CLOCK_HPP
#include <stdint.h>
#include "../../../device.hpp"
#include "../generic/common_clock.hpp"
// #include "static.hpp"
using namespace xpcc::clock;
namespace xpcc
{
namespace stm32
{
/**
* Clock management.
*
* For using the internal clock (which is 16MHz) use:
* \code
* typedef xpcc::stm32::Clock C;
* enablePll(C::PllSource::PLL_HSI, 8, 120); // for STM32F2xx
* enablePll(C::PllSource::PLL_HSI, 8, 168); // for STM32F4xx
* switchToPll();
* \endcode
*
* For using an external crystal with 8 MHz use:
* \code
* typedef xpcc::stm32::Clock C;
* if (enableHse(C::HseConfig::HSE_CRYSTAL))
* {
* enablePll(C::PllSource::PLL_HSE, 4, 120); // for STM32F2xx
* enablePll(C::PllSource::PLL_HSE, 4, 168); // for STM32F4xx
* switchToPll();
* }
* \endcode
*
* For using an external oscillator with 25 MHz use:
* \code
* if (enableHse(HSE_BYPASS))
* {
* enablePll(PLL_HSE, 25, 240); // for STM32F2xx
* enablePll(PLL_HSE, 25, 336); // for STM32F4xx
* switchToPll();
* }
* \endcode
*
* \ingroup stm32f2_4
*/
class ClockControl
{
public:
enum class
ClockSource
{
InternalClock,
ExternalClock,
ExternalCrystal,
LowSpeedInternalClock,
LowSpeedExternalClock,
LowSpeedExternalCrystal,
};
enum class
PllSource : uint32_t
{
/// High speed internal clock (8 MHz)
Hsi = 0,
/// High speed external clock (see HseConfig)
Hse = RCC_CFGR_PLLSRC,
InternalClock = Hsi,
ExternalClock = Hse,
ExternalCrystal = Hse,
};
enum class
SystemClockSource : uint32_t
{
Hsi = RCC_CFGR_SW_HSI,
Hse = RCC_CFGR_SW_HSE,
Pll = RCC_CFGR_SW_PLL,
InternalClock = Hsi,
ExternalClock = Hse,
ExternalCrystal = Hse,
};
enum class
RealTimeClockSource : uint32_t
{
Lsi = RCC_BDCR_RTCSEL_LSI,
Lse = RCC_BDCR_RTCSEL_LSE,
Hse = RCC_BDCR_RTCSEL_HSE,
ExternalClock = Hse,
ExternalCrystal = Hse,
LowSpeedInternalClock = Lsi,
LowSpeedExternalClock = Lse,
LowSpeedExternalCrystal = Lse
};
enum class
WatchdogClockSource : uint32_t
{
LowSpeedInternalClock = 0
};
enum class
AhbPrescaler : uint32_t
{
Div1 = RCC_CFGR_HPRE_DIV1,
Div2 = RCC_CFGR_HPRE_DIV2,
Div4 = RCC_CFGR_HPRE_DIV4,
Div8 = RCC_CFGR_HPRE_DIV8,
Div16 = RCC_CFGR_HPRE_DIV16,
Div64 = RCC_CFGR_HPRE_DIV64,
Div128 = RCC_CFGR_HPRE_DIV128,
Div256 = RCC_CFGR_HPRE_DIV256,
Div512 = RCC_CFGR_HPRE_DIV512
};
enum class
Apb1Prescaler : uint32_t
{
Div1 = RCC_CFGR_PPRE1_DIV1,
Div2 = RCC_CFGR_PPRE1_DIV2,
Div4 = RCC_CFGR_PPRE1_DIV4,
Div8 = RCC_CFGR_PPRE1_DIV8,
Div16 = RCC_CFGR_PPRE1_DIV16
};
enum class
Apb2Prescaler : uint32_t
{
Div1 = RCC_CFGR_PPRE2_DIV1,
Div2 = RCC_CFGR_PPRE2_DIV2,
Div4 = RCC_CFGR_PPRE2_DIV4,
Div8 = RCC_CFGR_PPRE2_DIV8,
Div16 = RCC_CFGR_PPRE2_DIV16
};
enum class
ClockOutputSource : uint32_t
{
SystemClock = RCC_CFGR_MCO_SYSCLK,
InternalClock = RCC_CFGR_MCO_HSI,
ExternalClock = RCC_CFGR_MCO_HSE,
ExternalCrystal = RCC_CFGR_MCO_HSE,
Pll = RCC_CFGR_MCO_PLLCLK_DIV2, ///< divided by 2
};
enum class
UsbPrescaler : uint32_t
{
DivideBy1Point5 = 0,
DoNotDivide = RCC_CFGR_USBPRE,
};
public:
// sources
static bool
enableInternalClock(uint32_t waitCycles = 2048);
static bool
enableExternalClock(uint32_t waitCycles = 2048);
static bool
enableExternalCrystal(uint32_t waitCycles = 2048);
static bool
enableLowSpeedInternalClock(uint32_t waitCycles = 2048);
static bool
enableLowSpeedExternalClock(uint32_t waitCycles = 2048);
static bool
enableLowSpeedExternalCrystal(uint32_t waitCycles = 2048);
// plls
static bool
enablePll(PllSource source,
UsbPrescaler usb,
uint8_t pllMul, uint8_t pllPrediv, uint32_t waitCycles = 2048);
// sinks
static bool
enableSystemClock(SystemClockSource src, uint32_t waitCycles = 2048);
static inline bool
enableRealTimeClock(RealTimeClockSource src)
{
RCC->BDCR = (RCC->BDCR & ~RCC_BDCR_RTCSEL) | RCC_BDCR_RTCEN | uint32_t(src);
return true;
}
static inline bool
enableWatchdogClock(WatchdogClockSource /*src*/)
{ return true; }
static inline bool
enableClockOutput(ClockOutputSource src)
{
RCC->CFGR = (RCC->CFGR & ~(RCC_CFGR_MCO))| uint32_t(src);
return true;
}
public:
static inline bool
setAhbPrescaler(AhbPrescaler prescaler)
{
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_HPRE) | uint32_t(prescaler);
return true;
}
static inline bool
setApb1Prescaler(Apb1Prescaler prescaler)
{
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_PPRE1) | uint32_t(prescaler);
return true;
}
static inline bool
setApb2Prescaler(Apb2Prescaler prescaler)
{
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_PPRE2) | uint32_t(prescaler);
return true;
}
public:
static inline uint32_t
getCpuFrequency()
{
return xpcc::clock::fcpu;
}
static inline uint32_t
getCpuFrequencykHz()
{
return xpcc::clock::fcpu_kHz;
}
static inline uint32_t
getCpuFrequencyMHz()
{
return xpcc::clock::fcpu_MHz;
}
};
} // namespace stm32
} // namespace xpcc
#endif // XPCC_STM32_CLOCK_HPP
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment