diff --git a/samples/subsys/debug/debugmon/CMakeLists.txt b/samples/subsys/debug/debugmon/CMakeLists.txt new file mode 100644 index 00000000000..14df78068fa --- /dev/null +++ b/samples/subsys/debug/debugmon/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(debugmon) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/subsys/debug/debugmon/README.rst b/samples/subsys/debug/debugmon/README.rst new file mode 100644 index 00000000000..4d3812ad288 --- /dev/null +++ b/samples/subsys/debug/debugmon/README.rst @@ -0,0 +1,42 @@ +.. _debugmon-sample: + +Debug monitor +############# + +Overview +******** + +The Debug Monitor sample shows a basic configuration of debug monitor feature. + + +The source code shows how to: + +#. Configure registers to enable degugging in debug monitor mode +#. Specify custom interrupt to be executed when entering a breakpoint + +.. _debugmon-sample-requirements: + +Requirements +************ + +Your board must: + +#. Support Debug Monitor feature (available on Cortex-M processors with the exception of Cortex-M0) +#. Have an LED connected via a GPIO pin (these are called "User LEDs" on many of + Zephyr's :ref:`boards`). +#. Have the LED configured using the ``led0`` devicetree alias. + +Building and Running +******************** + +Build and flash Debug Monitor as follows, changing ``reel_board`` for your board: + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/debug/debugmon + :board: reel_board + :goals: build flash + :compact: + +After flashing the board enters a breakpoint and executes debug monitor exception code. +The LED starts to blink, indicating that even though the processor spins in debug monitor +interrupt, other higher priority interrupts continue to execute. diff --git a/samples/subsys/debug/debugmon/prj.conf b/samples/subsys/debug/debugmon/prj.conf new file mode 100644 index 00000000000..fd4651957c1 --- /dev/null +++ b/samples/subsys/debug/debugmon/prj.conf @@ -0,0 +1 @@ +CONFIG_CORTEX_M_DEBUG_MONITOR_HOOK=y diff --git a/samples/subsys/debug/debugmon/sample.yaml b/samples/subsys/debug/debugmon/sample.yaml new file mode 100644 index 00000000000..ce2d05c6663 --- /dev/null +++ b/samples/subsys/debug/debugmon/sample.yaml @@ -0,0 +1,7 @@ +sample: + name: debug monitor sample +tests: + sample.debug.debugmon: + build_only: true + platform_allow: reel_board + tags: debug diff --git a/samples/subsys/debug/debugmon/src/main.c b/samples/subsys/debug/debugmon/src/main.c new file mode 100644 index 00000000000..b82f7642e89 --- /dev/null +++ b/samples/subsys/debug/debugmon/src/main.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#define LED0_NODE DT_ALIAS(led0) +static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios); + +void timer_handler(struct k_timer *timer) +{ + gpio_pin_toggle_dt(&led); +} +K_TIMER_DEFINE(led_timer, timer_handler, NULL); + +int debug_mon_enable(void) +{ + /* + * Cannot enable monitor mode if C_DEBUGEN bit is set. This bit can only be + * altered from debug access port. It is cleared on power-on-reset. + */ + bool is_in_halting_mode = (CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk) == 1; + + if (is_in_halting_mode) { + return -1; + } + + /* Enable monitor mode debugging by setting MON_EN bit of DEMCR */ + CoreDebug->DEMCR |= CoreDebug_DEMCR_MON_EN_Msk; + return 0; +} + +/* + * Interrupt handler that will be called each time the device + * enters a breakpoint while debugging in monitor mode. + * With CONFIG_CORTEX_M_DEBUG_MONITOR_HOOK enabled this exception is set to lowest + * possible priority (IRQ_PRIO_LOWEST). + */ +void z_arm_debug_monitor(void) +{ + /* + * Implement the logic or use a ready implementation available for your platform + * (ie. SEGGER implementation for their debug probes) + */ + printk("Entered debug monitor interrupt\n"); + + /* Spin in breakpoint. Other, higher-priority interrupts will continue to execute */ + while (true) + ; +} + +void main(void) +{ + /* Set up led and led timer */ + if (!device_is_ready(led.port)) { + printk("Device not ready\n"); + return; + } + + int err = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE); + + if (err) { + printk("Error configuring LED\n"); + return; + } + k_timer_start(&led_timer, K_NO_WAIT, K_SECONDS(1)); + + /* Set up debug monitor */ + err = debug_mon_enable(); + if (err) { + printk("Error enabling monitor mode:\n" + "Cannot enable DBM when CPU is in Debug mode"); + return; + } + + /* Enter a breakpoint */ + __asm("bkpt"); +}