STM32L1开发心得(一、RCC/PWR篇)
$ ]$ f8 ` p/ [2 k _' x- 因为电压及功耗方面的要求,需要从STM32F103将程序移植到STM32L151上面,以下内容就是程序移植过程中的心得体会。1 h% ?6 K, C8 X7 M' H
- STM32F系列的应用很多,网上大把都是F系列的经验文章和例程,但是L系列的文章就很少,尤其是中文的资料就更少,所以使用L系列最痛苦的就是必须啃英文资料,这里写的开发心得就算是为同样英文不好工程师参考吧。
& x! q; ^0 h- h - 本篇主要说说RCC/PWR的配置。! X/ I3 W% y/ I: {! d* @
- 与F1系列相比,L1系列有以下几个关键地方不太一样,需要特别注意:
0 G3 ?; s: H* E! `6 C - 1、 L1系列的最高频率只能达到32M
8 z$ S; {$ Q( x% n$ n( N' n - 2、L1系列的HSI是16M的% B4 r: X, R8 N: R: \. G. p
- 3、L1系列的内部RC振荡器除了HSI外,还增加了一个MSI,但MSI不能做为PLL的源- p/ _2 u4 O% b5 p8 d3 n
- 4、MSI提供了从64K到4M之间几种超低频率,特别适合那种不能睡眠又没多少事干的节能应用场合
7 H% c$ T' W7 j4 n/ h+ ^, m/ f$ V& U - 5、内核电压Vcore是可以配置的,而Vcore的不同也影响最大工作频率和FLASH的配置6 n8 z; V6 ^" e. U
- 6、L1的最低可运行电压为1.65V,用ADC或DAC时最低1.8V/ A' l4 i( N( @/ n
- 7、某些外设的总线改变,比如GPIOA在L1系列被映射到AHB总线上4 v# J B" f/ ^
- 除了以上需要注意的事项外,笔者在调试RCC时,发现按照F1系列的通常例程修改后很难调通,建议编程时以ST公司提供的例程为蓝本,在此基础上修改成自已所需要的参数,以下是例程(HSI源的PLL):
6 ]/ G& R7 Z% a3 ~ - RCC_DeInit();2 T( i }" r* b: ^2 {% x7 ~
- RCC_HSICmd(ENABLE); //开启内部晶振HSI
% {6 s, b& B! }3 H' { - while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY)== RESET); //等待HSI就绪% E5 J- w2 F1 k4 o$ I7 C
- FLASH->ACR |= FLASH_ACR_ACC64; //使能64位FLASH
0 S4 w3 q5 M" O$ W, I! w - FLASH->ACR |= FLASH_ACR_PRFTEN; //使能FLASH预取功能
$ V6 U# y! h' D! O: q8 q8 g - FLASH->ACR |= FLASH_ACR_LATENCY; //1个等待周期
3 r/ t4 P* m/ G7 b7 n$ a8 y9 q - RCC->APB1ENR |= RCC_APB1ENR_PWREN; //使能POWER
5 J3 g" T5 N! A- s! j - PWR->CR = PWR_CR_VOS_0; //选择内核电压1级(1.8V)( Y" T# _) H k$ h: G S0 w4 o
- while((PWR->CSR & PWR_CSR_VOSF) != RESET) {}; //等待内核电压稳定
+ w8 W: a( y( |" C5 x" B - RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; //HCLK
+ y+ n4 ~3 |1 b" |1 o) ?2 p3 U - RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; //PCLK2
- a, A! ~ _: j8 P, h7 _8 S# e - RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV1; //PCLK1. j# Z! F: l3 p# S7 u: O
- // PLL =16MHZ*2=32MHZ
; Q4 H) ~7 G1 g& e( G - RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLMUL |$ ~# q6 h4 w- s, Z7 L: {
- RCC_CFGR_PLLDIV));. S8 Q- F4 U1 w" O3 B
- RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSI | RCC_CFGR_PLLMUL6 | RCC_CFGR_PLLDIV3);
* @$ h, d2 f1 l+ p" C j - RCC->CR |= RCC_CR_PLLON; //使能RCC
3 @ O- I5 M _% V2 ^' P5 l - while((RCC->CR & RCC_CR_PLLRDY) == 0){} //等待PLL稳定
& f9 v% z# H8 v6 f1 { - //选择PLL做为系统时钟
( E- |" u. o* O% n, N( `) J - RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
/ a; {2 A' ]+ F, W! e8 j - RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; 7 [' \: k7 S9 ~, w) v/ L
- //等待PLL稳定. G1 w; p2 v6 F1 }' L- u. L
- while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL){}
( r: U2 x6 s, I - //上面配置完成后,就可以将外设联接到时钟总线上了,比如联接GPIOA( c' V! I4 z$ B) w/ X; F: [' F
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
复制代码 ' I$ j [# p c+ e
9 D' Q6 I& B7 \
4 o$ j+ R# [' y- y; ~0 f
|