IoT Zephyr

Zephyr Weekly Update – Multiplexing all the things!

Howdy! Before diving into this week’s updates, I would like to take a minute to encourage you to have a look at the Call for Papers for two really good open source conferences where I would love to see lots of cool Zephyr content 😉

  • FOSDEM 2024, Feb. 3-4 in Brussels, Belgium—The CfP for the Embedded, Mobile and Automotive devroom closes a week from now, on December 8, so don’t wait to submit.
  • Zephyr Developer Summit 2024 (co-located with Embedded Open Source Summit), Apr. 16-18 in Seattle, WA— You have a bit more time for this one, but make sure to not miss the January 14, 2024 deadline if you are interested in speaking at the event!

Also, a quick plug for the next Zephyr Tech Talk live stream on Wednesday, December 6 (note: we’ll be going live one hour later than our usual time, at 2pm GMT).

I will be chatting with open source rockstar Keith Packard about Picolibc, and how it can help you make your Zephyr application faster and leaner. I am very much looking forward to this one and hearing tons of C trivia from Keith 🙂

You can register here to make sure you get a reminder when we’ll go live, and you may of course consider spreading the word with your network, it’s always much appreciated!

Device multiplexing

There are many (maybe too many!) interesting tricks that can be implemented on top of Devicetree, and it gives a lot of flexibility in describing and tweaking the capabilities of your hardware.

This week, a new device multiplexer pseudo-device has been introduced. In a nutshell, this gives you a way to have a node in your Devicetree that acts as a proxy for other devices.

A typical application for this would be to be able to dynamically change which UART to use as the Zephyr console. Another interesting use case would be to have the devmux act as that one accel0 accelerometer sensor you’re using in your code, except that you could easily switch back and forth between an actual sensor, and an emulated one, for example. And all of this without having to continually update your Devicetree, recompile it, and run it again.

A picture being worth a thousands word, here’s a diagram that summarizes what’s going on under the hood.

            +----------+                            +----------+
            |  devmux  |                            |  devmux  |
            |          |                            |          |
 dev0       |          |                 dev0       |          |
 +---------->   \      |                 +---------->          |
            |    \     |                            |          |
 dev1       |     \    |       dev0      dev1       |          |       dev2
 +---------->      O   +---------->      +---------->      O   +---------->
            |          |                            |     /    |
 dev2       |          |                 dev2       |    /     |
 +---------->          |                 +---------->   /      |
            |          |                            |          |
            |          |                            |          |
            |          |                            |          |
            +-----^----+                            +-----^----+
                  |                                       |
   select == 0    |                       select == 2     |
   +--------------+                       +---------------+

From a Devicetree perspective, and for a use case where you’d want to multiplex multiple UARTs, it would look like the below:

/ {
    chosen {
        zephyr,console = &devmux0;
        zephyr,shell_uart = &devmux0;

    &uart0 {
        status = "okay";

    euart0: uart_emul0 {
        compatible = "zephyr,uart-emul";
        current-speed = <0>;
        status = "okay";

    euart1: uart_emul1 {
        compatible = "zephyr,uart-emul";
        current-speed = <0>;
        status = "okay";

Memory attributes based allocator

When configuring memory regions in the Devicetree, one can use the zephyr,memory-attr property to specify some flags that can then be used at runtime. This may be used for example by some drivers to indicate that they won’t function properly if used with specific types of memory, e.g. a DMA driver may require the use of non-cacheable memory.

A recently added feature makes it possible to fine-tune the way memory can be allocated from the heap, to help you easily get the right type of memory for your use case.

When CONFIG_MEM_ATTR_HEAP is set, all memory regions marked with specific flags (ex. DT_MEM_SW_ALLOC_CACHE) are added to a pool of memory heaps from which one can then allocate memory from by requesting chunks of memory of the desired type.

// Init the pool

// Allocate 0x100 bytes of cacheable memory
block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_CACHE, 0x100);

// Allocate 0x200 bytes of non-cacheable memory aligned to 32 bytes
block = mem_attr_heap_aligned_alloc(ATTR_SW_ALLOC_NON_CACHE, 0x100, 32);

// Allocate 0x100 bytes of cacheable and dma-able memory
block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_CACHE | DT_MEM_SW_ALLOC_DMA, 0x100);

Adding support for recvmsg()

Zephyr’s BSD Sockets now implement proper support for the recvmsg() API.

As opposed to recv(), recvmsg() can be used with both connected (ex. TCP) and connection-less (ex. UDP) protocols to receive a message from an arbitrary network address.

When used alongside the IP_PKTINFO flag, it can also be useful to get additional information about an incoming packet, for example the address of the sender.

Check out PR #65694 for more details.

Boards & SoCs

  • Arduino has gone a long way since its beginnings as a protyping tool for interaction design students. There is now a plethora of Arduino products very much geared towards industrial applications, and Arduino OPTA is one of them.
    Based on an STM32H747XI dual-core Arm® Cortex®-M7 +M4 MCU, it is basically a highly capable PLC (Programmable Logic Controller), that includes high-power relay switches, Modbus TCP and RTU capabilities, and more.
    As of this week and PR #64101, the M4 core of the Arduino OPTA is now officially supported in Zephyr!
Arduino OPTA.
  • The NXP UCANS32K1SIC is a CAN signal improvement capability (SIC) evaluation board designed for both automotive and industrial applications that provides 2 CAN SIC interfaces and is based on a Cortex-M4F NXP S32K146 MCU. Now supported 🙂 (PR #65461)
  • The Renesas R-Car Spider board is the reference board for evaluating the Renesas R-Car S4 SoC family.
    Both the SoC and the board are now supported as of this week! (PR #56043)
  • The Waveshare Pico UPS-B shield is a UPS (Uninterruptible Power supply) module designed for the Raspberry Pi Pico.
    It communicates with the Raspberry Pi Pico over I²C and allows to transparently control the charge of its battery and use it to power the Pi. It just joined the list of supported shields in Zephyr. (PR #60384)


  • The recently added GNSS subsystem gets a new generic NMEA driver, that can be used with any source of NMEA frames.
    When you really only care about getting and decoding the raw NMEA data straight from your GPS receiver, and have no interest in tinkering with the module’s settings (or maybe it doesn’t even have any), then this driver will be your new friend. (PR #65422)
&uart0 {
          current-speed = <9600>;
          gnss: gnss-nmea-generic {
                  compatible = "gnss-nmea-generic";
  • I²C support added for Nuvoton Numaker. (PR #65673)
  • Added support for NXP TJA1103 Ethernet PHY. (PR #65756)
  • New experimental NXP ENET Ethernet driver. (PR #62833)


A big thank you to the 9 individuals who had their first pull request accepted this week, 💙 🙌: @ShaharHD, @kilejin, @boz, @timwoolliscroft-opteran, @marcowidmer, @Grin00, @borrelunde, @arkwad, and @adamfc2000.

As always, I very much welcome your thoughts and feedback in the comments below!

If you enjoyed this article, don’t forget to subscribe to this blog to be notified of upcoming publications! And of course, you can also always find me on Twitter and Mastodon.

Catch up on all previous issues of the Zephyr Weekly Update:

IoT Zephyr

Zephyr Weekly Update – Bringing userspace to Xtensa

It was a lot of fun to play the guest in this week’s Zephyr Tech Talk. There was a lot to cover in “just” one hour (and there were tons of great questions from the audience to answer!), but I am happy that all the demos I wanted to show worked like I wanted. There are quite a few things that made my life easier when deciding I would migrate my “hackish” Arduino code to Zephyr, and the video dives into what these are.

Interestingly, by the end of the talk, I had shown most of the code on screen, all while digressing about many other things, answering questions, etc. I hope that helps make the point that Zephyr can really help you not reinvent the wheel, and help you focus more on the code that’s actually your application, and less on the boilerplate low-level stuff 🙂

Catch up on the recording here:

And as a reminder, all the code of the project is on GitHub, at so I encourage you to check it out!

And now, for the news from this past week…

Userspace on Xtensa

When building your application on top of Zephyr, you probably don’t want or need your entire code to run in supervisor mode, with full access to the memory, kernel objects, etc. While, say, a custom driver of your might require low-level interactions with the system, but your “actual” application probably only really cares about calling into a few APIs that will expose the data or functionality you need in your applications.

For architectures that include an MMU/MPU (Memory Management Unit / Memory Protection Unit), it is possible to instruct Zephyr to create so-called user-mode threads that end up running in their own sandbox, with very limited permissions unless explicitly granted.

This week, PR #61303 has introduced userspace support for Xtensa architectures, which is a major improvement, alongside a complete re-implementation of the MMU layer for Xtensa.

Picolibc 1.8.5

The newly released Zephyr SDK, version 0.16.4, ships the latest version of Picolibc, 1.8.5.

As per PR #62882, this new version of Picolibc brings more flexibility in selecting a printf/scanf variant to support only the format specifiers that one really needs, i.e. not bloat your binary if you don’t care about printing floats, for example.

As a reminder, while using a pre-compiled version from Picolibc straight from the SDK will give you faster compilation times, there is always the possibility to enable Kconfig option CONFIG_PICOLIBC_USE_MODULE if you want to tweak Picolibc further.

Stay tuned for a Zephyr Tech Talk entirely dedicated to Picolibc C on Wednesday, Dec. 6!

IGMPv3 support

The Internet Group Management Protocol (IGMP) is a protocol primarily used for managing multicast group memberships on IPv4 networks. It enables a host to inform its local router about its desire to join or leave a multicast group, which can be useful when building e.g. sensor networks where you want to use network resources as efficiently as possible.

As of this week, IGMPv3 is now supported. (PR #65293)

Among other things, IGMPv3 allows source filtering, enabling a system to report interest in receiving packets only from specific source addresses, or from all but specific source addresses, sent to a particular multicast address.

Boards & SoCs

STM32U5A9J-DK development board


  • A new pwm-clock binding allows to add a clock control device for a PWM node, such that the PWM can be controlled using the clock control API.
pwmclock: pwmclock {
    status = "okay";
    compatible = "pwm-clock";
    #clock-cells = <1>;
    pwms = <&pwm_ccu40 2 PWM_HZ(1000000) PWM_POLARITY_NORMAL>;
  • New regulator driver for Smartbond DA1469X SoC. (PR #65226)


  • The Bluetooth Hearing Access (HAS) server now uses non-volatile settings to restore the client awareness of preset list entries exposed by the server. (PR #64164)
  • A lot of work went into cleaning up the documentation of the POSIX API available in Zephyr.
  • A new Kconfig option, CONFIG_SDL_DISPLAY_ZOOM_PCT allows to artificially tweak the scale of the main display when using a native simulation on your desktop.
    This can be really useful when testing, say, a 200x200px smartwatch GUI on your 32″ Retina display, without killing your eyes 🙂 (PR #65556)
  • New shell commands (that can be enabled using CONFIG_PLIC_SHELL) to display the hit count of each interrupt controller’s IRQ line. (PR #65533)
uart:~$ plic stats get interrupt-controller@c000000
   IRQ        Hits
    10         236

uart:~$ plic stats clear interrupt-controller@c000000
Cleared stats of interrupt-controller@c000000.

uart:~$ plic stats get interrupt-controller@c000000
   IRQ        Hits
    10          90

  • Various improvements and optimizations to the modem UART backend (PR #65194)

A big thank you to the 12 individuals who had their first pull request accepted this week, 💙 🙌: @ajarmouni-st, @lukas-fwdev, @adolfogc, @adleris, @arnaudmz, @adrienbruant, @wmrsouza, @falvia, @deveritec-rosc, @kamilrakoczy, @ndrs-pst, and @idruzhinin.

As always, I very much welcome your thoughts and feedback in the comments below!

If you enjoyed this article, don’t forget to subscribe to this blog to be notified of upcoming publications! And of course, you can also always find me on Twitter and Mastodon.

Catch up on all previous issues of the Zephyr Weekly Update:

IoT Zephyr

Zephyr Weekly Update – C11 threads, Enhanced logging, and more

This has been a very busy week for the community, with an above average amount of new drivers and boards getting merged. Speaking of recently added boards, I am very excited to include one, the super tiny M5Stack AtomS3, in my Zephyr Tech Talk presentation next Wednesday! 🙂

I hope many of you will join, as I will be covering how I ended up migrating my now pretty old, and frankly quite hackish, Artificial Nose project to Zephyr in a matter of hours. I used this opportunity to deep more into some Zephyr features that I hadn’t add a chance to touch before, like Zbus, and I can’t wait to share my experience with y’all.

You should register to make sure you don’t miss the live stream, and of course feel free to also share the event with your network!

Support for C11 threads

The C11 standard introduced a native multi-threading API that aims at establishing a portable API for all things threads.

POSIX is of course a very popular programming model for manipulating threads, but being part of the language itself, the API introduced in the 2011 version of the C standard is effectively (or should be at least!) supported on *any* platform that supports the C11 standard.

#include <stdio.h>
#include <threads.h>

// Thread function
int printHelloWorld(void *arg) {
    printf("Hello, World!\n");
    return 0;

int main() {
    thrd_t thread;

    // Create a new thread
    if (thrd_create(&thread, printHelloWorld, NULL) != thrd_success) {
        fprintf(stderr, "Error creating thread\n");
        return 1;

    // Wait for the created thread to terminate
    thrd_join(thread, NULL);

    return 0;

Chris Friedt has been working on bringing C11 threads support to Zephyr and this materialized this week with PR #60759 being merged. Quite interestingly, since Zephyr already exposes a POSIX API, most of the threads.h APIs end up mapping mostly 1-to-1 to POSIX functions.

Logging to multiple UARTs

A new zephyr,log-uart chosen node can be used to indicate that log outputs may be sent to multiple UARTs.

Until now, the UART log backend would have been only logging to the zephyr,console chosen node, but with PR #64917 it’s now possible to have the following kind of node in your Devicetree to indicate the various UARTs where you’d like logs to show up:

/ {
	chosen {
		zephyr,log-uart = &log_uarts;

	log_uarts: log_uarts {
		compatible = "zephyr,log-uart";
		uarts = <&uart0 &uart1>;


New keyboard matrix GPIO driver

A new type of driver has been introduced to allow modeling a keyboard matrix out of any set of GPIOs. The gpio-kbd-matrix binding allows you to define your keyboard matrix configuration such as:

  kbd-matrix {
          compatible = "gpio-kbd-matrix";
          row-gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>,
                      <&gpio0 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
          col-gpios = <&gpio0 2 GPIO_ACTIVE_LOW>,
                      <&gpio0 3 GPIO_ACTIVE_LOW>,
                      <&gpio0 4 GPIO_ACTIVE_LOW>;

More details in PR #65117.

Boards & SoCs

  • The nRF9131 Evaluation Kit from Nordic is a single-board evaluation kit for the nRF9131 SiP for LTE-M and NB-IoT.
nRF9131 EK (Credit: Nordic Semiconductor)
  • The M5Stack AtomS3 is a *very* tiny ESP32-S3 based developer kit that manages to fit a small 0.85″ LCD display on what is effectively a 1×1″ (24×24mm) piece of electronics!
    Since it also has an on-board accelerometer, it can run the LVGL Accelerometer Chart code sample out-of-the-box!
LVGL Accelerometer Chart code sample running on the M5Stack AtomS3 board.
  • The Renesas Starter Kit+ for RZ/T2M is an evaluation and development kit for the RZ/T2M MPU. (PR #64566)
  • Support has been added for the Verdin iMX8M Plus Computer on Module (CoM) from Toradex. (PR #61713)
  • UP Squared Pro 7000 is now supported. It is the 3rd generation of palm-sized developer board of UP Boards series and it is powered by an Intel Alder Lake N (Intel N-series Platform) SoC. (PR #65019)
  • Support has been added for the STM32H7B0 SoC series. (PR #65092)


  • New driver for the Linear Technologies LTC2451 ADC, an ultra-tiny 16-bit ADC. (PR #64390)
  • New driver for Renesas HS3001 and HS3003 temperature/humidity sensors (PR #63016)
  • A charger driver has been added to the already existing regulator driver for the MAX20335 multi-function device. (PR #64971)
  • The LPS22DF altimeter / pressure sensor is now supported. It is an ultracompact, piezoresistive, absolute pressure sensor that can be used as a digital output barometer, with an output data rate up to 200 Hz (PR #62028)
  • The NXP LPC DMA driver now supports hardware triggering. (PR #64573)
  • New driver for NXP FlexRAM memory controller. FlexRAM is a highly configurable and flexible RAM memory array, found on e.g. RT10XX and RT11XX series. (PR #62788)
  • New modem driver for Quectel EG25-G. (PR #64746)
  • New driver for ExplorIR-M CO2 sensor. A new co2_polling code samples was also introduced to make it easy to try things out with this driver (or any other CO2 driver really!). (PR #64621)
  • A new CAN shell command (can timing) adds support for setting raw timing values. (PR #65054)


  • The inter-core messaging (ICMsg) backend now supports the transfer of dynamically allocated buffers. (PR #58741)
  • Added API to BLE Audio CAP to set codec capabilities. (PR #63223)
  • Zephyr native simulator is now the recommended target for running Zephyr in your desktop/POSIX environment, and the documentation has been updated to reflect that.
  • The UART Shell backend has been reworked to support the asynchronous UART API. (PR #63967)
  • A new set of shell commands (cred ...) allow to interactively set TLS network credentials. See the list of commands here. (PR #64343)
  • MCUmgr OS management group now has functions for getting/setting the current time to/from the rtc alias device. (PR #64934)
  • The Bluetooth “broadcast audio source” code sample now supports using e.g. your host computer as the audio source.
    Granted that you are running the sample on a device that has a USB Device stack and Audio support, enabling CONFIG_USE_USB_AUDIO_INPUT will make your device show up as a sound device when plugged to your computer, and any audio that you will send to this “virtual speaker”, will be broadcast over LE Audio! 🔊

A big thank you to the 11 individuals who had their first pull request accepted this week, 💙 🙌: @TimTTP, @GabrielHAFs, @LipinskiPNordicSemi, @michael-whg, @josuah, @CkovMk, @CharlesDias, @ndaneil, @xvigo, @KamilxPaszkiet, and @mpenate-ellenbytech.

As always, I very much welcome your thoughts and feedback in the comments below!

If you enjoyed this article, don’t forget to subscribe to this blog to be notified of upcoming publications! And of course, you can also always find me on Twitter and Mastodon.

Catch up on all previous issues of the Zephyr Weekly Update: