Implement RCC's clock configuration
For now, flash configuration is hard-coded. This will fixed in future commits
This commit is contained in:
parent
50dc10b76e
commit
dd6d5fbdd1
126
drivers/rcc.c
Normal file
126
drivers/rcc.c
Normal file
@ -0,0 +1,126 @@
|
||||
/** @file rcc.c
|
||||
* Module handling Reset and Clocks Control (RCC).
|
||||
*
|
||||
* The module provides functions to configure clocks according to presets as
|
||||
* well as to enable/disable/reset peripherals.
|
||||
*/
|
||||
|
||||
//--includes--------------------------------------------------------------------
|
||||
|
||||
#include "rcc.h"
|
||||
#include "rcc_regs.h"
|
||||
|
||||
|
||||
//--local definitions-----------------------------------------------------------
|
||||
|
||||
static void apply_default_preset(void);
|
||||
static void apply_speed_preset(void);
|
||||
|
||||
|
||||
//--local variables-------------------------------------------------------------
|
||||
|
||||
static volatile struct RCC* regs = (struct RCC*)RCC_BASE_ADDRESS;
|
||||
|
||||
|
||||
//--public functions------------------------------------------------------------
|
||||
|
||||
void rcc_configure(enum RccPreset preset)
|
||||
{
|
||||
//disable all peripherals during clock configuration
|
||||
union RCC_APB1ENR apb1_enr = regs->APB1ENR;
|
||||
regs->APB1ENR.word = 0x0;
|
||||
union RCC_APB2ENR apb2_enr = regs->APB2ENR;
|
||||
regs->APB2ENR.word = 0x0;
|
||||
|
||||
switch (preset) {
|
||||
case RCC_PRESET_DEFAULT:
|
||||
apply_default_preset();
|
||||
break;
|
||||
case RCC_PRESET_SPEED:
|
||||
apply_speed_preset();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
//re-enable peripherals
|
||||
regs->APB1ENR = apb1_enr;
|
||||
regs->APB2ENR = apb2_enr;
|
||||
}
|
||||
|
||||
|
||||
//--local functions-------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Apply the default clock preset, using HSI whithout PLL or prescalers. This is
|
||||
* similar to the reset configuration. Most buses run at 8Mhz, except ADCs wich
|
||||
* run at 4Mhz, and Systick wich only reaches 1Mhz.
|
||||
*/
|
||||
static void apply_default_preset(void)
|
||||
{
|
||||
//ensures HSI is enabled
|
||||
regs->CR.HSION = 0x1;
|
||||
while (regs->CR.HSIRDY != 0x1);
|
||||
|
||||
//set HSI as main clock source and disable prescalers
|
||||
regs->CFGR.word &= !0x077fff3;
|
||||
|
||||
//disable all options
|
||||
regs->CR.HSITRIM = 0x10;
|
||||
regs->CR.HSEON = 0x0;
|
||||
regs->CR.HSEBYP = 0x0;
|
||||
regs->CR.CCSON = 0x0;
|
||||
regs->CR.PLLON = 0x0;
|
||||
|
||||
//disable all interrupts
|
||||
regs->CIR.LSIRDYIE = 0x0;
|
||||
regs->CIR.LSERDYIE = 0x0;
|
||||
regs->CIR.HSIRDYIE = 0x0;
|
||||
regs->CIR.HSERDYIE = 0x0;
|
||||
regs->CIR.PLLRDYIE = 0x0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the speed preset, using HSE with PLL to achieve 72MHz on AHB, APB2 and
|
||||
* timer buses. APB1 is limited to its maximum clock of 36Mhz and the ADCs run
|
||||
* at 12MHz. Systick runs at 9Mhz.
|
||||
*/
|
||||
static void apply_speed_preset(void)
|
||||
{
|
||||
//restore sane values
|
||||
apply_default_preset();
|
||||
|
||||
//try enabling HSE, fallback to HSI if HSE fails
|
||||
regs->CR.HSEON = 0x1;
|
||||
for (uint32_t i=0; i<1000; ++i) {
|
||||
__asm__("nop");
|
||||
}
|
||||
if (regs->CR.HSERDY == 0x1) {
|
||||
regs->CFGR.PLLSCR = 0x1;
|
||||
} else {
|
||||
regs->CR.HSEON = 0;
|
||||
}
|
||||
|
||||
//configure PLL, fallback to HSI if PLL fails
|
||||
regs->CFGR.PLLMUL = 0x7; //PLL x9
|
||||
regs->CR.PLLON = 0x1;
|
||||
for (uint32_t i=0; i<1000; ++i) {
|
||||
__asm__("nop");
|
||||
}
|
||||
if (regs->CR.PLLRDY != 0x1) {
|
||||
regs->CR.PLLON = 0x0;
|
||||
return; //clock low enough, no need for prescalers
|
||||
}
|
||||
|
||||
//configure prescalers
|
||||
regs->CFGR.PPRE1 = 0x4; // /2
|
||||
regs->CFGR.ADCPRE = 0x2; // /6
|
||||
|
||||
//configure flash
|
||||
volatile uint32_t* ACR = (uint32_t*)0x40022000;
|
||||
*ACR |= 0x12;
|
||||
|
||||
//switch to PLL output
|
||||
regs->CFGR.SW = 0x2;
|
||||
}
|
||||
|
||||
38
drivers/rcc.h
Normal file
38
drivers/rcc.h
Normal file
@ -0,0 +1,38 @@
|
||||
/** @file rcc.h
|
||||
* Module handling Reset and Clocks Control (RCC).
|
||||
*
|
||||
* The module provides functions to configure clocks according to presets as
|
||||
* well as to enable/disable/reset peripherals.
|
||||
*/
|
||||
|
||||
#ifndef _RCC_H_
|
||||
#define _RCC_H_
|
||||
|
||||
//--includes--------------------------------------------------------------------
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
|
||||
//--type definitions------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Available clock configuration presets
|
||||
*/
|
||||
enum RccPreset {
|
||||
RCC_PRESET_DEFAULT, //sane values, identical to reset config
|
||||
RCC_PRESET_SPEED, //highest clocks, uses 8MHz HSE if available
|
||||
};
|
||||
|
||||
|
||||
//--functions-------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Configures the clocks and buses according to the given preset.
|
||||
*
|
||||
* @param preset the preset to use for configuration
|
||||
*/
|
||||
void rcc_configure(enum RccPreset preset);
|
||||
|
||||
|
||||
#endif //_RCC_H_
|
||||
|
||||
@ -1,3 +1,10 @@
|
||||
/** @file rcc_regs.h
|
||||
* Module defining Reset and Clocks Control (RCC) registers.
|
||||
*
|
||||
* Mainly made to be used by the rcc module. It is recommanded to go through
|
||||
* the functions provided by that module instead of directly using the registers
|
||||
* defined here.
|
||||
*/
|
||||
|
||||
#ifndef _RCC_REGS_H_
|
||||
#define _RCC_REGS_H_
|
||||
|
||||
Loading…
Reference in New Issue
Block a user