|
|
#include "stm32f4xx.h"
|
|
|
#include <stdint.h>
|
|
|
#include <stdlib.h>
|
|
|
#include <stdio.h>
|
|
|
#include <bsp.h>
|
|
|
#include <stm32f4xx_rcc.h>
|
|
|
|
|
|
void reset_AHB1()
|
|
|
{
|
|
|
RCC->AHB1RSTR = -1;
|
|
|
RCC->AHB1RSTR = 0;
|
|
|
}
|
|
|
|
|
|
void reset_AHB2()
|
|
|
{
|
|
|
RCC->AHB2RSTR = -1;
|
|
|
RCC->AHB2RSTR = 0;
|
|
|
}
|
|
|
|
|
|
void reset_APB1()
|
|
|
{
|
|
|
RCC->APB1RSTR = -1;
|
|
|
RCC->APB1RSTR = 0;
|
|
|
}
|
|
|
|
|
|
void reset_APB2()
|
|
|
{
|
|
|
RCC->APB2RSTR = -1;
|
|
|
RCC->APB2RSTR = 0;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t getCpuFreq()
|
|
|
{
|
|
|
extern uint32_t OSC0;
|
|
|
extern uint32_t INTOSC;
|
|
|
uint32_t cpufreq = OSC0;
|
|
|
uint32_t PLLN,PLLM,PLLP;
|
|
|
|
|
|
if((RCC->CFGR & 0xC) == 8) //PLL used as sys clk
|
|
|
{
|
|
|
uint32_t pllinput=INTOSC;
|
|
|
if((RCC->PLLCFGR & (1<<22)) == (1<<22))
|
|
|
{
|
|
|
pllinput=OSC0;
|
|
|
}
|
|
|
PLLN = (RCC->PLLCFGR>>6) & 0x1FF;
|
|
|
PLLM = RCC->PLLCFGR & 0x3F;
|
|
|
PLLP = 1<<(((RCC->PLLCFGR>>16) & 3 )+1);
|
|
|
cpufreq = (pllinput * PLLN )/(PLLM*PLLP);
|
|
|
}
|
|
|
else if((RCC->CFGR & 0xC) == 0) //HSI used as sys clk
|
|
|
{
|
|
|
cpufreq=INTOSC;
|
|
|
}
|
|
|
if((RCC->CFGR & (1<<7))==1<<7)
|
|
|
{
|
|
|
return cpufreq>>((RCC->CFGR & (7<<4))>>4);
|
|
|
}
|
|
|
return cpufreq;
|
|
|
}
|
|
|
|
|
|
|
|
|
/*
|
|
|
| 2.7->3.6V
|
|
|
-------------------------
|
|
|
0WS | 0<HCLK<=30
|
|
|
1WS | 30<HCLK<=60
|
|
|
2WS | 60<HCLK<=90
|
|
|
3WS | 90<HCLK<=120
|
|
|
4WS | 120<HCLK<=150
|
|
|
5WS | 150<HCLK<=168
|
|
|
|
|
|
f(VCO clock) = f(PLL clock input) × (PLLN / PLLM) [1]
|
|
|
64MHz <= f(VCO clock) <= 432MHz [2]
|
|
|
|
|
|
f(VCO clock input) must be between 1MHz and 2MHz and as close to 2MHz as possible!! [3]
|
|
|
|
|
|
f(PLL general clock output) = f(VCO clock) / PLLP [4]
|
|
|
|
|
|
CPU<168MHz AHB1<168MHz AHB2<168MHz APB1<42MHz APB2<84MHz [5]
|
|
|
|
|
|
! 63<=PLLN<=432 [6]
|
|
|
! 2<=PLLM<=63 [7]
|
|
|
! PLLP=2,4,6,8 [8]
|
|
|
4<=PLLM*PLLP<=504
|
|
|
|
|
|
F= f(PLL clock input) * A/B with
|
|
|
63<=A<=432
|
|
|
4<=B<=504
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
int optimizePLLcfg(uint32_t freq, uint32_t srcfreq,uint32_t PLLM,uint32_t* PLLP, uint32_t* PLLN,uint8_t* AHBPRindx)
|
|
|
{
|
|
|
uint32_t AHBPRtbl[9]={1,2,4,8,16,64,128,256,512};
|
|
|
uint32_t AHBPR=0,AHBPR_r=0,PLLN_r=0,PLLP_r=0;
|
|
|
uint32_t Fplli=0;
|
|
|
int32_t f_error=100000000;
|
|
|
int32_t f_errornw=100000000;
|
|
|
Fplli = srcfreq / PLLM;
|
|
|
//not efficient but should find the best parameters
|
|
|
for((*AHBPRindx)=0;(*AHBPRindx)<9;(*AHBPRindx)++) //lowest priority
|
|
|
{
|
|
|
AHBPR = AHBPRtbl[(*AHBPRindx)];
|
|
|
for(*PLLP=2;*PLLP<9;*PLLP+=2)
|
|
|
{
|
|
|
*PLLN = (freq*(*PLLP)*AHBPR)/Fplli;
|
|
|
if(((*PLLN)>62) && ((*PLLN)<433) && ((Fplli * (*PLLN)) < 433000000))
|
|
|
{
|
|
|
f_errornw = abs((int32_t)((int32_t)((Fplli*(*PLLN))/((*PLLP)*AHBPR))-freq));
|
|
|
if( ( (f_error)>(f_errornw) ) || ( (*AHBPRindx==0)&&(*PLLP==2)&&(*PLLN==63) ) )
|
|
|
{
|
|
|
f_error=f_errornw;
|
|
|
PLLN_r = *PLLN;
|
|
|
PLLP_r = *PLLP;
|
|
|
AHBPR_r=*AHBPRindx;
|
|
|
if(f_error==0)
|
|
|
{
|
|
|
*PLLN = PLLN_r;
|
|
|
*PLLP = PLLP_r;
|
|
|
*AHBPRindx = AHBPR_r;
|
|
|
return 1;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
*PLLN = PLLN_r;
|
|
|
*PLLP = PLLP_r;
|
|
|
*AHBPRindx = AHBPR_r;
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
|
|
|
int setPll(uint32_t freq)
|
|
|
{
|
|
|
extern uint32_t OSC0;
|
|
|
extern uint32_t INTOSC;
|
|
|
uint32_t srcfreq = INTOSC;
|
|
|
uint8_t AHBPRindx;
|
|
|
uint32_t AHBPRtbl[9]={1,2,4,8,16,64,128,256,512};
|
|
|
uint32_t PLLN=0,PLLM=0,PLLP=0,AHBPR=0;
|
|
|
uint32_t Fplli=0;
|
|
|
if((RCC->PLLCFGR & (1<<22))==(1<<22))
|
|
|
{
|
|
|
srcfreq = OSC0;
|
|
|
}
|
|
|
PLLM = srcfreq / 1500000; // [3]
|
|
|
Fplli = srcfreq / PLLM;
|
|
|
optimizePLLcfg(freq,srcfreq,PLLM,&PLLP,&PLLN,&AHBPRindx);
|
|
|
srcfreq = (Fplli*PLLN)/(PLLP*AHBPRtbl[AHBPRindx]); //Put real clk freq in srcfreq for return value
|
|
|
//now switch to HSIs
|
|
|
if((RCC->CR & 1)==0)RCC->CR |= 1; //turn ON HSI
|
|
|
while((RCC->CR & 2)!=2); //wait for HSI Ready
|
|
|
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
|
|
|
RCC->CFGR |= RCC_CFGR_SW_HSI; //set HSI as main clk
|
|
|
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_HSI);
|
|
|
RCC->CR &= ~(1<<24); //Turn OFF PLL
|
|
|
RCC->PLLCFGR &= ~0x37FFF; //clear PLLP PLLM PLLN
|
|
|
RCC->PLLCFGR |= PLLM + (PLLN<<6) + (((PLLP>>1) -1)<<16);
|
|
|
RCC->CR |= RCC_CR_PLLON; //Turn ON PLL
|
|
|
while((RCC->CR & (1<<25))!=(1<<25)); //wait for PLL Ready
|
|
|
if(AHBPRindx!=0)AHBPRindx|=0x8;
|
|
|
RCC->CFGR &= ~(0xF<<4);
|
|
|
RCC->CFGR |= (uint32_t)(AHBPRindx<<4);
|
|
|
AHBPR=0;
|
|
|
while((srcfreq>>AHBPR)>42000000)AHBPR++; //[5] //Thune APB1 prescaler to keep APB1 CLK below 42MHz
|
|
|
if(AHBPR!=0)
|
|
|
{
|
|
|
AHBPR-=1;
|
|
|
AHBPR|=0x4;
|
|
|
}
|
|
|
RCC->CFGR &= ~(0x7<<10);
|
|
|
RCC->CFGR |= (uint32_t)(AHBPR<<10);
|
|
|
AHBPR=0;
|
|
|
while((srcfreq>>AHBPR)>84000000)AHBPR++; //[5] //Thune APB2 prescaler to keep APB2 CLK below 42MHz
|
|
|
if(AHBPR!=0)
|
|
|
{
|
|
|
AHBPR-=1;
|
|
|
AHBPR|=0x4;
|
|
|
}
|
|
|
RCC->CFGR &= ~(0x7<<13);
|
|
|
RCC->CFGR |= (uint32_t)(AHBPR<<13);
|
|
|
FLASH->ACR |= FLASH_ACR_LATENCY_7WS;
|
|
|
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));//Switch to PLL as main clk source
|
|
|
RCC->CFGR |= RCC_CFGR_SW_PLL;
|
|
|
/* Wait till the main PLL is used as system clock source */
|
|
|
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
|
|
|
if(srcfreq>150000000)
|
|
|
{
|
|
|
FLASH->ACR &= (~7)|FLASH_ACR_LATENCY_5WS;
|
|
|
}
|
|
|
if((srcfreq<150000000) && (srcfreq>=120000000))
|
|
|
{
|
|
|
FLASH->ACR &= (~7)|FLASH_ACR_LATENCY_4WS;
|
|
|
}
|
|
|
if((srcfreq<120000000) && (srcfreq>=90000000))
|
|
|
{
|
|
|
FLASH->ACR &= (~7)|FLASH_ACR_LATENCY_3WS;
|
|
|
}
|
|
|
if((srcfreq<90000000) && (srcfreq>=60000000))
|
|
|
{
|
|
|
FLASH->ACR &= (~7)|FLASH_ACR_LATENCY_2WS;
|
|
|
}
|
|
|
if((srcfreq<60000000) && (srcfreq>=30000000))
|
|
|
{
|
|
|
FLASH->ACR &= (~7)|FLASH_ACR_LATENCY_1WS;
|
|
|
}
|
|
|
if(srcfreq<30000000)
|
|
|
{
|
|
|
FLASH->ACR &= (~7)|FLASH_ACR_LATENCY_0WS;
|
|
|
}
|
|
|
return srcfreq;
|
|
|
}
|
|
|
|
|
|
int setCpuFreq(uint32_t freq)
|
|
|
{
|
|
|
extern uint32_t OSC0;
|
|
|
extern uint32_t INTOSC;
|
|
|
uint8_t i=0;
|
|
|
uint32_t curentFeq = getCpuFreq();
|
|
|
if(curentFeq==freq)return curentFeq;
|
|
|
if((freq>2000000) && (freq<=250000000)) //be carefull with 250MHz!!!
|
|
|
{
|
|
|
if((RCC->CFGR & 0xC) == 8) //PLL used as sys clk
|
|
|
{
|
|
|
return setPll(freq);
|
|
|
}
|
|
|
else if((RCC->CFGR & 0xC) == 0) //HSI used as sys clk
|
|
|
{
|
|
|
if((INTOSC%freq)==0) //now check if we can directly divide HSI
|
|
|
{
|
|
|
if(freq==INTOSC)
|
|
|
{
|
|
|
RCC->CFGR &= ~(0xF<<4);
|
|
|
return freq;
|
|
|
}
|
|
|
for(i=1;i<8;i++)
|
|
|
{
|
|
|
if((freq<<i)==INTOSC)
|
|
|
{
|
|
|
RCC->CFGR &= ~(0xF<<4);
|
|
|
RCC->CFGR |= ((0x8|i)<<4);
|
|
|
return freq;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
return setPll(freq);
|
|
|
}
|
|
|
else //HSE used as sys clk
|
|
|
{
|
|
|
if((OSC0%freq)==0) //now check if we can directly divide HSI
|
|
|
{
|
|
|
if(freq==OSC0)
|
|
|
{
|
|
|
RCC->CFGR &= ~(0xF<<4);
|
|
|
return freq;
|
|
|
}
|
|
|
for(i=1;i<8;i++)
|
|
|
{
|
|
|
if((freq<<i)==OSC0)
|
|
|
{
|
|
|
RCC->CFGR &= ~(0xF<<4);
|
|
|
RCC->CFGR |= ((0x8|i)<<4);
|
|
|
return freq;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
return setPll(freq);
|
|
|
}
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
#include <stdio.h>
|
|
|
extern int main();
|
|
|
|
|
|
inline void enable_FPU()
|
|
|
{
|
|
|
SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
|
|
|
__asm__("dsb");
|
|
|
__asm__("isb");
|
|
|
}
|
|
|
|
|
|
void cpu_init()
|
|
|
{
|
|
|
extern uint32_t currentCpuFreq;
|
|
|
currentCpuFreq = 80000000;
|
|
|
enable_FPU();
|
|
|
RCC->CR |= (uint32_t)0x00000001;
|
|
|
FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
|
|
|
reset_AHB1();
|
|
|
reset_AHB2();
|
|
|
reset_APB1();
|
|
|
reset_APB2();
|
|
|
RCC->CR |= (uint32_t)0x00000001;
|
|
|
FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
|
|
|
RCC->CFGR = 0x00000000;
|
|
|
RCC->CIR = 0x00000000;
|
|
|
SCB->VTOR = FLASH_BASE;
|
|
|
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
|
|
|
PWR->CR |= PWR_CR_PMODE;
|
|
|
bsp_init();
|
|
|
printf("Configure PLL to reach %uHz\n\r",(unsigned int)currentCpuFreq);
|
|
|
currentCpuFreq=setCpuFreq(currentCpuFreq);
|
|
|
bsp_uart_init();
|
|
|
RCC_ClocksTypeDef RCC_ClocksStatus;
|
|
|
RCC_GetClocksFreq(&RCC_ClocksStatus);
|
|
|
printf("PLL Configured got:\n\r SYS=%uHz\n\r CPU=%uHz\n\r APB1=%uHz\n\r APB2=%uHz\n\r",(unsigned int)RCC_ClocksStatus.SYSCLK_Frequency,(unsigned int)RCC_ClocksStatus.HCLK_Frequency,(unsigned int)RCC_ClocksStatus.PCLK1_Frequency,(unsigned int)RCC_ClocksStatus.PCLK2_Frequency);
|
|
|
printf("Enter Main\n\r");
|
|
|
int res=main();
|
|
|
printf("\n\rprogram exited with code ");
|
|
|
printf("%u",res);
|
|
|
printf("\n\r");
|
|
|
while(1)
|
|
|
{
|
|
|
for(volatile int i=0;i<1024*64;i++);
|
|
|
gpioset(PD14);
|
|
|
for(volatile int i=0;i<1024*64;i++);
|
|
|
gpioclr(PD14);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|