When debugging the STM32 with OpenOCD and GDB, OpenOCD does not continue to debug when the MCU wakes up from STOP mode.
I have the following code which sleeps the MCU for 10 seconds and then wakes it up:
uint32_t seconds = 10;
uint32_t counter = (uint32_t)(seconds * 1000) / 0.488;
HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, counter,
RTC_WAKEUPCLOCK_RTCCLK_DIV16);
HAL_SuspendTick();
HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI);
SystemClock_Config();
HAL_ResumeTick();
do_stuff():
When I use the STM32CubeIDE with ST's Programmer, it works as expected. The debugging process continues to the next line after the MCU wakes up.
With OpenOCD and GDB and stays stuck at
Continuing.
halted: PC: 0x080010f0
How can I make it behave similar to the ST debugger, where it continues debugging after sleep?
I use the following line to start the OpenOCD session:
openocd -f interface/stlink-v2.cfg -f target/stm32f4x.cfg
You have to enable debugger STOP-mode support. Quote from the reference manual:
The core does not allow FCLK or HCLK to be turned off during a debug
session. As these are required for the debugger connection, during a
debug, they must remain active. The MCU integrates special means to
allow the user to debug software in low-power modes. For this, the
debugger host must first set some debug configuration registers to
change the low-power mode behavior:
• In Sleep mode, DBG_SLEEP bit of DBGMCU_CR register must be
previously set by the debugger. This will feed HCLK with the same
clock that is provided to FCLK (system clock previously configured by
the software).
• In Stop mode, the bit DBG_STOP must be previously set by the
debugger. This will enable the internal RC oscillator clock to feed
FCLK and HCLK in STOP mode
From description of the DBGMCU_CR register.
Bit 1 DBG_STOP: Debug Stop mode
0: (FCLK=Off, HCLK=Off) In STOP mode, the clock controller disables all clocks (including HCLK and FCLK). When exiting from STOP
mode, the clock configuration is identical to the one after RESET (CPU
clocked by the 8 MHz internal RC oscillator (HSI)). Consequently, the
software must reprogram the clock controller to enable the PLL, the
Xtal, etc.
1: (FCLK=On, HCLK=On) In this case, when entering STOP mode, FCLK and HCLK are provided by the internal RC oscillator which remains
active in STOP mode. When exiting STOP mode, the software must
reprogram the clock controller to enable the PLL, the Xtal, etc. (in
the same way it would do in case of DBG_STOP=0)
I think HAL_DBGMCU_EnableDBGStopMode() function is resposible for this register. But you may need to check the exact library version you using.
Probably STProgrammer modifies this bit silently.
Related
I have some PLC code which crashes two different PLCs.
On one PLC (CX2040 x64) whenever I activate the solution, the CPU cores where the project is running on, jumps to 99%. At this time it seems to be stuck in some infinite loop. When this happens, it is impossible to get the TwinCAT runtime into config mode. Neither from the visual studio remote manager, neither if I would remote desktop onto the PLC itself and try to set the TwinCAT run time into config mode using the tray icon.
This is very frustrating. But even more frustrating is that occasionally the PLC would become totally unresponsive. No connection was possible from the Visual Studio remote manager or normal windows remote desktop. The PLC didn't even respond to ping requests from another PC. The only solution was to power cycle the PLC and let it reboot.
On a second PLC (CX2040 x86) I get the following TcRTime watchdog exception:
This PLC never jumps to 99% CPU usage and no hardware reset is needed, because it never goes into a non-recoverable state. I can just put it back into config mode, since it always goes into the exception state. How can I enable the TcRTime watchdog on the x64 PLC, to prevent that one from going into the unrecoverable state.
I know there are some functions which enable a watchdog on the PLC, but these functions are not used in this project! So I have no clue how the watchdog is activated on one PLC, but not the other since the code is the same. Does anyone know?
Turns out I completely forgot that I had enabled the watchdog cycles in the project.
However, I do not understand why the watchdog cycles were triggered on the x86 PLC, but not the x64 one. Maybe on the x64 one the 99% CPU usage didn't cause cycle overruns? Although that seems very unlikely to me.
I'm using GDB (through an IDE) to debug an arm cortex microcontroller, and I've encountered an issue where the micro is halted briefly (for 10-20ms) whenever a breakpoint is set or cleared (not hit, but set, as in the code has not yet reached the breakpoint). This long of a pause can cause significant problems when driving an electric motor, for example.
The IDE has a debug console which shows that the GDB client is sending a SIGINT to the GDB server whenever I add or remove a breakpoint. I know that in the command-line client you have to use ctrl+c to interrupt the process to issue any command, but for modern microcontrollers (ARM cortex-m, etc.) it is not necessary to interrupt the processor to insert breakpoints, read memory, and in some cases to trace program execution. I am wondering if this is something that is being imposed by the GDB interface artificially.
Is there any way to create a new breakpoint without halting the target?
I have tried using "async" mode in GDB, but it informs me that I must halt the program to insert breakpoints. I have also verified that breakpoints can be set with the underlying debug server (OpenOCD) without halting, so in this case GDB is incorrect.
Any input is appreciated, and thanks in advance.
I used to think that a process may switch from user mode to kernel mode by system call, after the kernel routine is done, it will check if there is any other process which has higher priority before return to user mode, if not, it will return to user mode directly. But Understanding the Linux Kernel, 3rd Edition 1.6.1. The Process/Kernel Model just confused me:
On a uniprocessor system, only one process is running at a time, and
it may run either in User or in Kernel Mode. If it runs in Kernel
Mode, the processor is executing some kernel routine. Figure 1-2
illustrates examples of transitions between User and Kernel Mode.
Process 1 in User Mode issues a system call, after which the process
switches to Kernel Mode, and the system call is serviced. Process 1
then resumes execution in User Mode until a timer interrupt occurs,
and the scheduler is activated in Kernel Mode. A process switch takes
place, and Process 2 starts its execution in User Mode until a
hardware device raises an interrupt. As a consequence of the
interrupt, Process 2 switches to Kernel Mode and services the
interrupt.
The following description just don't make sense
Process 1 then resumes execution in User Mode until a timer interrupt
occurs, and the scheduler is activated in Kernel Mode.
I think that returning to user mode have noting to do with interrupt and what does it mean by "scheduler is activated in Kernel Mode"?
The scheduler is the part of the kernel that performs task switching. Each time the scheduler runs, it chooses which process should have control of the CPU next, and switches to it. The scheduler needs to run often enough to ensure that all processes get a fair share of time on the CPU.
System calls can invoke the scheduler, but that alone isn't sufficient, because a process might spend a long time running code in user space, not making any system calls. To ensure that the scheduler runs often enough, the kernel configures a hardware timer to periodically send interrupt signals to the CPU. Each time the interrupt signal occurs, the CPU stops running the user program, switches to kernel mode, and runs an "interrupt handler" in the kernel that calls the scheduler. Since it's triggered by a timer instead of by code, this works even if the user program isn't making any calls into the kernel.
I've captured a read memory trace (i.e. addresses of all read accesses) of a program-run by Intel PIN, ASLR was off. I can capture it several times and the trace is still exactly the same.
Then I take an address from the trace (a specific address I am interested in), set a watchpoint in GDB by rwatch *0x7fffe309e643 but GDB does not notice the access. I'm doing this in the same terminal where the trace has been taken so it should access the same addresses; when I capture it then again, the trace is still very the same.
Do you have any ideas or hints why GDB does not catch it?
I have to note that the access very likely happens within a (C++) structure loaded from a Boost serialization and that the code has been compiled with -g3 -O1 flags (-O1 is really crucial for other reasons but a minimal example showed me that GDB breaks correctly even with -O1).
UPDATE:
As suggested, I tried PIN debugger (which actually utilizes GDB) but there is some problem with watchpoints. To present this problem, I made a minimal example.
int main()
{
unsigned char i = 4;
i++;
i = 3;
return 0;
}
I acquired a read memory trace with PIN and chose 0x7fffffffd89f (or similar) as the address of interest. Then I started PIN debugger and GDB in parallel terminals and connected GDB to PIN ((gdb) target remote :57946, as suggested by PIN). In GDB I set watchpoint (gdb) rwatch *0x7fffffffd89f and started execution but I get
Continuing.
Warning:
Could not insert hardware watchpoint 1.
Could not insert hardware breakpoints:
You may have requested too many hardware breakpoints/watchpoints.
even though I only inserted a single watchpoint. I also tried to explicitly disable hardware breakpoints by set can-use-hw-watchpoints 0 but then it ran for an hour with no result and no processor load so I killed it.
Is there any other way how to set a functional watchpoint at a specific address when GDB is connected to PIN debugger? Note that there is no such problem with standalone GDB.
I use GDB 7.7.1, PIN 2.14-71313 and GCC 4.4.7, running Ubuntu 14.04.
The original problem would be likely solved then.
From pin user guide:
The "pin" Executable (Launcher)
The kit's root directory contains a "pin" executable. This is a 32-bit
launcher, used for launching Pin in 32 and 64 bit modes. The launcher
sets up the environment to find the libraries supplied with the kit.
It is likely that the environment is different when running pinbin, and therefore stack addresses will also be different (0x7fffe309e643 looks like a possible stack address) even without ASLR.
Your best bet is probably to use Pin application debugging interface.
I have ARM board at remote location. Some time I had a kernel panic error in it. At this same time there is no option to hardware restart. bus no one is available at this place to restart it.
I want to restart my board automatically after kernel panic error. so what to do in kernel.
If your hardware contains watchdog timer, then compile the kernel with watchdog support and configure it. I suggest to follow this blog http://www.jann.cc/2013/02/02/linux_watchdog.html
Caution :: I never tried this. If the problem is solved, request you to update here.
You can modify the panic() function kernel/panic.c to call the kernel_restart(*cmd) at the point you want it to restart (like probably after printing the required debug information).
I am assuming you are bringing up a board, so Please note that you need to supply the ops for the associated functions in machine_restart() - (called by kernel_restart) in accordance to the MACH . If you are just using the board as is , then i guess rebuilding the kernel with kernel_restart(*cmd) should do.
The panic() is usually due to events that the kernel can not recover from. If you do not have a watchdog, you need to look at your hardware to see if a GPIO, etc is connected to the RESET line. If so, you can toggle this pin to reboot the CPU. Trying to alter panic() may just make things worse, depending on the root cause and the type of features you use.
You may hook arm_pm_restart with your custom restart functionality. You can test it with the shell command reboot, if present. panic() should call the same routine. With current ARM Linux versions
You may wish to turn off the MMU and block interrupts in this routine. It will make it more resilient when called from panic(). As you are going to reset, you can copy the routine to any physical address you like.
The watchdog maybe better; it may catch cases where even panic() may not be called. You may have a watchdog and not realize it. Many Cortex-A CPUs, have one built in. It is fairly rare for hardware not to have a watchdog.
However, if you don't have the watchdog, you can use the GPIO mechanism above; hardware should usually provide someway for software to restart the device (and peripherals). The panic() maybe due to some mis-behaving device tromping memory, latched up DRAM/Flash, etc. Toggling a RESET line maybe better than a watchdog in this case; if the RESET is also connected to other hardware, besides the CPU.
Related: How to debug kernel freeze, How to change watchdog timer
AFAIK, a simple way to restart the board after kernel panic is to pass a kernel parameter (from the bootloader usually)
panic=1
The board will then auto-reboot '1' second(s) after a panic.
Search the Documentation for more.
Some examples from the documentation:
...
panic= [KNL] Kernel behaviour on panic: delay <timeout>
timeout > 0: seconds before rebooting
timeout = 0: wait forever
timeout < 0: reboot immediately
Format: <timeout>
...
oops=panic Always panic on oopses. Default is to just kill the
process, but there is a small probability of
deadlocking the machine.
This will also cause panics on machine check exceptions.
Useful together with panic=30 to trigger a reboot.
...
As suggested in previous comments watchdog timer is your friend here. If your hardware contains watchdog timer, Enable it in kernel option and configure it.
Other alternative is use Phidget. If you usb connection available at remote location. Phidget controller/software is used to control your board using USB. Check for board support.