Building Board Support Package (BSP) for STM32F411-Nucleo64 Part9: Adding debugging output over SWO

In this ninth part of board support package (BSP), we shall add the debugging output over Serial Wire Output (SWO) to display different level of debugging.

In this guide, we shall cover the following:

  • Developing the header file.
  • Developing the source file.
  • Enabling SWV in STM32CubeIDE.
  • Results.

1. Developing the header file:

Before heading into developing the header file, please refer to this guide about SWO and what is it.

We start off by creating new header file with name of bsp_debug.h file.

Within the header file:

Include these two header file:

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

Declare the following functions:

void log_error(char *p);
void log_info(char *p);
void log_debug(char *p);

All the functions will take character pointer and return nothing

Hence, the entire header file as following:

#ifndef BSP_DEBUG_H_
#define BSP_DEBUG_H_

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

void log_error(char *p);
void log_info(char *p);
void log_debug(char *p);

#endif /* BSP_DEBUG_H_ */

Thats all for the header file

2. Developing the source file

Create new source file with name of bsp_debug.c.

Within the source file, include the following header file:

#include "bsp_debug.h"

Declare this define statement to enable disable all those debugging output with single line modification:

#define DEBUG 1

We shall redefine the printf state to another function as following:

#if DEBUG
#define printk(p) printf(p)
#else
#define printk(p)
#endif

If the debug is enabled by setting the value to 1, printk will act as printf. If not, printk will point to nothing, hence no memory will be used and disabled.

Now, we shall retarget the printf to use SWO as following:

int __io_putchar(int ch)
{
	 ITM_SendChar(ch);
	return ch;
}

For log_error:

void log_error(char *p)
{

	printk("log Error: ");
	printk((char*)p);
	printk("\r\n");
}

For log_info:

void log_info(char *p)
{

	printk("log info: ");
	printk((char*)p);
	printk("\r\n");
}

For log_debug:

void log_debug(char *p)
{

	printk("log debug: ");
	printk((char*)p);
	printk("\r\n");
}

Hence, the entire source code file as following:

#include "bsp_debug.h"

#define DEBUG 1


#if DEBUG
#define printk(p) printf(p)
#else
#define printk(p)
#endif


int __io_putchar(int ch)
{
	 ITM_SendChar(ch);
	return ch;
}


void log_error(char *p)
{

	printk("log Error: ");
	printk((char*)p);
	printk("\r\n");
}

void log_info(char *p)
{

	printk("log info: ");
	printk((char*)p);
	printk("\r\n");
}

void log_debug(char *p)
{

	printk("log debug: ");
	printk((char*)p);
	printk("\r\n");
}

3. Enabling SWV in STM32CubeIDE:

Please follow the instruction in this video for enabling SWV in STM32CubeIDE:

4. Results:

In main.c:

#include "bsp.h"
#include "uart_bsp.h"
#include "exti_bsp.h"
#include "bsp_debug.h"

void clock_config(void);

int main()
{

	clock_config();

	BSP_Ticks_Init(100000000);

	while(1)
	{
		log_info("hello from stm32f411");
		BSP_Delay(100);

	}
}

void clock_config(void)
{
	Clock_Config_Typedef clockConfig;

	clockConfig.PLL_M= 4;
	clockConfig.PLL_N= 200;
	clockConfig.PLL_P= 4;

	clockConfig.AHB1Prescaler=AHB1_Prescaler1;
	clockConfig.APB1Prescaler=APB1_Prescaler2;
	clockConfig.APB2Prescaler=APB2_Prescaler1;

	clockConfig.clockSourc=External_Oscillator;
	clockConfig.flash_latency= Three_wait_state;

	Clock_Configuration(&clockConfig);
}

void uart2_interrupt_handler(void)
{
	if (USART2->SR & USART_SR_RXNE) /*Check if the interrupt source is RXNE*/
	{
		(void)USART2->DR;			/*Read the DR register to clear everything*/

		GPIO_TogglePin(GPIOA,&LED); /*Toggle the LED to for character reception*/

	}

}

Note: Change the core frequency in debug settings from 16 to 100 in order to display anything since the BSP will run STM32F411 at 100MHz.

When you run the code, you should get the following:

Happy coding 🙂

Add Comment

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