Redirecting printf to UART on STM32F4-Discovery using Keil

Keywords: Embedded systems, ARM, STM32F4, UART, ITM, printf

Code Link: Source Code Github Link

The “C” printf is one of the most commonly used debug function/assistant used in DESKTOP applications. In embedded systems, the printf is not used frequently due to:

  • Larger Footprint
  • High CPU cycles consumptions

which indeed is a problem on memory space limited and relatively slower speed embedded systems. In such systems “Blinky Led” is the best alternative and most commonly used debug assistant BUT if printf is affordable on embedded board, it can provide much better assistance than “Blinky Led”.

Anyhow irrespective of printf pros and coins, we will discuss how it can be used on STM32F4-Discovery Microcontroller/kit platform using Keil. The Keilv5 is used with MDK5.

Keil provides Run-Time libraries to direct printf messages to:

  1. User defined Medium like UART, SPI, CAN etc.
  2. STLINK Debugger via ARM Instrumentation Trace Macrocell (ITM)
  3. None, Just stop processor to analyze system state.

In this tutorial we will focus on first method i.e. printf redirection to user defined Medium. The second method i.e. printf redirection to Stlink Debugger is described in the following tutorial.

For illustration purpose we will direct printf messages to USART-3 of STM32F4-Discovery board.

User defined Medium- printf-to-UART/USART:

In this method, the supplied characters of printf are redirected to user defined medium as defined by void stdout_putchar (int ch) function. The background working procedure is that the “C” printf formats the text as per supplied arguments and passes the formated string characters one by one to int fputc (int c, FILE * stream) character by character. The int fputc (int c, FILE * stream) simply redirect received character in its first argument to void stdout_putchar (int ch) or void stderr_putchar (int ch) function – Figure-1.

Figure-1: printf flow in Keil.

Now its upto void stdout_putchar (int ch) or void stderr_putchar (int ch) function implementation where the character needs to be sent.

NOTE: There is a way around of directing printf characters to UART. But to keep things simple, we will stick to default flow which is easy, portable and straight forward.

NOTE: Before we can redirect printf messages to UART, UART needs to configured properly for desired baudrate. Configuring UART is not in scope of this tutorial. We already have another tutorial which discusses how to configure and use UART on STM32F4-Discovery board (Link given bellow).

Following are steps to redirect printf messages to UART in Keil.

Steps:

1. Create a black project in for STM32F407VG (Microcontroller on STM32F4-Discovery board). Create a new main.c file with the simple main function as shown bellow.

#include <stm32f4xx.h>
#include <stdio.h>

// main function main.c
int main () {
	
	volatile int x = 0;
	
	/*
		configure DESIRED USART to which printf string will 
		be redirected. 
	*/
	init_usart3();
	
	for (;;) {
		
		/*
			Transmit string PB.10
		*/
		printf ("Test String redirection to UART\n");

		for (x = 0; x < 5000; x++);
	}
}

2. Click on Manage Run-Time Environment ()in Keil.

Click Compiler –> I/O –> STDIO –> check the enable check box and select “User” from drop down menu – Figure-2.

Figure-2: Keil run-time Environment Manager

a file with name retarget_io.c will be added automatically added to the project.

3. Initialize desired UART in main function or in separate function. For demonstration purpose we will use USART3 on STM32F407VG. All related USART3 initialization is done in a separate function static void init_usart3 (void).

static void init_usart3 (void) {

    /*
        enable clock to GPIOB
    */
    RCC->AHB1ENR |= (1u << 1);
	
    /*
        enable clock to USART3
    */
    RCC->APB1ENR |= (1U << 18);
	
    /*
        1-stop bit
    */
    USART3->CR2	&amp;=  ~(1u << 12);
    USART3->CR2	&amp;=  ~(1u << 13);
	
    /*
        9600 baudrate at 16Mhz
        B.R = f / 8 x (2 - OVER8) x USARTDIV
		
        B.R = 9600
        f = 16000000
        OVER8 = 0
		
        ==> USARTDIV 	= 104
		
        fraction = 0
        mantissa = 104
    */
	
    USART3->BRR = (104U << 4);
	
    /*
        enabble Transmission
    */
    USART3->CR1 |= (1U <<3);
	
    /*
        disable parity
    */
    USART3->CR1 &amp;= ~(1U << 10);
	
    /*
        1-start bit, 8-bits data, n-stop bits
    */
    USART3->CR1 &amp;= ~ (1U << 12);
	
	
    /********************************
		
     ENABLE GPIOB Pin.10 as USART Tx
			
    *********************************/

    /*
        setting alternate function for GPIOB.10
    */
    GPIOB->MODER |= (1U << 21);
	
    /* 
        medium speed 
    */
    GPIOB->OSPEEDR |= (1U << 20);
	
    /*
        pull up
    */
    GPIOB->PUPDR  |= (1U << 20);
	
    /*
        alternate function - 7 (USART-3 Tx)
    */
    GPIOB->AFR[1] |=  (0x7U << 8);
	
    /*
        finally enable USART3
    */
    USART3->CR1 |= (1U << 13);
}

4. Copy and past the following function to main.c. Remember to keep the scope “Global”.

int stdout_putchar (int ch) {
	
    USART3->DR = ch;
	
    /* wait until the transmission completes */
    while ((USART3->SR &amp; (1U << 6)) != (1U << 6));
	
    return 1;
}

5. That’s it. Compile it and burn to STM32F407VG flash. Connect USB-to-Serial to board. In our case as we have configured USART3 Tx line only so connect Rx line of USB-to-Serial cable to PB.10 of STM32F4-Discovery board. Open a serial window like Termite, Putty, Docklight etc. and set it to desired port (as shown in device manager for USB-to-Serial cable) and set the baudrate to 9600 (as per our USART3 configuration).
FINALLY RUN THE PROGRAM.

For demonstration, see the following video.

Video demonstration:

Click the full screen button for more clear view.

[1] – Reference manual-RM0090



23 thoughts on “Redirecting printf to UART on STM32F4-Discovery using Keil”

Leave a Reply

Your email address will not be published. Required fields are marked *