About BLE advertising and sleep system ON mode in Ble_App_Uart

 I am build an application with features : When I not used nRF it imediately in sleep mode and be wake up by BLE events to send some text, and return to sleep mode ( the reson why I choose system On sleep mode).

1. So I think my nRF make sure

-> advertising continuosly in sleep mode (because my phone will connect to nRF anytime to wake nRF up and send text)

2. To make nRF advertisin continously I did

- set the flags   // init.advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE => BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE; to disable advertising timeout
- in BLE_ADV_EVT_IDLE  I commented sleep_mode_enter();, and call ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST); to restart advertising

static void on_adv_evt(ble_adv_evt_t ble_adv_evt)
{
    uint32_t err_code;

    switch (ble_adv_evt)
    {
    case BLE_ADV_EVT_FAST:
        err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
        APP_ERROR_CHECK(err_code);
        break;
    case BLE_ADV_EVT_IDLE:
        NRF_LOG_INFO("call idle");
        //sleep_mode_enter();
        ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
        break;
    default:
        break;
    }
}

3. To wake up nRF I debug the NRF_LOG_PROCESS() in debug terminal this is 'true' when I connect to device or send some data from  mobile phone to nRF
-> so I think nRF was wake up in these BLE events

4. What is the different between ble_idle and ble_timeout ?  In idle mode can nRF advertising and my phone can connect to it ?
5. Does such continuous advertising make nRF consume a lot of energy? Can you suggest me some another ways ?
my main loop()

    // Enter main loop.
    for (;;)
    {
        idle_state_handle();
        NRF_LOG_INFO("%d", NRF_LOG_PROCESS());
        nrf_delay_ms(200);
    }

the rest of code is similar ble_app_uart ().
Please answer for me 5 above questions. Thank you !

Parents
  • Hello,

    1. So I think my nRF make sure

    -> advertising continuosly in sleep mode (because my phone will connect to nRF anytime to wake nRF up and send text)

    I am not sure if I have understood you correctly here, but I can confirm that you can stay in SYSTEM_ON sleep - like demonstrated in our examples - since the SoftDevice will wake the device when an advertising is upcoming, perform the advertising, and then go back to SYSTEM_ON sleep.

    2. To make nRF advertisin continously I did

    - set the flags   // init.advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE => BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE; to disable advertising timeout
    - in BLE_ADV_EVT_IDLE  I commented sleep_mode_enter();, and call ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST); to restart advertising

    Your flag change to general discoverability is correct, and must be set to general since your advertisings does not time out. However, you should not restart the advertisings as part of the BLE_ADV_EVT_IDLE event handler, but instead just set your advertising duration to 0, which means 'no timeout'.
    This happens during the advertising init / configuration.

    3. To wake up nRF I debug the NRF_LOG_PROCESS() in debug terminal this is 'true' when I connect to device or send some data from  mobile phone to nRF
    -> so I think nRF was wake up in these BLE events

    You do not need anything else than idle_state_handle in your main loop - the SoftDevice will make sure to wake the device from the SYSTEM_ON sleep before any upcoming BLE events. There is no need for you to do this manually. Furthermore, I would not recommend using the nrf_delay_ms function anywhere in a finished product if it can be avoided, since it just estimates the number of NOP instructions needed to be performed for the specified time to have elapsed - it is not very accurate, and it keeps the CPU awake unnecessarily which wastes power.

    4. What is the different between ble_idle and ble_timeout ?  In idle mode can nRF advertising and my phone can connect to it ?

    Could you elaborate what you mean by this question?
    If you are referring to the BLE_ADV_EVT_IDLE it is usually used to put the device into SYSTEM_OFF sleep because the advertising has finished without any peers connecting.

    5. Does such continuous advertising make nRF consume a lot of energy? Can you suggest me some another ways ?

    In general, yes: advertising without a timeout will consume a lot of power - but this heavily depends on your application as well. If your device will spend most of its time in a connection then advertising without a timeout does not really matter. If your device very seldom will enter into a connection and it is feasible for the user to press a button or otherwise wake the device prior to use, then it is wasteful to advertise without a timeout.
    The power consumption of your advertising also heavily depends on your advertising configurations, such as advertising interval and advertising payload.
    You can estimate the power consumption of your advertising using the Online Power Profiler to better see how the different configurations affect the power consumption.

    Best regards,
    Karl

  • Hi Karl, Thank for your clearly answers


    4. What is the different between ble_idle and ble_timeout ?  In idle mode can nRF advertising and my phone can connect to it ?

    Could you elaborate what you mean by this question?

    1. I means when my nRF call idle BLE_ADV_EVT_IDLE event, my phone can not scan nRF and when my nRF timeout I can not scan too. so what is the different. Or can you explain for me more detail about idle ble mode

    5. Does such continuous advertising make nRF consume a lot of energy? Can you suggest me some another ways ?

    In general, yes: advertising without a timeout will consume a lot of power

    2. My application need to wake up remotely. So I think wakeup by BLE is the unique way.
    So can you optimize or suggest some type of advertising to save enegy. With my basic knowlegde about nRF.  I think nRF have to advertising contiously to my phone can connect at any time and call the event BLE_GAP_EVT_CONNECTED to wake nRF up (call event BLE_GAP_EVT_CONNECTED generate an interrupt ? ) and receive data through nus_data_handler.

    I build an application that when I need to find my nRF, my phone will ping the signal by BLE to nRF and nRF will ring the bell. 

  • John12 said:
    Thank for your clearly answers

    No problem at all, I am happy to help!

    John12 said:
    I build an application that when I need to find my nRF, my phone will ping the signal by BLE to nRF and nRF will ring the bell. 

    Thank you for the additional detail, this makes it easier to understand your project and use-case.

    John12 said:
    1. I means when my nRF call idle BLE_ADV_EVT_IDLE event, my phone can not scan nRF and when my nRF timeout I can not scan too. so what is the different. Or can you explain for me more detail about idle ble mode

    True, the ADV IDLE event is meant to signify that advertising has ended, and that the advertising module now is in idle state. This means that the device is no longer advertising, and so it can not be found by any scanning device.
    Advertising duration is the parameter that determines how long a certain type of advertising will last.
    The GAP connection supervision timeout parameter determines how long the device will keep trying to reach its peer in a connection if the peer stops responding.
    The connection is not considered broken / terminated until the timeout occurs, even if the peer stops responding entirely.

    John12 said:
    2. My application need to wake up remotely. So I think wakeup by BLE is the unique way.
    So can you optimize or suggest some type of advertising to save enegy. With my basic knowlegde about nRF.  I think nRF have to advertising contiously to my phone can connect at any time and call the event BLE_GAP_EVT_CONNECTED to wake nRF up (call event BLE_GAP_EVT_CONNECTED generate an interrupt ? ) and receive data through nus_data_handler.

    Yes, it if needs to wake up remotely then it must be in SYSTEM_ON sleep mode and advertising. The SYSTEM_OFF sleep mode will require an external interrupt in order to wake, so this is then not an option. Furthermore you must be advertising as connectable for the device to be receptible for connection requests.

    In general, to reduce power consumption you can space out your advertisings as much as possible. If you for example use longer advertising intervals (longer time between each advertisements) you will see a lower average power consumption than if you advertise at a higher frequency.
    The BLE events does generate interrupts for your device, yes. While in SYSTEM_ON sleep the CPU will wake up to handle any interrupt or event, and the SoftDevice will always wake it up when there is an upcoming BLE event.

    Best regards,
    Karl

Reply
  • John12 said:
    Thank for your clearly answers

    No problem at all, I am happy to help!

    John12 said:
    I build an application that when I need to find my nRF, my phone will ping the signal by BLE to nRF and nRF will ring the bell. 

    Thank you for the additional detail, this makes it easier to understand your project and use-case.

    John12 said:
    1. I means when my nRF call idle BLE_ADV_EVT_IDLE event, my phone can not scan nRF and when my nRF timeout I can not scan too. so what is the different. Or can you explain for me more detail about idle ble mode

    True, the ADV IDLE event is meant to signify that advertising has ended, and that the advertising module now is in idle state. This means that the device is no longer advertising, and so it can not be found by any scanning device.
    Advertising duration is the parameter that determines how long a certain type of advertising will last.
    The GAP connection supervision timeout parameter determines how long the device will keep trying to reach its peer in a connection if the peer stops responding.
    The connection is not considered broken / terminated until the timeout occurs, even if the peer stops responding entirely.

    John12 said:
    2. My application need to wake up remotely. So I think wakeup by BLE is the unique way.
    So can you optimize or suggest some type of advertising to save enegy. With my basic knowlegde about nRF.  I think nRF have to advertising contiously to my phone can connect at any time and call the event BLE_GAP_EVT_CONNECTED to wake nRF up (call event BLE_GAP_EVT_CONNECTED generate an interrupt ? ) and receive data through nus_data_handler.

    Yes, it if needs to wake up remotely then it must be in SYSTEM_ON sleep mode and advertising. The SYSTEM_OFF sleep mode will require an external interrupt in order to wake, so this is then not an option. Furthermore you must be advertising as connectable for the device to be receptible for connection requests.

    In general, to reduce power consumption you can space out your advertisings as much as possible. If you for example use longer advertising intervals (longer time between each advertisements) you will see a lower average power consumption than if you advertise at a higher frequency.
    The BLE events does generate interrupts for your device, yes. While in SYSTEM_ON sleep the CPU will wake up to handle any interrupt or event, and the SoftDevice will always wake it up when there is an upcoming BLE event.

    Best regards,
    Karl

Children
  • Hi Karl, please confirm for me this information

    int main(void)
    {
        bool erase_bonds;
        log_init();
        bsp_board_init(BSP_INIT_LEDS);
        // Initialize.
        uart_init();
        timers_init();
        buttons_leds_init(&erase_bonds);
        power_management_init();
        ble_stack_init();
        gap_params_init();
        gatt_init();
        services_init();
        advertising_init();
        conn_params_init();
    
        // Start execution.
        printf("\r\nUART started.\r\n");
        NRF_LOG_INFO("Debug logging for UART over RTT started.");
        advertising_start();
    
        // Enter main loop.
        for (;;)
        {
            idle_state_handle();
            //NRF_LOG_INFO("%d", NRF_LOG_PROCESS());
            //nrf_delay_ms(200);   
            bsp_board_led_invert(2); // toggle LED_2 P0.14
            nrf_delay_ms(100);
    
        }
    }

    in for (;;)  loop

    I call  idle_state_handle();  in line 26 and toggle led and delay  (100ms). This delay to make sure I can realize the led change status.When I test on my nRF
    step1. My nRF will blink once time and stop (turn on)

    step2: I scan and connect to my nRF -> my led blink once time and stop (turn on)
    I think when I wake up my nRF it imediately execute the first line in for (;;) loop that is idle_state_handle(); (line26) = > check NRF_LOG_PROCESS  == true, and execute the rest of lines of for (;;) loop until return line 26 and back to sleep.

    1. So is this principle right for all basic applicaiton (I means need to put idle_state_handle(); at  the first of for(;;) to make sure another feature is all executed and return to sleep.)

    2. What is NRF_LOG_PROCESS(). Is it unique signal to check are there any interrupt or event to wake nRF up ? Because I found in idle_state_handle() only check status of NRF_LOG_PROCESS() == false to call nrf_pwr_mgmt_run();

    3. In sleep system ON mode, nRF is still advertising BLE continously.Timout was counted => there are at least a timer working. So what is actually "sleep" mode here ?( what are actually sleep ?). I'm not sure about this sleep systemON mode so it's  too hard to handle other perpheral or clock. Because I'm using libuarte in my application so if libuarte is working whn nRF in sleep system ON mode or not ? and more I'm using MPU6050 sensor also to detect motion If in sleep mode can I disable this peripheral that this sensor connected and when my nRF move MPU6050 will generate interrupt to wake nRF up.

    4. I'm using nRF52833 chip on custom board. Can you suggest for me some link to measure current consumption. I follow many threads but it too hard to understand.

    5. if my application advertise continously and use 1000maH battery . How long do you think the nRf will live?

    Sorry about my expression. Because English is not my mother language ^^

  • Hello,

    John12 said:
    Sorry about my expression. Because English is not my mother language ^^

    No need to apologize! I do my best to understand what you have meant, and if I am unsure I will ask you to clarify, it is no problem at all :) 

    John12 said:
    I call  idle_state_handle();  in line 26 and toggle led and delay  (100ms). This delay to make sure I can realize the led change status.

    You do not really need this delay here, the LED will be toggled without it as well. 100 ms is an ocean of time in the context of the nRF52833, so you will spent a lot of power in the 100 ms delay.

    John12 said:

    I think when I wake up my nRF it imediately execute the first line in for (;;) loop that is idle_state_handle(); (line26) = > check NRF_LOG_PROCESS  == true, and execute the rest of lines of for (;;) loop until return line 26 and back to sleep.

    1. So is this principle right for all basic applicaiton (I means need to put idle_state_handle(); at  the first of for(;;) to make sure another feature is all executed and return to sleep.)

    This is not quite correct - when the CPU is awoken from SYSTEM_ON sleep by an event it will complete the processing of that event before it moves on to the main for(;;) loop. The main loop has the lowest priority of the application, which means that it will only return there once all other events are processed. This ensures that the device goes into low power SYSTEM_ON whenever it has nothing else that needs processing.

    John12 said:
    I think when I wake up my nRF it imediately execute the first line in for (;;) loop that is idle_state_handle(); (line26) = > check NRF_LOG_PROCESS  == true, and execute the rest of lines of for (;;) loop until return line 26 and back to sleep.

    No, it will first process the event that woke it and any other event that is generated during the handling of the first event. It only goes back to the main context once it has finished all its other work, which is why the main for(;;) loop should only contain the idle_state_handler, since this puts it into SYSTEM_ON sleep.

    John12 said:
    2. What is NRF_LOG_PROCESS(). Is it unique signal to check are there any interrupt or event to wake nRF up ? Because I found in idle_state_handle() only check status of NRF_LOG_PROCESS() == false to call nrf_pwr_mgmt_run();

    No, this just checks if there are any logs that needs processing before it goes to sleep. Processing logs thus also has a very low priority.
    Any event is able to interrupt the main() context at any time.

    John12 said:
    So what is actually "sleep" mode here ?( what are actually sleep ?)

    The crucial difference here is between SYSTEM_OFF sleep and SYSTEM_ON sleep. In SYSTEM_OFF sleep the whole device is shut off, while in SYSTEM_ON sleep it is only the CPU who is put into a low-power sleep state (called 'idle').
    When the device is in SYSTEM_ON sleep it means that the CPU is in the low-power sleep, but able to wake up to process any incoming events (like an upcoming advertising event), while peripherals may still function as usual. That is to say, the SAADC can for example be sampling while the CPU is sleeping since it does not require CPU interaction to do so. Likewise peripherals like TIMER and RTC can still run while the CPU is sleeping and the device is in SYSTEM_ON sleep.

    John12 said:
    and more I'm using MPU6050 sensor also to detect motion If in sleep mode can I disable this peripheral that this sensor connected and when my nRF move MPU6050 will generate interrupt to wake nRF up.

    An event from the external sensor can be used to wake the nRF device from both SYSTEM_ON and SYSTEM_OFF sleep, yes.

    John12 said:
    4. I'm using nRF52833 chip on custom board. Can you suggest for me some link to measure current consumption. I follow many threads but it too hard to understand.

    You could for example use a Power Profiler Kit in order to measure your power consumption.
    I do not know anything about your custom board, but does its layout enable you to measure the power consumption of the nRF device alone, or will you be measuring it for the whole board?

    John12 said:
    5. if my application advertise continously and use 1000maH battery . How long do you think the nRf will live?

    This is impossible for me to estimate since it depends on what else the device is doing and how you have configured your advertising.
    I would suggest that you input your advertising configuration into the Online Power Profiler to see how much the estimated consumption is, and then calculate how long it would take to deplete a 1000 mAH battery.

    Best regards,
    Karl

  • Hi Karl, I'm back after weekend  :))

    When the device is in SYSTEM_ON sleep it means that the CPU is in the low-power sleep, but able to wake up to process any incoming events (like an upcoming advertising event), while peripherals may still function as usual. That is to say, the SAADC can for example be sampling while the CPU is sleeping since it does not require CPU interaction to do so. Likewise peripherals like TIMER and RTC can still run while the CPU is sleeping and the device is in SYSTEM_ON sleep.

    I have 2 questions for this quote
    In SYSTEM_ON sleep mode, in my case my nRF will advertising continuosly. (not BLE timeout, not BLE idle) so I means I checked that when my nRF call idle_state_handle(), it's still advertising, receiving data from mobile phone via BLE and send to UART. So Is nRF actually sleeping when it's advertising like that ?

    I measure  the current consumption it show 1.5mA. I disable my loggger ? Does Uart cause this problem ? 
    Here is my main.C and skd_config.h
    6153.sdk_config.h

    /**
     * Copyright (c) 2014 - 2019, 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_uart_over_ble_main main.c
     * @{
     * @ingroup  ble_sdk_app_nus_eval
     * @brief    UART over BLE application main file.
     *
     * This file contains the source code for a sample application that uses the Nordic UART service.
     * This application uses the @ref srvlib_conn_params module.
     */
    
    #include <stdint.h>
    #include <string.h>
    #include "nordic_common.h"
    #include "nrf.h"
    #include "ble_hci.h"
    #include "ble_advdata.h"
    #include "ble_advertising.h"
    #include "ble_conn_params.h"
    #include "nrf_sdh.h"
    #include "nrf_sdh_soc.h"
    #include "nrf_sdh_ble.h"
    #include "nrf_ble_gatt.h"
    #include "nrf_ble_qwr.h"
    #include "app_timer.h"
    #include "ble_nus.h"
    #include "app_uart.h"
    #include "app_util_platform.h"
    #include "bsp_btn_ble.h"
    #include "nrf_pwr_mgmt.h"
    #include "nrf_delay.h"
    
    #if defined(UART_PRESENT)
    #include "nrf_uart.h"
    #endif
    #if defined(UARTE_PRESENT)
    #include "nrf_uarte.h"
    #endif
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #define APP_BLE_CONN_CFG_TAG 1 /**< A tag identifying the SoftDevice BLE configuration. */
    
    #define DEVICE_NAME "Nordic_UART_XFinder"                /**< Name of device. Will be included in the advertising data. */
    #define NUS_SERVICE_UUID_TYPE BLE_UUID_TYPE_VENDOR_BEGIN /**< UUID type for the Nordic UART Service (vendor specific). */
    
    #define APP_BLE_OBSERVER_PRIO 3 /**< Application's BLE observer priority. You shouldn't need to modify this value. */
    
    #define APP_ADV_INTERVAL 64 /**< The advertising interval (in units of 0.625 ms. This value corresponds to 40 ms). */
    
    #define APP_ADV_DURATION 6000//18000 /**< The advertising duration (180 seconds) in units of 10 milliseconds. */
    //#define APP_ADV_DURATION 0//18000 /**< The advertising duration (180 seconds) in units of 10 milliseconds. */
    
    #define MIN_CONN_INTERVAL MSEC_TO_UNITS(20, UNIT_1_25_MS)    /**< Minimum acceptable connection interval (20 ms), Connection interval uses 1.25 ms units. */
    #define MAX_CONN_INTERVAL MSEC_TO_UNITS(75, UNIT_1_25_MS)    /**< Maximum acceptable connection interval (75 ms), Connection interval uses 1.25 ms units. */
    #define SLAVE_LATENCY 0                                      /**< Slave latency. */
    #define CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS)     /**< Connection supervisory timeout (4 seconds), Supervision Timeout uses 10 ms units. */
    #define FIRST_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(5000) /**< Time from initiating event (connect or start of notification) to first time sd_ble_gap_conn_param_update is called (5 seconds). */
    #define NEXT_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(30000) /**< Time between each call to sd_ble_gap_conn_param_update after the first call (30 seconds). */
    #define MAX_CONN_PARAMS_UPDATE_COUNT 3                       /**< Number of attempts before giving up the connection parameter negotiation. */
    
    #define DEAD_BEEF 0xDEADBEEF /**< Value used as error code on stack dump, can be used to identify stack location on stack unwind. */
    
    #define UART_TX_BUF_SIZE 256 /**< UART TX buffer size. */
    #define UART_RX_BUF_SIZE 256 /**< UART RX buffer size. */
    
    int testRamRetention = 5;
    
    BLE_NUS_DEF(m_nus, NRF_SDH_BLE_TOTAL_LINK_COUNT); /**< BLE NUS service instance. */
    NRF_BLE_GATT_DEF(m_gatt);                         /**< GATT module instance. */
    NRF_BLE_QWR_DEF(m_qwr);                           /**< Context for the Queued Write module.*/
    BLE_ADVERTISING_DEF(m_advertising);               /**< Advertising module instance. */
    
    static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID;               /**< Handle of the current connection. */
    static uint16_t m_ble_nus_max_data_len = BLE_GATT_ATT_MTU_DEFAULT - 3; /**< Maximum length of data (in bytes) that can be transmitted to the peer by the Nordic UART service module. */
    static ble_uuid_t m_adv_uuids[] =                                      /**< Universally unique service identifier. */
        {
            {BLE_UUID_NUS_SERVICE, NUS_SERVICE_UUID_TYPE}};
    
    /**@brief Function for assert macro callback.
     *
     * @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 analyse
     *          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] p_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 timer module.
     */
    static void timers_init(void)
    {
        ret_code_t err_code = app_timer_init();
        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_params_t gap_conn_params;
        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);
    
        memset(&gap_conn_params, 0, sizeof(gap_conn_params));
    
        gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
        gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
        gap_conn_params.slave_latency = SLAVE_LATENCY;
        gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT;
    
        err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
        APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Function for handling Queued Write Module errors.
     *
     * @details A pointer to this function will be passed to each service which may need to inform the
     *          application about an error.
     *
     * @param[in]   nrf_error   Error code containing information about what went wrong.
     */
    static void nrf_qwr_error_handler(uint32_t nrf_error)
    {
        APP_ERROR_HANDLER(nrf_error);
    }
    
    /**@brief Function for handling the data from the Nordic UART Service.
     *
     * @details This function will process the data received from the Nordic UART BLE Service and send
     *          it to the UART module.
     *
     * @param[in] p_evt       Nordic UART Service event.
     */
    /**@snippet [Handling the data received over BLE] */
    static void nus_data_handler(ble_nus_evt_t *p_evt)
    {
    NRF_LOG_INFO("Received data from BLE NUS. Writing data on UART.");
        if (p_evt->type == BLE_NUS_EVT_RX_DATA)
        {
            uint32_t err_code;
    NRF_LOG_INFO ("Received mobilephone.");
            NRF_LOG_DEBUG("Received data from BLE NUS. Writing data on UART.");
            NRF_LOG_HEXDUMP_DEBUG(p_evt->params.rx_data.p_data, p_evt->params.rx_data.length);
    
            for (uint32_t i = 0; i < p_evt->params.rx_data.length; i++)
            {
                do
                {
                    err_code = app_uart_put(p_evt->params.rx_data.p_data[i]);
                    if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_BUSY))
                    {
                        NRF_LOG_ERROR("Failed receiving NUS message. Error 0x%x. ", err_code);
                        APP_ERROR_CHECK(err_code);
                    }
                } while (err_code == NRF_ERROR_BUSY);
            }
            if (p_evt->params.rx_data.p_data[p_evt->params.rx_data.length - 1] == '\r')
            {
                while (app_uart_put('\n') == NRF_ERROR_BUSY)
                    ;
            }
        }
    }
    /**@snippet [Handling the data received over BLE] */
    
    /**@brief Function for initializing services that will be used by the application.
     */
    static void services_init(void)
    {
        uint32_t err_code;
        ble_nus_init_t nus_init;
        nrf_ble_qwr_init_t qwr_init = {0};
    
        // Initialize Queued Write Module.
        qwr_init.error_handler = nrf_qwr_error_handler;
    
        err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init);
        APP_ERROR_CHECK(err_code);
    
        // Initialize NUS.
        memset(&nus_init, 0, sizeof(nus_init));
    
        nus_init.data_handler = nus_data_handler;
    
        err_code = ble_nus_init(&m_nus, &nus_init);
        APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Function for handling an event from the Connection Parameters Module.
     *
     * @details This function will be called for all events in the Connection Parameters Module
     *          which are passed to the application.
     *
     * @note All this function does is to disconnect. This could have been done by simply setting
     *       the disconnect_on_fail config parameter, but instead we use the event handler
     *       mechanism to demonstrate its use.
     *
     * @param[in] p_evt  Event received from the Connection Parameters Module.
     */
    static void on_conn_params_evt(ble_conn_params_evt_t *p_evt)
    {
        uint32_t err_code;
    
        if (p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED)
        {
            err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
            APP_ERROR_CHECK(err_code);
        }
    }
    
    /**@brief Function for handling errors from the Connection Parameters module.
     *
     * @param[in] nrf_error  Error code containing information about what went wrong.
     */
    static void conn_params_error_handler(uint32_t nrf_error)
    {
        APP_ERROR_HANDLER(nrf_error);
    }
    
    /**@brief Function for initializing the Connection Parameters module.
     */
    static void conn_params_init(void)
    {
        uint32_t err_code;
        ble_conn_params_init_t cp_init;
    
        memset(&cp_init, 0, sizeof(cp_init));
    
        cp_init.p_conn_params = NULL;
        cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
        cp_init.next_conn_params_update_delay = NEXT_CONN_PARAMS_UPDATE_DELAY;
        cp_init.max_conn_params_update_count = MAX_CONN_PARAMS_UPDATE_COUNT;
        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 Function for putting the chip into sleep mode.
     *
     * @note This function will not return.
     */
    static void sleep_mode_enter(void)
    {
        NRF_LOG_INFO("call sleep_mode_enter");
        uint32_t err_code = bsp_indication_set(BSP_INDICATE_IDLE);
        APP_ERROR_CHECK(err_code);
    
        // Prepare wakeup buttons.
        err_code = bsp_btn_ble_sleep_mode_prepare();
        APP_ERROR_CHECK(err_code);
    
        // Go to system-off mode (this function will not return; wakeup will cause a reset).
        err_code = sd_power_system_off();
        APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Function for handling advertising events.
     *
     * @details This function will be called for advertising events which are passed to the application.
     *
     * @param[in] ble_adv_evt  Advertising event.
     */
    static void on_adv_evt(ble_adv_evt_t ble_adv_evt)
    {
        uint32_t err_code;
    
        switch (ble_adv_evt)
        {
        case BLE_ADV_EVT_FAST:
            err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
            APP_ERROR_CHECK(err_code);
            break;
        case BLE_ADV_EVT_IDLE:
            NRF_LOG_INFO("call idle");
            //sleep_mode_enter();
            break;
        default:
            break;
        }
    }
    
    /**@brief Function for handling BLE events.
     *
     * @param[in]   p_ble_evt   Bluetooth stack event.
     * @param[in]   p_context   Unused.
     */
    static void ble_evt_handler(ble_evt_t const *p_ble_evt, void *p_context)
    {
        uint32_t err_code;
    
        switch (p_ble_evt->header.evt_id)
        {
        case BLE_GAP_EVT_CONNECTED:
            NRF_LOG_INFO("Connected");
            err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
            APP_ERROR_CHECK(err_code);
            m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
            err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_conn_handle);
            APP_ERROR_CHECK(err_code);
            break;
    
        case BLE_GAP_EVT_DISCONNECTED:
            NRF_LOG_INFO("Disconnected");
            // LED indication will be changed when advertising starts.
            m_conn_handle = BLE_CONN_HANDLE_INVALID;
            break;
    
        case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
        {
            NRF_LOG_DEBUG("PHY update request.");
            ble_gap_phys_t const phys =
                {
                    .rx_phys = BLE_GAP_PHY_AUTO,
                    .tx_phys = BLE_GAP_PHY_AUTO,
                };
            err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
            APP_ERROR_CHECK(err_code);
        }
        break;
    
        case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
            // Pairing not supported
            err_code = sd_ble_gap_sec_params_reply(m_conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL);
            APP_ERROR_CHECK(err_code);
            break;
    
        case BLE_GATTS_EVT_SYS_ATTR_MISSING:
            // No system attributes have been stored.
            err_code = sd_ble_gatts_sys_attr_set(m_conn_handle, NULL, 0, 0);
            APP_ERROR_CHECK(err_code);
            break;
    
        case BLE_GATTC_EVT_TIMEOUT:
            // Disconnect on GATT Client timeout event.
            err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,
                                             BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
            APP_ERROR_CHECK(err_code);
            break;
    
        case BLE_GATTS_EVT_TIMEOUT:
            // Disconnect on GATT Server timeout event.
            err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle,
                                             BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
            APP_ERROR_CHECK(err_code);
            break;
    
        default:
            // No implementation needed.
            break;
        }
    }
    
    /**@brief Function for the SoftDevice initialization.
     *
     * @details This function 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);
    
        // Register a handler for BLE events.
        NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
    }
    
    /**@brief Function for handling events from the GATT library. */
    void gatt_evt_handler(nrf_ble_gatt_t *p_gatt, nrf_ble_gatt_evt_t const *p_evt)
    {
        if ((m_conn_handle == p_evt->conn_handle) && (p_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED))
        {
            m_ble_nus_max_data_len = p_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH;
            NRF_LOG_INFO("Data len is set to 0x%X(%d)", m_ble_nus_max_data_len, m_ble_nus_max_data_len);
        }
        NRF_LOG_DEBUG("ATT MTU exchange completed. central 0x%x peripheral 0x%x",
                      p_gatt->att_mtu_desired_central,
                      p_gatt->att_mtu_desired_periph);
    }
    
    /**@brief Function for initializing the GATT library. */
    void gatt_init(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_ble_gatt_init(&m_gatt, gatt_evt_handler);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_ble_gatt_att_mtu_periph_set(&m_gatt, NRF_SDH_BLE_GATT_MAX_MTU_SIZE);
        APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Function for handling events from the BSP module.
     *
     * @param[in]   event   Event generated by button press.
     */
    void bsp_event_handler(bsp_event_t event)
    {
        uint32_t err_code;
        switch (event)
        {
        case BSP_EVENT_SLEEP:
            NRF_LOG_INFO("bsp_event_sleep");
            sleep_mode_enter();
            break;
    
        case BSP_EVENT_DISCONNECT:
            err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
            if (err_code != NRF_ERROR_INVALID_STATE)
            {
                APP_ERROR_CHECK(err_code);
            }
            break;
    
        case BSP_EVENT_WHITELIST_OFF:
            if (m_conn_handle == BLE_CONN_HANDLE_INVALID)
            {
                err_code = ble_advertising_restart_without_whitelist(&m_advertising);
                if (err_code != NRF_ERROR_INVALID_STATE)
                {
                    APP_ERROR_CHECK(err_code);
                }
            }
            break;
    
        default:
            break;
        }
    }
    
    /**@brief   Function for handling app_uart events.
     *
     * @details This function will receive a single character from the app_uart module and append it to
     *          a string. The string will be be sent over BLE when the last character received was a
     *          'new line' '\n' (hex 0x0A) or if the string has reached the maximum data length.
     */
    /**@snippet [Handling the data received over UART] */
    void uart_event_handle(app_uart_evt_t *p_event)
    {
        static uint8_t data_array[BLE_NUS_MAX_DATA_LEN];
        static uint8_t index = 0;
        uint32_t err_code;
    
        switch (p_event->evt_type)
        {
        case APP_UART_DATA_READY:
            UNUSED_VARIABLE(app_uart_get(&data_array[index]));
            index++;
    
            if ((data_array[index - 1] == '\n') ||
                (data_array[index - 1] == '\r') ||
                (index >= m_ble_nus_max_data_len))
            {
                if (index > 1)
                {
                    NRF_LOG_DEBUG("Ready to send data over BLE NUS");
                    NRF_LOG_HEXDUMP_DEBUG(data_array, index);
    
                    do
                    {
                        uint16_t length = (uint16_t)index;
                        err_code = ble_nus_data_send(&m_nus, data_array, &length, m_conn_handle);
                        if ((err_code != NRF_ERROR_INVALID_STATE) &&
                            (err_code != NRF_ERROR_RESOURCES) &&
                            (err_code != NRF_ERROR_NOT_FOUND))
                        {
                            APP_ERROR_CHECK(err_code);
                        }
                    } while (err_code == NRF_ERROR_RESOURCES);
                }
    
                index = 0;
            }
            break;
    
        case APP_UART_COMMUNICATION_ERROR:
            APP_ERROR_HANDLER(p_event->data.error_communication);
            break;
    
        case APP_UART_FIFO_ERROR:
            APP_ERROR_HANDLER(p_event->data.error_code);
            break;
    
        default:
            break;
        }
    }
    /**@snippet [Handling the data received over UART] */
    
    /**@brief  Function for initializing the UART module.
     */
    /**@snippet [UART Initialization] */
    static void uart_init(void)
    {
        uint32_t err_code;
        app_uart_comm_params_t const comm_params =
        {
            .rx_pin_no = RX_PIN_NUMBER1,
            .tx_pin_no = TX_PIN_NUMBER1,
            .rts_pin_no = RTS_PIN_NUMBER,
            .cts_pin_no = CTS_PIN_NUMBER,
            .flow_control = APP_UART_FLOW_CONTROL_DISABLED,
            .use_parity = false,
    #if defined(UART_PRESENT)
            .baud_rate = NRF_UART_BAUDRATE_115200
    #else
            .baud_rate = NRF_UARTE_BAUDRATE_115200
    #endif
        };
    
        APP_UART_FIFO_INIT(&comm_params,
                           UART_RX_BUF_SIZE,
                           UART_TX_BUF_SIZE,
                           uart_event_handle,
                           APP_IRQ_PRIORITY_LOWEST,
                           err_code);
        APP_ERROR_CHECK(err_code);
    }
    /**@snippet [UART Initialization] */
    
    /**@brief Function for initializing the Advertising functionality.
     */
    static void advertising_init(void)
    {
        uint32_t err_code;
        ble_advertising_init_t init;
    
        memset(&init, 0, sizeof(init));
    
        init.advdata.name_type = BLE_ADVDATA_FULL_NAME;
        init.advdata.include_appearance = false;
       // init.advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE;
        init.advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
    
        init.srdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
        init.srdata.uuids_complete.p_uuids = m_adv_uuids;
    
        init.config.ble_adv_fast_enabled = true;
        init.config.ble_adv_fast_interval = APP_ADV_INTERVAL;
        init.config.ble_adv_fast_timeout = APP_ADV_DURATION;
        init.evt_handler = on_adv_evt;
    
        err_code = ble_advertising_init(&m_advertising, &init);
        APP_ERROR_CHECK(err_code);
    
        ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);
    }
    
    /**@brief Function for initializing buttons and leds.
     *
     * @param[out] p_erase_bonds  Will be true if the clear bonding button was pressed to wake the application up.
     */
    static void buttons_leds_init(bool *p_erase_bonds)
    {
        bsp_event_t startup_event;
    
        uint32_t err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, bsp_event_handler);
        APP_ERROR_CHECK(err_code);
    
        err_code = bsp_btn_ble_init(NULL, &startup_event);
        APP_ERROR_CHECK(err_code);
    
        *p_erase_bonds = (startup_event == BSP_EVENT_CLEAR_BONDING_DATA);
    }
    
    /**@brief Function for initializing the nrf log module.
     */
    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 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_LOG_INFO("call Sleep ON"); => khi không có vi?c g? th? l?p t?c nh?y vào sleep ON
          //  ki?m tra nrf_log_process() == false
          //  ch? c?n có s? ki?n ng?t g? đó như truy?n uart qua th? s? t?o ng?t và cho wakeup
            nrf_pwr_mgmt_run();
        }
    }
    
    /**@brief Function for starting advertising.
     */
    static void advertising_start(void)
    {
        uint32_t err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
        APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Application main function.
     */
    int main(void)
    {
        bool erase_bonds;
        log_init();
        // Initialize.
        uart_init();
        timers_init();
        buttons_leds_init(&erase_bonds);
        power_management_init();
        ble_stack_init();
        gap_params_init();
        gatt_init();
        services_init();
        advertising_init();
        conn_params_init();
    
        // Start execution.
        printf("\r\nUART started.\r\n");
        NRF_LOG_INFO("Debug logging for UART over RTT started.");
        advertising_start();
    
        // Enter main loop.
        for (;;)
        {
            idle_state_handle();
            //NRF_LOG_INFO("%d", NRF_LOG_PROCESS());
            //nrf_delay_ms(200);
        }
    }
    
    /**
     * @}
     */
    

  • Hello,

    John12 said:
    I'm back after weekend  :))

    So am I! :)  - I hope you had a great weekend!

    John12 said:
    In SYSTEM_ON sleep mode, in my case my nRF will advertising continuosly. (not BLE timeout, not BLE idle) so I means I checked that when my nRF call idle_state_handle(), it's still advertising, receiving data from mobile phone via BLE and send to UART. So Is nRF actually sleeping when it's advertising like that ?

    Yes, your device will then enter SYSTEM_ON sleep in between every advertisement, and then wake up whenever an advertising event is upcoming so that it may process it, and then go back to sleep.
    Currently your advertising interval is 40 ms, which means that your device will wakeup to advertise every 40 ms. Since you are doing indefinite advertising it may be advisable for you to increase this, since this will have a high current consumption.
    Is there any requirements or constraints for your application on how fast it needs to be able to establish a connection?

    John12 said:
    I measure  the current consumption it show 1.5mA. I disable my loggger ? Does Uart cause this problem ? 
    Here is my main.C and skd_config.h

    Logger and the UART consumes a lot of power, yes. It seems that you have unabled the logger, but the UART peripheral is still enabled an in use in your application.

    Best regards,
    Karl

  • Hi Karl,

    1. In sleep ON mode, can my MPU6050 is still active ?. How can I set that. I want to use my MPU6050 to wake my nRF up 
    My temporatity idea is using MPU6050 interrupt, but I got the problem if MPU6050 active it will generate the interrupt continously => it's bad idea.

    2. In system ON, can I using timer to wake nRF up => can you suggest for me the example about this topic. Im very appriciate about that.

    3. I want to turn off uart dma (libuartes) to save enegry. Can I do that ?

    4. In main loop
    After idle_state_handle().
    I have to handle some event will be sent via BLE (in this case is set checkBuzzer = true).
    I have some confusions about this problem when handle some applications, events after idle_state_handle() whether it afffect to my sleep mode ?

        for (;;) {
          idle_state_handle();
          while(checkBuzzer == true){
            for (uint8_t i = 0; i < 40; ++i)
            {
                value = (i < 20) ? (i * 5) : (100 - (i - 20) * 5);
                ready_flag = false;
                while (app_pwm_channel_duty_set(&PWM1, 0, value) == NRF_ERROR_BUSY);
                while (!ready_flag);
                APP_ERROR_CHECK(app_pwm_channel_duty_set(&PWM1, 0, value));
                nrf_delay_ms(25);
            }
            }
           if(checkBuzzer == false){
              while (app_pwm_channel_duty_set(&PWM1, 0, 100) == NRF_ERROR_BUSY);
          }
         
        }

    Maybe it seems unrelated to this topic but I have a bunch of sleep mode confusions. Thank you for your help

Related