Use ITM mechanism to debug stm32 microcontroller and implement printf and scanf.
1. Introduction to ITM
The ITM mechanism is a debugging mechanism and a new generation of debugging method. Before this, there was a more famous debugging method called semihosting.
Anyone who has written C language on a PC knows that printf can output to the console and scanf can get input from the console. The printf/scanf functions here are standard library functions. Using these functions of the operating system, we can easily debug the program. On embedded devices (such as the STM32 microcontroller platform), development tools (such as MDK/IAR) also provide standard library functions, and naturally also provide printf/scanf functions. So can these functions be used? The question is, where does printf output? And in most cases, there is no keyboard, so how can scanf be used to input?
As we all know, embedded devices generally use emulators, such as the common Jlink/ulink, which can achieve burning, single-stepping, breakpoints, variable viewing, etc. The emulator connects the PC and the microcontroller. Smart designers are considering whether it is possible to use the emulator to enable the microcontroller to use the PC screen and PC keyboard to achieve printf output and scanf key acquisition.
In other words, the following hello, world program
#include
int main()
{
//Hardware initialization
//....
printf("hello, world");
for(;;);
}
After this program is burned into the microcontroller, the emulator connects the microcontroller to the PC and starts online debugging. Then, this program will output "Hello, world" to the PC and display it in a window of the development tool (MDK/IAR, etc.).
This is equivalent to the MCU using the display/input devices of the PC to achieve its own output/input. This method can undoubtedly facilitate debugging for program developers.
There are many ways to implement this mechanism, the most famous ones are semihosting and ITM.
ITM is a new generation debugging mechanism launched by ARM after the launch of semihosting. Now let's try debugging in this way.
2. STM32 uses ITM to debug
MCU: stm32f207VG
Emulator: Jlink V8
IDE: MDK4.50
2.1 Hardware connection
The ITM mechanism requires the use of a SWD interface and the SWO line needs to be connected. The general four-wire SWD method (VCC SDCLK, SDIO, GND) is not acceptable. The standard 20-pin JTAG interface is acceptable. You only need to set the SWD interface in MDK.
2.2 Add a redirection file
Save the following file as any C file and add it to the project. Here is a brief description of this file. We should know that our program is running on the microcontroller, so why can printf be output to the MDK window? This is because printf in the standard library actually calls fputc to achieve output, so we need to write an fputc function ourselves. This function will use the registers provided by ITM (similar to USART) to achieve data transmission. The emulator will receive this data and send it to the PC.
In fact, if your microcontroller is connected to an LCD, you only need to re-implement the fputc function and output to the LCD, then when you call printf, the output will be on the LCD. This mechanism is called the redirection mechanism.
#include
#define ITM_Port8(n) (*((volatile unsigned char *)(0xE0000000+4*n)))
#define ITM_Port16(n) (*((volatile unsigned short*)(0xE0000000+4*n)))
#define ITM_Port32(n) (*((volatile unsigned long *)(0xE0000000+4*n)))
#define DEMCR (*((volatile unsigned long *)(0xE000EDFC)))
#define TRCENA 0x01000000
struct __FILE { int handle; /* Add whatever you need here */ };
FILE __stdout;
FILE __stdin;
int fputc(int ch, FILE *f)
{
if (DEMCR & TRCENA)
{
while (ITM_Port32(0) == 0);
ITM_Port8(0) = ch;
}
return(ch);
}
2.2 Configure JLINK's initialization configuration file.
Place the following file under your project and give it any name. Here I named it STM32DBG.ini
/******************************************************************************/
/* STM32DBG.INI: STM32 Debugger Initialization File */
/******************************************************************************/
// <<
/******************************************************************************/
/* This file is part of the uVision/ARM development tools. */
/* Copyright (c) 2005-2007 Keil Software. All rights reserved. */
/* This software may only be used under the terms of a valid, current, */
/* end user licence from KEIL for a compatible version of KEIL software */
/* development tools. Nothing else gives you the right to use this software. */
/******************************************************************************/
FUNC void DebugSetup (void) {
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
_WDWORD(0xE0042004, 0x00000027); // DBGMCU_CR
_WDWORD(0xE000ED08, 0x20000000); // Setup Vector Table Offset Register
}
DebugSetup(); // Debugger Setup
Here is a brief explanation of this file,
_WDWORD(0xE0042004, 0x00000027); // DBGMCU_CR
This sentence means that you want to write 0x000000027 to the address 0xE0042004. The meaning of each bit of this register is explained in detail in the comments. 0x27 means
BIT0 DBG_SLEEP
BIT1 DBG_STOP
BIT2 DBG_STANDBY
BIT5 TRACE_IOEN
Note that to use the ITM mechanism, BIT5 must be turned on.
Open the MDK project and modify it according to the figure below.
2.3 Configuration of JLINK in MDK
Note two points in the figure below:
1). The CoreClock here is 120M, because the author uses the stm32F207VG chip, and the clock is configured to 120M, so fill in 120M here. If you use stm32F10x, the clock is configured to 72M, then you need to fill in 72M here. That is, it needs to be consistent with the actual situation.
2). Finally, be sure to check 0 and remove the check marks on other bits. It is best to keep it consistent with this figure, except for CoreClock.
2.4 Burn the program and start debugging. As you can see, I inserted a printf statement in the program source code, and then you can see the output of the program according to the figure below.
3. Comprehensive version uses scanf and printf
3.1 Add retarget file
Save the following code as retarget.c and add it to the project.
[cpp] view plain copy
#pragma import(__use_no_semihosting_swi)
struct __FILE { int handle; /* Add whatever you need here */ };
FILE __stdout;
FILE __stdin;
int fputc(int ch, FILE *f)
{
return ITM_SendChar(ch);
}
volatile int32_t ITM_RxBuffer;
int fgetc(FILE *f)
{
while (ITM_CheckChar() != 1) __NOP();
return (ITM_ReceiveChar());
}
int ferror(FILE *f)
{
/* Your implementation of ferror */
return EOF;
}
void _ttywrch(int c)
{
fputc(c, 0);
}
int __backspace()
{
return 0;
}
void _sys_exit(int return_code)
{
label:
goto label; /* endless loop */
}
3.2 Compile and run
Compile, burn, run, open the Debug (printf) viewer, and you can see the input, see the figure below
Here are some explanations about the retarget.c file.
1). The above code is actually modified from X:\Keil\ARM\Startup\Retarget.c. There are two functions that scanf depends on, fgetc and __backspace, which need to be implemented. If the __backespace function is missing, scanf cannot get input from the Debug Viewer Dialog window. In addition, the code provided above is just a demo to demonstrate the effect. It should be processed more perfectly when used in production. See reference [1].
2). The functions ITM_SendChar, ITM_CheckChar, and ITM_ReceiveChar are in the library file CMSIS\Include\core_cm3.h.
3) To view the symbolic reference relationship of the function, you can generate a detailed map file. Add the --verbose --list rtt.map option to the command line to generate a file named rtt.map.
4. Combining ITM and RTT (to be implemented)
grissiom wrote:
I suddenly thought that maybe we can make this semihost into a device, and then rt_console_set_device("semi") can directly use semihost to do finsh/rt_kprintf... I don't know if it is feasible...
prife: I don't know whether ITM reception supports interrupts. Currently, the reception of characters uses polling. It only makes sense if it is an interrupt. In this way, the ITM device can be made into an rtt device, and finsh can run in the Debug printf Viewer window. In the future, you only need to connect a jtag/SWD port to debug, and you don't need to connect a serial port line.
References
[1] MDK help. Indirect semihosting C library function dependencies
[2] MDK help ARM Development Tools.
Debugger Adapter User's Guides
J-Link/J-Trace User's Guide
Libraries and Floating Point Support Referencee
Libraries and Floating Point Support Guide
Linker Reference Guid
Previous article:STM32F103RC restarts repeatedly after power-on
Next article:Experience in tuning the serial port ISP of STM32-eagleCom
- Popular Resources
- Popular amplifiers
- Learn ARM development(16)
- Learn ARM development(17)
- Learn ARM development(18)
- Embedded system debugging simulation tool
- A small question that has been bothering me recently has finally been solved~~
- Learn ARM development (1)
- Learn ARM development (2)
- Learn ARM development (4)
- Learn ARM development (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- Do you know all the various motors commonly used in automotive electronics?
- What are the functions of the Internet of Vehicles? What are the uses and benefits of the Internet of Vehicles?
- Power Inverter - A critical safety system for electric vehicles
- Analysis of the information security mechanism of AUTOSAR, the automotive embedded software framework
- Brief Analysis of Automotive Ethernet Test Content and Test Methods
- How haptic technology can enhance driving safety
- Let’s talk about the “Three Musketeers” of radar in autonomous driving
- Why software-defined vehicles transform cars from tools into living spaces
- How Lucid is overtaking Tesla with smaller motors
- Wi-Fi 8 specification is on the way: 2.4/5/6GHz triple-band operation
- Disable AD auto-start JLink
- Seeking guidance - stc microcontroller remote upgrade program
- Problems with creating sheet symbols for multi-page schematics
- Zigbee Z-Stack 3.0.1 Modify channels using broadcasting
- The STM32 FFT library calculates the amplitude normally, but the phase is different each time. Has anyone encountered this problem?
- EEWORLD University----UCD3138 Analog Front End (AFE) Module
- "Show goods" to come to a wave of commonly used development boards
- Measurement of the phase difference between a sine wave and a square wave
- [Sipeed LicheeRV 86 Panel Review] - 6 waft-ui component tests (3)
- Hardware System Engineer's Handbook