Federico Fuga

Engineering, Tech, Informatics & science

Enabling the Logging service in Zephyr

16 Mar 2023 10:15 CET

Starting with Zephyr may be a bit steep due to the lack of step by step tutorials. In particular, when you need to start using a service or a driver, you either find the Zephyr documentation that is pretty precise and for this reason you are lost because of the huge amount of informations; or you find some step-by-step tutorial that start by explaining how to install the Operating System. But you just need to know how to integrate the logger!

This is the main reason for this post.

To enable the logger you have a few steps to complete:

  1. decide what kind of backend to use,
  2. enable the device needed for the backend
  3. start the service
  4. fill the calls for logging.

There are multiple backend that can be used for logging, depending on your needs. The most obvious is to use the Segger SWIO interface, but it is also the most complex to set up, because you need a Segger debugger (available in the nrf52840-DK board for example), and the software.

Easy to use is a serial console. It can be a UART or a CDC-USB uart if you want to enable the USB stack and all the other things. Personally I prefer the former, because it doesn’t interfere with the USB stack (if for example you want to use the USB for something different) and because you don’t need to remove it in production, if you don’t want to expose the debugging messages to the user.

Anyway, the good news is that you don’t need to decide it before you start, Zephyr is good enough to abstract this decision.

I remind you that you can always change the configuration by firing up the menuconfig by typing west build -t menuconfig and you’ll find the logging options in (top) -> Subsystems and OS Services -> Logging.

This is also useful because you can simply put the options in the prj.conf file by prepending the CONFIG_ prefix to the option name (hit thje ‘?’ key to see it in the menuconfig option entry).

Some important option are:

  • LOG=y will enable the logging service, you need it.
  • LOG_MODE can select how the logging will work. deferred, immediate and minimal are valid options, deferred is the default but you may want to see the other options. Immediate, for example, will flush the messages immediately, impacting the performances. See the API documentation.
  • Some backened is available:
    • SWO enabled by LOG_BACKEND_SWO
    • LOG_BACKEND_IPC_SERVICE will enable the IPC service
    • the UART backend is selected by LOG_BACKEND_UART
  • Output through UART can be formatted in different ways. We’ll use text format.

The Recipe

First, add the following lines to the prj.conf file:

CONFIG_LOG=y
CONFIG_LOG_BACKEND_UART=y
CONFIG_SERIAL=y

You may want to remove the serial console from UART, to have less code and reserve the UART for logging only:

CONFIG_CONSOLE=n
CONFIG_UART_CONSOLE=n

You don’t need to add anything to the device tree (app.overlay file) if you want to keep the original setup. In case of the Feather nrf52840, the UART signals (TX,RX) are in 2 pins in the left connector when looking the board with the USB connector up. Connect them to the TXD and RXD respectively of a TTL to USB converter. And you need the GND.

Adafruit nrf52840 feather pinout

In the main.c (and any other file where logging is needed) you need to add some header:

#include <zephyr/logging/log.h>

and this macro to register the module

LOG_MODULE_REGISTER(main);

If you didn’t change the LOG_BACKEND_UART_AUTOSTART option (default is y), you don’t need to call log_backend_enable() when setting up the board.

Then you can start logging.

void main(void)
{
	// ...
	LOG_INF("Starting demo");
	// ... 
}

Build, convert, flash. Profit.

[00:34:14.921,051] <inf> main: Blinking
[00:34:15.921,203] <inf> main: Blinking
[00:34:16.921,386] <inf> main: Blinking
[00:34:17.921,539] <inf> main: Blinking