You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by an...@apache.org on 2020/11/25 12:07:57 UTC

[mynewt-core] branch master updated (60361f2 -> 5f5cb2b)

This is an automated email from the ASF dual-hosted git repository.

andk pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git.


    from 60361f2  nucleo: Add missing BUTTON_1 definitions
     new c4c5236  hw/mcu/dialog: Add support for Micro Trace Buffer (MTB)
     new 592f61e  hw/mcu/dialog: Fix msplim handling
     new 6533786  hw/mcu/dialog: Add helpers to control MTB
     new d2109a9  kernel/os/arch: Stop M33-MTB on exception
     new 5f5cb2b  hw/scripts: Add GDB script to handle MTB

The 5 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../src/arch/cortex_m33/gcc_startup_da1469x.S      |  27 +++
 hw/mcu/dialog/da1469x/da1469x.ld                   |   9 +-
 hw/mcu/dialog/da1469x/include/mcu/cortex_m33.h     |  15 ++
 .../src/arch/cortex_m33/da1469x_m33_sleep.S        |  25 +++
 hw/mcu/dialog/da1469x/src/hal_system_start.c       |   6 +-
 hw/mcu/dialog/da1469x/src/system_da1469x.c         |   5 +
 hw/mcu/dialog/da1469x/syscfg.yml                   |  13 ++
 hw/scripts/micro-trace-buffer.py                   | 227 +++++++++++++++++++++
 kernel/os/src/arch/cortex_m33/os_fault.c           |  17 ++
 9 files changed, 342 insertions(+), 2 deletions(-)
 create mode 100644 hw/scripts/micro-trace-buffer.py


[mynewt-core] 03/05: hw/mcu/dialog: Add helpers to control MTB

Posted by an...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

andk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git

commit 65337861c0c2ac57ca8550ee1adb39bac7690965
Author: Andrzej Kaczmarek <an...@codecoup.pl>
AuthorDate: Sat Nov 21 01:39:02 2020 +0100

    hw/mcu/dialog: Add helpers to control MTB
    
    These helpers allow to enable/disable MTB tracing from code. It may be
    useful to start tracing for interesting pieces of code, or temporarily
    disable for uniteresting pieces of code to spare buffer space (e.g.
    on some long loops that create a lot of branches).
---
 hw/mcu/dialog/da1469x/include/mcu/cortex_m33.h | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/hw/mcu/dialog/da1469x/include/mcu/cortex_m33.h b/hw/mcu/dialog/da1469x/include/mcu/cortex_m33.h
index c981e63..297facd 100644
--- a/hw/mcu/dialog/da1469x/include/mcu/cortex_m33.h
+++ b/hw/mcu/dialog/da1469x/include/mcu/cortex_m33.h
@@ -35,6 +35,21 @@ hal_debug_break(void)
     __BKPT(1);
 }
 
+static inline void
+mcu_mtb_enable(void)
+{
+    *(uint32_t *)0xe0043004 |= (1 << 31);
+    __DSB();
+    __ISB();
+}
+
+static inline void
+mcu_mtb_disable(void)
+{
+    __ISB();
+    *(uint32_t *)0xe0043004 &= ~(1 << 31);
+}
+
 #ifdef __cplusplus
 }
 #endif


[mynewt-core] 02/05: hw/mcu/dialog: Fix msplim handling

Posted by an...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

andk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git

commit 592f61efd0762e63f59dec3a6d0755bee052e33a
Author: Andrzej Kaczmarek <an...@codecoup.pl>
AuthorDate: Sat Nov 21 01:34:29 2020 +0100

    hw/mcu/dialog: Fix msplim handling
    
    We have stack checking enabled by default and it can be triggered if
    app has different stack location than bootloader or, in case of RAM
    app, different than current app.
    
    To avoid this we should reset MSPLIM before jumping from bootloader
    to app and also when starting RAM app.
---
 .../dialog_da1469x-dk-pro/src/arch/cortex_m33/gcc_startup_da1469x.S | 5 +++++
 hw/mcu/dialog/da1469x/src/hal_system_start.c                        | 6 +++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/hw/bsp/dialog_da1469x-dk-pro/src/arch/cortex_m33/gcc_startup_da1469x.S b/hw/bsp/dialog_da1469x-dk-pro/src/arch/cortex_m33/gcc_startup_da1469x.S
index d173f79..c5e1281 100644
--- a/hw/bsp/dialog_da1469x-dk-pro/src/arch/cortex_m33/gcc_startup_da1469x.S
+++ b/hw/bsp/dialog_da1469x-dk-pro/src/arch/cortex_m33/gcc_startup_da1469x.S
@@ -157,6 +157,11 @@ wakeup_handler:
     .globl Reset_Handler
     .type  Reset_Handler, %function
 Reset_Handler:
+#if MYNEWT_VAL(RAM_RESIDENT)
+    mov     r0, #0
+    msr     msplim, r0
+#endif
+
 #if MYNEWT_VAL(MCU_MTB_ENABLE)
     mov     r2, #0
     ldr     r1, =MTB_POSITION_REG
diff --git a/hw/mcu/dialog/da1469x/src/hal_system_start.c b/hw/mcu/dialog/da1469x/src/hal_system_start.c
index 62f00fe..2445f9c 100644
--- a/hw/mcu/dialog/da1469x/src/hal_system_start.c
+++ b/hw/mcu/dialog/da1469x/src/hal_system_start.c
@@ -47,12 +47,16 @@ hal_system_start(void *img_start)
     img_data = (uint32_t *)img_data_addr;
 
     asm volatile (".syntax unified        \n"
+                  /* Reset MSPLIM */
+                  "    mov  r0, #0        \n"
+                  "    msr  msplim, r0    \n"
                   /* 1st word is stack pointer */
                   "    msr  msp, %0       \n"
                   /* 2nd word is a reset handler (image entry) */
                   "    bx   %1            \n"
                   : /* no output */
-                  : "r" (img_data[0]), "r" (img_data[1]));
+                  : "r" (img_data[0]), "r" (img_data[1])
+                  : "r0");
 }
 
 void


[mynewt-core] 05/05: hw/scripts: Add GDB script to handle MTB

Posted by an...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

andk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git

commit 5f5cb2bfd6c4d9f4bdd18f566c380cf4f0164b1b
Author: Andrzej Kaczmarek <an...@codecoup.pl>
AuthorDate: Mon Nov 23 17:46:18 2020 +0100

    hw/scripts: Add GDB script to handle MTB
    
    This adds script for GDB to easily analyze Micro Trace Buffer (MTB)
    contents. A new "mtb" command is available in GDB:
    
    - "mtb base" -> set base address for MTB, default is 0xe0043000 (CM33)
    - "mtb enable" -> enables MTB (has to be already configured!)
    - "mtb disable" -> disables MTB
    - "mtb decode" -> decodes current MTB contents; it prints complete
                      disassembled trace along with source code if proper
                      symbol file is loaded and sources are available
    - "mtb colors <on/off>" -> enables/disables colors in decoder output,
                               disabled by default and requires colorama
                               module
    
    As a convenient shortcut, plain "mtb" command defaults to "mtb decode".
    That means if MCU has MTB already configured and enabled, it's enough
    to just issue that command to get valid output.
---
 hw/scripts/micro-trace-buffer.py | 227 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 227 insertions(+)

diff --git a/hw/scripts/micro-trace-buffer.py b/hw/scripts/micro-trace-buffer.py
new file mode 100644
index 0000000..80df78e
--- /dev/null
+++ b/hw/scripts/micro-trace-buffer.py
@@ -0,0 +1,227 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+try:
+    import colorama
+except ImportError:
+    pass
+import re
+
+
+class MicroTraceBuffer(gdb.Command):
+    _arch = None
+    _file = None
+    _func = None
+    _line = None
+    _src_file = None
+    _src_lines = None
+
+    _mtb_base_addr = 0xe0043000
+
+    _colorize = False
+    _colors = {}
+
+    def __init__(self):
+        super(MicroTraceBuffer, self).__init__("mtb", gdb.COMMAND_STATUS, gdb.COMPLETE_NONE)
+        if colorama:
+            self._colors = {"A": colorama.Fore.BLUE,
+                            "D": colorama.Fore.RESET,
+                            "E": colorama.Fore.GREEN,
+                            "F": colorama.Fore.YELLOW,
+                            "L": colorama.Fore.RESET,
+                            "S": colorama.Fore.RESET,
+                            "X": colorama.Fore.RED}
+
+    def _print(self, s: str):
+        def repl(m):
+            if m.group(1) in self._colors:
+                return self._colors[m.group(1)]
+            else:
+                return colorama.Fore.RESET
+
+        if not colorama or not self._colorize:
+            s = re.sub(r"~([A-Z])~", "", s)
+        else:
+            s = re.sub(r"~([A-Z])~", repl, s) + colorama.Style.RESET_ALL
+        print(s)
+
+    def _get_src(self, file, line):
+        if file != self._src_file:
+            self._src_file = file
+            try:
+                f = open(file, "r")
+                self._src_lines = f.readlines()
+            except OSError:
+                self._src_lines = None
+
+        if not self._src_lines:
+            return "<not found>"
+
+        src = self._src_lines[line - 1].strip()
+        return src
+
+    def _describe_instr(self, addr: int, asm: str):
+        blk = gdb.block_for_pc(addr)
+        while blk and not blk.function:
+            blk = blk.superblock
+        func = str(blk.function) if blk else "<unknown>"
+
+        pcl = gdb.find_pc_line(addr)
+        file = pcl.symtab.filename if pcl.symtab else "<unknown>"
+        line = pcl.line
+
+        if (self._file != file) or (self._func != func):
+            self._file = file
+            self._func = func
+            self._print(f"~F~{func} ~R~@ ~E~{file}")
+
+        if self._line != line:
+            self._line = line
+            if pcl.symtab:
+                fname = pcl.symtab.fullname()
+                src = self._get_src(fname, line)
+                self._print(f"~L~{line}\t~S~{src}")
+
+        self._print(f"    ~A~0x{addr:08x}:    ~D~{asm}")
+
+    def _disassemble(self, start: int, end: int):
+        disasm = self._arch.disassemble(start, end)
+        for instr in disasm:
+            addr = instr["addr"]
+            asm = instr["asm"].expandtabs(8)
+            self._describe_instr(addr, asm)
+        print()
+
+    def _cmd_decode(self):
+        print(f"NOTE: using 0x{self._mtb_base_addr:08x} as MTB base address")
+        print()
+
+        u32_ptr_t = gdb.lookup_type("uint32_t").pointer()
+        mtb_reg_pos = int(gdb.Value(self._mtb_base_addr).cast(u32_ptr_t).dereference())
+        mtb_reg_master = int(gdb.Value(self._mtb_base_addr + 0x04).cast(u32_ptr_t).dereference())
+        mtb_reg_base = int(gdb.Value(self._mtb_base_addr + 0x0c).cast(u32_ptr_t).dereference())
+
+        # size of trace buffer
+        mtb_size = 1 << ((mtb_reg_master & 0x1f) + 4)
+
+        # check buffer position
+        mtb_wrap = bool(mtb_reg_pos & 0x04)
+        mtb_reg_pos = mtb_reg_pos & 0xfffffff8
+
+        # if pointer already wrapped, we start at current entry and process complete buffer,
+        # otherwise we start at beginning and process up to current entry
+        mtb_size = mtb_size if mtb_wrap else mtb_reg_pos
+        mtb_reg_pos = mtb_reg_pos if mtb_wrap else 0
+
+        # use current frame to get architecture for later disassembling
+        self._arch = gdb.newest_frame().architecture()
+
+        mtb_pkt_dst = None
+
+        for pos in range(0, mtb_size, 8):
+            exec_begin = mtb_pkt_dst
+
+            mtb_pkt = mtb_reg_base + (mtb_reg_pos + pos) % mtb_size
+            mtb_pkt_src = int(gdb.Value(mtb_pkt).cast(u32_ptr_t).dereference())
+            mtb_pkt_dst = int(gdb.Value(mtb_pkt + 4).cast(u32_ptr_t).dereference())
+
+            bit_a = mtb_pkt_src & 1
+            bit_s = mtb_pkt_dst & 1
+
+            mtb_pkt_src = mtb_pkt_src & 0xfffffffe
+            mtb_pkt_dst = mtb_pkt_dst & 0xfffffffe
+
+            # print(f"pkt> 0x{mtb_pkt_src:08x} -> 0x{mtb_pkt_dst:08x} A:{bit_a} S:{bit_s}")
+
+            exec_end = mtb_pkt_src
+
+            # exception entry/exit events are handled separately
+            if bit_a != 0:
+                if mtb_pkt_src & 0xff000000 == 0xff000000:
+                    self._print(f"~X~Exception return (LR: 0x{mtb_pkt_src:08x}, "
+                                f"ret address: 0x{mtb_pkt_dst:08x})")
+                else:
+                    self._print(f"~X~Exception entry (ret address: 0x{mtb_pkt_src:08x})")
+                print()
+                continue
+
+            # on 1st entry in trace buffer, disassemble source of the branch
+            if exec_begin is None:
+                self._disassemble(mtb_pkt_src, mtb_pkt_src)
+                continue
+
+            # on 1st entry after MTB was enabled, disasssemble source of the branch
+            if bit_s != 0:
+                self._disassemble(mtb_pkt_src, mtb_pkt_src)
+                continue
+
+            # print(f"exe> 0x{exec_begin:08x} -> 0x{exec_end:08x}")
+
+            self._disassemble(exec_begin, exec_end)
+
+        # disassemble target of last branch
+        self._disassemble(mtb_pkt_dst, mtb_pkt_dst)
+
+    def _cmd_colors(self, args):
+        for arg in args:
+            if arg == "on":
+                self._colorize = True
+            elif arg == "off":
+                self._colorize = False
+            else:
+                # TODO: handle colors configuration
+                pass
+
+    def _cmd_enable(self):
+        u32_ptr_t = gdb.lookup_type("uint32_t").pointer()
+        addr = self._mtb_base_addr + 0x04
+        mtb_reg_master = int(gdb.Value(addr).cast(u32_ptr_t).dereference())
+        mtb_reg_master = mtb_reg_master | 0x80000000
+        gdb.execute(f"set *0x{addr:08x} = 0x{mtb_reg_master:08x}")
+
+    def _cmd_disable(self):
+        u32_ptr_t = gdb.lookup_type("uint32_t").pointer()
+        addr = self._mtb_base_addr + 0x04
+        mtb_reg_master = int(gdb.Value(addr).cast(u32_ptr_t).dereference())
+        mtb_reg_master = mtb_reg_master & 0x7fffffff
+        gdb.execute(f"set *0x{addr:08x} = 0x{mtb_reg_master:08x}")
+
+    def _cmd_base(self, arg):
+        try:
+            addr = int(arg, 0)
+            self._mtb_base_addr = addr
+            print(f"MTB base address set to 0x{self._mtb_base_addr:08x}")
+        except ValueError:
+            print(f"Invalid value for MTB base address")
+
+    def invoke(self, arg: str, from_tty: bool):
+        args = arg.split(" ")
+        if len(args[0]) == 0 or args[0] == "decode":
+            self._cmd_decode()
+        elif args[0] == "colors":
+            self._cmd_colors(args[1:])
+        elif args[0] == "enable":
+            self._cmd_enable()
+        elif args[0] == "disable":
+            self._cmd_disable()
+        elif args[0] == "base":
+            self._cmd_base(args[1])
+        else:
+            print("wut?")
+
+
+MicroTraceBuffer()


[mynewt-core] 04/05: kernel/os/arch: Stop M33-MTB on exception

Posted by an...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

andk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git

commit d2109a94881c93186732c39672b2659bd9bf930b
Author: Andrzej Kaczmarek <an...@codecoup.pl>
AuthorDate: Sat Nov 21 01:40:52 2020 +0100

    kernel/os/arch: Stop M33-MTB on exception
    
    If MTB is enabled, we should better stop it in exception handler so
    we do not overwrite potentially interesting trace data with not so
    interesting trace data for exception handler.
    
    We also need to check if MTB is available on given MCU since this is
    optional feature for Cortex-M33.
---
 kernel/os/src/arch/cortex_m33/os_fault.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/kernel/os/src/arch/cortex_m33/os_fault.c b/kernel/os/src/arch/cortex_m33/os_fault.c
index 5c45da9..c4d7cbc 100644
--- a/kernel/os/src/arch/cortex_m33/os_fault.c
+++ b/kernel/os/src/arch/cortex_m33/os_fault.c
@@ -163,6 +163,23 @@ os_default_irq(struct trap_frame *tf)
     uint32_t orig_sp;
 #endif
 
+    /* Stop MTB if implemented so interrupt handler execution is not recorded */
+    asm volatile (".syntax unified           \n"
+                  "    ldr  r1, =0xe00ff000  \n"
+                  "    ldr  r2, [r1, #0x1c]  \n"
+                  "    tst  r2, #1           \n"
+                  "    beq  1f               \n"
+                  "    bic  r2, #0x00ff      \n"
+                  "    bic  r2, #0x0f00      \n"
+                  "    add  r1, r2           \n"
+                  "    ldr  r2, [r1, #4]     \n"
+                  "    bic  r2, #0x80000000  \n"
+                  "    str  r2, [r1, #4]     \n"
+                  " 1:                       \n"
+                  :
+                  :
+                  : "r1", "r2");
+
     console_blocking_mode();
     console_printf("Unhandled interrupt (%ld), exception sp 0x%08lx\n",
       SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk, (uint32_t)tf->ef);


[mynewt-core] 01/05: hw/mcu/dialog: Add support for Micro Trace Buffer (MTB)

Posted by an...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

andk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git

commit c4c5236fd867ed2fadd509be9127d637604ecfa0
Author: Andrzej Kaczmarek <an...@codecoup.pl>
AuthorDate: Sat Nov 21 01:27:53 2020 +0100

    hw/mcu/dialog: Add support for Micro Trace Buffer (MTB)
    
    This adds support for Micro Trace Buffer (MTB) which allows to store
    trace information of executed instructions in dedicated RAM area.
    Stored data can be then used to recreate exact program flow.
    
    MTB support is enabled by "MCU_MTB_ENABLE: 1". This will configure
    MTB on boot, enable code which persists MTB registers state in deep
    sleep and also reserves last 8KB of RAM for trace buffer.
    
    Additionally, by setting "MCU_MTB_AUTO_START: 1", MTB is enabled on
    boot.
    
    Note that enabling MTB changes main stack location since it cannot be
    placed at the end of RAM anymore since that area (8KB) is used by MTB.
    Make sure to rebuild flash loader, bootloader and app with new code as
    otherwise jumping from bootloader to app or from app to flash loader
    will fail.
---
 .../src/arch/cortex_m33/gcc_startup_da1469x.S      | 22 +++++++++++++++++++
 hw/mcu/dialog/da1469x/da1469x.ld                   |  9 +++++++-
 .../src/arch/cortex_m33/da1469x_m33_sleep.S        | 25 ++++++++++++++++++++++
 hw/mcu/dialog/da1469x/src/system_da1469x.c         |  5 +++++
 hw/mcu/dialog/da1469x/syscfg.yml                   | 13 +++++++++++
 5 files changed, 73 insertions(+), 1 deletion(-)

diff --git a/hw/bsp/dialog_da1469x-dk-pro/src/arch/cortex_m33/gcc_startup_da1469x.S b/hw/bsp/dialog_da1469x-dk-pro/src/arch/cortex_m33/gcc_startup_da1469x.S
index 616f319..d173f79 100644
--- a/hw/bsp/dialog_da1469x-dk-pro/src/arch/cortex_m33/gcc_startup_da1469x.S
+++ b/hw/bsp/dialog_da1469x-dk-pro/src/arch/cortex_m33/gcc_startup_da1469x.S
@@ -32,6 +32,9 @@
     .equ    SYS_CTRL_REG,       0x50000024
     .equ    CACHE_FLASH_REG,    0x100C0040
     .equ    RESET_STAT_REG,     0x500000BC
+    .equ    MTB_POSITION_REG,   0xE0043000
+    .equ    MTB_MASTER_REG,     0xE0043004
+    .equ    MTB_FLOW_REG,       0xE0043008
 
     .globl  __StackTop
     .globl  __StackLimit
@@ -154,6 +157,25 @@ wakeup_handler:
     .globl Reset_Handler
     .type  Reset_Handler, %function
 Reset_Handler:
+#if MYNEWT_VAL(MCU_MTB_ENABLE)
+    mov     r2, #0
+    ldr     r1, =MTB_POSITION_REG
+    str     r2, [r1]
+    ldr     r1, =MTB_FLOW_REG
+    str     r2, [r1]
+    ldr     r1, =MTB_MASTER_REG
+#if MYNEWT_VAL(MCU_MTB_AUTO_START)
+    ldr     r2, =0x80000009
+#else
+    ldr     r2, =0x00000009
+#endif
+    str     r2, [r1]
+#else
+    ldr     r1, =MTB_MASTER_REG
+    mov     r2, #0
+    str     r2, [r1]
+#endif
+
  /* Make sure interrupt vector is remapped at 0x0 */
     ldr     r1, =SYS_CTRL_REG
     ldrh    r2, [r1, #0]
diff --git a/hw/mcu/dialog/da1469x/da1469x.ld b/hw/mcu/dialog/da1469x/da1469x.ld
index d76ef05..f6714d9 100644
--- a/hw/mcu/dialog/da1469x/da1469x.ld
+++ b/hw/mcu/dialog/da1469x/da1469x.ld
@@ -210,11 +210,18 @@ SECTIONS
         *(.stack*)
     } > RAM
 
+    /* Dummy section to calculate whether we need to move stack out of MTB
+     * buffer or not. */
+    .mtb (NOLOAD) :
+    {
+        KEEP(*(.mtb));
+    }
+
     _ram_start = ORIGIN(RAM);
 
     /* Set stack top to end of RAM, and stack limit move down by
      * size of stack_dummy section */
-    __StackTop = ORIGIN(RAM) + LENGTH(RAM);
+    __StackTop = ORIGIN(RAM) + LENGTH(RAM) - SIZEOF(.mtb);
     __StackLimit = __StackTop - SIZEOF(.stack_dummy);
     PROVIDE(__stack = __StackTop);
 
diff --git a/hw/mcu/dialog/da1469x/src/arch/cortex_m33/da1469x_m33_sleep.S b/hw/mcu/dialog/da1469x/src/arch/cortex_m33/da1469x_m33_sleep.S
index df0d75e..d380465 100644
--- a/hw/mcu/dialog/da1469x/src/arch/cortex_m33/da1469x_m33_sleep.S
+++ b/hw/mcu/dialog/da1469x/src/arch/cortex_m33/da1469x_m33_sleep.S
@@ -46,6 +46,10 @@ da1469x_m33_sleep_state:
 .saved_fpu:
     .space 8    /* FPCCR, FPDSCR */
 #endif
+#if MYNEWT_VAL(MCU_MTB_ENABLE)
+.saved_mtb:
+    .space 12   /* POSITION, MASTER, FLOW */
+#endif
 
     .size   da1469x_m33_sleep_state, . - da1469x_m33_sleep_state
 
@@ -64,6 +68,9 @@ da1469x_m33_sleep_state:
     .equ QSPIC_CTRLBUS_OFFSET,      0x000
     .equ QSPIC_CTRLMOD_OFFSET,      0x004
     .equ QSPIC_WRITEDATA_OFFSET,    0x018
+    .equ MTB_POSITION_REG,          0xE0043000
+    .equ MTB_MASTER_REG,            0xE0043004
+    .equ MTB_FLOW_REG,              0xE0043008
 
     .equ SCB_CPACR_MASK,            0x00F00000  /* CP10 and CP11 */
     .equ SCB_SHCSR_MASK,            0x000F0000  /* xxxFAULTENA */
@@ -114,6 +121,13 @@ da1469x_m33_sleep:
     stmia   r3!, {r4-r5}
 #endif
 
+#if MYNEWT_VAL(MCU_MTB_ENABLE)
+/* Save MTB state  */
+    ldr     r0, =MTB_POSITION_REG
+    ldm     r0, {r4-r6}
+    stmia   r3!, {r4-r6}
+#endif
+
 /* Clear RESET_STAT_REG so wakeup handler can detect wakeup from deep sleep */
     ldr     r0, =RESET_STAT_REG
     movs    r3, #0
@@ -231,6 +245,17 @@ da1469x_m33_wakeup:
     str     r5, [r0, #(FPU_FPDSCR_OFFSET)]
 #endif
 
+#if MYNEWT_VAL(MCU_MTB_ENABLE)
+/* Restore MTB state */
+    ldmia   r3!, {r4-r6}
+    ldr     r0, =MTB_POSITION_REG
+    str     r4, [r0]
+    ldr     r0, =MTB_FLOW_REG
+    str     r6, [r0]
+    ldr     r0, =MTB_MASTER_REG
+    str     r5, [r0]
+#endif
+
 /* Restore MSP, PSP and CONTROL */
     ldr     r3, =.saved_msp
     ldmia   r3!, {r0-r2}
diff --git a/hw/mcu/dialog/da1469x/src/system_da1469x.c b/hw/mcu/dialog/da1469x/src/system_da1469x.c
index 5539fd0..9d1e8f6 100644
--- a/hw/mcu/dialog/da1469x/src/system_da1469x.c
+++ b/hw/mcu/dialog/da1469x/src/system_da1469x.c
@@ -38,6 +38,11 @@
 
 extern uint8_t __StackLimit;
 
+#if MYNEWT_VAL(MCU_MTB_ENABLE)
+/* Dummy symbol to reserve 8KB of RAM for MTB */
+uint32_t __attribute__((section(".mtb"))) mtb_dummy[2048];
+#endif
+
 void
 SystemInit(void)
 {
diff --git a/hw/mcu/dialog/da1469x/syscfg.yml b/hw/mcu/dialog/da1469x/syscfg.yml
index 0671504..9369cf9 100644
--- a/hw/mcu/dialog/da1469x/syscfg.yml
+++ b/hw/mcu/dialog/da1469x/syscfg.yml
@@ -86,6 +86,19 @@ syscfg.defs:
             general usage.
         value: 0
 
+    MCU_MTB_ENABLE:
+        description: >
+            Enable support for Micro Trace Buffer (MTB).
+            This will reserve RAM space for MTB buffer, configure
+            MTB on boot and properly store/restore MTB registers
+            state during deep sleep to allow continuous trace.
+        value: 0
+    MCU_MTB_AUTO_START:
+        description: >
+            Auto start MTB trace on boot. If disabled, MTB can be
+            still enabled manually either via code or debugger.
+        value: 0
+
     MCU_FLASH_MIN_WRITE_SIZE:
         description: >
             Specifies the required alignment for internal flash writes.