STM32L1开发心得(一、RCC/PWR篇)
+ J! K4 K! `) c J1 Q9 I2 j7 Y- 因为电压及功耗方面的要求,需要从STM32F103将程序移植到STM32L151上面,以下内容就是程序移植过程中的心得体会。% D D% x3 N1 t4 j1 B
- STM32F系列的应用很多,网上大把都是F系列的经验文章和例程,但是L系列的文章就很少,尤其是中文的资料就更少,所以使用L系列最痛苦的就是必须啃英文资料,这里写的开发心得就算是为同样英文不好工程师参考吧。
' l1 s$ H* d6 u0 u; _ - 本篇主要说说RCC/PWR的配置。. t# x$ ?0 i# J
- 与F1系列相比,L1系列有以下几个关键地方不太一样,需要特别注意:( y) o5 ^9 w1 k. E
- 1、 L1系列的最高频率只能达到32M
3 K% k3 d6 w7 N& R, V) j5 O# G - 2、L1系列的HSI是16M的
J- Z5 b) w/ J2 W3 o - 3、L1系列的内部RC振荡器除了HSI外,还增加了一个MSI,但MSI不能做为PLL的源
6 b4 `8 Z0 E( `0 y4 C& `" d6 } - 4、MSI提供了从64K到4M之间几种超低频率,特别适合那种不能睡眠又没多少事干的节能应用场合- r& V$ b: l- \, ?4 q# D9 [% e% k
- 5、内核电压Vcore是可以配置的,而Vcore的不同也影响最大工作频率和FLASH的配置
- L: {4 C$ V% |2 I% b( Q - 6、L1的最低可运行电压为1.65V,用ADC或DAC时最低1.8V
9 z6 D) G' } g( r! k0 y! g N3 o - 7、某些外设的总线改变,比如GPIOA在L1系列被映射到AHB总线上' S, v* [) [$ i! ?) N
- 除了以上需要注意的事项外,笔者在调试RCC时,发现按照F1系列的通常例程修改后很难调通,建议编程时以ST公司提供的例程为蓝本,在此基础上修改成自已所需要的参数,以下是例程(HSI源的PLL):6 z. V( B1 ^1 B0 {6 S4 h9 j
- RCC_DeInit();
3 k6 R% }8 S/ u/ M ] - RCC_HSICmd(ENABLE); //开启内部晶振HSI0 A8 h- k, g. F, j4 z( e
- while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY)== RESET); //等待HSI就绪6 k% u: m$ ] i0 D7 G# @' u
- FLASH->ACR |= FLASH_ACR_ACC64; //使能64位FLASH$ w/ K0 ^* o& Y3 f
- FLASH->ACR |= FLASH_ACR_PRFTEN; //使能FLASH预取功能. R% e: m8 Y( W( O+ |/ F, @
- FLASH->ACR |= FLASH_ACR_LATENCY; //1个等待周期
. u' ~# X# i' X4 \: J. { - RCC->APB1ENR |= RCC_APB1ENR_PWREN; //使能POWER* x Q4 s) X# w
- PWR->CR = PWR_CR_VOS_0; //选择内核电压1级(1.8V)
- [7 h8 S2 s" U! M' ]4 d& K! o* e - while((PWR->CSR & PWR_CSR_VOSF) != RESET) {}; //等待内核电压稳定/ Z9 J8 }' f, T# \
- RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; //HCLK
+ i9 ^5 S0 J' \' N4 i0 S - RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; //PCLK23 o# K& y5 X: _8 V6 ]# Q8 S
- RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV1; //PCLK10 _% y; C% h( M" _
- // PLL =16MHZ*2=32MHZ
, U' x7 C% V$ _9 d5 Y e; }" Z - RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLMUL |' b; s! j$ k7 v( Q s4 ~( s7 N
- RCC_CFGR_PLLDIV));9 U/ m* I1 l" d4 z0 a
- RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSI | RCC_CFGR_PLLMUL6 | RCC_CFGR_PLLDIV3);
7 B* w9 C2 T# O( b - RCC->CR |= RCC_CR_PLLON; //使能RCC) f2 ^+ L+ r# Q. b
- while((RCC->CR & RCC_CR_PLLRDY) == 0){} //等待PLL稳定" M) z; Z, S2 l4 L4 T4 N$ F6 b. u
- //选择PLL做为系统时钟
) d1 Y, Z* M5 F3 G0 v - RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
4 R, h0 K' V: n. X - RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; ; I8 `& v5 N0 Q
- //等待PLL稳定/ D1 V2 ]% C8 e5 C* ?
- while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL){}. T: @0 r+ ?8 g k: H ^2 M
- //上面配置完成后,就可以将外设联接到时钟总线上了,比如联接GPIOA
3 j4 Y( Q% y$ m, E - RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
复制代码
6 M- z' \: g6 s1 R* |. |
6 z5 l2 b( E2 j Y+ L3 r0 ^1 n& ^5 }% Z/ N K3 y, C* i) P
|