c - How to properly configure the USART_BRR register in STM32L476RG uC?
问题描述
I'm trying to write my own driver for USART_TX on an STM32L476RG Nucleo Board. Here the datasheet and the reference manual.
I'm using Keil uVision 5 and I set in the Manage dialog:
- CMSIS > Core
- Device > Startup
- Xtal=16MHz
I want to create a single character transmitter. According to the manual instructions in Sec. 40 p 1332 I wrote this code:
// APB1 connects USART2
// The USART2 EN bit on APB1ENR1 is the 17th
// See alternate functions pins and label for USART2_TX! PA2 is the pin and AF7 (AFRL register) is the function to be set
#include "stm32l4xx.h" // Device header
#define MASK(x) ((uint32_t) (1<<(x)));
void USART2_Init(void);
void USART2_Wr(int ch);
void delayMs(int delay);
int main(void){
USART2_Init();
while(1){
USART2_Wr('A');
delayMs(100);
}
}
void USART2_Init(void){
RCC->APB1ENR1 |= MASK(17); // Enable USART2 on APB1
// we know that the pin that permits the USART2_TX is the PA2, so...
RCC->AHB2ENR |= MASK(0); // enable GPIOA
// Now, in GPIOA 2 put the AF7, which can be set by placing AF7=0111 in AFSEL2 (pin2 selected)
// AFR[0] refers to GPIOA_AFRL register
// Remember: each pin asks for 4 bits to define the alternate functions. see pg. 87
// of the datasheet
GPIOA->AFR[0] |= 0x700;
GPIOA->MODER &= ~MASK(4);// now ... we set the PA2 directly with moder as alternate function "10"
// USART Features -----------
//USART2->CR1 |=MASK(15); //OVER8=1
USART2->BRR = 0x683; //USARTDIV=16Mhz/9600?
//USART2->BRR = 0x1A1; //This one works!!!
USART2->CR1 |=MASK(0); //UE
USART2->CR1 |=MASK(3); //TE
}
void USART2_Wr(int ch){
//wait when TX buffer is empty
while(!(USART2->ISR & 0x80)) {} //when data is transfered in the register the ISR goes 0x80.
//then we lock the procedure in a while loop until it happens
USART2->TDR =(ch & 0xFF);
}
void delayMs(int delay){
int i;
for (; delay>0; delay--){
for (i=0; i<3195; i++);
}
}
Now, the problem:
The system works, but not properly. I mean: if I use RealTerm at 9600 baud-rate, as configured by 0x683 in USART_BRR reg, it shows me wrong char but if I set 2400 as baud rate on real term it works!
To extract the 0x683 in USART_BRR reg i referred to Sec. 40.5.4 USART baud rate generation and it says that if OVER8=0 the USARTDIV=BRR. In my case, USARTDIV=16MHz/9600=1667d=683h.
I think that the problem lies in this code row:
USART2->BRR = 0x683; //USARTDIV=16Mhz/9600?
because if I replace it as
USART2->BRR = 0x1A1; //USARTDIV=16Mhz/9600?
THe system works at 9600 baud rate.
What's wrong in my code or in the USARTDIV computation understanding?
Thank you in advance for your support.
Sincerely, GM
解决方案
USART 的默认时钟源是PCLK1
(图 15 PCLK1
)SYSCLK / AHB_PRESC / AHB1_PRESC
。如果0x1A1
波特率为 9600,则表明PCLK1
= 4MHz。
当从内部 MSI RC 振荡器运行时,4MHz 恰好是您的处理器(和PCLK1
)启动时的默认频率。所以最可能的解释是您没有配置时钟树,并且没有像您认为的那样从 16MHz HSE 运行。
将时钟树配置为使用 16MHz 源,或对 MSI 频率执行计算。MSI 精度在正常温度范围内几乎足够好,可以保持足够准确的波特率,但并不理想。
推荐阅读
- html - 在父活动上应用 CSS 样式但排除特定的子活动事件
- ajax - ASP.NET MVC Ajax 请求在大数据量期间因 net::ERR_HTTP2_PROTOCOL_ERROR 失败
- r - 用于计算R中重复序列的循环
- android - 如何从 MediaRecorder 获取输出记录并将其保存到 Firebase 存储中
- autodesk-forge - 在 Autodesk forge 上为渲染 geo tiff 文件创建 bubble.json 文件
- r - 从 Rmarkdown 文档中提取部分作为向量
- matplotlib - 如何断线 ax.legend
- javascript - 从 JavaScript 嵌入编辑 CSS 样式(删除 JotForm 页脚)
- javascript - 如何在reactjs中检查eles条件是否在警报中
- reactjs - 没有可滚动的内容时删除滚动条