How to detect if a debugger is attached on an STM32
Hi reader,
This is just a quick how-to for the google robots to find, nothing Mooshimeter related. I didn’t see any good answers for this out there, but it’s very useful if you’re debugging firmware on an STM32 to know if a debugger is attached. If an error condition arises while a debugger is attached, you can raise a breakpoint and halt to allow examining the system state at the time of error, and if no debugger is present, you can indicate the error in some other way and carry on.
My setup:
- Using SW4STM32 IDE (frontend for ARM gcc/g++ compiler)
- STM32F4xxx (though this should work on all STM32’s)
The debugger can be detected by examining the DBGMCU_CR, the control register for the debug peripheral within the MCU. The bottom 3 bits default to 0 after a power-on reset, but the debugging session will set some or all of them high when it attaches (except in very specific circumstances where you’re changing the debugger settings). So we can just examine these bits to infer if a debugger is attached:
1 2 3 | // Set this appropriate to your stm32 processor. #include "stm32fxxx.h" #define IS_DEBUGGER_ATTACHED() (DBGMCU->CR & 0x07) |
Generally I use this in whatever assert_failed
handler I set up. If you’re using the STM32 HAL with USE_FULL_ASSERT on, you can override the assert_failed(uint8_t*, uint32_t)
function so any assertion failures in the HAL layer also get caught. In the example below, debug_print is rigged to work like printf and DMAs the data out UART3, you’ll probably want to do something else with the information. Also I do a little string processing to grab just the filename instead of the full path to the file supplied by the preprocessor.
1 2 3 4 5 6 7 8 9 10 11 | // If the debugger is attached, halt for debugging // Otherwise, print the file and line where the failure occurred void assert_failed(uint8_t *path, uint32_t line) { if(IS_DEBUGGER_ATTACHED()) { asm("BKPT 0"); } else { uint8_t *file = (uint8_t*)strrchr((const char*)path, '/'); file = file==NULL? path : file+1; debug_print("ASSERT@%s%u\r\n", file, line); } } |
As a test, here is a code block being run within a debug session and after a power-on-reset (no debug session, debugger still physically attached):
1 2 3 4 5 6 | if(IS_DEBUGGER_ATTACHED()) { debug_print("Debugger detected\r\n"); } else { debug_print("No debugger detected\r\n"); } ASSERT(0); |
Running this code in a debug session halts on the ASSERT(0) as you would expect. Power cycling the board yields:
1 2 | No debugger detected ASSERT@application.cpp:66 |
Before the code continues on its way. Which is what we expected. Hope this was useful!
Extremely useful. STM32 ecosystem is huge and even the simplest task can take days or weeks to understand, not due to difficulty but the amount of information in references manuals and not very well sorted really.
Your explanation is simple and direct. Wonderful.