Program:
/* STM32 - USART - Asynchronous mode
LSB first
Baud Rate = 9600, SysClk = 72 MHz
Start bit - 8 data bits - 1 Stop bit
*/
#include "stm32f10x.h"
#define baud_9600 0x1D4C // for SysClk = 72 MHz
void RCC_config(void);
void USART1_IRQHandler(void);
static uint32_t data;
void USART1_IRQHandler()
{
// Transmission complete
if((USART1 -> SR & USART_SR_TC)){
GPIOC -> BSRR = GPIO_BSRR_BR13; // PC13 LED - ON
}
// Received data
if((USART1 -> SR & USART_SR_RXNE)){
GPIOC -> BSRR = GPIO_BSRR_BS13; // PC13 LED - OFF
data = USART1 -> DR; // Read the received data
// Disable USART if required
}
}
void RCC_config() // RCC clock configuration
{
RCC -> CR |= RCC_CR_HSEON; // HSE ON
RCC -> CFGR |= (RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL9);
// Setting PLL - HSE * 9
RCC -> CFGR |= RCC_CFGR_SW_1; // SysClk = PLLCLK
RCC -> CR |= RCC_CR_PLLON;
// Turn ON PLL after above PLL configurations, making SysClk = HSE * 9 = 8 * 9 = 72 MHz
RCC -> CFGR |= RCC_CFGR_PPRE1_DIV2;
// APB1 = AHB / 2 = 72 / 2 = 36 MHz (max)
}
int main()
{
RCC_config();
/* PC13 LED configuration */
RCC -> APB2ENR |= RCC_APB2ENR_IOPCEN; // Enable Port-C Clock
GPIOC -> CRH |= GPIO_CRH_MODE13_1 | GPIO_CRH_CNF13_0; // PortC_Pin 13 as output @2MHZ with open-drain
GPIOC -> BSRR = GPIO_BSRR_BS13; // Initialize PC13 LED - OFF
/* USART1 configuration */
RCC -> APB2ENR |= RCC_APB2ENR_USART1EN | RCC_APB2ENR_IOPAEN; // Enable UART and Port A clock
GPIOA -> CRH |= (GPIO_CRH_MODE9_1 | GPIO_CRH_CNF9_1 | GPIO_CRH_CNF10_1);
// PA9- CNF: 10, MODE: 10; PA10- CNF: 10, MODE: 00
GPIOA -> CRH &= ((~GPIO_CRH_CNF9_0) & (~GPIO_CRH_CNF10_0)); // Clear default reset value
USART1 -> BRR = baud_9600; // Baud Rate = 9600
USART1 -> CR1 |= USART_CR1_UE;
// Enable USART, M = 0 - 8 data bits
/* USART1 -> CR2 : STOP = 0 -> Indicating 1 stop bit */
USART1 -> CR1 |= USART_CR1_TCIE;
// Enable Transmission complete interrupt
USART1 -> CR1 |= USART_CR1_TE; // Sending a Idle line
/* This should clear TXE and TC flag, after which interrupt is enabled */
NVIC_EnableIRQ(USART1_IRQn);
// Enable USART1 global interrupt in NVIC
USART1 -> DR = 'A'; // Sending data
USART1 -> CR1 |= USART_CR1_RXNEIE; // Enable Receiver interrupt
USART1 -> CR1 |= USART_CR1_RE; // Enable Receiver
while(1)
{
// Do nothing
}
return 0;
}
For more details on RCC configuration, see previous post.
Baud Rate generation:
Below is the formula to calculate the baud rate:
FCLK = 72 MHz
Lets say, required baud rate = 9600
Tx/ Rx baud = FCK
---------------------
(16*USARTDIV)
USARTDIV = FCK = 72000000 = 468.75
--------------------- ----------------
(16 * baud rate) (16 * 9600)
USARTDIV is an unsigned fixed point number that is coded on the USART_BRR (baud rate) register, which requires DIV_Fraction and DIV_Mantissa
DIV_Fraction (4 - bit) = 16 * 0.75 = 12 = 0xC
DIV_Mantissa (12 - bit) = 468 = 0x1D4
So, USART_BRR = 0x1D4C
Refer reference manual for more details.
Steps:
1. Enable clock for USART1 = 72 MHz
Refer previous post for detailed RCC configuration
2. We are using USART1 and the Tx and Rx pins should be configured based on alternate functionality table, refer datasheet and reference manual
Note: Only USART1 is clocked with PCLK2 (72 MHz max). Other USARTs are clocked with
PCLK1 (36 MHz max).
3. Set baud rate in USART_BRR register
4. Enable USART and configure no. of data bits, in this case M = 0 -> 8 data bits
5. Configure no. of stop bits in USART_CR2 register, in this case STOP = 0 -> 1 stop bit
Transmission:
6. Set the TE bit in USART_CR1 to send an idle frame as first transmission
7. Write the data to send in the USART_DR register
TX flag:
After writing data to USART_DR register, TXE bit is set to indicate transmission started
On continuous data transmission, next write to USART_DR register clears the TXE flag,
else TXE flag stays set even after transmission ends, setting TC flag. Which indicates end of transmission.
TC bit is cleared by a
software sequence (a read from the USART_SR register followed by a write to the
USART_DR register). The TC bit can also be cleared by writing a '0' to it. This clearing
sequence is recommended only for multibuffer communication (i.e., continuous communication).
8. Enable Transmission complete interrupt - TCIE to indicate end of transmission or monitor the TC bit in USART_SR register (polling method).
Note: When using interrupt, enable the specific interrupt in NVIC
Lets turn on the in-built LED connected to PC13 on Transmission complete interrupt.
Receiver:
9. Set the RE bit USART_CR1. This enables the receiver which begins searching for a
start bit.
Rx flag:
In single buffer mode, clearing the RXNE bit is performed by a software read to the
USART_DR register. The RXNE flag can also be cleared by writing a zero to it. The
RXNE bit must be cleared before the end of the reception of the next character to avoid
an overrun error
In multibuffer, RXNE is set after every byte received and is cleared by the DMA read to
the Data register.
10. Enable Transmission complete interrupt - RXNEIE to to know when data is received or monitor the RXNE bit in USART_SR register (polling method).
USART1_IRQ is a global interrupt, so the same handler / ISR is used for both Tx and Rx interrupt.
Result: Connect the STM32 UART to USB to Serial converter and connect to PC/Laptop and observe the sent data in any serial terminal (realterm), also use send option to send data to STM32
Connection: TX -> RX(PA10), RX -> TX(PA9), VCC -> 3.3V, Gnd -> Gnd
For DMA in STM32, see next post
Comments
Post a Comment