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

[Strategy] Multiple Tasks (SoftDevice + Scheduler + App Timer)

Hello guys. I'm beginner in Nordic Devices.

I'm working in project that sends Acceleration Data from KX220 sensor over LoRa network or if there is a BLE device connected, my nRF52 (SDK 14.2) should stream the data over BLE.

The acceleration data is currently collected by TIMER1 + SAADC + PPI, but I want collect the acelleration sampling 5KHz with LFXTAL due the low power consuption.

For LoRa network, I'm using this port:

https://github.com/gluedig/nrf52-lora

I built a Custom Board with my peripherals, LoRa Radio, Accelerometer KX220 and the nRF52832 is my main CPU. So, the nrf52-lora uses RTC2 to control the LoRaMAC timer. Soft Device uses the RTC0 and app_timer uses RTC1.

In the current scenario i want to keep my device sleeping for a long period, like 30 minutes for example. But I dont known exactly how can I count these 30 minutes sleeping, because RTC0, RTC1 and RTC2 have been used for other purpourse.

My first idea is using the app_timer lib to create a new task event but I'm note sure how could I do this.

I followed this tutorial:

https://devzone.nordicsemi.com/nordic/short-range-guides/b/software-development-kit/posts/application-timer-tutorial

I started to work with the ble_app_uart, this example uses the app_timer but this code doesnt follow the above steps for app_timer, I didn't understand very well how to use the app_timer with soft device. In the ble_app_uart we just see the following code:

// Initialize.
    err_code = app_timer_init();

In the ble_app_uart example there is not a app_timer callback like the tutorial, see the example bellow.

/**@brief Create timers.
 */
static void create_timers()
{
    ret_code_t err_code;

    // Create timers
    err_code = app_timer_create(&m_repeated_timer_id,
                                APP_TIMER_MODE_REPEATED,
                                repeated_timer_handler);
    APP_ERROR_CHECK(err_code);
}

So I want to use app_timer to create tasks to wake up my device after sleep minutes and control a sampling process. Can i do this with app_timer ? Do I need to use the scheduler ? Which is the best strategy for this case ?

Parents
  • Hi,

    Can i do this with app_timer ?

    Yes, app_timer supports timeout_ticks up to the maximum length of a uint32_t variable. 30 minutes should correspond to 1 800 000 ms, or 58 982 400 ticks with the default prescaler. You can change the prescaler for app_timer in sdk_config.h to support event longer intervals:

    // <o> APP_TIMER_CONFIG_RTC_FREQUENCY  - Configure RTC prescaler.
     
    // <0=> 32768 Hz 
    // <1=> 16384 Hz 
    // <3=> 8192 Hz 
    // <7=> 4096 Hz 
    // <15=> 2048 Hz 
    // <31=> 1024 Hz 
    
    #ifndef APP_TIMER_CONFIG_RTC_FREQUENCY
    #define APP_TIMER_CONFIG_RTC_FREQUENCY 0
    #endif

    Do I need to use the scheduler ?

    That should not be required. Scheduler is typically used to execute tasks from interrupt handlers in main context, to make sure everything is handled in the correct order.

    Best regards,
    Jørgen

  • Hi Jorgen thanks for replying.

    I tried the APP_TIMER_DEF and I created a new timer for controlling my sleeping time.

    It works very well. But sometimes I receive in my Jlink Segger Rtt the error ("Fatal error") and the whole application stops.

    I believe this occurs because my PPI enable and disable could be wrong. Can you take a look in my summarized code please?

    And how about the sampling process ? What do you think is better ? Do I use the TIMER + PPI for sampling? Do I create a new app_timer task and use RTC+PPI for sampling ? (In my final project I wanna use sampling in 5KHz).

    Best Regards.

    /*
     * main.c
     *
     *  Created on: 21 de jun de 2020
     *      Author: Augusto Peterle
     */
    #include "kx220_driver.h"
    #include <stdbool.h>
    #include <stdint.h>
    #include <string.h>
    #include "kx220_driver.h"
    #include "nrf_gpio.h"
    #include "nrf_delay.h"
    #include "app_util_platform.h"
    #include "custom_board.h"
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    #include "ble_serial_api.h"
    #include "app_timer.h"
    #include "nrf_drv_saadc.h"
    #include "nrf_drv_ppi.h"
    #include "nrf_drv_timer.h"
    
    #define SLEEP_INTERVAL					APP_TIMER_TICKS(10000)
    #define SAMPLING						APP_TIMER_TICKS(5000)
    #define SAADC_SAMPLES_IN_BUFFER         4											 /**<Amount of samples in Buffer */
    #define SAADC_SAMPLE_RATE		        2000                                         /**< SAADC sample rate in ms. */
    volatile uint8_t state = 1;
    static const nrf_drv_timer_t   			m_timer = NRF_DRV_TIMER_INSTANCE(3);
    static nrf_saadc_value_t     			m_buffer_pool[1][SAADC_SAMPLES_IN_BUFFER];
    static nrf_ppi_channel_t       			m_ppi_channel;
    static uint32_t              			m_adc_evt_counter;
    uint8_t statusSampling = 0;
    
    //Sleep timer
    APP_TIMER_DEF(m_sleep_timer);
    
    //Ohter timer not applicable yet
    APP_TIMER_DEF(m_timer_write);
    
    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);
    
        //Timer Configure Init
        nrf_drv_timer_config_t timer_config = NRF_DRV_TIMER_DEFAULT_CONFIG;
        timer_config.frequency = NRF_TIMER_FREQ_31250Hz;
        err_code = nrf_drv_timer_init(&m_timer, &timer_config, timer_handler);
        APP_ERROR_CHECK(err_code);
    
        /* setup m_timer for compare event */
        uint32_t ticks = nrf_drv_timer_ms_to_ticks(&m_timer,SAADC_SAMPLE_RATE);
        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_event_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);
    
        // PPI Interconnect Timer Event NRF_TIMER_CC_CHANNEL0 to saadc_sample_event_addr
        err_code = nrf_drv_ppi_channel_assign(m_ppi_channel, timer_compare_event_addr, saadc_sample_event_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_sampling_event_disable(void)
    {
        ret_code_t err_code = nrf_drv_ppi_channel_disable(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;
            uint16_t adc_value;
            uint8_t value[SAADC_SAMPLES_IN_BUFFER*2];
            uint8_t bytes_to_send;
    
            // set buffers
            err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAADC_SAMPLES_IN_BUFFER);
            APP_ERROR_CHECK(err_code);
    
    
            NRF_LOG_INFO("ADC event number: %d\r\n",(int)m_adc_evt_counter);
            NRF_LOG_PROCESS();
            for (int i = 0; i < SAADC_SAMPLES_IN_BUFFER; i++)
            {
                //printf("%d\r\n", p_event->data.done.p_buffer[i]);
    
                NRF_LOG_INFO("%d\r\n", p_event->data.done.p_buffer[i]);
    			NRF_LOG_PROCESS();
                adc_value = p_event->data.done.p_buffer[i];
                value[i*2] = adc_value;
                value[(i*2)+1] = adc_value >> 8;
            }
    
            // Send data over BLE via NUS service. Makes sure not to send more than 20 bytes.
    			if((SAADC_SAMPLES_IN_BUFFER*2) <= 20)
    			{
    				bytes_to_send = (SAADC_SAMPLES_IN_BUFFER*2);
    			}
    			else
    			{
    				bytes_to_send = 20;
    			}
    
    			//I can evaluate adc read here
    			if (err_code != NRF_ERROR_INVALID_STATE)
    			{
    				APP_ERROR_CHECK(err_code);
    			}
    
            m_adc_evt_counter++;
        }
    }
    
    void saadc_init(void)
    {
        ret_code_t err_code;
    
        nrf_drv_saadc_config_t saadc_config = NRF_DRV_SAADC_DEFAULT_CONFIG;
        saadc_config.resolution = NRF_SAADC_RESOLUTION_14BIT;
    
        nrf_saadc_channel_config_t channel_0_config =
            NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN4);
        channel_0_config.gain = NRF_SAADC_GAIN1_4;
        channel_0_config.reference = NRF_SAADC_REFERENCE_VDD4;
    
        nrf_saadc_channel_config_t channel_1_config =
            NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN5);
        channel_1_config.gain = NRF_SAADC_GAIN1_4;
        channel_1_config.reference = NRF_SAADC_REFERENCE_VDD4;
    
        nrf_saadc_channel_config_t channel_2_config =
    		NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN6);
        channel_2_config.gain = NRF_SAADC_GAIN1_4;
        channel_2_config.reference = NRF_SAADC_REFERENCE_VDD4;
    
        nrf_saadc_channel_config_t channel_3_config =
            NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN7);
        channel_3_config.gain = NRF_SAADC_GAIN1_4;
        channel_3_config.reference = NRF_SAADC_REFERENCE_VDD4;
    
        err_code = nrf_drv_saadc_init(&saadc_config, saadc_callback);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_saadc_channel_init(0, &channel_0_config);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_saadc_channel_init(1, &channel_1_config);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_saadc_channel_init(2, &channel_2_config);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_saadc_channel_init(3, &channel_3_config);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0],SAADC_SAMPLES_IN_BUFFER);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1],SAADC_SAMPLES_IN_BUFFER);
        APP_ERROR_CHECK(err_code);
    }
    
    /* Logger Segger RTT */
    static void log_init(void)
    {
        ret_code_t err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    static void battery_level_meas_timeout_handler(void * p_context)
    {
        UNUSED_PARAMETER(p_context);
        nRF_BLE_write();
    
        if( statusSampling == 1){
    
        	//Enable Timer interconnect to SAAD Interrupt
        	nrf_drv_timer_enable(&m_timer);
        	saadc_sampling_event_enable();
        	statusSampling = 0;
        } else {
    
        	//Disable Timer interconnect to SAAD Interrupt
        	nrf_drv_timer_disable(&m_timer);
        	saadc_sampling_event_disable();
        	statusSampling = 1;
        }
    
    }
    
    
    static void timers_init(void)
    {
        ret_code_t err_code;
    
        err_code = app_timer_init();
        APP_ERROR_CHECK(err_code);
    
        // Create battery timer.
        err_code = app_timer_create(&m_sleep_timer,
                                    APP_TIMER_MODE_REPEATED,
                                    battery_level_meas_timeout_handler);
    
    }
    
    static void timers_start(void)
    {
        ret_code_t err_code;
    
        err_code = app_timer_start(m_sleep_timer, SLEEP_INTERVAL, NULL);
        APP_ERROR_CHECK(err_code);
    }
    
    
    
    int main(){
    
    	//Setup Accelerometer Functions
    	log_init();											//Segger Log functions
    	setupKX220();										//Start Pins in KX220
    	saadc_sampling_event_init();						//Sampling Init
    	saadc_init();										//SAADC Config Init
    	nrf_delay_ms(50);
    
    	//UART for NUS services
    	uart_init();
    
    	//App timer init
    	timers_init();
    
    	//Setup BLE Functions
    	nRF_hardware_init();
    	nRF_BLE_init();
    	nRF_BLE_start_advertising();
    
    	//NRF_LOG Flag Start
    	NRF_LOG_INFO("Start");
    	NRF_LOG_PROCESS();
    
    	timers_start();
    
    	while(true){
    		power_manage();
    	}
    }
    
    

Reply
  • Hi Jorgen thanks for replying.

    I tried the APP_TIMER_DEF and I created a new timer for controlling my sleeping time.

    It works very well. But sometimes I receive in my Jlink Segger Rtt the error ("Fatal error") and the whole application stops.

    I believe this occurs because my PPI enable and disable could be wrong. Can you take a look in my summarized code please?

    And how about the sampling process ? What do you think is better ? Do I use the TIMER + PPI for sampling? Do I create a new app_timer task and use RTC+PPI for sampling ? (In my final project I wanna use sampling in 5KHz).

    Best Regards.

    /*
     * main.c
     *
     *  Created on: 21 de jun de 2020
     *      Author: Augusto Peterle
     */
    #include "kx220_driver.h"
    #include <stdbool.h>
    #include <stdint.h>
    #include <string.h>
    #include "kx220_driver.h"
    #include "nrf_gpio.h"
    #include "nrf_delay.h"
    #include "app_util_platform.h"
    #include "custom_board.h"
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    #include "ble_serial_api.h"
    #include "app_timer.h"
    #include "nrf_drv_saadc.h"
    #include "nrf_drv_ppi.h"
    #include "nrf_drv_timer.h"
    
    #define SLEEP_INTERVAL					APP_TIMER_TICKS(10000)
    #define SAMPLING						APP_TIMER_TICKS(5000)
    #define SAADC_SAMPLES_IN_BUFFER         4											 /**<Amount of samples in Buffer */
    #define SAADC_SAMPLE_RATE		        2000                                         /**< SAADC sample rate in ms. */
    volatile uint8_t state = 1;
    static const nrf_drv_timer_t   			m_timer = NRF_DRV_TIMER_INSTANCE(3);
    static nrf_saadc_value_t     			m_buffer_pool[1][SAADC_SAMPLES_IN_BUFFER];
    static nrf_ppi_channel_t       			m_ppi_channel;
    static uint32_t              			m_adc_evt_counter;
    uint8_t statusSampling = 0;
    
    //Sleep timer
    APP_TIMER_DEF(m_sleep_timer);
    
    //Ohter timer not applicable yet
    APP_TIMER_DEF(m_timer_write);
    
    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);
    
        //Timer Configure Init
        nrf_drv_timer_config_t timer_config = NRF_DRV_TIMER_DEFAULT_CONFIG;
        timer_config.frequency = NRF_TIMER_FREQ_31250Hz;
        err_code = nrf_drv_timer_init(&m_timer, &timer_config, timer_handler);
        APP_ERROR_CHECK(err_code);
    
        /* setup m_timer for compare event */
        uint32_t ticks = nrf_drv_timer_ms_to_ticks(&m_timer,SAADC_SAMPLE_RATE);
        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_event_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);
    
        // PPI Interconnect Timer Event NRF_TIMER_CC_CHANNEL0 to saadc_sample_event_addr
        err_code = nrf_drv_ppi_channel_assign(m_ppi_channel, timer_compare_event_addr, saadc_sample_event_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_sampling_event_disable(void)
    {
        ret_code_t err_code = nrf_drv_ppi_channel_disable(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;
            uint16_t adc_value;
            uint8_t value[SAADC_SAMPLES_IN_BUFFER*2];
            uint8_t bytes_to_send;
    
            // set buffers
            err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAADC_SAMPLES_IN_BUFFER);
            APP_ERROR_CHECK(err_code);
    
    
            NRF_LOG_INFO("ADC event number: %d\r\n",(int)m_adc_evt_counter);
            NRF_LOG_PROCESS();
            for (int i = 0; i < SAADC_SAMPLES_IN_BUFFER; i++)
            {
                //printf("%d\r\n", p_event->data.done.p_buffer[i]);
    
                NRF_LOG_INFO("%d\r\n", p_event->data.done.p_buffer[i]);
    			NRF_LOG_PROCESS();
                adc_value = p_event->data.done.p_buffer[i];
                value[i*2] = adc_value;
                value[(i*2)+1] = adc_value >> 8;
            }
    
            // Send data over BLE via NUS service. Makes sure not to send more than 20 bytes.
    			if((SAADC_SAMPLES_IN_BUFFER*2) <= 20)
    			{
    				bytes_to_send = (SAADC_SAMPLES_IN_BUFFER*2);
    			}
    			else
    			{
    				bytes_to_send = 20;
    			}
    
    			//I can evaluate adc read here
    			if (err_code != NRF_ERROR_INVALID_STATE)
    			{
    				APP_ERROR_CHECK(err_code);
    			}
    
            m_adc_evt_counter++;
        }
    }
    
    void saadc_init(void)
    {
        ret_code_t err_code;
    
        nrf_drv_saadc_config_t saadc_config = NRF_DRV_SAADC_DEFAULT_CONFIG;
        saadc_config.resolution = NRF_SAADC_RESOLUTION_14BIT;
    
        nrf_saadc_channel_config_t channel_0_config =
            NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN4);
        channel_0_config.gain = NRF_SAADC_GAIN1_4;
        channel_0_config.reference = NRF_SAADC_REFERENCE_VDD4;
    
        nrf_saadc_channel_config_t channel_1_config =
            NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN5);
        channel_1_config.gain = NRF_SAADC_GAIN1_4;
        channel_1_config.reference = NRF_SAADC_REFERENCE_VDD4;
    
        nrf_saadc_channel_config_t channel_2_config =
    		NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN6);
        channel_2_config.gain = NRF_SAADC_GAIN1_4;
        channel_2_config.reference = NRF_SAADC_REFERENCE_VDD4;
    
        nrf_saadc_channel_config_t channel_3_config =
            NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN7);
        channel_3_config.gain = NRF_SAADC_GAIN1_4;
        channel_3_config.reference = NRF_SAADC_REFERENCE_VDD4;
    
        err_code = nrf_drv_saadc_init(&saadc_config, saadc_callback);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_saadc_channel_init(0, &channel_0_config);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_saadc_channel_init(1, &channel_1_config);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_saadc_channel_init(2, &channel_2_config);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_saadc_channel_init(3, &channel_3_config);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0],SAADC_SAMPLES_IN_BUFFER);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1],SAADC_SAMPLES_IN_BUFFER);
        APP_ERROR_CHECK(err_code);
    }
    
    /* Logger Segger RTT */
    static void log_init(void)
    {
        ret_code_t err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    static void battery_level_meas_timeout_handler(void * p_context)
    {
        UNUSED_PARAMETER(p_context);
        nRF_BLE_write();
    
        if( statusSampling == 1){
    
        	//Enable Timer interconnect to SAAD Interrupt
        	nrf_drv_timer_enable(&m_timer);
        	saadc_sampling_event_enable();
        	statusSampling = 0;
        } else {
    
        	//Disable Timer interconnect to SAAD Interrupt
        	nrf_drv_timer_disable(&m_timer);
        	saadc_sampling_event_disable();
        	statusSampling = 1;
        }
    
    }
    
    
    static void timers_init(void)
    {
        ret_code_t err_code;
    
        err_code = app_timer_init();
        APP_ERROR_CHECK(err_code);
    
        // Create battery timer.
        err_code = app_timer_create(&m_sleep_timer,
                                    APP_TIMER_MODE_REPEATED,
                                    battery_level_meas_timeout_handler);
    
    }
    
    static void timers_start(void)
    {
        ret_code_t err_code;
    
        err_code = app_timer_start(m_sleep_timer, SLEEP_INTERVAL, NULL);
        APP_ERROR_CHECK(err_code);
    }
    
    
    
    int main(){
    
    	//Setup Accelerometer Functions
    	log_init();											//Segger Log functions
    	setupKX220();										//Start Pins in KX220
    	saadc_sampling_event_init();						//Sampling Init
    	saadc_init();										//SAADC Config Init
    	nrf_delay_ms(50);
    
    	//UART for NUS services
    	uart_init();
    
    	//App timer init
    	timers_init();
    
    	//Setup BLE Functions
    	nRF_hardware_init();
    	nRF_BLE_init();
    	nRF_BLE_start_advertising();
    
    	//NRF_LOG Flag Start
    	NRF_LOG_INFO("Start");
    	NRF_LOG_PROCESS();
    
    	timers_start();
    
    	while(true){
    		power_manage();
    	}
    }
    
    

Children
No Data
Related