This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Low Power Mode using SAADC with ble_app_beacon

Hello !!

I have custom board on nrf52832 having 10 buttons which is pull down by default. I have achieved 22uA after modifying the ble_app_beacon example to broadcast when button is pressed.I am also having coin cell with the custom board so i want to check the battery voltage so that i could indicate the battery level (2 conditons i.e <10% & >10% ) using bi-colour led. 

I have modified ble_app_beacon as per requirement and then integrated SAADC example with modified ble_app_beacon example. I am now getting more than 2 mA current consumption.

So, If anyone could help me with the code so that I could monitor the battery (on any interval) to indicate battery percentage. I am also attaching the main code so that it would be more understandable. My requirement is 3uA when there is no broadcasting.

/**
 * Copyright (c) 2014 - 2020, Nordic Semiconductor ASA
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form, except as embedded into a Nordic
 *    Semiconductor ASA integrated circuit in a product or a software update for
 *    such product, must reproduce the above copyright notice, this list of
 *    conditions and the following disclaimer in the documentation and/or other
 *    materials provided with the distribution.
 *
 * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
 *    contributors may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * 4. This software, with or without modification, must only be used with a
 *    Nordic Semiconductor ASA integrated circuit.
 *
 * 5. Any software provided in binary form under this license must not be reverse
 *    engineered, decompiled, modified and/or disassembled.
 *
 * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
/** @file
 *
 * @defgroup ble_sdk_app_beacon_main main.c
 * @{
 * @ingroup ble_sdk_app_beacon
 * @brief Beacon Transmitter Sample Application main file.
 *
 * This file contains the source code for an Beacon transmitter sample application.
 */

#include <stdbool.h>
#include <stdint.h>
#include "nordic_common.h"
#include "bsp.h"
#include "nrf_soc.h"
#include "nrf_sdh.h"
#include "nrf_sdh_ble.h"
#include "ble_advdata.h"
#include "app_timer.h"
#include "nrf_drv_clock.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_drv_saadc.h"
#include "nrf_drv_ppi.h"
#include "nrf_drv_timer.h"
#include "boards.h"
#include "nrf.h"
#include "nrf_delay.h"

#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"

/*****  Broadcast Parameters *******/

#define DEVICE_NAME                     "BLE_APP_BEACON"
#define APP_BLE_CONN_CFG_TAG            1                                  /**< A tag identifying the SoftDevice BLE configuration. */
#define NON_CONNECTABLE_ADV_INTERVAL    MSEC_TO_UNITS(400, UNIT_0_625_MS)  /**< The advertising interval for non-connectable advertisement (100 ms). This value can vary between 100ms to 10.24s). */

#define APP_ADV_DATA_LENGTH             0x15                               /**< Length of manufacturer specific data in the advertisement. */
#define APP_DEVICE_TYPE                 0x02                               /**< 0x02 refers to Beacon. */
#define APP_COMPANY_IDENTIFIER          0x0059                             /**< Company identifier for Nordic Semiconductor ASA. as per www.bluetooth.org. */

#define DEAD_BEEF                       0xDEADBEEF                    /**< Value used as error code on stack dump, can be used to identify stack location on stack unwind. */
#define HIGH 1
#define LOW  0

static ble_gap_adv_params_t m_adv_params;                                  /**< Parameters to be passed to the stack when starting advertising. */
static uint8_t              m_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; /**< Advertising handle used to identify an advertising set. */
static uint8_t              m_enc_advdata[BLE_GAP_ADV_SET_DATA_SIZE_MAX];  /**< Buffer for storing an encoded advertising set. */

uint16_t remote_led_indication;

static uint8_t      packet_buf;          /****** TX buffer for buttons ******/


/******    ADC parameters  *********/
#define SAMPLES_IN_BUFFER 1

volatile uint8_t state = 1;
static const nrf_drv_timer_t m_timer = NRF_DRV_TIMER_INSTANCE(1);
static nrf_saadc_value_t     m_buffer_pool[2][SAMPLES_IN_BUFFER];
static nrf_ppi_channel_t     m_ppi_channel;
//static uint32_t              m_adc_evt_counter;

#define ADC_REF_VOLTAGE_IN_MILLIVOLTS   600                                     /**< Reference voltage (in milli volts) used by ADC while doing conversion. */
#define ADC_PRE_SCALING_COMPENSATION    6                                       /**< The ADC is configured to use VDD with 1/3 prescaling as input. And hence the result of conversion is to be multiplied by 3 to get the actual value of the battery voltage.*/
//#define DIODE_FWD_VOLT_DROP_MILLIVOLTS  270                                   /**< Typical forward voltage drop of the diode . */
#define ADC_RES_10BIT                   1024                                    /**< Maximum digital value for 10-bit ADC conversion. */
#define ADC_RESULT_IN_MILLI_VOLTS(ADC_VALUE) \
        ((((ADC_VALUE) *ADC_REF_VOLTAGE_IN_MILLIVOLTS) / ADC_RES_10BIT) * ADC_PRE_SCALING_COMPENSATION)

void timer_handler(nrf_timer_event_t event_type, void * p_context)
{
}

void saadc_sampling_event_init(void)
{
    ret_code_t err_code;

    err_code = nrf_drv_ppi_init();
    APP_ERROR_CHECK(err_code);

    nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
    timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;
    err_code = nrf_drv_timer_init(&m_timer, &timer_cfg, timer_handler);
    APP_ERROR_CHECK(err_code);

    /* setup m_timer for compare event every 400ms */
    uint32_t ticks = nrf_drv_timer_ms_to_ticks(&m_timer, 400);
    nrf_drv_timer_extended_compare(&m_timer,
                                   NRF_TIMER_CC_CHANNEL0,
                                   ticks,
                                   NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
                                   false);
    nrf_drv_timer_enable(&m_timer);

    uint32_t timer_compare_event_addr = nrf_drv_timer_compare_event_address_get(&m_timer,
                                                                                NRF_TIMER_CC_CHANNEL0);
    uint32_t saadc_sample_task_addr   = nrf_drv_saadc_sample_task_get();

    /* setup ppi channel so that timer compare event is triggering sample task in SAADC */
    err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_ppi_channel_assign(m_ppi_channel,
                                          timer_compare_event_addr,
                                          saadc_sample_task_addr);
    APP_ERROR_CHECK(err_code);
}

void saadc_sampling_event_enable(void)
{
    ret_code_t err_code = nrf_drv_ppi_channel_enable(m_ppi_channel);

    APP_ERROR_CHECK(err_code);
}

void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
    if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
    {
        ret_code_t err_code;
        nrf_saadc_value_t adc_result;
        uint16_t batt_lvl_in_milli_volts;
        err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER);
        APP_ERROR_CHECK(err_code);

        int i;

        //NRF_LOG_INFO("ADC event number: %d", (int)m_adc_evt_counter);

        for (i = 0; i < SAMPLES_IN_BUFFER; i++)
        {
          adc_result=p_event->data.done.p_buffer[0];
         
          batt_lvl_in_milli_volts = ADC_RESULT_IN_MILLI_VOLTS(adc_result);

        }
        remote_led_indication = batt_lvl_in_milli_volts;  
        //m_adc_evt_counter++;
    }
}

void saadc_init(void)
{
    ret_code_t err_code;
    nrf_saadc_channel_config_t channel_config =
    NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_VDD);

    err_code = nrf_drv_saadc_init(NULL, saadc_callback);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_channel_init(0, &channel_config);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], SAMPLES_IN_BUFFER);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1], SAMPLES_IN_BUFFER);
    APP_ERROR_CHECK(err_code);

}

/**@brief Function for the GAP initialization.
 *
 * @details This function will set up all the necessary GAP (Generic Access Profile) parameters of
 *          the device. It also sets the permissions and appearance.
 */
static void gap_params_init(void)
{
   uint32_t err_code;
   ble_gap_conn_sec_mode_t     sec_mode;
   BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
   err_code = sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *)DEVICE_NAME,
   strlen(DEVICE_NAME));
   APP_ERROR_CHECK(err_code);
}

/**@brief Struct that contains pointers to the encoded advertising data. */
static ble_gap_adv_data_t m_adv_data =
{
    .adv_data =
    {
        .p_data = m_enc_advdata,
        .len    = BLE_GAP_ADV_SET_DATA_SIZE_MAX
    },
    .scan_rsp_data =
    {
        .p_data = NULL,
        .len    = 0

    }
};

/**@brief Callback function for asserts in the SoftDevice.
 *
 * @details This function will be called in case of an assert in the SoftDevice.
 *
 * @warning This handler is an example only and does not fit a final product. You need to analyze
 *          how your product is supposed to react in case of Assert.
 * @warning On assert from the SoftDevice, the system can only recover on reset.
 *
 * @param[in]   line_num   Line number of the failing ASSERT call.
 * @param[in]   file_name  File name of the failing ASSERT call.
 */
void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
{
    app_error_handler(DEAD_BEEF, line_num, p_file_name);
}

/**@brief Function for initializing the Advertising functionality.
 *
 * @details Encodes the required advertising data and passes it to the stack.
 *          Also builds a structure to be passed to the stack when starting advertising.
 */

static void advertising_data_update(void)
{
    uint32_t      err_code;
    ble_advdata_t advdata;
    uint8_t       flags = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE;

    ble_advdata_manuf_data_t manuf_specific_data;

    manuf_specific_data.company_identifier = APP_COMPANY_IDENTIFIER;
    manuf_specific_data.data.p_data = (uint8_t *) &packet_buf;
    manuf_specific_data.data.size   = sizeof(packet_buf);
    advdata.p_manuf_specific_data = &manuf_specific_data;

    // Build and set advertising data.
    memset(&advdata, 0, sizeof(advdata));
    //advdata.name_type             = BLE_ADVDATA_NO_NAME;
    advdata.name_type             = BLE_ADVDATA_FULL_NAME;
    advdata.flags                 = flags;
    advdata.p_manuf_specific_data = &manuf_specific_data;

    // Initialize advertising parameters (used when starting advertising).
    memset(&m_adv_params, 0, sizeof(m_adv_params));

    m_adv_params.properties.type = BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED;
    m_adv_params.p_peer_addr     = NULL;    // Undirected advertisement.
    m_adv_params.filter_policy   = BLE_GAP_ADV_FP_ANY;
    m_adv_params.interval        = NON_CONNECTABLE_ADV_INTERVAL;
    m_adv_params.duration        = 400;       // Broadcast for 4 sec.

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

    err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &m_adv_data, &m_adv_params);
    APP_ERROR_CHECK(err_code);
}
/**@brief Function for starting advertising.
 */
static void advertising_start(void)
{
    ret_code_t err_code;

    err_code = sd_ble_gap_adv_start(m_adv_handle, APP_BLE_CONN_CFG_TAG);
    APP_ERROR_CHECK(err_code);

/**** LED indication while advertising ****/
    if (remote_led_indication > ("%d", 1920)){
        nrf_gpio_pin_write(LED_1, LOW);   // Green Led will Blink on less than 10% battery
        nrf_delay_ms(50);

        nrf_gpio_pin_write(LED_1, HIGH);
        nrf_delay_ms(50);

       }

    if (remote_led_indication < ("%d", 1920)){
        nrf_gpio_pin_write(LED_2, LOW);   // Red Led will Blink on more than 10% battery
        nrf_delay_ms(50);

        nrf_gpio_pin_write(LED_2, HIGH);  
        nrf_delay_ms(50);

       }

    //err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
    //APP_ERROR_CHECK(err_code);
}


/**@brief Function for starting advertising.
 */
static void advertising_stop()
{
    ret_code_t err_code;

    err_code = sd_ble_gap_adv_stop(m_adv_handle);
    APP_ERROR_CHECK(err_code);
}


/**@brief Function for initializing the BLE stack.
 *
 * @details Initializes the SoftDevice and the BLE event interrupt.
 */
static void ble_stack_init(void)
{
    ret_code_t err_code;
    err_code = nrf_sdh_enable_request();
 
    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);
}


/**@brief Function for initializing logging. */
static void log_init(void)
{
    ret_code_t err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);

    NRF_LOG_DEFAULT_BACKENDS_INIT();
}

/**@brief Function for initializing LEDs. */
static void leds_init(void)
{
    ret_code_t err_code = bsp_init(BSP_INIT_LEDS, NULL);
    APP_ERROR_CHECK(err_code);
}


/**@brief Function for initializing timers. */
static void timers_init(void)
{
    ret_code_t err_code = app_timer_init();
    APP_ERROR_CHECK(err_code);
}


/**@brief Function for initializing power management.
 */
static void power_management_init(void)
{
    ret_code_t err_code;
    err_code = nrf_pwr_mgmt_init();
    APP_ERROR_CHECK(err_code);
}


/**@brief Function for handling the idle state (main loop).
 *
 * @details If there is no pending log operation, then sleep until next the next event occurs.
 */
static void idle_state_handle(void)
{
    if (NRF_LOG_PROCESS() == false)
    {
        nrf_pwr_mgmt_run();
    }
}

/**@brief Function for handling bsp events.
 */
void bsp_evt_handler(bsp_event_t evt)
{ 
    switch (evt)
    {
          case BSP_EVENT_KEY_0:
          packet_buf = BSP_EVENT_KEY_0;
          break;

          case BSP_EVENT_KEY_1:
          packet_buf = BSP_EVENT_KEY_1;
          break;

          case BSP_EVENT_KEY_2:
          packet_buf = BSP_EVENT_KEY_2;
          break;

          case BSP_EVENT_KEY_3:
          packet_buf = BSP_EVENT_KEY_3;
          break;

          case BSP_EVENT_KEY_4:
          packet_buf = BSP_EVENT_KEY_4;
          break;
           
          case BSP_EVENT_KEY_5:
          packet_buf = BSP_EVENT_KEY_5;
          break;
   
          case BSP_EVENT_KEY_6:
          packet_buf = BSP_EVENT_KEY_6;
          break;
      
          case BSP_EVENT_KEY_7:
          packet_buf = BSP_EVENT_KEY_7;
          break;

          case BSP_EVENT_KEY_8:
          packet_buf = BSP_EVENT_KEY_8;
          break;
   
          case BSP_EVENT_KEY_9:
          packet_buf = BSP_EVENT_KEY_9;
          break;
      
          case BSP_EVENT_KEY_10:
          packet_buf = BSP_EVENT_KEY_10;
          break;  
    }
   
    NRF_LOG_INFO("%u", packet_buf);
    (void)sd_ble_gap_adv_stop(m_adv_handle);
    advertising_data_update();
    advertising_start();
}


/**
 * @brief Function for application main entry.
 */
int main(void)
{
    NRF_POWER->DCDCEN = 1;    
    uint32_t err_code = NRF_SUCCESS; 
 
    // Initialize.
    nrf_pwr_mgmt_init();
    //log_init();
    timers_init();
    //leds_init();
    //power_management_init();
    ble_stack_init();
    gap_params_init();
    //advertising_init();
    advertising_data_update();
    
    
    err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, bsp_evt_handler);
    APP_ERROR_CHECK(err_code);

    saadc_init();
    saadc_sampling_event_init();
    saadc_sampling_event_enable();


    // Start execution.
    NRF_LOG_INFO("Beacon example started.");
    advertising_start();

    // Enter main loop.
    for(;;)
    {
        idle_state_handle();
    }
}


/**
 * @}
 */

I would appreciate any help!!!

Thanks!!!

  • Hi!

    Is it possible that you may have a floating input? Either way, please check if you get the same result if you remove the initialization of your button inputs.

    If I remove the initialisation of button input then it is going to sleep mode and i guess, there is no floating point as i pull down.

    The device is should enter system OFF (deep sleep) when you let this standby timer expire,

    Will it harm to my program further?

    i am attaching my code below so that if you could check what i am missing

    /**
     * Copyright (c) 2014 - 2020, Nordic Semiconductor ASA
     *
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     *
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     *
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     *
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     *
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    /** @file
     *
     * @defgroup ble_sdk_app_beacon_main main.c
     * @{
     * @ingroup ble_sdk_app_beacon
     * @brief Beacon Transmitter Sample Application main file.
     *
     * This file contains the source code for an Beacon transmitter sample application.
     */
    
    /******** Ble_beacon_remote **********/
    
    #include <stdbool.h>
    #include <stdint.h>
    #include "nordic_common.h"
    #include "bsp.h"
    #include "nrf_soc.h"
    #include "nrf_sdh.h"
    #include "nrf_sdh_ble.h"
    #include "ble_advdata.h"
    #include "app_timer.h"
    #include "nrf_pwr_mgmt.h"
    #include "nrf_drv_clock.h"
    #include "nrf_drv_saadc.h"
    #include "nrf_drv_ppi.h"
    #include "nrf_drv_timer.h"
    #include "boards.h"
    #include "nrf.h"
    #include "nrf_delay.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #define DEVICE_NAME                     "Device_Name"
    #define APP_BLE_CONN_CFG_TAG            1                                  /**< A tag identifying the SoftDevice BLE configuration. */
    
    #define BATTERY_LEVEL_MEAS_INTERVAL     APP_TIMER_TICKS(5000)              /**< Battery level measurement interval (ticks). */
    
    #define NON_CONNECTABLE_ADV_INTERVAL    MSEC_TO_UNITS(100, UNIT_0_625_MS)  /**< The advertising interval for non-connectable advertisement (100 ms). This value can vary between 100ms to 10.24s). */
    
    #define APP_BEACON_INFO_LENGTH          0x17                               /**< Total length of information advertised by the Beacon. */
    #define APP_ADV_DATA_LENGTH             0x15                               /**< Length of manufacturer specific data in the advertisement. */
    #define APP_DEVICE_TYPE                 0x02                               /**< 0x02 refers to Beacon. */
    #define APP_COMPANY_IDENTIFIER          0x0059  
    
    
    #define ADC_REF_VOLTAGE_IN_MILLIVOLTS   600                               /**< Reference voltage (in milli volts) used by ADC while doing conversion. */
    #define ADC_PRE_SCALING_COMPENSATION    6                                 /**< The ADC is configured to use VDD with 1/3 prescaling as input. And hence the result of conversion is to be multiplied by 3 to get the actual value of the battery voltage.*/
    #define DIODE_FWD_VOLT_DROP_MILLIVOLTS  270                               /**< Typical forward voltage drop of the diode . */
    #define ADC_RES_10BIT                   1024                              /**< Maximum digital value for 10-bit ADC conversion. */
    
    uint16_t remote_led_indication;
    static uint8_t      packet_buf[2];          /****** TX buffer for buttons ******/
    
    /**@brief Macro to convert the result of ADC conversion in millivolts.
     *
     * @param[in]  ADC_VALUE   ADC result.
     *
     * @retval     Result converted to millivolts.
     */
    #define ADC_RESULT_IN_MILLI_VOLTS(ADC_VALUE)\
            ((((ADC_VALUE) * ADC_REF_VOLTAGE_IN_MILLIVOLTS) / ADC_RES_10BIT) * ADC_PRE_SCALING_COMPENSATION)
    
    #define DEAD_BEEF                       0xDEADBEEF                         /**< Value used as error code on stack dump, can be used to identify stack location on stack unwind. */
    #define HIGH        1
    #define LOW         0
    
    static ble_gap_adv_params_t m_adv_params;                                  /**< Parameters to be passed to the stack when starting advertising. */
    static uint8_t              m_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; /**< Advertising handle used to identify an advertising set. */
    static uint8_t              m_enc_advdata[BLE_GAP_ADV_SET_DATA_SIZE_MAX];  /**< Buffer for storing an encoded advertising set. */
    
    static nrf_saadc_value_t m_adc_buf;
    
    APP_TIMER_DEF(m_battery_timer_id);                                         /**< Battery timer. */
    
    /**@brief Function for the GAP initialization.
    212 
     *
    213 
     * @details This function will set up all the necessary GAP (Generic Access Profile) parameters of
    214 
     *          the device. It also sets the permissions and appearance.
    215 
     */ 
    static void gap_params_init(void)
    {
       uint32_t err_code;
       ble_gap_conn_sec_mode_t     sec_mode;
       BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
    
       err_code = sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *)DEVICE_NAME,
    
       strlen(DEVICE_NAME));
     
       APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Struct that contains pointers to the encoded advertising data. */
    static ble_gap_adv_data_t m_adv_data =
    {
        .adv_data =
        {
            .p_data = m_enc_advdata,
            .len    = BLE_GAP_ADV_SET_DATA_SIZE_MAX
        },
        .scan_rsp_data =
        {
            .p_data = NULL,
            .len    = 0
    
        }
    };
    
    /**@brief Callback function for asserts in the SoftDevice.
     *
     * @details This function will be called in case of an assert in the SoftDevice.
     *
     * @warning This handler is an example only and does not fit a final product. You need to analyze
     *          how your product is supposed to react in case of Assert.
     * @warning On assert from the SoftDevice, the system can only recover on reset.
     *
     * @param[in]   line_num   Line number of the failing ASSERT call.
     * @param[in]   file_name  File name of the failing ASSERT call.
     */
    void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
    {
        app_error_handler(DEAD_BEEF, line_num, p_file_name);
    }
    
    
    /**@brief Function for handling the ADC interrupt.
     *
     * @details  This function will fetch the conversion result from the ADC, convert the value into
     *           percentage and send it to peer.
     */
    void saadc_event_handler(nrf_drv_saadc_evt_t const * p_event)
    {
        if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
        {
            nrf_saadc_value_t adc_result;
            uint16_t batt_lvl_in_milli_volts;
            uint8_t percentage_batt_lvl;
            uint32_t err_code;
    
            adc_result = p_event->data.done.p_buffer[0];
    
            batt_lvl_in_milli_volts =
                ADC_RESULT_IN_MILLI_VOLTS(adc_result) + DIODE_FWD_VOLT_DROP_MILLIVOLTS;
    
            NRF_LOG_INFO("Battery Level Measurement : %d [mV]", batt_lvl_in_milli_volts);
            
            remote_led_indication = batt_lvl_in_milli_volts;
        }
        else if (p_event->type == NRF_DRV_SAADC_EVT_CALIBRATEDONE)
        {
            NRF_LOG_INFO("SAADC calibration complete");
        }
    }
    
    
    /**@brief Function for handling the Battery measurement timer timeout.
     *
     * @details This function will be called each time the battery level measurement timer expires.
     *
     * @param[in] p_context  Pointer used for passing some arbitrary information (context) from the
     *                       app_start_timer() call to the timeout handler.
     */
    static void battery_level_meas_timeout_handler(void * p_context)
    {
        UNUSED_PARAMETER(p_context);
        
        ret_code_t err_code = nrf_drv_saadc_buffer_convert(&m_adc_buf, 1);
        APP_ERROR_CHECK(err_code);
        
        err_code = nrf_drv_saadc_sample();
        APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Function for initializing the Advertising functionality.
     *
     * @details Encodes the required advertising data and passes it to the stack.
     *          Also builds a structure to be passed to the stack when starting advertising.
     */
    static void advertising_data_update(void)
    {
        uint32_t      err_code;
        ble_advdata_t advdata;
        uint8_t       flags = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE;
        ble_advdata_manuf_data_t manuf_specific_data;
    
        manuf_specific_data.company_identifier = APP_COMPANY_IDENTIFIER;
        manuf_specific_data.data.p_data = (uint8_t *) &packet_buf;
        manuf_specific_data.data.size   = sizeof(packet_buf);
        advdata.p_manuf_specific_data = &manuf_specific_data;
    
        // Build and set advertising data.
        memset(&advdata, 0, sizeof(advdata));
    
        advdata.name_type             = BLE_ADVDATA_FULL_NAME;
        advdata.flags                 = flags;
        advdata.p_manuf_specific_data = &manuf_specific_data;
    
        // Initialize advertising parameters (used when starting advertising).
        memset(&m_adv_params, 0, sizeof(m_adv_params));
    
        m_adv_params.properties.type = BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED;
        m_adv_params.p_peer_addr     = NULL;    // Undirected advertisement.
        m_adv_params.filter_policy   = BLE_GAP_ADV_FP_ANY;
        m_adv_params.interval        = NON_CONNECTABLE_ADV_INTERVAL;
        m_adv_params.duration        = 400;       // Broadcast for 4 sec.
    
        err_code = ble_advdata_encode(&advdata, m_adv_data.adv_data.p_data, &m_adv_data.adv_data.len);
        APP_ERROR_CHECK(err_code);
    
        err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &m_adv_data, &m_adv_params);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for starting advertising.
     */
    static void advertising_start(void)
    {
        ret_code_t err_code;
    
        err_code = sd_ble_gap_adv_start(m_adv_handle, APP_BLE_CONN_CFG_TAG);
        APP_ERROR_CHECK(err_code);
    
    /**** LED indication while advertising ****/
        if (remote_led_indication > ("%d", 1920)){
            nrf_gpio_pin_write(LED_1, LOW);  
            nrf_delay_ms(50);
    
            nrf_gpio_pin_write(LED_1, HIGH);
            nrf_delay_ms(50);
     
            NRF_LOG_INFO("More than 10 percent battery level");
           }
    
        if (remote_led_indication < ("%d", 1920)){
            nrf_gpio_pin_write(LED_2, LOW);  
            nrf_delay_ms(50); 
    
            nrf_gpio_pin_write(LED_2, HIGH);   
            nrf_delay_ms(50);
    
            NRF_LOG_INFO("Less than 10 percent battery level");
           }
    }
    
    /**@brief Function for starting advertising.
     */
    static void advertising_stop()
    {
        ret_code_t err_code;
     
        err_code = sd_ble_gap_adv_stop(m_adv_handle);
        APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Function for initializing the BLE stack.
     *
     * @details Initializes the SoftDevice and the BLE event interrupt.
     */
    static void ble_stack_init(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_sdh_enable_request();
        APP_ERROR_CHECK(err_code);
    
        // Configure the BLE stack using the default settings.
        // Fetch the start address of the application RAM.
        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);
    }
    
    /**@brief Function for handling bsp events.
    412 
     */
    
    void bsp_evt_handler(bsp_event_t evt)
    {
        switch (evt) 
        {
              case BSP_EVENT_KEY_0:
              packet_buf[0] = BSP_EVENT_KEY_0;
              packet_buf[1]++;
              break;
    
              case BSP_EVENT_KEY_1: 
              packet_buf[0] = BSP_EVENT_KEY_1;
              packet_buf[1]++;
              break;
    
              case BSP_EVENT_KEY_2: 
              packet_buf[0] = BSP_EVENT_KEY_2;
              packet_buf[1]++;
              break;
    
              case BSP_EVENT_KEY_3: 
              packet_buf[0] = BSP_EVENT_KEY_3;
              packet_buf[1]++;
              break;
     
              case BSP_EVENT_KEY_4: 
              packet_buf[0] = BSP_EVENT_KEY_4;
              packet_buf[1]++;
              break;
              
              case BSP_EVENT_KEY_5:
              packet_buf[0] = BSP_EVENT_KEY_5;
              packet_buf[1]++;
              break;
      
              case BSP_EVENT_KEY_6: 
              packet_buf[0] = BSP_EVENT_KEY_6;
              packet_buf[1]++;
              break;
          
              case BSP_EVENT_KEY_7:
              packet_buf[0] = BSP_EVENT_KEY_7;
              packet_buf[1]++;
              break;
    
              case BSP_EVENT_KEY_8: 
              packet_buf[0] = BSP_EVENT_KEY_8;
              packet_buf[1]++;
              break; 
    
              case BSP_EVENT_KEY_9: 
              packet_buf[0] = BSP_EVENT_KEY_9;
              packet_buf[1]++;
              break;
          
              case BSP_EVENT_KEY_10:
              packet_buf[0] = BSP_EVENT_KEY_10;
              packet_buf[1]++;
              break;  
        }
    
        NRF_LOG_INFO("%u", packet_buf);
        (void)sd_ble_gap_adv_stop(m_adv_handle);
        advertising_data_update();
        advertising_start();
    }
    
    
    /**@brief Function for initializing logging. */
    static void log_init(void)
    {
        ret_code_t err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    
    /**@brief Function for initializing timers. */
    static void timers_init(void)
    {
        ret_code_t err_code = app_timer_init();
        APP_ERROR_CHECK(err_code);
     
        // Create timers.
        err_code = app_timer_create(&m_battery_timer_id,
                                    APP_TIMER_MODE_REPEATED,
                                    battery_level_meas_timeout_handler);
        APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Function for starting application timers.
     */
    static void application_timers_start(void)
    {
        ret_code_t err_code;
    
        // Start application timers.
        err_code = app_timer_start(m_battery_timer_id, BATTERY_LEVEL_MEAS_INTERVAL, NULL);
        APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Function for initializing power management.
     */
    static void power_management_init(void)
    {
        ret_code_t err_code;
        err_code = nrf_pwr_mgmt_init();
        APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Function for configuring ADC to do battery level conversion.
     */
    static void adc_configure(void)
    {
        ret_code_t err_code = nrf_drv_saadc_init(NULL, saadc_event_handler);
        APP_ERROR_CHECK(err_code);
    
        nrf_saadc_channel_config_t config =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_VDD);
    
        config.burst = NRF_SAADC_BURST_ENABLED;
    
        err_code = nrf_drv_saadc_channel_init(0, &config);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_saadc_calibrate_offset();
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling the idle state (main loop).
     *
     * @details If there is no pending log operation, then sleep until next the next event occurs.
     */
    static void idle_state_handle(void)
    {
        if (NRF_LOG_PROCESS() == false)
        {
            nrf_pwr_mgmt_run();
        }
    }
    
    
    /**
     * @brief Function for application main entry.
     */
    int main(void)
    {
        // Initialize.
        timers_init();
        power_management_init();
        ble_stack_init();
        gap_params_init();
        (void)sd_power_dcdc_mode_set(NRF_POWER_DCDC_ENABLE);
        advertising_data_update();
    
        uint8_t err_code = NRF_SUCCESS;
        //err_code = bsp_init(BSP_INIT_BUTTONS, bsp_evt_handler);
    
        err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, bsp_evt_handler);
        APP_ERROR_CHECK(err_code);
    
        adc_configure();
    
        // Start execution.
        NRF_LOG_INFO("Beacon example started.");
        application_timers_start();
        advertising_start();
    
        // Enter main loop.
        for (;; )
        {
            idle_state_handle();
        }
    }
    
    
    /**
     * @}
     */

    Thanks!!

  • Hi,

    The chip is powered down in System OFF mode and a wake-up from this mode will lead to a system reset. Is this what you want, or should the chip always stay in System ON mode and do periodic advertising? 

  • Hi!

    I just want to system should be on while advertising on button press and else it should be either on system on sleep mode or system off sleep mode as it's not that much concern as per my requirements. 

    Also system should be always wake up immediately on each button press. If you could review the above code so that you could provide yours suggestions whether if I missed something.

  • Hi,

    It makes sense to use System OFF if the device is expected to stay inactive (i.e. no advertising) for longer periods of time, and that you only rely on the button press as the wake-up source.

    Before entering system OFF you should also make that there is no ongoing SAADC sampling. From the PS:

    Before entering System OFF mode, the user must make sure that all on-going EasyDMA transactions have been completed. This is usually accomplished by making sure that the EasyDMA enabled peripheral is not active when entering System OFF.

Related