2021-08-02 10:47 AM
Hello!
As the title says, I haven't managed to get the printf function to work on my STM32H7 MCU. I am using the Nucleo-H745ZI-Q with STM32Cube MX and Keil. Here is the code I'm using:
#include "stdio.h"
/* USER CODE BEGIN 0 */
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/* USER CODE END 0 */
/* USER CODE BEGIN 4 */
/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here */
/* e.g. write a character to the USART3 and Loop until the end of transmission */
HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/* USER CODE END 4 */
When running the code in debug mode, I keep getting stuck on this line in the disassembly:
0x080006XX BEAB BKPT 0xAB
After looking it up online, the most common answer I found was that I needed to add a retarget.c and retarget.h to my project. I tried looking for those files (specific for the H7) online but came up empty-handed. I think it is also worth mentioning that when I comment the line with the printf command, the rest of the code works fine.
I have used the exact same code (except with USART 2 instead of 3) on a Nucleo F446RE board and it worked perfectly fine. I have also read the printf via UART section in the STM32 debug application note (https://www.st.com/resource/en/application_note/dm00354244-stm32-microcontroller-debug-toolbox-stmicroelectronics.pdf) and can't find what I'm missing. Finally, I also tried to find an example code in the STM32H745 github repo (https://github.com/STMicroelectronics/STM32CubeH7/tree/master/Projects/NUCLEO-H745ZI-Q) but there wasn't one for the printf.
Any help would be greatly appreciated!
2021-08-02 11:45 AM
//****************************************************************************
// Hosting of stdio functionality through USART
//****************************************************************************
/* Implementation of putchar (also used by printf function to output data) */
int SendChar(int ch) /* Write character to Serial Port */
{
ITM_SendChar(ch); // From core_cm4.c (Via SWO/SWV)
HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, 0xFFFF);
return(ch);
}
//****************************************************************************
#include <rt_misc.h>
#ifdef __ARM_CC // Only for v5 compiler, skip with v6
#pragma import(__use_no_semihosting_swi)
struct __FILE { int handle; /* Add whatever you need here */ };
FILE __stdout;
FILE __stdin;
#endif // _ARM_CC
int fputc(int ch, FILE *f) { return (SendChar(ch)); }
int ferror(FILE *f)
{
/* Your implementation of ferror */
return EOF;
}
void _ttywrch(int ch) { SendChar(ch); }
void _sys_exit(int return_code)
{
label: goto label; /* endless loop */
}
//******************************************************************************
2021-08-02 03:39 PM
> BKPT 0xAB
IIRC this means that you need to implement _write for GNU & libc_nano toolchain like CubeIDE.
The Cube should have generated syscalls.c file for you.
2021-08-02 04:18 PM
In Keil it relates to the "Semi-Hosting" interface, ie where the debugger spoofs Target side interfaces on the Host, say file access, or stdio type stuff.
2021-08-03 12:52 PM
Thank you for your reply! If I understand correctly, I would have to put the SendChar function in the User Code Begin 4 section in the main.c files for both cores. Where would the bottom portion of the code in your reply go? In a separate file or somewhere else in the main.c file? Do I need to put it in the main file for both cores?
2021-08-03 01:29 PM
I would generally put this at the end of main.c for the core(s) I want to debug. Sharing a single USART might work, content might interleave.
Each of the H7 cores has it's own debug logic, the SWV data has to go through a funnel. Not played with it in a while.
It would take some time to come up with a thoroughly tested example, but the BKPT issue you have is due to semi-hosting software interrupt code.
2021-08-03 01:41 PM
Alright! Thank you so much for your help, I really appreciate it :)
2021-08-24 01:42 PM
I forgot about this post for a while, but I just thought I would share what I did to solve my problem!
The first thing I did was switch from Keil to STM32CubeIDE. I think the root of my problem was that I wasn't generating the code properly in CubeMX for Keil. Here are the main reasons why I think that was the case:
I'm by no means an expert on STM32 MCUs, so it was probably a user error on my part.
Now onto my solution for the printf:
I found this video on YouTube that was extremely helpful in setting everything up: https://youtu.be/jI1k6p-fduE. Once I was able to flash my code onto both cores, I simply followed the instructions on p. 70-71 of the debug application note (https://www.st.com/resource/en/application_note/dm00354244-stm32-microcontroller-debug-toolbox-stmicroelectronics.pdf). Here is my final code:
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */
.
.
.
/* USER CODE BEGIN 4 */
/*
* Function: putchar
* Description:
* Function to enable printf
* To enable float print:
* Project -> Properties -> C/C++ Build -> Settings
* Tool Settings -> MCU GCC Linker -> Miscellaneous -> Other flags
* Add flag: -u _printf_float
*/
int __io_putchar(int ch) {
HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
Hope this helps anyone reading this in the future!