/*------------------------------------------------------------------------------ -- This file is a part of the libuc, microcontroler library -- Copyright (C) 2011, Alexis Jeandet -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ------------------------------------------------------------------------------- -- Author : Alexis Jeandet -- Mail : alexis.jeandet@gmail.com -------------------------------------------------------------------------------*/ #include #include #include #include #include #include extern uint32_t OSC0; extern uint32_t INTOSC; extern uint32_t RTCOSC; volatile uint32_t tickCounter=0; void SysTick_Handler(void) { tickCounter+=1; } void delay_us(uint32_t value) { extern uint32_t currentCpuFreq; if(value) { uint32_t tickperus=currentCpuFreq/(1000*10); uint32_t tickCounterSnap = SysTick->VAL+((value%100)*tickperus); uint32_t targetVal=tickCounterSnap +(value/100); if(targetVal < tickCounterSnap) { while(tickCounter > targetVal); } while((tickCounter < targetVal) | (SysTick->VALVAL; uint32_t targetVal=tickCounterSnap +(value); if(targetVal < tickCounterSnap) { while(tickCounter > targetVal); } while((tickCounter < targetVal) | (SysTick->VALCFGR & 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; } 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; } /* | 2.7->3.6V ------------------------- 0WS | 062) && ((*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; } void configureSysTick() { extern uint32_t currentCpuFreq; uint32_t us=currentCpuFreq/(1000*10); SysTick_Config(us); } 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<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<CFGR &= ~(0xF<<4); RCC->CFGR |= ((0x8|i)<<4); return freq; } } } else return setPll(freq); } } return 0; } void enable_FPU() { SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */ __asm__("dsb"); __asm__("isb"); }