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