I was try to interface USART of STMF103RCT6(specifically USART1 PA9- Tx and PA10- RX). I have done my PLL Configuration for running my system at 72MHz and having few problems.
I have connected RX/TX pin of stm32f103rct6 to USB-to-Serial TX/RX and receive a character 'A' in the terminal(Software: Tera Term) at baud rate of 115200. But its not working.
Here is my code:
#include "stm32f10x.h"
#define HPRE_RESET_MASK ((uint32_t)0xFFFFFF0F)
#define PPRE2_RESET_MASK ((uint32_t)0xFFFFC7FF)
#define PPRE1_RESET_MASK ((uint32_t)0xFFFFF8FF)
#define PLLCLK_CONFIG_RESET_MASK ((uint32_t)0xFFC0FFFF)
#define SW_RESET_MASK ((uint32_t)0xFFFFFFFC)
#define LED_PORT_EN() ( RCC->APB2ENR |= RCC_APB2ENR_IOPDEN )
#define LED_PORT GPIOD
#define LED_MODE_BIT1 8
#define LED_MODE_BIT2 9
#define LED_CNF_BIT1 10
#define LED_CNF_BIT2 11
#define CNF_SET_PORTD(BIT1,BIT2) ( LED_PORT->CRL &= ~((1<<BIT1) | (1<<BIT2)) ) //General purpose output push-pull
#define MODE_SET_PORTD(BIT1,BIT2) ( LED_PORT->CRL |= (1<<BIT1) | (1<<BIT2) ) //Output mode, max speed 50 MHz.
#define SET_GPIO_BIT_PORTD(BIT) ( LED_PORT->BSRR = (1 << BIT) ) //For setting the Bit
#define RESET_GPIO_BIT_PORTD(BIT) ( LED_PORT->BSRR = ( (1 << BIT) << 16 ) ) //For Resseting Bit
void PLL_Config(void);
void Clock_Reset(void);
void HCLK_Config(uint32_t RCC_SYSCLK);
void PCLK2_Config(uint32_t RCC_HCLK);
void PCLK1_Config(uint32_t RCC_HCLK);
void PLLCLK_Config(uint32_t RCC_PLLSource, uint32_t RCC_PLLMul);
void SYSCLK_Config(uint32_t RCC_SYSCLKSource);
void Delay(int ms);
void Led_Init(void);
void Blink_Led(int ms);
void Transmit_Char(char data);
int main(void)
{
PLL_Config();
Led_Init();
//RCC configure for PORTA
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
/*for uart 1*/
GPIOA->CRH |= GPIO_CRH_MODE9; //Configure TX PORTA 9 push pull
GPIOA->CRH &= ~(GPIO_CRH_CNF9);
GPIOA->CRH |= GPIO_CRH_MODE10; //Configure RX PORTA 10 push pull
GPIOA->CRH &= ~(GPIO_CRH_CNF10);
RCC->APB2ENR |= RCC_APB2ENR_USART1EN; //enable clock for usart
USART1->BRR = 0x271; //set Baud mantisa 0x27 fraction 0x1
/*enable usart, enable RX,TX */
USART1->CR1 = USART_CR1_RE | USART_CR1_TE | USART_CR1_UE;
while(1)
{
Transmit_Char('A'); //transmit a data
Delay(1000);
Blink_Led(1000);
}
}
/** @breif: Transmit a character
* @param: the character to be transmitted
* @retVal: None
*/
void Transmit_Char(char data)
{
while (!(USART1->SR & USART_SR_TXE));
USART1->DR = data & 0xFF;
}
/** @breif: For wait and doing nothing i.e for delay
* @param: delaya time
* @retVal: None
*/
void Delay(int ms)
{
int i,j;
for (i = 0; i < ms; ++i) {
for (j = 0; j < 1000; ++j);
}
}
/** @breif: Initalize GPIO For Led
* @param: None
* @retVal: None
*/
void Led_Init()
{
LED_PORT_EN(); //Enable RCC for Led Port
CNF_SET_PORTD(LED_CNF_BIT1,LED_CNF_BIT2); //SET CNF General purpose output push-pull
MODE_SET_PORTD(LED_MODE_BIT1,LED_MODE_BIT2); //SET MODE Output mode, max speed 50 MHz.
}
/** @breif: Blink Led Placed in PORT D Pin 2
* @param: Delay for each state(ON/OFF)
* @retVal: None
*/
void Blink_Led(int ms)
{
RESET_GPIO_BIT_PORTD(2); //Make Led High
Delay(ms); //wait
SET_GPIO_BIT_PORTD(2); //Make Led Low
Delay(ms); //wait
}
/** @breif: Configure PLL 72 MHz
* @param: None
* @retVal: None
*/
void PLL_Config(void)
{
Clock_Reset(); //RESET Clock
RCC->CR |= RCC_CR_HSEON; //ENABLE HSE
/* wait till HSE Ready */
while ( !( RCC->CR & RCC_CR_HSERDY ));
/* Doubt: Enable Prefetch Buffer */
/* Doubt: Flash 2 wait state */
HCLK_Config(RCC_CFGR_HPRE_DIV1); //configure HCLK AHB clock
PCLK2_Config(RCC_CFGR_PPRE2_DIV1); //cofigure PCLK2 APB2 clock
PCLK1_Config(RCC_CFGR_PPRE1_DIV2); //configure PCLK1 APB1 clock
PLLCLK_Config(RCC_CFGR_PLLSRC, RCC_CFGR_PLLMULL9); //configure PLLCLK 72MHz
RCC->CR |= RCC_CR_PLLON; //ENABLE PLL
/* Wait till PLL is Ready */
while (!(RCC->CR & RCC_CR_PLLRDY));
SYSCLK_Config(RCC_CFGR_SW_PLL);
/* wait till PLL is used as system clock */
while (!(RCC->CFGR & RCC_CFGR_SWS_PLL));
}
/** @breif: Select PLL as system clock source
* @param: RCC_CFGR_SW_PLL = ((uint32_t)0x00000002)
* @retVal: None
*/
void SYSCLK_Config(uint32_t RCC_SYSCLKSource)
{
uint32_t tmpreg = 0;
tmpreg = RCC->CFGR;
/* Clear SW[1:0] bits */
tmpreg &= SW_RESET_MASK;
/* Set SW[1:0] bits according to RCC_SYSCLKSource value */
tmpreg |= RCC_SYSCLKSource;
/* Store the new value */
RCC->CFGR = tmpreg;
}
/** @breif: Set PCLK1 = HCLK/2
* HCLK divided by 2
* @param: RCC_CFGR_PLLSRC = ((uint32_t)0x00010000)
* @param: RCC_CFGR_PLLMULL9 = ((uint32_t)0x001C0000)
* @retVal: None
*/
void PLLCLK_Config(uint32_t RCC_PLLSource, uint32_t RCC_PLLMul)
{
uint32_t tmpreg = 0;
tmpreg = RCC->CFGR;
/* Clear PLLSRC, PLLXTPRE and PLLMUL[3:0] bits */
tmpreg &= PLLCLK_CONFIG_RESET_MASK;
/* Set the PLL configuration bits */
tmpreg |= RCC_PLLSource | RCC_PLLMul;
/* Store the new value */
RCC->CFGR = tmpreg;
}
/** @breif: Set PCLK1 = HCLK/2
* HCLK divided by 2
* @param: RCC_CFGR_PPRE1_DIV2 = ((uint32_t)0x00000400)
* @retVal: None
*/
void PCLK1_Config(uint32_t RCC_HCLK)
{
uint32_t tmpreg = 0;
tmpreg = RCC->CFGR;
/* Clear PPRE1[2:0] bits */
tmpreg &= PPRE1_RESET_MASK;
/* Set PPRE1[2:0] bits according to RCC_HCLK value */
tmpreg |= RCC_HCLK;
/* Store the new value */
RCC->CFGR = tmpreg;
}
/** @breif: Set PCLK2 = HCLK
* HCLK not divided
* @param: RCC_CFGR_PPRE2_DIV1 = ((uint32_t)0x00000000)
* @retVal: None
*/
void PCLK2_Config(uint32_t RCC_HCLK)
{
uint32_t tmpreg = 0;
tmpreg = RCC->CFGR;
/* Clear PPRE2[2:0] bits */
tmpreg &= PPRE2_RESET_MASK;
/* Set PPRE2[2:0] bits according to RCC_HCLK value */
tmpreg |= RCC_HCLK;
/* Store the new value */
RCC->CFGR = tmpreg;
}
/** @breif: Set HCLK = SYSCLK
* SYSCLK not divided
* @param: RCC_CFGR_HPRE_DIV1 = ((uint32_t)0x00000000)
* @retVal: None
*/
void HCLK_Config(uint32_t RCC_SYSCLK)
{
uint32_t tmpreg = 0;
tmpreg = RCC->CFGR;
/* Clear HPRE[3:0] bits */
tmpreg &= HPRE_RESET_MASK;
/* Set HPRE[3:0] bits according to RCC_SYSCLK value */
tmpreg |= RCC_SYSCLK;
/* Store the new value */
RCC->CFGR = tmpreg;
}
/** @breif: Resets the Clock
* @param: None
* @retVal: None
*/
void Clock_Reset(void)
{
/* Set HSION bit */
RCC->CR |= (uint32_t)0x00000001;
/* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
RCC->CFGR &= (uint32_t)0xF0FF0000;
/* Reset HSEON, CSSON and PLLON bits */
RCC->CR &= (uint32_t)0xFEF6FFFF;
/* Reset HSEBYP bit */
RCC->CR &= (uint32_t)0xFFFBFFFF;
/* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
RCC->CFGR &= (uint32_t)0xFF80FFFF;
/* Disable all interrupts and clear pending bits */
RCC->CIR = 0x009F0000;
}
I have few doubts with this code.
Fractional Baud rate generation:
Formula given is:
Tx/Rx baud = fclk/(16 * USARTDIV)
fclk(after pll setup will be 72MHz) : 72MHz
Tx/Rx Baud required is: 115200
so USARTDIV = fclk/(16*baud)
i.e USARTDIV = 72000000/(16*115200) = 39.0625(which is given in Table 192. Error calculation for programmed baud rates)
Then there is an example question (Example 2) where it says to program USARTDIV as 39.0625(Your USARTDIV)
DIV_Fraction = 16*0d0.0625 = 0d1 = 0x1
DIV_Mantissa = mantissa (0d39.0625) = 0d39 = 0x27
Then, USART_BRR = 0x271
i have used this value on my USART_BRR register but not getting the correct value.
Is the code correct for Usart tx?
Any suggestions will be really helpful. Because nothing is showing in the terminal i.e usart is not working
Thanks in advance
First - do not use "magic numbers" like 1<<7 as ARM uC are to complicated to remember remember bit numbers in the registers.
You have the CMSIS human readable definitions and you should use them.
If if understand correct your question you want to find the moment when the U(S)ART has finished the transmission of the data - to be for example disabled.
The TXE bit in the SR register shows that there is a space in the DR transmit register to put new data. It happens when the previous data has been transmitted to the internal transmit register. It does not mean that the data has been transmitted. You need to check if the TC bit is set before disabling the U(S)ART or entering the halt mode to avoid last data corruption.
CMSIS symbols for those flags are:
USART_SR_TXE USART_SR_TC
So if you want to check if you can put new data into the DR register you need to check (in your case)
while(!(USART1 -> SR & USART_SR_TXE));
and before disabling the peripheral
while(!(USART1 -> SR & USART_SR_TC));
Answering the second question.
The clock in the table in the RM is 32MHz. Your clock is 8MHz. And that is the problem and why UART does not work. Your real transfer speed is 4 times slower than you think and configure on the other side of the serial calble
TX Empty is bit 7 of the USART status register. It looks from your code like you're using USART 1, so your check is simply
while((USART1->SR & (1 << 7)) != (1 << 7));
It would be worth defining a constant somewhere for (1 << 7) when used like this, or using the one which is probably defined in whatever library it is you're using.
User contributions licensed under CC BY-SA 3.0