:orphan:

.. _ug_nrf54h20_logging:

nRF54H20 logging
################
.. contents::
   :local:
   :depth: 2

To read logs on the nRF54H20 DK, you can use the following methods:

* A direct UART connection to a specific core.
* Local domain logging with System Trace Macrocell (STM).
  STM has two modes:

  * Standalone logging
  * Assisted multicore logging

For general information on how logging works in the |NCS|, consult the :ref:`ug_logging` and :ref:`zephyr:logging_api` documentation pages.

nRF54H20 logging using a direct UART connection
***********************************************

.. to review

Similarly to other SoCs from Nordic Semiconductor, to use a UART connection for reading logs, follow the :ref:`ug_logging_backends_uart` logging guide in the application development section.

nRF54H20 logging using System Trace Macrocell (STM)
***************************************************

.. to review

nRF54H20 domains contain ARM Coresight System Trace Macrocell (STM) hardware devices for collecting trace data from multiple domains, using either standalone logging or assisted multicore logging.
The STM uses memory-mapped registers to write trace data generated by the domains in the system.
It multiplexes the data as trace protocol data, formatted according to the MIPI System Trace Protocol (STP) v2, and synchronizes the data on a single output, such as a single UART.
This approach has a minimal cost on performance and code size, allowing for a non-intrusive collection of system debug-and-trace information.

The STM implements a frontend of the Zephyr logging subsystem, allowing you to use the standard Zephyr logging API.

Embedded Trace Router (ETR)
===========================

.. to review

The Embedded Trace Router (ETR) is a hardware feature that provides a circular buffer in RAM for trace data.
It can trigger interrupts when the buffer is half-full or full, allowing the CPU to be woken up in time to handle the data.
The ETR buffer size is limited to 4 Kb, and it requires additional formatting with 16-byte frames.

When using ETR, one of the cores is designated as a *proxy* to manage the trace data.

.. note::
   Currently, the Secure Domain is the only core that can be designated as proxy.

The proxy core is responsible for handling the data from the ETR and outputting it through the desired transport mechanism (like UART or USB).
The proxy core approach allows for on-chip data processing, offering more flexibility than the Trace Port Interface Unit (TPIU).
However, due to the limited size of the ETR buffer, there is a risk of data loss if not handled promptly.

Standalone logging
==================

.. to review

The current implementation for the standalone logging mode with STM works as follows:

1. All domains write the raw encoded log data to their own STM peripheral called the STM Extended Stimulus Port (STMESP).
#. The STMESP generates a data stream based on the register writes.
#. The STM multiplexes the data stream with streams from other domains, and it places them in the single memory buffer provided by the ETR.
#. The Secure Domain Firmware (SDFW), acting as the ETR-designated proxy, reads the buffer and decodes the raw encoded log data.
#. The SDFW outputs the logging data in a human-readable format over UART.

Standalone logging leverages the frontend API of the Zephyr logging subsystem to select the stimulus ports and writes log messages directly to memory-mapped registers.
This method bypasses the need for string formatting functions and peripheral drivers, as the core writes directly to the STM port.

Configuration
-------------

.. to review

To show the logs for a given domain in the UART output, you must enable the STM for that domain.

To enable the STM for a domain, set the :kconfig:option:`CONFIG_LOG_STM` Kconfig option for that domain's image to ``y``.
The STM will be enabled by the build system in the configuration of the SDFW.

Reading the logs
----------------

.. to review

To read the STM log output on the UART, consult the following documentation pages:

* If you want to use the *nRF Serial Terminal* from the |nRFVSC|, see the `nRF Terminal documentation`_ on the `nRF Connect for Visual Studio Code`_ documentation site.
* If you want to use PuTTY, see :ref:`putty`.

.. note::
   To use UART in your application, the UART's node must be described in devicetree.
   For more details, see :ref:`zephyr:devicetree-intro`.

The following is an example log output::

   [00:00:00.154,790] <inf> app/spsc_pbuf: alloc in 0x2f0df800
   [00:00:00.163,319] <inf> app/spsc_pbuf: alloc 0x2f0df800 wr_idx:20
   [00:00:00.181,112] <inf> app/spsc_pbuf: commit in 0x2f0df800
   [00:00:00.189,090] <inf> app/spsc_pbuf: commit 0x2f0df800, len:20 wr_idx: 44
   [00:00:00.202,577] <inf> rad/icmsg: mbox_callback
   [00:00:00.214,750] <inf> rad/spsc_pbuf: claim 0x2f0df800 rd_idx:20
   [00:00:00.235,823] <inf> rad/spsc_pbuf: free 0x2f0df800 len:20 rd_idx: 44
   [00:00:00.244,507] <inf> rad/spsc_pbuf: read done 0x2f0df800 len:20
   [00:00:00.272,444] <inf> rad/host: ep recv 0x330021f0, len:20
   [00:00:00.283,939] <inf> rad/host: rx:00 exp:00
   [00:00:00.292,200] <inf> rad/icmsg: read 0
   [00:00:05.077,026] <inf> rad/spsc_pbuf: alloc in 0x2f0df000
   [00:00:05.077,068] <inf> rad/spsc_pbuf: alloc 0x2f0df000 wr_idx:44
   [00:00:05.077,098] <inf> rad/spsc_pbuf: commit in 0x2f0df000
   [00:00:05.077,134] <inf> rad/spsc_pbuf: commit 0x2f0df000, len:20 wr_idx

Each log line contains a domain-related or core-related prefix between the log level and the module name, indicating the core that generated the log entry.
The following are the prefixes used to indicate the cores:

.. csv-table:: nRF54H20 log prefixes
   :header: "Core", "Prefix"

   Secure Domain, ``sec``
   Application core, ``app``
   Radio core, ``rad``
   System Controller (SysCtrl), ``sys``
   Fast Lightweight Processor (FLPR), ``flpr``
   Peripheral Processor (PPR), ``ppr``

Assisted multicore logging
==========================

.. to review

Assisted multicore logging uses dictionary-based logging to send messages without redundant strings to STM, and is based on the :ref:`logging_guide_dictionary` feature of the logging API provided by Zephyr.
Instead of including the format strings in the log messages, it logs the addresses (message IDs) where the strings are stored, which reduces the size of the logging subsystem.
If the data goes to the ETR buffer, the proxy core's responsibility is to dump this data.
The host PC, equipped with a decoder tool, translates these addresses back into human-readable text using a JSON database generated during the build process.

When using logs, this method has the following advantages:

* It reduces the size of the binary, as the strings used in the log messages are not stored in the binary itself.
* It reduces the amount of data that needs to be sent to and processed by the application core, as the string formatting is offloaded to the host side.

Configuration
-------------

.. to review

To enable the assisted multicore logging for a domain, set the :kconfig:option:`CONFIG_LOG_STM_DICT` Kconfig option for that domain's image to ``y``.

After building your application, a dictionary database file named :file:`log_database.json` will be generated in the :file:`build/zephyr` directory.
This file is crucial for decoding the logs and is updated with every build.

Reading the logs
----------------

.. to review

To read the dictionary-based STM log output, do the following:

1. Set up the log capture.

   Use the ``nrfutil trace stm`` command to start capturing logs from the device, specifying the database configuration for each domain ID, as well as the serial port, the baud rate, and the output file name::

      nrfutil trace stm --database-config 33:build/secdom/src/secdombuild/zephyr/log_dictionary.json,34:build/zephyr/log_dictionary.json --input-serialport /dev/ttyACM1 --baudrate 115200 --output-ascii out.txt

#. Capture and decode the logs.

   nrfutil will capture the log data from the specified UART port and use the provided dictionary databases to decode the logs into a human-readable format.
   The decoded logs will be saved in the specified output file (the :file:`out.txt` file in the previous example).

#. Open the output file to review the decoded log messages.

   The file will contain timestamps and the log messages in a format that is human-readable.

If the log capture fails to find a sync, rerun the capture process.

.. note::
   Decoding artifacts or incorrect timestamps might occur when rerunning the process.

Each log line contains a domain-related or core-related prefix between the log level and the module name, indicating the core that generated the log entry.
The following are the prefixes used to indicate the cores:

.. csv-table:: nRF54H20 log prefixes
   :header: "Core", "Prefix", "ID"

   Secure Domain, ``sec``, 0x21
   Application core, ``app``, 0x22
   Radio core, ``rad``, 0x23
   System Controller (SysCtrl), ``sys``, 0x2c
   Fast Lightweight Processor (FLPR), ``flpr``, 0x2d
   Peripheral Processor (PPR), ``ppr``, 0x2e
    , ``mod``, 0x24

Additional considerations
-------------------------

.. to review

When using assisted multicore logging, consider the following:

* Use optimized log macros (having up to 2 word size numeric arguments, like ``LOG_INF("%d %c", (int)x, (char)y)``) to improve the size and speed of logging.
* For memory constrained applications (for example, when running on the PPR or FLPR cores), disable the ``printk()`` function by setting both the :kconfig:option:`CONFIG_PRINTK` and :kconfig:option:`CONFIG_BOOT_BANNER` Kconfig options to ``n`` in your project configuration.
* When working with multiple domains, such as the Secure Domain and Application core, ensure that each database is prefixed with the correct domain ID.
* Some log messages might be dropped due to the limited size of the RAM buffer that stores STM logs.
