From 19af7131e28d35a5afcfa77cb5c1b7e19e000f56 Mon Sep 17 00:00:00 2001 From: Aidan MacDonald Date: Thu, 5 Feb 2026 22:11:40 +0000 Subject: [PATCH] echoplayer: allow enabling system debug in normal builds Allow toggling the system debug state from the debug menu in Rockbox, or by holding a button combo at boot, so that an SWD/JTAG debugger can be attached to normal non-debug builds without too much hassle. Change-Id: Iee47ef916ade2e5ec1094a63c68e48f1b27b0bbb --- bootloader/echoplayer.c | 16 ++++ firmware/SOURCES | 2 + firmware/reggen/cortex-m.regs | 7 ++ firmware/target/arm/stm32/debug-stm32h7.c | 107 +++++++++++++++++++++- 4 files changed, 131 insertions(+), 1 deletion(-) diff --git a/bootloader/echoplayer.c b/bootloader/echoplayer.c index 6f742aec50..97b5ec2749 100644 --- a/bootloader/echoplayer.c +++ b/bootloader/echoplayer.c @@ -34,6 +34,7 @@ #include "rbversion.h" #include "system-echoplayer.h" #include "gpio-stm32h7.h" +#include "regs/cortex-m/cm_debug.h" #define SDRAM_SIZE (MEMORYSIZE * 1024 * 1024) @@ -136,6 +137,14 @@ static bool is_usbmode_button_pressed(void) return button_status() & BUTTON_DOWN; } +static bool is_sysdebug_button_pressed(void) +{ + const int mask = BUTTON_A | BUTTON_B; + + /* Both buttons must be held */ + return (button_status() & mask) == mask; +} + static int send_event_on_tmo(struct timeout *tmo) { button_queue_post(tmo->data, 0); @@ -370,6 +379,13 @@ void main(void) power_init(); button_init(); + /* Enable system debugging if button combo held or debugger attached */ + if (reg_readf(CM_DEBUG_DHCSR, C_DEBUGEN) || + is_sysdebug_button_pressed()) + { + system_debug_enable(true); + } + /* Start monitoring power button / usb state */ monitor_init(); diff --git a/firmware/SOURCES b/firmware/SOURCES index 6c0bec8219..4fa1cfaaf1 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -1943,7 +1943,9 @@ target/arm/rk27xx/ihifi2/audio-ihifi800.c target/arm/stm32/crt0-stm32h7.S target/arm/stm32/vectors-stm32h7.S target/arm/stm32/adc-stm32h7.c +#ifndef BOOTLOADER target/arm/stm32/debug-stm32h7.c +#endif target/arm/stm32/gpio-stm32h7.c target/arm/stm32/i2c-stm32h7.c target/arm/stm32/pcm-stm32h7.c diff --git a/firmware/reggen/cortex-m.regs b/firmware/reggen/cortex-m.regs index 4be406b928..cb95bed5cf 100644 --- a/firmware/reggen/cortex-m.regs +++ b/firmware/reggen/cortex-m.regs @@ -168,3 +168,10 @@ CM_SYSTICK @ 0xe000e000 : block { 23 00 TENMS } } + +// Debug +CM_DEBUG @ 0xe000edf0 : block { + DHCSR @ 0x00 : reg { + 0 C_DEBUGEN + } +} diff --git a/firmware/target/arm/stm32/debug-stm32h7.c b/firmware/target/arm/stm32/debug-stm32h7.c index e7ffd1c37a..99a3849b41 100644 --- a/firmware/target/arm/stm32/debug-stm32h7.c +++ b/firmware/target/arm/stm32/debug-stm32h7.c @@ -19,10 +19,115 @@ * ****************************************************************************/ #include "system.h" +#include "kernel.h" +#include "button.h" +#include "lcd.h" +#include "font.h" +#include "action.h" +#include "list.h" +#include "regs/stm32h743/dbgmcu.h" +#include "regs/cortex-m/cm_debug.h" +#include + +enum +{ + SWD_MENU_IS_ENABLED, + SWD_MENU_IS_ATTACHED, + SWD_MENU_NUM_ENTRIES +}; + +static int swd_menu_action_cb(int action, struct gui_synclist *lists) +{ + int sel = gui_synclist_get_sel_pos(lists); + + if (sel == SWD_MENU_IS_ENABLED && action == ACTION_STD_OK) + { + if (reg_readf(DBGMCU_CR, DBGSLEEP_D1)) + system_debug_enable(false); + else + system_debug_enable(true); + + action = ACTION_REDRAW; + } + + if (action == ACTION_NONE) + action = ACTION_REDRAW; + + return action; +} + +static const char *swd_menu_get_name(int item, void *data, char *buf, size_t bufsz) +{ + (void)data; + + switch (item) + { + case SWD_MENU_IS_ENABLED: + snprintf(buf, bufsz, "System debug enabled: %d", + (int)!!reg_readf(DBGMCU_CR, DBGSLEEP_D1)); + return buf; + + case SWD_MENU_IS_ATTACHED: + snprintf(buf, bufsz, "DHCSR.C_DEBUGEN bit: %d", + (int)!!reg_readf(CM_DEBUG_DHCSR, C_DEBUGEN)); + return buf; + + default: + return ""; + } +} + +static bool swd_menu(void) +{ + struct simplelist_info info; + simplelist_info_init(&info, "SWD/JTAG", SWD_MENU_NUM_ENTRIES, NULL); + info.action_callback = swd_menu_action_cb; + info.get_name = swd_menu_get_name; + return simplelist_show_list(&info); +} + +/* Menu definition */ +static const struct { + const char *name; + bool (*function) (void); +} menuitems[] = { + {"SWD/JTAG", swd_menu}, +}; + +static int hw_info_menu_action_cb(int btn, struct gui_synclist *lists) +{ + if (btn == ACTION_STD_OK) + { + int sel = gui_synclist_get_sel_pos(lists); + FOR_NB_SCREENS(i) + viewportmanager_theme_enable(i, false, NULL); + + menuitems[sel].function(); + btn = ACTION_REDRAW; + + FOR_NB_SCREENS(i) + viewportmanager_theme_undo(i, false); + } + + return btn; +} + +static const char* hw_info_menu_get_name(int item, void *data, char *buf, size_t bufsz) +{ + (void)buf; + (void)bufsz; + (void)data; + return menuitems[item].name; +} bool dbg_hw_info(void) { - return false; + struct simplelist_info info; + simplelist_info_init(&info, MODEL_NAME " debug menu", + ARRAYLEN(menuitems), NULL); + info.action_callback = hw_info_menu_action_cb; + info.get_name = hw_info_menu_get_name; + return simplelist_show_list(&info); } bool dbg_ports(void)