Tutorial 8: UART (Universal asynchronous receiver/transmitter)

UART (Universal asynchronous receiver/transmitter) one of the important topic in embedded programming. In this tutorial a simple uart program was implemented.

First create a project and include following libraries from repository.

  • CMSIS
  • RCC
  • GPIO
  • USART
  • MISC
  • Retargeted Printf

All the libraries and their functions are almost same for all the libraries except Retargeted Printf. Printf is a built-in functions in c programming language which used print a formatted text on screen. This printf functions has lot of features. UART messages also require almost all the features in prinf function. For simply saying requirement of UART functions are already implemented in prinf function. By retargeting what we do is, instead of printing on screen, we modify the library to send it via UART. This can be done simply by overriding the built-in function is stdio printf library.

Creating new library

Right click on include folder and select New file. Then give a name(uart) for the file and save it as .c file.

Creating New File

Creating New File

uart.c

#include <stm32f30x.h>
#include <stm32f30x_rcc.h>
#include <stm32f30x_gpio.h>
#include <stdio.h>
#include <string.h>
#include <stm32f30x_usart.h>
#include <stm32f30x_misc.h>

#define RX_BUFFER_LENGTH	40			//maximum number of characters to hold in the receive buffer

void UART4_Init(uint32_t speed);
void Delay(unsigned int);
void UART4_IRQHandler(void);

uint8_t rx_buffer[RX_BUFFER_LENGTH];	//used by the IRQ handler
uint8_t rx_counter = 0; 				//used by the IRQ handler
uint8_t uart_msg[RX_BUFFER_LENGTH];		//variable that contains the latest string received on the RX pin
uint8_t new_uart_msg = 0;				//flag variable to indicate if there is a new message to be serviced

void UART4_Init(uint32_t speed){

	USART_InitTypeDef USART_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	/* USARTx configured as follow:
				- BaudRate = speed parameter above
				- Word Length = 8 Bits
				- One Stop Bit
				- No parity
				- Hardware flow control disabled (RTS and CTS signals)
				- Receive and transmit enabled
	*/

	/* Enable GPIO clock */
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);

	/* Enable USART clock */
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);

	/* USART configuration */
	USART_InitStructure.USART_BaudRate = speed;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_Init(UART4, &USART_InitStructure);

	/* Configure USART Tx as alternate function push-pull */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_2;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init(GPIOC, &GPIO_InitStructure);

	/* Configure USART Rx as alternate function push-pull */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
	GPIO_Init(GPIOC, &GPIO_InitStructure);

	/* Connect PXx to USARTx_Tx */
	GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_5);

	/* Connect PXx to USARTx_Rx */
	GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_5);

	/* Enable USART */
	USART_Cmd(UART4, ENABLE);

	/* Enable the UART4 Receive interrupt: this interrupt is generated when the
    UART4 receive data register is not empty */
	USART_ITConfig(UART4, USART_IT_RXNE, ENABLE);

	/* Enable the USART4 Interrupt */
	NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}

void UART4_IRQHandler(void){
	int x;

  if(USART_GetITStatus(UART4, USART_IT_RXNE) != RESET)
  {
		/* Read one byte from the receive data register */
    rx_buffer[rx_counter] = USART_ReceiveData(UART4); //(USART_ReceiveData(UART4) & 0x7F);

		/* if the last character received is the NEWLINE ('\n') or LF ('\r') character OR if the RX_BUFFER_LENGTH (40) value has been reached ...*/
    if(rx_counter + 1 == RX_BUFFER_LENGTH || rx_buffer[rx_counter] == '\n' || rx_buffer[rx_counter] == '\r')
    {
      new_uart_msg = 1;
			for(x=0; x<= rx_counter; x++)	//copy each character in the rx_buffer to the uart_msg variable
				uart_msg[x] = rx_buffer[x];
			uart_msg[x] = '';			//terminate with NULL character

      memset(rx_buffer, 0, RX_BUFFER_LENGTH);		//clear rx_buffer
      rx_counter = 0;
    }
    else
    {
			rx_counter++;
    }
  }
}

 

Enter above code in the uart.c file.

Retargeting printf

When retargeted printf library include into project, it adds the printf.c file into project. Open that file and look for function which has header int fputc(int ch, FILE *f) then delete that function. Same function is implemented in uart.c library with retargeted uart features and it will override the existing function behavior with uart behavior. After that printf function can be used to send uart messages.

Finally enter the following code in main.c file to test the application.

#include <stm32f30x.h>
#include <stm32f30x_rcc.h>
#include <stm32f30x_gpio.h>
#include <stdio.h>
#include <string.h>
#include <stm32f30x_usart.h>
#include <stm32f30x_misc.h>

int main(void)
{
	uint8_t count=0;
	UART4_Init(115200);																						//initialize the UART4 module at 115200 baud

	printf("Engineering Physics!\n\n");
	printf("Department of Physics Physics!\n");
    while(1)
    {
    	
    }
}


void Delay(unsigned int n){
	unsigned int i =0;
	for ( i = 0; i < n; ++i) ;
}

Testing uart application

Tx Rx pin functions

Tx Rx pin functions

According to datasheet PC10 and PC11 has alternative function of UART4_TX and UART4_RX respectively. Connect a usb ttl shown in figure below and connect pins to suitable connection and see the result.

USB TTL Module

USB TTL Module

Result can be observe using termite (Serial Communication terminal).

Termite serial terminal

Termite serial terminal

Device uart settings must match software serial settings. Otherwise it will read it wrong.

Termite serial settings

Termite serial settings