Persistent Failure in ble_stack_init() with sd_softdevice_enable (Error 8194) on nRF52840 (PCA10056, S140)

Hello Nordic community,

I’m working on a project with the nRF52840 DK (PCA10056) using the nRF5 SDK and the S140 SoftDevice.

My goal is to:

1. Read two NTC thermistors using SAADC (P0.30/AIN6 and P0.31/AIN7) every 100 ms.
2. Control an NTC enable pin (NTC_EN) on P0.29 to power the NTC circuit.
3. Toggle an LED (P0.24) every 200 ms.
4. Set a reset pin (P0.13) high after 10 seconds and stop NTC sampling.
5. Advertise via BLE


Issue:

The ble_stack_init() function consistently fails at sd_softdevice_enable(), returning error code 8194 (0x2002). I’ve confirmed the SoftDevice is flashed.

Here’s the relevant log:

<info> app: NTC SAADC with LED and Reset Control
<error> app: SoftDevice enable failed: 8194 

#include <stdint.h>
#include "nrf.h"
#include "nrf_gpio.h"
#include "nrf_delay.h"
#include "nrf_drv_saadc.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "nrf_sdh.h"
#include "nrf_sdh_ble.h"
#include "ble.h"
#include "ble_advdata.h"
#include "ble_conn_params.h"
#include "app_timer.h"
#include "app_error.h"

// Pin definitions (nRF52840)
#define LED_PIN 24        // P0.24 for LED
#define SR_RESET_PIN 13   // P0.13 for reset (pin 33)
#define NTC_EN 29        // P0.20 for NTC enable
#define NTC1_AIN NRF_SAADC_INPUT_AIN6  // P0.30 (pin 10)
#define NTC2_AIN NRF_SAADC_INPUT_AIN7  // P0.31 (pin 9)

// SAADC configuration
#define SAADC_BUFFER_SIZE 2            // One sample per channel
#define SAADC_SAMPLE_INTERVAL_MS 100   // Sample every 100 ms (10 Hz)
#define LED_INTERVAL_MS 200            // LED toggle every 200 ms
#define RESET_TIMEOUT_MS 10000         // Reset/NTC disable after 10 s

// BLE configuration
#define DEVICE_NAME "ProximityDevice"
#define APP_ADV_INTERVAL 300           // Advertising interval (300 * 0.625 ms = 187.5 ms)
#define APP_ADV_TIMEOUT_IN_SECONDS 0   // No timeout (advertise forever)
#define MIN_CONN_INTERVAL MSEC_TO_UNITS(100, UNIT_1_25_MS)
#define MAX_CONN_INTERVAL MSEC_TO_UNITS(200, UNIT_1_25_MS)
#define SLAVE_LATENCY 0
#define CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS)
#define APP_BLE_CONN_CFG_TAG 1         // BLE connection configuration tag
#define APP_BLE_OBSERVER_PRIO 3        // BLE observer priority

// Global variables
static nrf_saadc_value_t saadc_buffer_1[SAADC_BUFFER_SIZE];  // Single buffer
static bool ntc_sampling_enabled = true;                     // SAADC sampling state
static uint32_t number_counter = 0;                          // ADC reading counter
static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID;     // BLE connection handle
static uint8_t m_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; // Advertising handle
static ble_gap_adv_data_t m_adv_data;                        // Advertising data
static uint8_t m_enc_advdata[BLE_GAP_ADV_SET_DATA_SIZE_MAX]; // Encoded advertising data

/**@brief SAADC event handler.
 */
static void saadc_event_handler(nrf_drv_saadc_evt_t const * p_event)
{
    ret_code_t err_code;
    if (p_event->type == NRF_DRV_SAADC_EVT_DONE && ntc_sampling_enabled)
    {
        number_counter++;
        nrf_saadc_value_t ntc1_value = p_event->data.done.p_buffer[0];
        nrf_saadc_value_t ntc2_value = p_event->data.done.p_buffer[1];
        NRF_LOG_INFO("Reading #%lu: NTC1 (P0.30): %d, NTC2 (P0.31): %d",
                     number_counter, ntc1_value, ntc2_value);

        // Prepare the same buffer again
        nrf_saadc_buffer_init(saadc_buffer_1, SAADC_BUFFER_SIZE);
    }
    else
    {
        NRF_LOG_WARNING("Unexpected SAADC event: %d", p_event->type);
    }
}

/**@brief Initialize GPIO pins.
 */
static void gpio_init(void)
{
    nrf_gpio_cfg(LED_PIN, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT,
                 NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_H0H1, NRF_GPIO_PIN_NOSENSE);
    nrf_gpio_cfg(SR_RESET_PIN, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT,
                 NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_H0H1, NRF_GPIO_PIN_NOSENSE);
    nrf_gpio_cfg(NTC_EN, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT,
                 NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_H0H1, NRF_GPIO_PIN_NOSENSE);
    nrf_gpio_pin_clear(SR_RESET_PIN);
    nrf_gpio_pin_set(NTC_EN);
    nrf_delay_ms(10); // Allow pin state to settle
    NRF_LOG_INFO("NTC_EN pin state after set: %d", nrf_gpio_pin_read(NTC_EN));
    if (!nrf_gpio_pin_read(NTC_EN)) {
        NRF_LOG_WARNING("NTC_EN failed to set high, possible hardware issue");
        nrf_gpio_pin_set(NTC_EN); // Retry setting
        nrf_delay_ms(10);
        NRF_LOG_INFO("NTC_EN pin state after retry: %d", nrf_gpio_pin_read(NTC_EN));
    }
    NRF_LOG_INFO("GPIO PORT OUT: 0x%08x", NRF_GPIO->OUT);
}

/**@brief Initialize SAADC.
 */
static void saadc_init(void)
{
    ret_code_t err_code;

    // Initialize logging
    err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);
    NRF_LOG_DEFAULT_BACKENDS_INIT();
    NRF_LOG_INFO("NTC SAADC with LED and Reset Control");

    // Initialize SAADC
    nrf_drv_saadc_config_t saadc_config = NRF_DRV_SAADC_DEFAULT_CONFIG;
    saadc_config.resolution = NRF_SAADC_RESOLUTION_10BIT;
    saadc_config.oversample = NRF_SAADC_OVERSAMPLE_DISABLED;
    NRF_LOG_INFO("Initializing SAADC with interrupt priority: %d", saadc_config.interrupt_priority);
    err_code = nrf_drv_saadc_init(&saadc_config, saadc_event_handler);
    APP_ERROR_CHECK(err_code);
    NRF_LOG_INFO("SAADC initialized successfully");

    // Configure two channels
    nrf_saadc_channel_config_t channel_config_1 = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NTC1_AIN);
    nrf_saadc_channel_config_t channel_config_2 = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NTC2_AIN);
    NRF_LOG_INFO("Initializing SAADC channel 0");
    err_code = nrf_drv_saadc_channel_init(0, &channel_config_1);
    APP_ERROR_CHECK(err_code);
    NRF_LOG_INFO("Initializing SAADC channel 1");
    err_code = nrf_drv_saadc_channel_init(1, &channel_config_2);
    APP_ERROR_CHECK(err_code);

    // Set up a single buffer
    NRF_LOG_INFO("Setting up SAADC buffer 1 at address: 0x%08x", (uint32_t)saadc_buffer_1);
    nrf_saadc_buffer_init(saadc_buffer_1, SAADC_BUFFER_SIZE);
}

/**@brief BLE event handler.
 */
static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
{
    switch (p_ble_evt->header.evt_id)
    {
        case BLE_GAP_EVT_CONNECTED:
            NRF_LOG_INFO("BLE connected");
            m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
            break;

        case BLE_GAP_EVT_DISCONNECTED:
            NRF_LOG_INFO("BLE disconnected");
            m_conn_handle = BLE_CONN_HANDLE_INVALID;
            break;

        default:
            break;
    }
}

/**@brief Initialize BLE stack.
 */
static void ble_stack_init(void)
{
    ret_code_t err_code;

    // Initialize the SoftDevice
    err_code = nrf_sdh_enable_request();
    APP_ERROR_CHECK(err_code);

    // Configure the BLE stack
    uint32_t ram_start = 0;
    err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
    APP_ERROR_CHECK(err_code);

    // Enable BLE stack
    err_code = nrf_sdh_ble_enable(&ram_start);
    APP_ERROR_CHECK(err_code);

    // Register BLE event handler
    NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
}

/**@brief Initialize advertising.
 */
static void advertising_init(void)
{
    ret_code_t err_code;
    ble_advdata_t advdata = {0};
    ble_uuid_t adv_uuids[] = {{0xFFFF, BLE_UUID_TYPE_BLE}};

    // Initialize advertising buffer
    m_adv_data.adv_data.p_data = m_enc_advdata;
    m_adv_data.adv_data.len = BLE_GAP_ADV_SET_DATA_SIZE_MAX;

    // Build advertising data
    advdata.name_type = BLE_ADVDATA_FULL_NAME;
    advdata.include_appearance = false;
    advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
    advdata.uuids_complete.uuid_cnt = sizeof(adv_uuids) / sizeof(adv_uuids[0]);
    advdata.uuids_complete.p_uuids = adv_uuids;

    err_code = ble_advdata_encode(&advdata, m_adv_data.adv_data.p_data, &m_adv_data.adv_data.len);
    APP_ERROR_CHECK(err_code);

    ble_gap_adv_params_t adv_params = {0};
    adv_params.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
    adv_params.interval = APP_ADV_INTERVAL;
    adv_params.duration = APP_ADV_TIMEOUT_IN_SECONDS;
    adv_params.p_peer_addr = NULL;
    adv_params.filter_policy = BLE_GAP_ADV_FP_ANY;
    adv_params.primary_phy = BLE_GAP_PHY_1MBPS;

    err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &m_adv_data, &adv_params);
    APP_ERROR_CHECK(err_code);
}

/**@brief Start advertising.
 */
static void advertising_start(void)
{
    ret_code_t err_code = sd_ble_gap_adv_start(m_adv_handle, APP_BLE_CONN_CFG_TAG);
    APP_ERROR_CHECK(err_code);
    NRF_LOG_INFO("Advertising started");
}

/**@brief Connection parameters event handler.
 */
static void on_conn_params_evt(ble_conn_params_evt_t * p_evt)
{
    if (p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED)
    {
        ret_code_t err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
        APP_ERROR_CHECK(err_code);
    }
}

/**@brief Connection parameters error handler.
 */
static void conn_params_error_handler(uint32_t nrf_error)
{
    APP_ERROR_HANDLER(nrf_error);
}

/**@brief Initialize connection parameters.
 */
static void conn_params_init(void)
{
    ret_code_t err_code;
    ble_conn_params_init_t cp_init = {0};

    cp_init.p_conn_params = NULL;
    cp_init.first_conn_params_update_delay = APP_TIMER_TICKS(5000);
    cp_init.next_conn_params_update_delay = APP_TIMER_TICKS(30000);
    cp_init.max_conn_params_update_count = 3;
    cp_init.start_on_notify_cccd_handle = BLE_GATT_HANDLE_INVALID;
    cp_init.disconnect_on_fail = false;
    cp_init.evt_handler = on_conn_params_evt;
    cp_init.error_handler = conn_params_error_handler;

    err_code = ble_conn_params_init(&cp_init);
    APP_ERROR_CHECK(err_code);
}

/**@brief Main function.
 */
int main(void)
{
    // Initialize GPIO
    gpio_init();
        saadc_init();
    // Initialize BLE stack
    ble_stack_init();

    // Initialize app timer
    ret_code_t err_code = app_timer_init();
    APP_ERROR_CHECK(err_code);

    // Initialize BLE advertising and connection parameters
    advertising_init();
    conn_params_init();

    // Start advertising
    advertising_start();

    // Initialize SAADC


    // Initialize counters
    uint32_t reset_counter = 0;
    uint32_t led_counter = 0;
    uint32_t saadc_counter = 0;

    const uint32_t reset_max_count = RESET_TIMEOUT_MS / 100; // 10 s / 100 ms
    const uint32_t led_interval = LED_INTERVAL_MS / 100;     // 200 ms / 100 ms
    const uint32_t saadc_interval = SAADC_SAMPLE_INTERVAL_MS / 100; // 100 ms / 100 ms

    while (1)
    {
        // Increment counters
        reset_counter++;
        led_counter++;
        saadc_counter++;

        // Toggle LED every 200 ms
        if (led_counter >= led_interval)
        {
            nrf_gpio_pin_toggle(LED_PIN);
            led_counter = 0;
        }

        // Sample ADC every 100 ms if enabled
        if (ntc_sampling_enabled && saadc_counter >= saadc_interval)
        {
            NRF_LOG_INFO("Sampling condition met: saadc_counter=%d, saadc_interval=%d", saadc_counter, saadc_interval);
            NRF_LOG_INFO("SAADC enable state before sampling: %d", NRF_SAADC->ENABLE);
            NRF_LOG_INFO("SAADC status: 0x%08x", NRF_SAADC->STATUS);
            NRF_LOG_INFO("SAADC events - START: %d, END: %d", NRF_SAADC->EVENTS_STARTED, NRF_SAADC->EVENTS_END);
            // Clear events
            NRF_SAADC->EVENTS_END = 0;
            NRF_SAADC->EVENTS_STARTED = 0;
            // Manually start SAADC
            NRF_SAADC->TASKS_START = 1;
            ret_code_t err_code = nrf_drv_saadc_sample();
            if (err_code != NRF_SUCCESS)
            {
                NRF_LOG_ERROR("SAADC sample failed: %d", err_code);
            }
            saadc_counter = 0;
        }

        // After 10 seconds, update pins and stop sampling
        if (reset_counter >= reset_max_count)
        {
            nrf_gpio_pin_set(SR_RESET_PIN);
            nrf_gpio_pin_clear(NTC_EN);
            ntc_sampling_enabled = false;
            reset_counter = reset_max_count; // Stop counter
        }

        // Process logs
        while (NRF_LOG_PROCESS() != NRF_SUCCESS);

        // Wait for 100 ms (SoftDevice compatible)
        nrf_delay_ms(100);
    }
}

Parents Reply
  • Hi Simon,

    I've reviewed the interrupt priority settings in my application, focusing on sdk_config.h for nRF5 SDK. All configured priorities for peripherals like GPIOTE and SAADC are set to safe values (e.g., 6 or 3), and none are using the restricted SoftDevice levels 0, 1, or 4. 

    Could you suggest other potential causes or specific areas to debug further?

    Any additional insights would be appreciated.

    Best regards,
    Zeel

Children
No Data
Related