Use ITM mechanism to debug stm32 microcontroller, implement printf and scanf.
1. Introduction to ITM
ITM mechanism is a debugging mechanism, 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. Here, printf/scanf are standard library functions. Using these functions of the operating system, we can debug the program very conveniently. On embedded devices (such as 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 to use scanf to input?
We all know that embedded devices generally use emulators, such as the common Jlink/ulink, which can realize burning, single-stepping, breakpoints, viewing variables, etc. The emulator connects the PC and the microcontroller. Smart designers are considering whether it is possible to use an 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 the program is burned into the MCU, the emulator connects the MCU to the PC, and the online debugging starts, the 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 realize its own output/input. This method is undoubtedly convenient for program developers to debug.
There are many ways to implement this mechanism, the more famous ones are semihosting (semihosting mechanism) and ITM mechanism.
ITM is a new generation of debugging mechanism launched by ARM after the launch of semihosting. Now let's try this debugging method.
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 the SWD interface and the connection of the SWO line. The general four-wire SWD method (VCC SDCLK, SDIO, GND) is not acceptable. The standard 20-pin JTAG interface is OK. You just need to set up the SWD interface in MDK.
2.2 Add redirection file
Save the following file as any C file and add it to the project. Here is a brief explanation of this file. You should know that our program is running on the microcontroller. 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, then you only need to re-implement the fputc function and output it to the LCD, so when you call printf, it will be output to the LCD. This mechanism is the so-called 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 */
/******************************************************************************/
// <<< Use Configuration Wizard in Context Menu >>> //
/******************************************************************************/
/* 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) {
//
Debug MCU Configuration //
DBG_SLEEP Debug Sleep Mode //
DBG_STOP Debug Stop Mode //
DBG_STANDBY Debug Standby Mode //
TRACE_IOEN Trace I/O Enable //
TRACE_MODE Trace Mode // <0=> Asynchronous
// <1=> Synchronous: TRACEDATA Size 1
// <2=> Synchronous: TRACEDATA Size 2
// <3=> Synchronous: TRACEDATA Size 4
//
DBG_IWDG_STOP Independant Watchdog Stopped when Core is halted //
DBG_WWDG_STOP Window Watchdog Stopped when Core is halted //
DBG_TIM1_STOP Timer 1 Stopped when Core is halted //
DBG_TIM2_STOP Timer 2 Stopped when Core is halted //
DBG_TIM3_STOP Timer 3 Stopped when Core is halted //
DBG_TIM4_STOP Timer 4 Stopped when Core is halted //
DBG_CAN_STOP CAN Stopped when Core is halted //
_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.
#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 Guide
Previous article:The USART interrupt of STM32 is in an infinite loop, resulting in a system crash.
Next article:Doubts in STM32 timer output comparison mode
Recommended ReadingLatest update time:2024-11-16 15:00
- Popular Resources
- Popular amplifiers
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- About the uboot compilation problem of am335x
- Here is the motor drive information on the national competition list
- RC snubber circuit design principles
- EEWORLD University ---- Linux driver tutorial (by itop4412)
- DSP 28335 program automatic upgrade solution
- What is the IoT edge? Where is the IoT edge?
- ISO13400 Ethernet Diagnostic Protocol
- The 4th volume of Mr. Yang's new book "New Concept Analog Circuits" is online! Hurry up if you need it~
- Design an electronic meter that can measure 0-1.5A current and automatically switch ranges
- Analysis of embedded C language pointers