Setting up SWV printf on a Nucleo STM32 board - debugging

I am developping a Firmware on various STM32L4 Nucleo boards with Atollic Truestudio IDE (basically Eclipse). Until now I was using printf through UART, thanks to the Virtual COM port.
I want to migrate to printf using STM32 ITM.
More precisely I work on Nucleo-L4A6ZG. Debug is through a gdb server.
On Atollic I modified my Debug Configuration to enable SWV with a core clock of 80MHz. I've modified my startup script as described in STM32L4 reference manual as follows. I'm not sure it is necessary since TrueStudio/Eclipse allows to setup SWV from the GUI but seems easier this way:
# Set character encoding
set host-charset CP1252
set target-charset CP1252
# Reset to known state
monitor reset
# Load the program executable
load
# Reset the chip to get to a known state. Remove "monitor reset" command
# if the code is not located at default address and does not run by reset.
monitor reset
# Enable Debug connection in low power modes (DBGMCU->CR) + TPIU for SWV
set *0xE0042004 = (*0xE0042004) | 0x67
# Write 0xC5ACCE55 to the ITM Lock Access Register to unlock the write access to the ITM registers
set *0xE0000FB0 =0xC5ACCE55
# Write 0x00010005 to the ITM Trace Control Register to enable the ITM with Synchronous enabled and an ATB ID different from 0x00
set *0xE0000E80= 0x00010005
# Write 0x1 to the ITM Trace Enable Register to enable the Stimulus Port 0
set *0xE0000E00= (*0xE0000E00) | 0x1
#write 1 to ITM trace privilege register to unmask Stimulus ports 7:0
set *0xE0000E40= (*0xE0000E40) | 0x1
# Set a breakpoint at main().
tbreak main
# Run to the breakpoint.
continue
I've modified my _write function as follows:
static inline unsigned long ITM_SendChar (unsigned long ch)
{
if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */
((ITM->TER & 1UL ) != 0UL) ) /* ITM Port #0 enabled */
{
while (ITM->PORT[0U].u32 == 0UL)
{
__asm("nop");
}
ITM->PORT[0U].u8 = (uint8_t)ch;
}
return (ch);
}
int _write(int file, char *ptr, int len)
{
//return usart_write(platform_get_console(), (u8 *)ptr, len);
int i=0;
for(i=0 ; i<len ; i++)
ITM_SendChar((*ptr++));
return len;
}
Debugging step by step I see that I get at line ITM->PORT[0U].u8 = (uint8_t)ch;
Finally I start the trace in the SWV console in the IDE but I get no output.
Any idea what I am missing ? What about the core clock of the SWV ? I'm not sure what it corresponds to.

I faced a similar situation on my Nucleo-F103RB. What got this working was selecting "Trace Asynchronous" debug option on CubeMX and not "Serial Wire". The trace asynchronous debug dedicates the PB3 pin as a SWO pin.
Then setup the debug configuration as follows:
Project debug configuration to enable Serial Wire Viewer (SWV)
Also, I'd defined the write function inside of the main.c file itself, changing the definition in the syscalls.c wouldn't work.
And finally when debugging the project, under the "Serial Wire Viewer settings" only enable (check) port 0 on ITM Stimulus Ports, like so:
Serial Wire Viewer settings in Debug perpective
One thing I noted when I had enabled the prescaler for timestamps and some trace events, the trace output would not show quite a few trace logs.

Anyone else finding this - The Nucleo-32 line of Nucleo development boards inexplicably DO NOT have the SWO pin routed to the MCU. The SWO pin is necessary for all the SWV features, so it will not work by design. The higher pin-count Nucleo boards seem to have it routed.
See for yourself:
https://www.st.com/resource/en/user_manual/dm00231744-stm32-nucleo32-boards-mb1180-stmicroelectronics.pdf (Nucleo-32)
https://www.st.com/resource/en/user_manual/dm00105823-stm32-nucleo-64-boards-mb1136-stmicroelectronics.pdf (Nucleo-64)

Small-factor Nucleo-32 pin boards generally do not support SWO/SWV but there is one exception: Nucleo-STM32G431KB. As of September 2021 this is probably the only small-factor Nucleo-32 pin, quite powerful board supporting ST-LINK V3 and SWO. See MB1430 schematic.
Although my response is loosely related to the original question pertaining to the Nucleo-L4A6ZG (144 pin large-factor), it may help someone finding this thread.

Just to mention that the ITM printf works perfectly on Keil IDE. Nothing particular to setup, just implement the ITM_SendChar function as showed in my first post and open the debug printf window.

Related

SWV in STM32F302 - printf() with different characters

I found some answers that didn't solve my issue for STM32F302.
I configured the debug run as follows, to printf() in the SWV ITM Data Console:
IMG-Debug_Config
I implemented the _write function as follows:
int _write(int file, char *ptr, int len)
{
int DataIdx;
for (DataIdx = 0; DataIdx < len; DataIdx++)
{
ITM_SendChar((*ptr++));
}
return len;
}
And tried to setup the sys clock for "Asynchronous Trace" and "Serial Wire", none worked and I keep getting the same output (SWV Graph does not work either):
IMG-SWV_Output
Any suggestion about this issue? I just want to debug the variable to make sure I'm getting the correct measurement.
PS. Just a brief of my project: An ADC for a light sensor. I need to generate a graph from a laser sample measurement. Make this measurement with the STM32 and a photodiode, finish the measurement and send the .csv or .txt from USB to a computer to analyse the data.
I found what my problem was:
My "Core Clock (MHz)", in the debug settings, was wrong and that's why my SWV was not working properly
If no SWV data - you need to connect the SWO pin to ST-LINKV2. The SWV data transmission is on the SWO pin. On my STM32F3DISCOVERY, the SB10 was not soldered, SB10 connecting the PB3 SWO pin to the T_SWO debugger net. After soldering SB10 SWV work perfectly.

How to debug a flash program on target ARM MCU with gdb

I am trying to debug a ARM flash program on target MCU using gdb
I am setting up the gdbserver on target system (cortex-m7) with jlinkgdbserver. And I have a elf ready for debug.
For the first time, it is OK for me do debug with the following
> arm-none-eabi-gdb flash_program.elf
(gdb)> target remote localhost:2331 # connect to gdb server on target
(gdb)> load # since it is a flash program, jlink will flash the program
# target is reset to elf entry point
(gdb)> .... (debugging begins)
However, when debug goes to some place, and I want to debug from the entry point again, the way I figured out is do flashing again
(gdb)> Ctrl+D # disconnect the gdbserver
> arm-none-eabi-gdb flash_program.elf
(gdb)> target remote localhost:2331
(gdb)> load
(gdb)> .... (debugging from start again)
So this seems a bit redundant, also it erase and program the same flash area again and again, I am afraid I will end up damaging the storage through my debugging.
The flash program has already been burned into the medium, I simply want to let the target to reset itself and run from entry point again. But I tried things like monitor reset and run. But the target M7 both can't start from beginning again.
Is there any other gdb command that I can try?
I used an STM32F103C8T6 for providing an answer, but you will just have to replace its ROM base address (0x20000000) by the one your Cortex-M7 uses: In my case, I loaded the initial value for the stack pointer from 0x20000000, and the initial value for the program counter from 0x20000000+4.
The program to be debugged was stm32f103c8t6.elf, was already flashed and did contain the debug symbols.
arm-none-eabi-gdb
target remote localhost:2331
0x20000480 in ?? ()
(gdb) monitor halt
(gdb) monitor reset 0
Resets core & peripherals via SYSRESETREQ & VECTRESET bit.
(gdb) monitor reset 1
Resets the core only, not peripherals.
(gdb) monitor reset 2
Resets core & peripherals using RESET pin.
(gdb) symbol-file stm32f103c8t6.elf
Reading symbols from stm32f103c8t6.elf...
(gdb) set $sp = *0x20000000
(gdb) set $pc = *0x20000004
(gdb) stepi
0x200003c2 121 {
(gdb)
0x200003c4 121 {
(gdb) stepi
122 SystemInit(); /* CMSIS System Initialization */
(gdb)
SystemInit () at /opt/arm/ARM.CMSIS.5.6.0//Device/ARM/ARMCM3/Source/system_ARMCM3.c:61
61 {
(gdb)
Depending on the type of reset strategy you want to use, you may have to explicit it in the monitor reset command:
As explained in the Segger documentation and this great article, you can use strategy number 0, 1 or 2:
# Normal
monitor reset
monitor reset 0
# Core
monitor reset 1
# ResetPin
monitor reset 2
My understanding is that being able to use strategy #2 depends on how your RESET pin was wired, i.e. if it is pulled-down or not on your board.
Disclaimer: I am a software person, and all interpretation errors related to hardware-related questions are mine...
gdb command load will flash the image, provided that you have not setup the link address specially.
You have two option to survive:
setup the link address / adjust the linker script, so the program will be totally in RAM. Or
Keep the address not changed, but each time after code change & compile, use load once only (to make the flash being programmed), then later use symbol-file command to load only symbol.

Embedded C, Bootloader configuration for PIC32MX795F512L

In MPLAB, I need to use bootloader for PIC32MX795F512L. I am able to program boot section into kseg boot memory till 0x8fc00000 and application code into kseg0_program_mem at 0x9d000000. I can jump from bootloader to application using jump to addr command but I am facing problem while jumping from application to bootloader. I have tried with jump to addr (bootloader address) but it won't work. Please assist me
Just use a reset command, it will set you back to the processor start address. Check the POR bits for a SW reset to see if you caused the reset or if the board was just powered on.
I found this in one of the many pdf's for my PIC32MX270, I believe it's consistent for the whole PIC32MX family:
/* The following code illustrates a software Reset */
// assume interrupts are disabled
// assume the DMA controller is suspended
// assume the device is locked
/* perform a system unlock sequence */
// starting critical sequence
SYSKEY = 0x00000000; //write invalid key to force lock
SYSKEY = 0xAA996655; //write key1 to SYSKEY
SYSKEY = 0x556699AA; //write key2 to SYSKEY
// OSCCON is now unlocked
/* set SWRST bit to arm reset */
RSWRSTSET = 1;
/* read RSWRST register to trigger reset */
_excep_code = RSWRST;
/* prevent any unwanted code execution until reset occurs*/
while(1);
The while(1) will also lock up the uC so that the watchdog should reset the device if all else fails. I've got this code in my exception handler too (system_exceptions.c if you are using Harmony), that way when something goes wonky (DMA disaster or you try to sprintf(foo_string, "%f", NAN)), the device will reset instead of becoming a paperweight.

I want MPLAB to reset and continue running after a software RESET instruction in debug mode

When running Release code, when the MicroChip PIC code program executes a RESET instructions, the processor is reset, it is in a well defined state, and execution starts from the beginning.
When running in the Debug mode, MPLAB halts completely; I must manually command it to run again. I want it instead to behave the same as the Release mode: reset and start execution from the beginning.
I tried replacing the RESET instruction with a GOTO 0, instruction, but the PIC processor is in a weird state when I do that, and the CAN2 port doesn't work (CAN1 works fine). Only a true hardware reset will restore normal operation.
I am using MPLAB 8.2, and the target has a PIC30F IC.
My solution is to declare a routine as follows, called whenever I want a software reset. The NOP has a breakpoint placed on it, so when vReset() is called, the debugger halts, and I can use MPLABX's reset function (Debug|Reset) to restart the processor myself. The routine executes normally for a release build.
void vReset(void)
// This routine resets the CPU
{
// Perform any other cleanup tasks before resetting...
// If in debug mode, hang here before the reset (a reset locks up the debugger)
#ifdef __DEBUG // Defined by MPLABX when building project for debugging
for(;;)
{
__asm__ volatile ("nop"); // In case a breakpoint is placed here, will not get optimized away
};
#endif
// Reset CPU
__asm__ volatile ("reset");
}
I do not use MPLAB8, so perhaps you need to test for something other than __DEBUG, and if you are using older compilers (e.g. C30), the asm construct might be formatted differently.

Change pin mode at runtime in kernel module on beaglebone black

I am trying to write a kernel module that takes control of the UART1 RX&TX pins a runtime, changes their mode to GPIO, sends some commands (using bitbanging) and changes their mode back to UART.
Now, is there a way to change pin modes at runtime in a kernel module on the beaglebone black? I tried accessing the CONTROL_MODULE directly, which did not return an error, however, nothing seems to be written out.
#define CONTROL_MODULE_START 0x44E10000 // CONTROL_MODULE starting address in memory
#define CONTROL_MODULE_END 0x44E11FFF // CONTROL_MODULE end address in memory
#define CONTROL_MODULE_SIZE (CONTROL_MODULE_END - CONTROL_MODULE_START)
#define GPIO1_17_OFFSET 0x844 // control offset for GPIO1_17
#define GPIO3_19_OFFSET 0x9a4 // control offset for GPIO3_19
.
.
.
if (!(control_module = ioremap(CONTROL_MODULE_START, CONTROL_MODULE_SIZE))) {
printk(KERN_ERR "UARTbitbangModule: unable to map control module\n");
return -1;
}
// set both GPIOs to mode 7, input enabled
value = 0x7;
iowrite32(value, control_module + GPIO1_17_OFFSET);
iowrite32(value, control_module + GPIO3_19_OFFSET);
printk(KERN_INFO "UARTbitbangModule: mode GPIO1_17: %d\n", control_module[GPIO1_17_OFFSET]);
printk(KERN_INFO "UARTbitbangModule: mode GPIO3_19: %d\n", control_module[GPIO3_19_OFFSET]);
the corresponding dmesg output looks like this:
[22637.953610] UARTbitbangModule: mode GPIO1_17: 0
[22637.960000] UARTbitbangModule: mode GPIO3_19: 0
I also thought about using the pinctrl subsystem directly (see https://www.kernel.org/doc/Documentation/pinctrl.txt), but I cannot make sense of how to interact with it.
Any ideas on how to change pin modes on the bone at runtime or gain write access to the control module?
Edit: I am using a slightly tweaked (better rt performance) 4.1.15-bone-rt-r17 kernel with a BeagleBoard.org Debian Image 2015-03-01
You can use "linux/gpio.h" header file. An example code from Derek Molloy is here. This code is simple and gpio_request and gpio_direction_input or gpio_direction_output commands do what you need and you can change pin direction without directly changing CONTROL_MODULE register.
Regards

Resources