STM32 + HAL + FreeRTOS Part II: UART

Previously we started a blinky project on STM32F429-Discovery board with HAL and FreeRTOS. I will continue to build up on it with Universal Asynchronous Receiver-Transmitter or UART.

If you remember well, during code generation, I instructed to leave USART1 in the list of peripherals to initialize in generated code. This was done so that we wouldn't have to figure out how to initialize it and provide it with clocks manually.

So STM32CubeMx generated usart.c/.h files for us, which contain USART1 initialization function, which defines UART parameters and two functions, which HAL expects user code to implement - HAL_UART_MspInit() and HAL_UART_MspDeInit() for setting up and teardown of hardware resources required for peripheral.

With this setup, UART should already be working and you could try to transmit data by using HAL_UART_Transmit(&huart1, &charbuffer, size, timeout):

 HAL_UART_Transmit(&huart1, &charbuffer, size, timeout)

But most of the time we don't want to deal with bytes and buffers, we want a convenient printf() function, which does all the formatting for us. So what we have to do, is called retargeting printf(). Meaning, that we tell it to send to USART1 as a default console. To accomplish that, all we have to do is (re)implement __io_putchar() and _write() functions:
#include "usart.h"

/* (Re)Define stdio functionality, so printf would output to USART1 */
int __io_putchar(int ch) {
 uint8_t c[1];
 c[0] = ch & 0x00FF;
 HAL_UART_Transmit(&huart1, &c[0], 1, 10);
 return ch;
}

int _write(int file,char *ptr, int len) {
 int DataIdx;
 for(DataIdx= 0; DataIdx< len; DataIdx++) {
  __io_putchar(*ptr++);
 }
 return len;
}

We shall call it printf_retarget.c. We'll make a companion header file, where we'll add include guards and prototypes:
#ifndef INC_PRINTF_RETARGET_H_

int __io_putchar(int ch);
int _write(int file,char *ptr, int len);

#define INC_PRINTF_RETARGET_H_

#endif /* INC_PRINTF_RETARGET_H_ */

For this bit of code to be used, we have to include it after usart.c in C_SOURCES definition in the Makefile and in main.c we can replace '#include "usart.h"' with '#include "printf_retarget.h"', for usart.h becomes a nested include.

And now we can use printf() function to our own pleasure. Let us add some output to the startup sequence:
..
  MX_USART1_UART_Init();

  printf("System configured!\r\n");

  /* Call init function for freertos objects (in freertos.c) */
  MX_FREERTOS_Init();
..

and to our task as well, so it would inform us, that it is turning the LED on:
void StartDefaultTask(void const * argument) {

  for(;;) {
   osDelay(500);
   HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_14);
   if(HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_13) == GPIO_PIN_RESET) {
    printf("Blink!\r\n");
   }
  }
}

Now, if we connect USART to our PC (I use FTDI232 for that. STM32 I/O pins are 5V tolerant, meaning that the serial converter does not necessarily have to be running in 3V3 mode) by connecting pins PA09 RX to PC TX, PA10 TX to PC RX, we can get our printouts:
It speaks!

The serial port settings are defined in usart.c:
  • 115200 baud
  • 8bit word length, 1 stop bit
  • Parity: none
  • Hardware control: none
That would be it for now. As before, sources are available on GitHub, notes and comments are welcome.

Next up: Part III: SPI in blocking mode

No comments:

Post a Comment