Samples

All samples can be found in the nRF9160 Feather Samples & Drivers repository.

Included samples:

  • accelerometer
  • accelerometer_zbus
  • active_sleep
  • at_client
  • battery
  • blinky
  • bme280
  • button
  • deep_sleep
  • direct_i2c_access
  • external_flash
  • external_rtc
  • external_rtc_time_sync
  • gps
  • https
  • led_pwm
  • mfw_update
  • sms
  • temperature_sensor
  • usb_detect

active_sleep

The active_sleep sample boots up and immediately puts the device into the lowest power state possible without fully turning off or entering deep_sleep. On the nRF9151 Feather it draws approximately 5 uA at room temperature (< 10 uA on the nRF9160 Feather).

The sample achieves this by:

  • Disconnecting all GPIOs
  • Disabling the accelerometer (setting ODR to 0)
  • Suspending the external SPI NOR flash
  • Initializing and then idling the modem
  • Suspending the console UART and stopping the HF clock
  • On the nRF9151: disabling BUCK2 on the nPM1300 PMIC (which powers down the RP2040)

Important: Because this sample disables power to the RP2040, your device will no longer appear as a USB device after running it. See Recovering from active_sleep for how to restore normal operation.

The green LED is the battery charging indicator. When plugged into USB without a battery it will light up. With a battery connected, its state depends on the charge level.

Building a periodic send/sleep application

The active_sleep sample demonstrates the target low-power state for production use, but it's a one-way trip — main() returns after disabling everything. For a real application that periodically wakes, sends data, and goes back to sleep, use the same peripheral shutdown steps but keep your main loop alive:

/* Peripheral shutdown (same as active_sleep) */
setup_gpio();
setup_accel();
nor_storage_init();
setup_pmic();  /* disables BUCK2 / RP2040 */
setup_uart();

/* Your loop */
while (1) {
    /* connect, send data, disconnect/idle */
    k_sleep(K_MINUTES(interval));
}

Zephyr automatically handles CPU power management during k_sleep() — no explicit sleep mode entry is needed.

For the modem, you have two options depending on your use case and cellular provider:

  • PSM (Power Saving Mode) — the modem stays registered but powers down the radio between TAU updates. No re-attach cost on wake. Good for frequent reporting intervals.
  • Full modem shutdown (nrf_modem_lib_shutdown() / nrf_modem_lib_init()) — fully powers down the modem between sends. Lower sleep current but pays the cost of re-attaching each cycle. Better for very long intervals or providers that don't support PSM well.

Keeping the console alive during development

Disabling BUCK2 powers down the RP2040, which means no USB programmer and no serial console. During development you'll want a way to skip that so you can still reprogram and see logs. The pattern below uses the mode button (sw0) — hold it during boot to keep the console and RP2040 alive:

#include <zephyr/drivers/gpio.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/atomic.h>

static atomic_t console_active = ATOMIC_INIT(0);
static struct gpio_callback button_cb_data;
static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET(DT_ALIAS(sw0), gpios);

void button_cb(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
    atomic_set(&console_active, 1);
}

void console_guard_init(void)
{
    gpio_pin_configure_dt(&button, GPIO_INPUT);
    gpio_pin_interrupt_configure_dt(&button, GPIO_INT_EDGE_TO_ACTIVE);
    gpio_init_callback(&button_cb_data, button_cb, BIT(button.pin));
    gpio_add_callback(button.port, &button_cb_data);
}

Then in main(), check the flag before shutting down the UART and PMIC:

console_guard_init();

/* Give the user a moment to press the button */
k_sleep(K_SECONDS(3));

/* Only enter low power if button was not pressed */
if (atomic_get(&console_active) == 0) {
    setup_uart();
    setup_pmic();
}

/* Clean up the interrupt either way */
gpio_remove_callback_dt(&button, &button_cb_data);

In production, remove this guard or compile it out with a Kconfig flag. If you do get locked out, use the recovery process to erase and reprogram.

DECT NR+ Samples

The nRF9151 supports DECT NR+ (Digital Enhanced Cordless Telecommunications New Radio), a license-free radio standard. Nordic provides two samples in the NCS repository under nrf/samples/dect/dect_phy/:

  • hello_dect — minimal example that transmits a DECT NR+ beacon. Good starting point for understanding the PHY layer API.
  • dect_shell — interactive shell for testing DECT NR+ functionality. Lets you configure channels, transmit/receive packets, and inspect PHY parameters at runtime.

To build the shell sample for the nRF9151 Feather:

west build -b circuitdojo_feather_nrf9151 nrf/samples/dect/dect_phy/dect_shell

Note: DECT NR+ and LTE cannot be active simultaneously on the nRF9151. Make sure the modem is in offline mode (AT+CFUN=0) before using DECT NR+.

External samples:

  • Serial Modem - used for controlling the nRF9151 via UART from another application processor.
  • Asset Tracker Template - template for common use case of asset tracking provided by Nordic.

Both of these samples can be setup the same way it's done in the Setup using Circuit Dojo Zephyr Tools. Instead of using the nfed repository address, use the git addresses for the specific sample you want to download & use.