STM32L1开发心得(一、RCC/PWR篇)
( a9 b' C5 y# b/ P- 因为电压及功耗方面的要求,需要从STM32F103将程序移植到STM32L151上面,以下内容就是程序移植过程中的心得体会。
+ V+ |1 C! |) R) { a" z W7 h2 \2 B - STM32F系列的应用很多,网上大把都是F系列的经验文章和例程,但是L系列的文章就很少,尤其是中文的资料就更少,所以使用L系列最痛苦的就是必须啃英文资料,这里写的开发心得就算是为同样英文不好工程师参考吧。: [$ [) z3 y' e- S1 o% S
- 本篇主要说说RCC/PWR的配置。9 J/ g# f3 r( B T
- 与F1系列相比,L1系列有以下几个关键地方不太一样,需要特别注意:
, h( {; p! h* _) m! w - 1、 L1系列的最高频率只能达到32M
* z5 r! n/ J4 g- k- G1 Z - 2、L1系列的HSI是16M的
% H1 m" [, l% G5 U0 T - 3、L1系列的内部RC振荡器除了HSI外,还增加了一个MSI,但MSI不能做为PLL的源6 w2 k& x& K$ v" X8 G+ I4 u7 @' I5 a
- 4、MSI提供了从64K到4M之间几种超低频率,特别适合那种不能睡眠又没多少事干的节能应用场合7 M) s% L2 v' o; k0 A
- 5、内核电压Vcore是可以配置的,而Vcore的不同也影响最大工作频率和FLASH的配置/ H0 e( K; W# G" H0 l/ Z$ y% T
- 6、L1的最低可运行电压为1.65V,用ADC或DAC时最低1.8V
9 r- ]# B m8 z4 @8 C- O - 7、某些外设的总线改变,比如GPIOA在L1系列被映射到AHB总线上* _6 d: i. a5 p+ G3 \. p+ L
- 除了以上需要注意的事项外,笔者在调试RCC时,发现按照F1系列的通常例程修改后很难调通,建议编程时以ST公司提供的例程为蓝本,在此基础上修改成自已所需要的参数,以下是例程(HSI源的PLL):5 T0 C# D' i8 V
- RCC_DeInit();) E2 e% K: k2 I4 t p0 u
- RCC_HSICmd(ENABLE); //开启内部晶振HSI
8 F: {: M; \+ P$ P - while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY)== RESET); //等待HSI就绪* E/ o A+ ?1 Q# t7 B
- FLASH->ACR |= FLASH_ACR_ACC64; //使能64位FLASH
$ y! ?+ m: J. A6 {+ o+ i5 V - FLASH->ACR |= FLASH_ACR_PRFTEN; //使能FLASH预取功能
8 h0 }$ P L0 B* Y - FLASH->ACR |= FLASH_ACR_LATENCY; //1个等待周期4 @1 a, [) K2 q" s
- RCC->APB1ENR |= RCC_APB1ENR_PWREN; //使能POWER" O' O1 A( k) }+ Q6 i* u& |; |. P
- PWR->CR = PWR_CR_VOS_0; //选择内核电压1级(1.8V). E$ y# z6 K& M3 Y. }4 ?
- while((PWR->CSR & PWR_CSR_VOSF) != RESET) {}; //等待内核电压稳定 ^, s9 I; W- o0 h" L) Y% m
- RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; //HCLK3 t: g& S+ V3 |) H1 l3 r
- RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; //PCLK2& D) B# l+ g9 [5 v% K8 q( y; X
- RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV1; //PCLK1! l( Z. n: A/ m
- // PLL =16MHZ*2=32MHZ * Q& p: g; i/ S1 L7 m4 H
- RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLMUL |' @6 [& c0 G3 F+ E
- RCC_CFGR_PLLDIV));% ?4 J$ d4 n; A% {/ n
- RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSI | RCC_CFGR_PLLMUL6 | RCC_CFGR_PLLDIV3);
1 v- F& ^) E+ [1 N - RCC->CR |= RCC_CR_PLLON; //使能RCC
e! i t# @$ m4 [0 f$ E8 {) B - while((RCC->CR & RCC_CR_PLLRDY) == 0){} //等待PLL稳定6 A" t1 u0 Z! M8 h$ L% P6 Q
- //选择PLL做为系统时钟
. I$ [$ _/ H" F$ k - RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));: w2 h' J0 Z; W0 @: s V# F' `# F+ ^
- RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; 8 J9 V& z/ h8 p2 a. Y
- //等待PLL稳定9 q9 p3 U; A$ u% M
- while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL){}* ?* C' f+ w: ?1 s
- //上面配置完成后,就可以将外设联接到时钟总线上了,比如联接GPIOA2 E7 R/ w5 O+ ?( s
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
复制代码
$ [5 E" R2 D* c- f/ x3 ^+ _* B
! t' l- N. g3 K- ` r, W/ @
7 k+ ]1 W. E8 T( T& ~ |