When we need some feedback from microcontroller usually we use USART. It allows to output messages, debug information to terminal screen. Also data can be sent to MCU same way. For this purpose STM32 microcontrollers have more than one USART interface allowing to have multiple streams of data output and input.
Image may be NSFW.
Clik here to view.
USART interface is designed to be very versatile allowing to have lots of modes including LIN, IrDA, Smart card emulation, DMA based transmissions. But for now lets focus on standard USART communications we we could send and receive messages from terminal window.
STM32F100RB microcontroller in Discovery board has three USARTs (USART1, USART2 and USART3). Other higher level STM32 microcontrollers have even more. USART1 is connected to APB2 bus while other USART’s are located on APB1. Every USART has a two DMA channels allowing data transfer between memory and Rx/Tx. Each USART has ten interrupt sources and all are mapped to same NVIC channel. So it is up to code to find out what triggered an interrupt. This is done by identifying flag in status register. Why don’t we take a real example and see how things work.
For this we are going to program USART1 in our STM32VLDiscovery board. Discovery board only comes with naked pins that we have to connect to USART level converter like RS232 or USB. For this example we are going to use widely acceptable FT232RL based TTL to USB converter.
The FT232RL is a USB to serial UART interface with optional clock generator output. It’s the essential tools for establishing communication between PC and mostly MCU.
Image may be NSFW.
Clik here to view.
So we connect board pins to converter as follows:
STM32VLDiscovery PA9 to Rx of FT232RL board
STM32VLDiscovery PA10 to Tx of FT232RL board
STM32VLDiscovery 3.3V to VCC of FT232RL board
STM32VLDiscovery GND to GND of FT232RL board
Using STM32F10x_StdPeriph_Driver library programming task becomes very easy. Lets use our template from previous example. This time we are going to add couple more files to project called usart.c and usart.h. Here we are gonna to write USART initialization function and byte read and write routines. Lets start with Initialization:
voidUsart1Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
USART_ClockInitTypeDef USART_ClockInitStructure;
//enable bus clocks
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
//Set USART1 Tx (PA.09) as AF push-pull
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//Set USART1 Rx (PA.10) as input floating
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_ClockStructInit(&USART_ClockInitStructure);
USART_ClockInit(USART1, &USART_ClockInitStructure);
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No ;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
//Write USART1 parameters
USART_Init(USART1, &USART_InitStructure);
//Enable USART1
USART_Cmd(USART1, ENABLE);
}
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
Next task is to set up USART pins where Tx pin should behave as alternate function push-pull while Rx floating input. Once pins are set we need to take care of USART clock. As we are going to use standard set up we can use function helper that does this by setting default values:
USART_ClockStructInit(&USART_ClockInitStructure);
USART_ClockInit(USART1, &USART_ClockInitStructure);
void Usart1Put(uint8_t ch)
{
USART_SendData(USART1, (uint8_t) ch);
//Loop until the end of transmission
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
{
}
}
uint8_t Usart1Get(void){
while ( USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
return (uint8_t)USART_ReceiveData(USART1);
}
In main program we can call these functions to send and receive single bytes of data as follows:
#include "stm32f10x.h"
#include "usart.h"
int main(void)
{
Usart1Init();
Usart1Put('A');
Usart1Put('R');
Usart1Put('M');
while (1) { }
}
int _read(int file, char *ptr, int len) {
int n;
int num = 0;
switch (file) {
case STDIN_FILENO:
for (n = 0; n < len; n++) {
char c = Usart1Get();
*ptr++ = c;
num++;
}
break;
default:
errno = EBADF;
return -1;
}
return num;
}
int _write(int file, char *ptr, int len) {
int n;
switch (file) {
case STDOUT_FILENO: /*stdout*/
for (n = 0; n < len; n++) {
Usart1Put(*ptr++ & (uint16_t)0x01FF);
}
break;
case STDERR_FILENO: /* stderr */
for (n = 0; n < len; n++) {
Usart1Put(*ptr++ & (uint16_t)0x01FF);
}
break;
default:
errno = EBADF;
return -1;
}
return len;
}
After setting this we can send formatted strings and read any type of data by using stdio functions:
#include "stm32f10x.h"
#include "usart.h"
#include
int main(void)
{
char ch[30];
int32_t a1,a2;
Usart1Init();
printf("\r\n USART1 Test \r\n");
printf("Enter any text: ");
scanf("%s",ch);
printf("\r\nYou entered: ");
printf("%s\r\n",ch);
while (1)
{
printf("\r\nEnter first number: ");
scanf("%ld",&a1);
printf("%ld", a1);
printf("\r\nEnter second number: ");
scanf("%ld",&a2);
printf("%ld\r\n", a2);
printf("Sum: %ld + %ld = %ld\r\n",a1, a2, a1 + a2);
}
}
Image may be NSFW.
Clik here to view.
In the next part we will be dealing with interrupt based buffered communications.
The post Programming STM32 USART using GCC tools: Part 1 appeared first on Key to Smart.