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);
}
}