Tag Archive for: zephyr

We always seem to meet people at conferences who are looking for a Bluetooth gateway solution. Golioth is the universal connector for IoT, and today we’re going to take a look at one way to extend that to your Bluetooth devices.

Luckily, Bluetooth is well supported by Zephyr. We’re going to run some sample code, then customize it to use Golioth as the cloud connection for a Bluetooth gateway device. Our target hardware is an nRF9160-DK as the gateway (we’ll refer to this as the central), and an nRF52840-DK as the sensor (which we’ll call the peripheral).

Two blue Nordic development boards on a wooden desk

Upper: nRF52840-DK as a Bluetooth health temperature sensor
Lower: nRF9160-DK as a Bluetooth-to-Cellular gateway

We’re using the nRF Connect SDK version of Zephyr. You can follow our NCS with Golioth documentation to install it locally if you have not already done so.

This guide uses Golioth Firmware SDK v0.12.0 with NCS v2.5.2

HCI low power UART

We chose the nRF9160-DK because it has both an nRF9160 to provide a cellular connection, and an nRF52840 as a Bluetooth radio. The nRF9160 will run the show, communicating with the nRF52840 over UART. Nordic has an HCI low power UART sample that we will compile and run on the nRF52840 (the one that’s on the nRF9160-DK board) before we work on the central code for the nRF9160.

1. Build the HCI low power UART

Note that this build command compiles code for the nRF52840 chip that is on the nRF9160-DK development board.

cd ~/golioth-ncs-workspace/nrf/samples/bluetooth/hci_lpuart
west build -b nrf9160dk_nrf52840 .

2. Move the Prog/Debug switch and flash

Locate the PROG/DEBUG switch on the nRF9160-DK and move it to the nRF52 position. This controls a mux that points at the Bluetooth chip. Use west to flash the firmware:

➜ west flash
-- west flash: rebuilding
ninja: no work to do.
-- west flash: using runner nrfjprog
Using board 960088581
-- runners.nrfjprog: Flashing file: /home/mike/golioth-compile/golioth-firmware-sdk/nrf/samples/bluetooth/hci_lpuart/build/zephyr/zephyr.hex
[ #################### ]   4.820s | Erase file - Done erasing
[ #################### ]   1.207s | Program file - Done programming
[ #################### ]   1.227s | Verify file - Done verifying
Enabling pin reset.
Applying pin reset.

When done, move the programming switch back to nRF9160 so it’s ready for the next step.

Load the central_ht sample on the nRF9160-DK

Zephyr includes a Health Temperature Service sample application which we’ll use as our hello world. Let’s compile and flash the “central” part of that sample.

1. Add board files to the central_ht sample code

Navigate to the central_ht sample code in the Zephry tree:

cd ~/golioth-ncs-workspace/zephyr/samples/bluetooth/central_ht/

We need to add a boards directory and create a conf file and and two overlay files for the nRF9160 in that directory. These configure the board to use the HCI low power UART firmware we flashed in the previous section as the Bluetooth radio (think of it as a secondary modem controlled by the application processor on the nRF9160).

In total we add 3 files:

  • nrf9160dk_nrf9160_ns.conf
  • nrf9160dk_nrf9160_ns.overlay
  • nrf9160dk_nrf9160_ns_0_14_0.overlay
# HCI low power UART
CONFIG_NRF_SW_LPUART=y
CONFIG_NRF_SW_LPUART_INT_DRIVEN=y

CONFIG_UART_2_ASYNC=y
CONFIG_UART_2_INTERRUPT_DRIVEN=n
CONFIG_UART_2_NRF_HW_ASYNC=y
CONFIG_UART_2_NRF_HW_ASYNC_TIMER=2
#include <nrf9160dk_nrf52840_reset_on_if5.dtsi>

/ {
    chosen {
        zephyr,bt-uart=&lpuart;
    };
};

&gpiote {
    interrupts = <49 NRF_DEFAULT_IRQ_PRIORITY>;
};

&uart2 {
    current-speed = <1000000>;
    status = "okay";
    /delete-property/ hw-flow-control;

    pinctrl-0 = <&uart2_default_alt>;
    pinctrl-1 = <&uart2_sleep_alt>;
    pinctrl-names = "default", "sleep";
    lpuart: nrf-sw-lpuart {
        compatible = "nordic,nrf-sw-lpuart";
        status = "okay";
        req-pin = <21>; /* <&interface_to_nrf52840 3 0>; */
        rdy-pin = <19>; /* <&interface_to_nrf52840 2 0>; */
    };
};

&pinctrl {
    uart2_default_alt: uart2_default_alt {
        group1 {
            psels = <NRF_PSEL(UART_TX, 0, 18)>,
                <NRF_PSEL(UART_RX, 0, 17)>;
        };
    };

    uart2_sleep_alt: uart2_sleep_alt {
        group1 {
            psels = <NRF_PSEL(UART_TX, 0, 18)>,
                <NRF_PSEL(UART_RX, 0, 17)>;
            low-power-enable;
        };
    };

};

It’s important to add this second overlay file that properly maps the reset line for newer nRF9160-DK boards:

/* Use the reset line that is available starting from v0.14.0 of the DK. */
#include <nrf9160dk_nrf52840_reset_on_if9.dtsi>

2. Build and flash the central_ht sample code

west build -b nrf9160dk_nrf9160_ns .
west flash

If you get an error when trying to flash the board, ensure you have the PROG/DEBUG switch in the nRF91 position.

The nRF9160-DK will immediately begin scanning for compatible Bluetooth human temperature services. Let’s set up one of those next.

Load the peripheral_ht sample on the nRF52840-DK

The previous steps complete the “central” part of the Bluetooth equation which will scan for available sensors. Now we need to create a “peripheral”, which is the sensor that will advertise itself and serve temperature readings from a sensor.

Building and flashing this sample code is very straight-forward:

cd ~/golioth-ncs-workspace/zephyr/samples/bluetooth/peripheral_ht/
west build -b nrf52840dk_nrf52840 .
west flash

Monitor the output

Connect to the nRF9160-DK over serial and you should see the device scan for a compatible peripheral, connect to it, and begin taking temperature readings:

*** Booting nRF Connect SDK v2.5.2 ***
Temperature 23.75C.
Connected: E9:E3:F1:6D:A9:87 (random)
[ATTRIBUTE] handle 25
[ATTRIBUTE] handle 26
[ATTRIBUTE] handle 28
[SUBSCRIBED]
Temperature 23.75C.
Temperature 23.75C.
Temperature 23.75C.
Temperature 23.75C.
Temperature 24C.

Next up, let’s connect Golioth and send these readings to the cloud!

Add Golioth to the project

To Golioth to this project we need three things:

  1. Ensure Golioth is installed as a Zephyr module
  2. Add Kconfig symbols to enable nRF9160 cellular and to add Golioth
  3. Add a few API calls to the central_ht code to connect to Golioth and push the temperature reading to the cloud

In this section we’ll be working with the Zephyr central_ht sample so let’s switch to that directory:

cd ~/golioth-ncs-workspace/zephyr/samples/bluetooth/central_ht/

1. Add Golioth as a Zephyr Module

If you followed our getting started guide for NCS, this is already done. If not, you can follow the Adding the Golioth Firmware SDK to an Existing Zephyr West Project section of our SDK readme.

2. Add Kconfig symbols for cellular and Golioth

For these changes, we’ll crib a lot of code from Golioth’s LightDB Stream sample since we’re using that service to stream the temperature to the cloud.

Add the contents of the nRF9160-DK board file from the Golioth lightdb_stream sample to the board file you previously created in the central_ht Zephyr sample. Here’s what that file should look like now:

# General config
CONFIG_HEAP_MEM_POOL_SIZE=4096
CONFIG_NEWLIB_LIBC=y

# Networking
CONFIG_NET_SOCKETS_OFFLOAD=y
CONFIG_NET_IPV6=y
CONFIG_NET_IPV6_NBR_CACHE=n
CONFIG_NET_IPV6_MLD=n

# Increase native TLS socket implementation, so that it is chosen instead of
# offloaded nRF91 sockets
CONFIG_NET_SOCKETS_TLS_PRIORITY=35

# Modem library
CONFIG_NRF_MODEM_LIB=y
CONFIG_NRF_MODEM_LIB_ON_FAULT_APPLICATION_SPECIFIC=y

# LTE connectivity with network connection manager
CONFIG_LTE_CONNECTIVITY=y
CONFIG_NET_CONNECTION_MANAGER=y
CONFIG_NET_CONNECTION_MANAGER_MONITOR_STACK_SIZE=1024

# Increased sysworkq size, due to LTE connectivity
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048

# Disable options y-selected by NCS for no good reason
CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED=n
CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED=n

# Generate MCUboot compatible images
CONFIG_BOOTLOADER_MCUBOOT=y

# HCI low power UART
CONFIG_NRF_SW_LPUART=y
CONFIG_NRF_SW_LPUART_INT_DRIVEN=y

CONFIG_UART_2_ASYNC=y
CONFIG_UART_2_INTERRUPT_DRIVEN=n
CONFIG_UART_2_NRF_HW_ASYNC=y
CONFIG_UART_2_NRF_HW_ASYNC_TIMER=2

Now in the prj.conf file for the central_ht code sample, add the following Kconfig symbols. These have the effect of enabling the Golioth SDK, enabling the Stream service, and using runtime settings to store your device credentials in the storage partition using the Zephyr shell. The main stack size is also increased to account for some additional memory usage.

CONFIG_BT=y
CONFIG_LOG=y
CONFIG_BT_CENTRAL=y
CONFIG_BT_SMP=y
CONFIG_BT_GATT_CLIENT=y
CONFIG_CBPRINTF_FP_SUPPORT=y
# Golioth Firmware SDK
CONFIG_GOLIOTH_FIRMWARE_SDK=y

# Application
CONFIG_MAIN_STACK_SIZE=2048
CONFIG_GOLIOTH_SAMPLE_COMMON=y
CONFIG_LOG_BACKEND_GOLIOTH=y
CONFIG_GOLIOTH_SETTINGS=y
CONFIG_GOLIOTH_STREAM=y

CONFIG_GOLIOTH_SAMPLE_HARDCODED_CREDENTIALS=n

CONFIG_FLASH=y
CONFIG_FLASH_MAP=y
CONFIG_NVS=y

CONFIG_SHELL=y
CONFIG_SETTINGS=y
CONFIG_SETTINGS_RUNTIME=y
CONFIG_GOLIOTH_SAMPLE_PSK_SETTINGS=y
CONFIG_GOLIOTH_SAMPLE_SETTINGS_AUTOLOAD=y
CONFIG_GOLIOTH_SAMPLE_SETTINGS_SHELL=y

CONFIG_LOG=y
CONFIG_EVENTFD_MAX=14
CONFIG_LOG_PROCESS_THREAD_STACK_SIZE=1536
CONFIG_MBEDTLS_ENABLE_HEAP=y
CONFIG_MBEDTLS_HEAP_SIZE=10240
CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=2048
CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=2048
CONFIG_NETWORKING=y
CONFIG_NET_IPV4=y
CONFIG_POSIX_MAX_FDS=23

3. Add Golioth API calls to main.c

With all the configuration in place, we’re now ready to update main.c to connect to Golioth and push temperature readings to the cloud.

First, add some includes, create a semaphore, and add a callback near the top of main.c:

#include <golioth/client.h>
#include <golioth/stream.h>
#include <samples/common/net_connect.h>
#include <samples/common/sample_credentials.h>

static struct golioth_client *client;
static K_SEM_DEFINE(golioth_connected, 0, 1);

static void on_client_event(struct golioth_client *client, enum golioth_client_event event,
                void *arg)
{
    bool is_connected = (event == GOLIOTH_CLIENT_EVENT_CONNECTED);
    if (is_connected) {
        k_sem_give(&golioth_connected);
    }
    printk("Golioth client %s\n", is_connected ? "connected" : "disconnected");
}

Next, in the notify_func() function, add an API call to send data to Golioth:

char sbuf[32];
snprintk(sbuf, sizeof(sbuf), "{\"temperature\":%g}", temperature);
printf("Sending to Golioth: %s\n", sbuf);


int err = golioth_stream_set_async(client,
                   "sensor",
                   GOLIOTH_CONTENT_TYPE_JSON,
                   sbuf,
                   strlen(sbuf),
                   NULL,
                   NULL);
if (err) {
    printf("Failed to push temperature: %d\n", err);
}

Finally, in main() add code to start the Golioth client connection:

char sbuf[32];
snprintk(sbuf, sizeof(sbuf), "{\"temperature\":%g}", temperature);
printf("Sending to Golioth: %s\n", sbuf);


int err = golioth_stream_set_async(client,
                   "sensor",
                   GOLIOTH_CONTENT_TYPE_JSON,
                   sbuf,
                   strlen(sbuf),
                   NULL,
                   NULL);
if (err) {
    printf("Failed to push temperature: %d\n", err);
}

Running the demo and viewing data on the cloud

The first time you run the nRF9160-DK you need to add device credentials. Open a serial terminal to the device and use the shell to issue the following commands:

uart:~$ settings set golioth/psk-id my-psk-id@my-project
uart:~$ settings set golioth/psk my-psk
uart:~$ kernel reboot warm

With both of our boards programmed and powered on, we can view the terminal output of the nRF9160-DK to see the connection and scanning process:

*** Booting nRF Connect SDK v2.5.2 ***                                                                                                                                                         
[00:00:00.465,972] <inf> fs_nvs: 2 Sectors of 4096 bytes                                                                                                                                       
[00:00:00.466,003] <inf> fs_nvs: alloc wra: 0, fb8                                                                                                                                             
[00:00:00.466,003] <inf> fs_nvs: data wra: 0, 68                                                                                                                                               
[00:00:00.466,278] <inf> golioth_samples: Bringing up network interface                                                                                                                        
[00:00:00.466,308] <inf> golioth_samples: Waiting to obtain IP address                                                                                                                         
[00:00:02.545,684] <inf> lte_monitor: Network: Searching                                                                                                                                       
[00:00:05.688,049] <inf> lte_monitor: Network: Registered (roaming)                                                                                                                            
[00:00:05.689,117] <inf> golioth_mbox: Mbox created, bufsize: 1232, num_items: 10, item_size: 112                                                                                              
[00:00:07.861,846] <inf> golioth_coap_client_zephyr: Golioth CoAP client connected                                                                                                             
Golioth client connected                                                                                                                                                                       
[00:00:07.862,365] <inf> golioth_coap_client_zephyr: Entering CoAP I/O loop                                                                                                                    
[00:00:08.559,051] <wrn> bt_hci_core: opcode 0x0000 pool id 5 pool 0x2000d430 != &hci_cmd_pool 0x2000d488                                                                                      
[00:00:08.600,585] <inf> bt_hci_core: HW Platform: Nordic Semiconductor (0x0002)                                                                                                               
[00:00:08.600,616] <inf> bt_hci_core: HW Variant: nRF52x (0x0002)                                                                                                                              
[00:00:08.600,646] <inf> bt_hci_core: Firmware: Standard Bluetooth controller (0x00) Version 141.732 Build 3324398027                                                                          
[00:00:08.610,504] <inf> bt_hci_core: Identity: E1:99:6F:78:C4:C4 (random)                                                                                                                     
[00:00:08.610,534] <inf> bt_hci_core: HCI: version 5.4 (0x0d) revision 0x1168, manufacturer 0x0059                                                                                             
[00:00:08.610,565] <inf> bt_hci_core: LMP: version 5.4 (0x0d) subver 0x1168                                                                                                                    
Bluetooth initialized                                                                                                                                                                          
Scanning successfully started                                                                                                                                                                  
[DEVICE]: F4:BC:DA:35:5E:68 (public), AD evt type 0, AD data len 27, RSSI -85                                                                                                                  
[AD]: 1 data_len 1                                                                                                                                                                             
[AD]: 9 data_len 12                                                                                                                                                                            
[AD]: 255 data_len 8                                                                                                                                                                           
[DEVICE]: F4:BC:DA:35:5E:68 (public), AD evt type 4, AD data len 31, RSSI -85                                                                                                                  
[DEVICE]: F0:5F:8B:2D:1C:A2 (random), AD evt type 0, AD data len 20, RSSI -82                                                                                                                  
[AD]: 9 data_len 5                                                                                                                                                                             
[AD]: 25 data_len 2                                                                                                                                                                            
[AD]: 1 data_len 1                                                                                                                                                                             
[AD]: 2 data_len 4                                                                                                                                                                             
[DEVICE]: F0:5F:8B:2D:1C:A2 (random), AD evt type 4, AD data len 0, RSSI -81                                                                                                                   
[DEVICE]: E9:E3:F1:6D:A9:87 (random), AD evt type 0, AD data len 11, RSSI -29                                                                                                                  
[AD]: 1 data_len 1                                                                                                                                                                             
[AD]: 3 data_len 6                                                                                                                                                                             
uart:~$ Temperature 21.5C.                                                                                                                                                                     
Sending to Golioth: {"temperature":21.5}                                                                                                                                                       
Connected: E9:E3:F1:6D:A9:87 (random)                                                                                                                                                          
[ATTRIBUTE] handle 25                                                                                                                                                                          
[ATTRIBUTE] handle 26                                                                                                                                                                          
[ATTRIBUTE] handle 28                                                                                                                                                                          
[SUBSCRIBED]                                                                                                                                                                                   
uart:~$ Temperature 21.5C.                                                                                                                                                                     
Sending to Golioth: {"temperature":21.5}                                                                                                                                                       
Temperature 21.25C.                                                                                                                                                                            
Sending to Golioth: {"temperature":21.25}                                                                                                                                                      
Temperature 21.5C.                                                                                                                                                                             
Sending to Golioth: {"temperature":21.5}                                                                                                                                                       
Temperature 21.25C.                                                                                                                                                                            
Sending to Golioth: {"temperature":21.25}

We see the chip boot, connect to the cell network, then connect to Golioth. After that, the Bluetooth scan begins, connecting to devices it finds to query for the desired health temperature service (HTS). Once a service is found, we see temperature readings that are then pushed to the cloud.

Checking on the LightDB Stream tab in the device view of the Golioth web console shows the data arriving on the cloud!

Bluetooth sensor data shown on the LightDB Stream tab of the Golioth web console

Connecting Bluetooth to the Cloud

This lays the groundwork for connecting your Bluetooth devices to the cloud. One gateway (or a relatively small number of them) can service multiple BLE peripheral devices for both read and write activities. It’s even possible to update firmware over a Bluetooth connection. But that’s a post for a different day.

Give Golioth a try, it’s free for individuals! If you have a need for a more involved Bluetooth to Cellular gateway, we’d love to hear about it. Reach out to the Golioth DevRel team.

If you want to dive into the code from this post, start with the Zephyr central_ht sample and apply the file changes found in this gist.

Golioth works with Qualcomm

We’re excited to announce the latest update to the Golioth Firmware SDK, release 0.12.0, which now includes support for Zephyr’s newly introduced Modem Subsystem. This enhancement significantly increases the flexibility of our platform, enabling support for a broader array of cellular modem technologies, starting with Qualcomm. 0.12.0 adds support for the Quectel BG95, joining the Nordic Semiconductor nRF9160 (our go-to modem around here!) as a first class cellular modem. We also introduced additional ways to securely store credentials.

Zephyr’s New Modem Subsystem

Introduced in Zephyr 3.5.0, the Modem Subsystem is a unified interface for modem drivers. This addition simplifies the integration of cellular modems (and others) into Zephyr-based projects, greatly expanding the range of devices and technologies that developers can utilize effectively. For a detailed overview of the modem subsystem, check out this summary from Zephyr’s Developer Advocate, Benjamin Cabé.

Integration in Golioth Firmware SDK

With the integration of this modem subsystem in the Golioth Firmware SDK, Golioth users can now more flexibly incorporate a wider array of modem technologies into their IoT projects. There are a lot of great modems and module vendors in the market and providing choice is at the heart of what we do at Golioth.

First Supported Modem and Board

The first modem we are supporting with this updated SDK is the BG95 from Quectel, based on Qualcomm technology. The BG95 is paired with the nRF52840 on the RAK5010 development board from RAKwireless. This combination highlights the flexibility of Qualcomm’s technology integrated into Quectel’s hardware, offering developers robust tools for deploying cellular IoT solutions efficiently.

Why Qualcomm?

We chose to support Qualcomm modems because our community asked for it! Developers have different design needs and want maximum flexibility. They need more options that accommodate diverse business needs. Qualcomm chipsets offer the latest in connectivity protocols and radio technology at competitive prices. Qualcomm provides silicon and support for a wide ecosystem of module vendors, such as Quectel, U-Blox, Telit, and more. Golioth customers have used Qualcomm modems in their products in the past, but needed to do much of the integration engineering themselves. Zephyr’s Modem Subsystem makes it easier to develop applications that integrate Qualcomm modems. Connecting this wider range of modems to Golioth is more hands-off for the user, reducing complexity. Developers can focus more on innovation and less on technical hurdles.

Also in This Release

In addition to new modem support, this release introduces a another feature: DTLS socket offloading for Zephyr. This includes an example for the long-supported Nordic Semiconductor nRF9160.

DTLS socket offloading leverages a modem’s secure credential store, which allows for the use of secure, offloaded sockets. This means there is not any private key material in RAM. This can be a significant advantage as it helps reduce RAM usage, code size, CPU load, and power consumption. Actual benefits will vary depending on the application and how the code is utilized.

This new feature enhances device security and efficiency, contributing further to the versatility and robustness of the Golioth Firmware SDK. Mike previously wrote how to store credentials on the nRF9160 using TLS tags.

Getting Started

To get started with the latest SDK:

  1. Update to the newest release, 0.12.0, from the Golioth Firmware SDK repository.
  2. Explore the documentation and examples provided for integrating the RAK5010 board or try DTLS socket offloading with the nRF9160.
  3. Visit our community forums or support channels if you need help or want to discuss your projects.

Focused on Your Success

At Golioth, we’re committed to providing you with the tools and flexibility needed to succeed in the fast-evolving world of IoT. By adding support for new modems and enhancing the ways you can manage credentials, we aim to streamline your development process and empower your innovative projects. Whether you’re integrating the latest modem technology or implementing secure credential management, Golioth is here to support every step of your journey towards building smarter, more connected solutions.

If you ask any seasoned hardware engineer, they will tell you there are only two types of people:

  1. Those who have accidentally swapped TX and RX
  2. And those who will
TX RX Fail

There’s even a fail badge of honor!

Despite our best efforts, mistakes can creep into hardware designs. Design specifications can change over time. Taking a hardware design from concept to production is a journey that nearly always involves iterating through multiple revisions of the PCB assembly.

In this post, we’ll walk through some of the tools that Zephyr & Golioth provide for managing multiple board revisions.

Let’s dive in and look at how you can support Rev ARev B, all the way to Rev X in your Zephyr firmware without losing your sanity!

Aludel Elixir Board

Here at Golioth, Chris Gammell has been designing a new rapid prototyping board called the “Aludel Elixir“. We use this board internally for developing and testing our growing collection of reference designs, and we’re using it for live demos at Embedded World 2024.

Aludel Elixir Rev B

The image above shows the 2nd hardware revision of the board (Rev B), which fixes some of the hardware issues we found when testing the 1st revision (Rev A).

Supporting the Rev B hardware requires changes to the Zephyr firmware that runs on the internal MCU in the nRF9160 SIP. However, since we have Rev A and Rev B hardware “in the wild”, we want to support building firmware for all current and future board revisions in Golioth projects—like our Reference Design Template.

Multiple board revisions in Zephyr

Fortunately, Zephyr has support for multiple board revisions as a standard part of the build system.

Note: Shortly after Zephyr 3.6.0 was released, a new hardware model was introduced to Zephyr. This new model overhauls the way both SoCs and boards are named and defined and is not backwards compatible. This blog post assumes the old hardware model used in Zephyr 3.6.0 or earlier.

Building for multiple board revisions in Zephyr

Before jumping into the implementation details, it’s helpful to see how an end-user would build for a specific board revision.

We can build a Golioth Zephyr app for a specific revision of the Aludel Elixir board by simply appending a @<revision> specifier to the board name:

# Build firmware for Rev A
west build -b aludel_elixir_ns@A

# Build firmware for Rev B
west build -b aludel_elixir_ns@B

# Build firmware for the "default" revision (which is currently Rev B)
west build -b aludel_elixir_ns

Adding multiple board revisions in Zephyr

The Zephyr Board Porting Guide has a detailed section on how to add support for multiple board revisions.

When we build for a board with a revision specifier—e.g. aludel_elixir_ns@B—the build system looks for a revision.cmake file in the board directory:

boards/arm/aludel_elixir
├── ...
└── revision.cmake

Here’s the revision.cmake file for the aludel_elixir board:

board_check_revision(
  FORMAT LETTER
  EXACT
  DEFAULT_REVISION B
  VALID_REVISIONS A B
)
  • FORMAT LETTER tells the build system that the revision format is “Letter revision matching” (A, B, C, etc)
  • EXACT requires that the revision is an exact match
  • DEFAULT_REVISION sets the revision to be used when no revision is specified (e.g. west build -b aludel_elixir_ns)
  • VALID_REVISIONS defines the set of valid revisions that can be specified

Kconfig settings for specific revisions

It’s possible to specify Kconfig symbols that are specific to a particular board revision by adding optional <board>_<revision>.conf files in the board directory. These will be merged into the board’s default Kconfig configuration.

For example, the Elixir Rev A board was accidentally built with the NB-IoT only variant of the nRF9160, which requires some Kconfig settings that only apply to the Rev A board revision.

boards/arm/aludel_elixir 
├── ...
├── aludel_elixir_A.conf
└── aludel_elixir_ns_A.conf

Devicetree overlays for specific revisions

It’s also possible to describe hardware changes in devicetree that are specific to a particular board revision by adding optional <board>_<revision>.overlay files in the board directory. These will be added to the common <board>.dts devicetree file.

For example, the Elixir Rev A board connects the spi2 peripheral to the mikroBUS socket headers, while the Rev B board connects the spi3 peripheral instead. We added devicetree overlay files for each board revision that specify the correct SPI peripheral to use:

boards/arm/aludel_elixir
├── ...
├── aludel_elixir_A.overlay
├── aludel_elixir_ns_A.overlay
├── aludel_elixir_B.overlay
└── aludel_elixir_ns_B.overlay

Distributing board definitions as a Zephyr Module

The golioth-zephyr-boards repo stores the Zephyr board definitions for the Aludel Elixir board revisions, allowing us to use them across multiple Zephyr projects as a Zephyr Module.

For example, here’s how it’s included in our Reference Design Template app via the west.yml manifest:

- name: golioth-zephyr-boards
  path: deps/modules/lib/golioth-boards
  revision: v1.1.1
  url: https://github.com/golioth/golioth-zephyr-boards

Note that it’s also possible to add application-specific Kconfig and devicetree overlay files for each board revision:

<app>/boards/
├── ...
├── aludel_elixir_ns_A.conf
├── aludel_elixir_ns_A.overlay
├── aludel_elixir_ns_B.conf
└── aludel_elixir_ns_B.overlay

If you leave off the @<revision> specifier, these will be applied to all revisions of the board:

<app>/boards/
├── ...
├── aludel_elixir_ns.conf
└── aludel_elixir_ns.overlay

Golioth Blueprints

In a real-world IoT deployment, it’s likely that a fleet of devices will have multiple hardware revisions deployed simultaneously. Golioth provides support for managing different hardware revisions through a concept called “Blueprints“.

Blueprints are a flexible way to segment devices based on variations in hardware characteristics, such as the board revision. For example, when creating a new over-the-air (OTA) firmware release in the Golioth console, a blueprint can be specified to limit the scope of the release to only Rev A hardware devices.

If you’d like a step-by-step introduction to deploying a fleet of IoT devices with Zephyr and Golioth, we’d love to have you join us for a free Zephyr developer training. Our next session is just two weeks away. Sign up now!

In a previous post on Debugging nRF9160 Zephyr apps with Ozone, I showed how to use the New Project Wizard to create a new Ozone project for debugging a Zephyr app.

However, the project files generated by the New Project Wizard contain hard-coded paths. This makes them unsuitable for sharing with colleagues or checking them into a git repository.

In this post, I’ll demonstrate how to create a portable Ozone project file that you can check into your Zephyr application’s git repository.

Build the example app

To make this example concrete, we’ll be debugging the zephyr/samples/basic/blinky/ app from the nRF Connect SDK Zephyr repo. The firmware image will be built for the nrf9160dk_nrf9160_ns target running on the Nordic nRF9160 DK board. However, the concepts in the examples below should apply to any Zephyr app or board.

I’ve manually added an additional debug KConfig fragment file that we’ll be merging in to this app during the build process. This debug.conf file enables thread-aware debugging in Ozone:

CONFIG_DEBUG_THREAD_INFO=y

# CONFIG_DEBUG_THREAD_INFO needs the heap memory pool to
# be defined for this app
CONFIG_HEAP_MEM_POOL_SIZE=256

To build the firmware for the example blinky app:

cd <your ncs workspace>/
west build -p -b nrf9160dk_nrf9160_ns zephyr/samples/basic/blinky/ -- -DEXTRA_CONF_FILE="debug.conf"

If the build completed successfully, you’ll see the build/zephyr/zephyr.elf & build/zephyr/merged.hex files we need to start a debugging session in Ozone.

Create a portable Ozone project file

Next, we’ll create a portable Ozone project file.

I’ll show the entire file first so you can see what it looks like all put together, and then I’ll walk through what each line in the file does in more detail.

I named my project file nRF9160.jdebug and located it in the root of my NCS workspace, but you can name this file anything you want (the file extension should be .jdebug):

void OnProjectLoad(void)
{
	Project.SetDevice("nRF9160_xxAA");
	Project.SetTargetIF("SWD");
	Project.SetTIFSpeed("4 MHz");
	Project.AddSvdFile("$(InstallDir)/Config/CPU/Cortex-M33F.svd");
	File.Open("$(ProjectDir)/build/zephyr/zephyr.elf");
	Project.SetOSPlugin("ZephyrPlugin.js");
}

void TargetDownload(void)
{
	Exec.Download("$(ProjectDir)/build/zephyr/merged.hex");
}

Ozone scripts

Project files in Ozone are scripts written in a simplified C-style language. Ozone defines a set of event handler functions that are called when specific debug events happen in the debugger.

The OnProjectLoad() event handler is executed when the project file is opened, so this is where we’ll do most of the setup for our project.

Project action functions

The nRF9160 DK board has an onboard SEGGER J-Link OB debugger which is connected to the nRF9160 SIP via SWD.

Ozone defines a set of project actions that can be used to configure the debugger settings:

  • Project.SetDevice("nRF9160_xxAA"); configures the debugger for the nRF9160 SIP
  • Project.SetTargetIF("SWD"); configures the debugger to use the Serial Wire Debug (SWD) protocol
  • Project.SetTIFSpeed("4 MHz"); sets the SWD signaling speed to 4 MHz

Next, we need to provide the debugger with a link to the System View Description (SVD) files for the ARM Cortex-M33F applications MCU in the nRF9160 SIP. Ozone comes bundled with a bunch of SVD files for different ARM cores, so we can provide a portable path to the file’s location by using the $(InstallDir) directory macro:

  • Project.AddSvdFile("$(InstallDir)/Config/CPU/Cortex-M33F.svd");

Since we’re debugging a Zephyr app, we can load the Zephyr RTOS awareness plugin automatically:

  • Project.SetOSPlugin("ZephyrPlugin.js");

File action functions

In addition, we need to provide Ozone with the path to the ELF file for the Zephyr app we’re trying to debug. We can use the $(ProjectDir) directory macro to provide a portable path to the ELF file relative to the directory containing the project file:

    • File.Open("$(ProjectDir)/build/zephyr/zephyr.elf");

Process replacement functions

In this example, we have a multi-image build for the nRF9160. We need to instruct the debugger to download the full merged image (not just the ELF). Ozone provides a set of process replacement functions that replace the default implementations of built-in debug operations. We can use the TargetDownload(); function to replace the default program download routine with one that loads the merged.hex file instead. Note that this also uses the $(ProjectDir) directory macro to provide a portable portable path to the merged image:

  • Exec.Download("$(ProjectDir)/build/zephyr/merged.hex");

Start the debug session

Now, click “File” → “Open…” and open the nRF9160.jdebug project file in Ozone.

Click on “Debug” → “Start Debug Session” → “Download & Reset Program” to start the debug session:

If you have multiple SEGGER devices plugged into your USB port, you’ll get a pop-up window asking which device should be used to flash the target:

If you don’t see the “Zephyr” window in the Ozone project, click on “View” → “Zephyr” to show the window:

That’s it!

You can relocate this file into any directory, including the git repository for your Zephyr app. Just make sure to update the relative paths in the file. Anyone who checks out the repo can quickly start a debug session without having to configure their own Ozone project.

Conclusion

Golioth can help you connect and secure your IoT devices, send sensor data to the web, update firmware over-the-air, and scale your fleet with an instant IoT cloud.

Try it today! You can make a small connected fleet and start sending data to and from the cloud immediately. Device management is free for individual users!

We are returning to Embedded World in 2024 (EW24) and will be showing off the things we’ve been working on at Golioth since last year. We’re also living a little closer to the edge and bringing some experiments and unreleased items to showcase on the floor. Demo gods, be kind!

We’ll be at the Zephyr booth, helping to showcase one of our favorite Real Time Operating Systems and Ecosystems (though not the only one we support!). Golioth generally only targets one part in our standard hardware setup, but we continuously verify a bunch of hardware on our Firmware SDK. This means that you can be certain that every new feature added to the Golioth Cloud and SDK is fully tested throughout our supported hardware. The great thing about Zephyr is that the underlying hardware works very similarly to all of our CVBs, because of the work from the silicon vendors that participate in the open source project. We’re excited because 2024 saw even more silicon vendors joining the fray!

Golioth Demos

Being part of a large project like Zephyr, we share time at the booth Kiosks. We’ll be at the Zephyr Booth (4-170) at the following times:

  • Tuesday, April 9th from 1500 to 1800
  • Wednesday, April 10th from 1200 to 1500
  • Thursday, April 11th from 0900 to 1130

All times CEST, which is GMT + 1

Hardware we’ll have on hand

  • Modbus Vibration monitor – This is our newest Reference Design that captures vibration and temperature data from a sensor normally used in industrial environments for large motors. The hardware in the Reference Design talks over RS-485 to the remote sensor and queries all of the available registers and publishes them to the Golioth cloud for processing and viewing.
  • Air Quality Monitor – It’s always interesting to see the trend lines of air quality metrics throughout the day. There are a lot of people that filter in and through the Nuremberg convention center, so we can track things like CO2 concentration just from the elevated number of bodies. The particulate counter is unlikely to go up a lot, but if there’s something like a cotton candy booth nearby, it could potentially have particulates flying through the air. I’ll be sure to go and investigate and clean up that particular air quality problem if the need arises.
  • Aludel Elixir – Powering our newer reference designs is the Aludel Elixir. This is an evolution of our previous designs (the Aludel Mini) that stitched together outside development boards that we loved like the Circuit Dojo nRF9160 Feather and the Sparkfun ThingPlus nRF9160. We pulled many of those components onto a bespoke PCB, and also added other components that can enhance any reference design. It all comes together in a custom milled case that enables maximum flexibility.

Aludel Elixir Rev B

Are you interested in your very own Aludel? Shoot me a note to discuss at Embedded World or fill out this form

Partner Demos:

AL2LOG at the AL2TECH booth (3A-335)

A render of the AL2LOG Unit

Our design partner AL2TECH based out of Italy is bringing an exciting new logging project based on the nRF9160 and an STM32 coprocessor. This is meant to target industrial applications that require a flexible way to capture data in a harsh environment.

The AL2LOG is a compact industrial logger with different sensor and actuator interfaces. This is based upon AL2TECH’s broad experience serving their clients in the energy meter/remote sensor monitoring industries.

The AL2LOG PCB (rev 1.0)

Some high level features include Cellular and GPS connectivity (nRF9160), as well as external module comms using USB-C, RS-485, and CAN. There is an Ultra Low Power acquisition and logging sub system (STM32) with a true 14 bit ADC. Industrial inputs including Digital Input, Dry Contact, Pulse Counter, 0-10V Voltage Analog Input, and 4-20mA Current Loop Input. There are outputs like Open Drain Output, and programmable supplies for devices downrange of the logger. The device can also switch external 220V via a relay. For powering the device you can use a 12-24V rail, or depend on the large D-Size High Power LTC Cells.

The device communicates back to Golioth using Zephyr/NCS and can be remotely updated using Golioth’s OTA service. Data routed from the field back to the cloud is accessible via the Golioth REST API.

BT Mesh demo from partner Ambient Sensors at the Zephyr booth (4-170)

BLE Mesh Demo from Ambient Sensors communicating through Golioth, on display at Embedded World

This demo shows Golioth controlling an LTE/BLE bridge (Thingy91) that communicates to a BLE Mesh composed of a series of lights that are running the Light Lightness Controller (the LC Server) model. Eight instances of the BBC micro:bit represent lights in this demo. The boards run BLE Mesh firmware on Nordic Semiconductor’s nRF52833, which could easily be controlling an LED driver instead of the demo LEDs.

The BLE SIG standard LC server code is running on each microbit, and is communicating with the Thingy91’s nRF52840, which communicates on the mesh as an LC client, Generic OnOff Client, and Light Lightness client. Using Golioth, the  demo remotely sends a command to turn the LC server on, and lights will then slowly dim over time (as is the functionality of the LC server). Normally lights dim after several hours, but for the purpose of the demo, we set that value to several seconds. Delay values may also be set via Golioth, showing how these settings can be tuned remotely if desired. Additionally, we have created commands to allow the Golioth user to turn on the lights, while turning off the LC Server (to prevent it from dimming the lights), and to set the lightness value to any desired value.

Golioth connectivity demo at the NXP FRDM Lab

Find Golioth at the FRDM Lab at EW24

NXP is another vendor that has great support in Zephyr. We’ll be showcasing Golioth’s solution on NXP boards at their FRDM Lab in the Messepark classroom (the main open area when you walk into the conference). You can also see all of NXPs new solutions at their main booth in the presentation hall, booth 4A-222.

Even more Golioth!

What’s that? You haven’t seen enough of us yet? You’d love to hear more on-site at Embedded World? Well let’s telegraph every place we’ll be! In addition to our time showcasing Golioth at the Zephyr booth, we’ll also be giving a couple of talks at the Zephyr stage (next to the Zephyr booth):

  • April 9th at 1400: “Building end-to-end Zephyr demos on IoT hardware”
  • April 10th at 1530: “Multi MCU OTA updates with Golioth and Simple Management Protocol”
  • April 11th at 1200: “Local toolchains, no more! Using GitHub Codespaces for training people on Zephyr throughout the world”

In the evenings (if we’re still standing), we plan to attend these open events and socialize with others in the industry:

  • IoT Stars – This is a short speaker event, as well as a networking session. We’ll have some of our portable demos with us.
  • PCBarts meetup – This is a more social event hosted by a local consulting and manufacturing company. Last year this was a wonderful group of engineers showing off their projects–personal and professional–after a long day at the tradeshow.

We really hope to see you at the conference! If you’d like to talk about Golioth and how we can work together, please fill out this form!

The latest release of the Golioth Firmware SDK is now available! Tagged with v0.11.0, this release includes support for Zephyr v3.6.0, nRF Connect SDK (NCS) v2.5.2, and ESP-IDF v5.2.1.

Our SDK supports multiple platforms and we actively track (and often participate in) upstream development. As new platform releases become available, we test against the Golioth platform, update as necessary, and cut new releases so the latest and greatest is available in your projects.

Also notable in these release is the addition of several code examples in the ESP-IDF port. We have long included examples in the Zephyr port that show each Golioth service used in isolation. The same examples are being added to ESP-IDF, alongside an example that shows off everything. These are nice references when adding a single service to existing applications.

Numerous minor annoyances have also been vanquished. Remote procedure call (RPC) error messages have been clarified when requesting an RPC that is not registered. Log messages for the LTE monitor in our Zephyr common library can now be filtered by log level. And a number of small fixes rounds out the list.

Check out all of the updates in the release notes. Star the repository for notifications of new releases. Please let us know in the forum if you find any issues or have feature requests!

Nordic’s nRF9160 cellular modem includes a great peripheral called the Key Management Unit (KMU). This secure key storage mechanism lets you write keys to it which cannot be read back. However, they can still be used for DTLS authentication. In this video and blog post I’ll walk you through how to use the feature with the newest release of the Golioth Firmware SDK.

Overview of secure storage and TLS Tag authentication

With the v0.10.0 release of the Golioth Firmware SDK, credentials may be selected using the TLS secure tag. One example of hardware that embraces this is the Nordic nRF9160, which implements Zephyr’s TLS credential management API. Credentials (either x509 certificates or pre-shared keys) are stored on the device using a security tag. Pass that tag to the Golioth Firmware SDK and enable offloaded DTLS sockets in order to utilize those securely stored secrets.

Since these credentials are stored separately from firmware, they are persistent and you can store multiple different credentials. At runtime, pass the security tag as a parameter when creating the Golioth client and you’re all set.

How to store credentials on the nRF9160

Storing credentials on the nRF9160 is accomplished in two steps: first generate and prepare the credentials, then place them on the device using AT commands. (Don’t worry, there are helper tools to generate the AT commands for you.)

Generating Certificates

Golioth has long supported certificate authentication. You can follow the Certificate Authentication guide in our Docs. You will need to use the .pem version of the device certificate and key, and you’ll also need the root certificate from the CA that issued Golioth’s server certificate (we use LetsEncrypt.org).

  1. Generate the root certificate and device certificate by following the docs page.
  2. Download the CA certificate from Let’s Encrypt

Now upload the public root certificate you generated (golioth.crt.pem) to Golioth so it may be used to authenticate your device. From the left sidebar choose Project Settings, select the Certificates tab, and click Add CA Certificate:

Upload public root certificate to Golioth

Generating PSK Credentials

You should not use PSK credentials for production purposes, certificates are far more secure. However, for demonstration purposes, here’s what you need to do to prepare your PSK:

  1. Use the Golioth console to add a new device.
  2. Copy the PSK-ID and PSK from your newly generated device.
  3. Use the following command to format your PSK as a HEX string—the format required by the nRF9160 (note this is only for the PSK, not for the PSK-ID).
echo "your-psk-here" | tr -d '\n' | xxd -ps -c 200

Loading Credentials onto the nRF9160

  1. Build and flash the Nordic at_client sample onto your device.
  2. Use the Nordic nRF Connect for Desktop tools to write credentials to the device.
    1. Older versions of this tool will use the LTE Link Monitor, newer versions will use the Cellular Monitor.
    2. Choose the security tag you wish to use.
    3. Add your credentials to the interface and use the Update certificates button to write to the device. I found that I wasn’t able to write all three certificate artifacts at the same time and instead needed to enter them one at a time.

Nordic Cellular Monitor used to store device credentials on nRF9160

The credentials are stored using AT commands over a serial connection. You do not need to use the Nordic desktop tools if you don’t care to as the commands can be sent from any serial terminal connection.

Configure Golioth to locate credentials by tag

Now that our credentials are stored on the device, it is a trivial process to adapt the Golioth client to use them. In the video, I stored my certificates at security tag 24. I simply pass this to my application by adding the following Kconfig symbols to the prj.conf file:

CONFIG_GOLIOTH_AUTH_METHOD_CERT=y
CONFIG_GOLIOTH_SAMPLE_AUTH_TYPE_TAG=y
CONFIG_GOLIOTH_COAP_CLIENT_CREDENTIALS_TAG=24

(If you are testing PSK authentication instead of certificates, do not use the Kconfig symbol that sets CERT as the auth method. Without it, PSK will be selected by default.)

You must also remove one symbol from the boards/nrf9160dk_nrf9160_ns.conf file. This symbol tells the application to skip the offloaded DTLS sockets, however, that’s exactly the feature we want when using tag-based credential selection. Remove this line to re-enable socket offloading:

# Remove this line from nrf9160dk_nrf9160_ns.conf
CONFIG_NET_SOCKETS_TLS_PRIORITY=35

With that in place, compile the application and flash it to your nRF9160. It will now use the stored credentials to authenticate with Golioth.

Understanding the Golioth client config

The Golioth samples are configured to use a common library that configures the Golioth client on your behalf. However, the configuration process is very simple as I demonstrated it in the video.

Create a config struct that chooses TLS tags. Use the struct to pass the security number where the credentials are stored. Here’s what that would look like for my credential authentication example:

/* Config for credential tag authentication */
struct golioth_client_config client_config = {
    .credentials =
        {
            .auth_type = GOLIOTH_TLS_AUTH_TYPE_TAG,
            .tag = 24,
        },
};

client = golioth_client_create(&client_config);

Device Credentials with Golioth

The new APIs present in the Golioth Firmware SDK make it really easy to select credentials using tags. We’d love to hear how you plan to utilize this functionality. Show off your project on the Golioth Forum, or hit us up at the DevRel email!

For more than a year, Golioth has been hosting free Zephyr training. We’re going to keep doing that. But the news today is that you can learn from our Zephyr course anytime, anywhere using Codespaces.

Ze…what?

IoT devices usually need a real time operating system (RTOS) to handle the networking aspect of connecting things to the Internet. Zephyr is an open source RTOS guided by the Linux Foundation. We like it for its far reaching cross-vendor support and handy network stack. Using Golioth with Zephyr is a snap because the Golioth Firmware SDK functions as a Zephyr module.

But for our customers to build devices with Zephyr they need to know how to use Zephyr. Which leads to our free Zephyr training!

Zephyr tools in your browser; code on your device

The Golioth Zephyr training is offered live via the video chat every month. We supply tools to everyone who participates, just bring your own dev board to run the code examples on.

The training documentation we use has always been publicly available, but this month we’ve started using Codespaces to host the build environment tools. Now it’s available to everyone, even outside of our synchronous training sessions.

Head over to our code repository now, and choose the Codespaces tab from the big green <> Code button in the middle of the screen. Launch your pre-configured development environment by clicking the Create codespace on main button.

Launch Codespaces from the Goilioth Zephyr-Training GitHub repository

Around 90-seconds after clicking that button, an instance of VS Code will open in your browser. It already includes the training code repository, but also has the Zephyr tree (all the code from the open-source operating system) and the compiling tools needed to build the code are pre-installed!

Golioth Zephyr Training inside of Codespaces

Follow our Zephyr Training document site to walk through how to use this tool with the training material. Because you are building in the cloud, but running the code on your local development board, there is a download-and-flash step necessary, but we’ll guide you through it.

For individuals, using Codespaces is free with a few generous monthly limits (at time of writing these that’s 15 GB storage a 120 core hours).

Now it’s your turn!

Our training code is built to run on either the nRF9160-DK or the nRF7002-DK (one codebase, two boards thanks to Zephyr). Grab one of those boards and make your way through the modules of the training site.

  1. Start with the Intro to Golioth course
    1. You’ll flash a pre-compiled binary, save your credentials to the device, then try out the IoT feature built on top of Zephyr RTOS
    2. Code for this first sample is available to learn from
  2. Move on to the Zephyr Training course
    1. Start with an overview of the major components of the Zephyr ecosystem
    2. Move on to build your own binaries from source using Codespaces
    3. You’ll go from Hello World, to defining your own hardware components and using the RTOS threads and timers to control them

Of course it’s more fun to take on the challenge along with other people in the same boat. You’re more than welcome to join us for a free Zephyr training. Our next session is January 24th, and we’ll have another coming up in February. Sign up now!

In the last blog post about the PPK2,we explained operating modes for embedded devices and how current consumption is generally measured. With Nordic’s Power Profiler Kit II, we were successful in reducing the current draw of Golioth’s hello sample by a factor of 10 by simply turning the modem off. But, truth be told, 4mA is still a significant current draw for battery-operated devices in Standby mode. The aim for today is to lower the current consumption even more.

General Power Saving Recommendations

Let’s discuss some general recommendations for lowering current consumption. Every device/product has a set of constraints. From the sensor reading period to the number of sensors connected to the MCU, the current consumption for your particular device may vary based on which function you are performing and how much you are asking of your device.

Disable Unused peripherals

Some peripherals are enabled by default, depending on the devicetree of the board you are using. Peripherals that are not in use should be disabled in the overlay file. Even though it might not seem obvious at first,  some peripherals could potentially draw current just by being enabled. And the result could be milliamps of unnecessary current draw.

Peripherals are enabled or disabled in the device overlay file. For the hello sample, we won’t use any of the peripherals, and we’ll disable them all in the nrf9160dk_nrf9160_ns.overlay file.

You only need to disable the peripherals which are not utilized in your project. You can use the Device Power Management module to put peripherals into sleep mode in inactivity periods; more about that later on.

Disable Serial Logging

By default, logging is performed over the serial port associated with the UART(E) peripheral with Nordic SoCs. If a device is expected to work without human interaction over the serial port, then there is no need for logging over serial output and having the associated current consumption. By doing this, we can reduce the current consumption by ~1mA.

  • Disable serial output with: CONFIG_SERIAL=n
  • Disable serial logging with: CONFIG_LOG=n
  • Disable the UART console with: CONFIG_UART_CONSOLE=n

For the purposes of the hello sample, we won’t disable the logging subsystem because we want the log messages to be sent to Golioth’s Logging device service, but we have disabled the uart0 peripheral, which is used as a serial console by default.

Enabling Device Power Management

The idea behind the Device Power Management module is to allow device drivers to handle power management operations. For instance, it turns off clocks and peripherals, lowering the current consumption. The Device PM module provides an interface that the device drivers use to be informed about entering the suspended state or resuming from the suspended state. This enables the application developer to suspend peripherals when the CPU goes to sleep, depending on the application’s behavior.

For example, we can turn of an SPI peripheral while it is not in use to reduce the current draw. A device driver must have an implementation of the PM action callback used by the PM subsystem to suspend or resume devices.

Since we won’t use any of the nRF9160 SoC peripherals in the hello sample, we won’t see any benefit from using the Device PM. Nordic’s documentation explains how to utilize the PM module on the external flash case.

Results

As in the previous blog post, we are going to connect to the cellular tower, Golioth Cloud, and send 5 hello messages; afterward, we’ll stop the Golioth system client and call the lte_lc_offline API function, which sets the device to flight mode, disabling both transmit and receive RF circuits and deactivating LTE and GNSS services.

 

From the picture above, we achieved an average current of 2.69 µA when all peripherals are disabled, the modem is turned off, and the CPU is in IDLE. It’s up to the application developer to decide when to enter this minimal operating state, and deal with the consequences when coming back online after this deep sleep. Things like ConnectionID can help cellular devices save power on handshakes with the tower when re-connecting.

Conclusion

We showed how disabling unused peripherals can benefit our current consumption bottom line and save milliamps in the process by achieving ~3uA current draw. In the next blog post, we’ll talk about Power Optimizations specific to the nRF9160 SoC and how to use Power Saving Mode (PSM) with the modem and eDRX method instead of turning the modem off completely.

Zephyr is the fastest growing real-time operating system. If you’re not already using it, you should be! Now’s your chance, Golioth’s next training and the next session is just two weeks away. Join our free Zephyr training on October 25th at 9am Pacific time to get yourself up to speed.

What Will I Learn?

This three hour training happens on real hardware—sign up now so yours arrives in time for training. By the end of the session, you will have compiled, run, and worked with the output from a Zephyr app numerous times. Along the way you’ll gain understanding of the major building blocks of Zephyr (CMake, Kconfig, Devicetree, etc). We delve into mapping hardware, working with threads, and troubleshooting build issues.

This training session is held live on a video chat platform. You move around as an 8-bit avatar, automatically opening chats when you get near people. This makes it pretty easy to ask questions from other people at your table. And when you get stuck, you can pair up with instructors to get help.

Golioth Uses Zephyr

Golioth is your instant IoT cloud. Chances are, we support the microcontrollers you want to use. This is thanks to Zephyr’s approach to building for a wide range of hardware while at the same time providing a fully-featured networking stack perfect for connected devices. The Golioth Zephyr SDK is a module that you add to any Zephyr project to enable device management, data transfer to/from the device, and over-the-air (OTA) firmware updates a simple matter of making a function call.

We’ll demo the Golioth platform and give you a chance to try it out at the beginning of the training. If you can’t wait until then, our free Dev Tier allows up to 50 connected devices, so give Golioth a spin today.