<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="https://devzone.nordicsemi.com/cfs-file/__key/system/syndication/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>[Strategy] Multiple Tasks (SoftDevice + Scheduler + App Timer)</title><link>https://devzone.nordicsemi.com/f/nordic-q-a/63117/strategy-multiple-tasks-softdevice-scheduler-app-timer</link><description>Hello guys. I&amp;#39;m beginner in Nordic Devices. 
 I&amp;#39;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</description><dc:language>en-US</dc:language><generator>Telligent Community 13</generator><lastBuildDate>Fri, 03 Jul 2020 15:15:32 GMT</lastBuildDate><atom:link rel="self" type="application/rss+xml" href="https://devzone.nordicsemi.com/f/nordic-q-a/63117/strategy-multiple-tasks-softdevice-scheduler-app-timer" /><item><title>RE: [Strategy] Multiple Tasks (SoftDevice + Scheduler + App Timer)</title><link>https://devzone.nordicsemi.com/thread/258385?ContentTypeID=1</link><pubDate>Fri, 03 Jul 2020 15:15:32 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:027fd94b-1b80-46bb-9f5b-ed00b58c9567</guid><dc:creator>J&amp;#248;rgen Holmefjord</dc:creator><description>&lt;p&gt;If you build the application in debug configuration mode (or with DEBUG flag set in preprocessor symbols), the exact function call/line number/error code should be output on the log. This will help with determining what is failing in your application.&lt;/p&gt;
&lt;p&gt;App_timer is a software timer implementation. It is not possible to use PPI with app_timer to trigger HW events. If you want to use RTC with PPI, you need to use another RTC instance and set this up manually (see for instance &lt;a href="https://github.com/NordicPlayground/nRF52-ADC-examples/tree/master/saadc_low_power"&gt;this example&lt;/a&gt;).&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: [Strategy] Multiple Tasks (SoftDevice + Scheduler + App Timer)</title><link>https://devzone.nordicsemi.com/thread/257448?ContentTypeID=1</link><pubDate>Mon, 29 Jun 2020 16:56:46 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:dcb24eb1-18f0-40b5-be0f-ab74aa60305d</guid><dc:creator>augustopeterle</dc:creator><description>&lt;p&gt;Hi Jorgen thanks for replying.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;I tried the APP_TIMER_DEF and I created a new timer for controlling my sleeping time.&lt;/p&gt;
&lt;p&gt;It works very well. But sometimes I receive in my Jlink Segger Rtt the error (&amp;quot;Fatal error&amp;quot;) and the whole application stops.&lt;/p&gt;
&lt;p&gt;I believe this occurs because my PPI enable and disable could be wrong. Can you take a look in my summarized code please?&lt;/p&gt;
&lt;p&gt;And how about the sampling process ? What do you think is better ? Do I use the TIMER + PPI for sampling?&amp;nbsp;Do I create a new app_timer task and use RTC+PPI for sampling ? (In my final project I wanna use sampling in 5KHz).&lt;/p&gt;
&lt;p&gt;Best Regards.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="text"&gt;/*
 * main.c
 *
 *  Created on: 21 de jun de 2020
 *      Author: Augusto Peterle
 */
#include &amp;quot;kx220_driver.h&amp;quot;
#include &amp;lt;stdbool.h&amp;gt;
#include &amp;lt;stdint.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;quot;kx220_driver.h&amp;quot;
#include &amp;quot;nrf_gpio.h&amp;quot;
#include &amp;quot;nrf_delay.h&amp;quot;
#include &amp;quot;app_util_platform.h&amp;quot;
#include &amp;quot;custom_board.h&amp;quot;
#include &amp;quot;nrf_log.h&amp;quot;
#include &amp;quot;nrf_log_ctrl.h&amp;quot;
#include &amp;quot;nrf_log_default_backends.h&amp;quot;
#include &amp;quot;ble_serial_api.h&amp;quot;
#include &amp;quot;app_timer.h&amp;quot;
#include &amp;quot;nrf_drv_saadc.h&amp;quot;
#include &amp;quot;nrf_drv_ppi.h&amp;quot;
#include &amp;quot;nrf_drv_timer.h&amp;quot;

#define SLEEP_INTERVAL					APP_TIMER_TICKS(10000)
#define SAMPLING						APP_TIMER_TICKS(5000)
#define SAADC_SAMPLES_IN_BUFFER         4											 /**&amp;lt;Amount of samples in Buffer */
#define SAADC_SAMPLE_RATE		        2000                                         /**&amp;lt; 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(&amp;amp;m_timer, &amp;amp;timer_config, timer_handler);
    APP_ERROR_CHECK(err_code);

    /* setup m_timer for compare event */
    uint32_t ticks = nrf_drv_timer_ms_to_ticks(&amp;amp;m_timer,SAADC_SAMPLE_RATE);
    nrf_drv_timer_extended_compare(&amp;amp;m_timer, NRF_TIMER_CC_CHANNEL0, ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);
    nrf_drv_timer_enable(&amp;amp;m_timer);

    uint32_t timer_compare_event_addr = nrf_drv_timer_compare_event_address_get(&amp;amp;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(&amp;amp;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-&amp;gt;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-&amp;gt;data.done.p_buffer, SAADC_SAMPLES_IN_BUFFER);
        APP_ERROR_CHECK(err_code);


        NRF_LOG_INFO(&amp;quot;ADC event number: %d\r\n&amp;quot;,(int)m_adc_evt_counter);
        NRF_LOG_PROCESS();
        for (int i = 0; i &amp;lt; SAADC_SAMPLES_IN_BUFFER; i++)
        {
            //printf(&amp;quot;%d\r\n&amp;quot;, p_event-&amp;gt;data.done.p_buffer[i]);

            NRF_LOG_INFO(&amp;quot;%d\r\n&amp;quot;, p_event-&amp;gt;data.done.p_buffer[i]);
			NRF_LOG_PROCESS();
            adc_value = p_event-&amp;gt;data.done.p_buffer[i];
            value[i*2] = adc_value;
            value[(i*2)+1] = adc_value &amp;gt;&amp;gt; 8;
        }

        // Send data over BLE via NUS service. Makes sure not to send more than 20 bytes.
			if((SAADC_SAMPLES_IN_BUFFER*2) &amp;lt;= 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(&amp;amp;saadc_config, saadc_callback);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_channel_init(0, &amp;amp;channel_0_config);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_drv_saadc_channel_init(1, &amp;amp;channel_1_config);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_drv_saadc_channel_init(2, &amp;amp;channel_2_config);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_drv_saadc_channel_init(3, &amp;amp;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(&amp;amp;m_timer);
    	saadc_sampling_event_enable();
    	statusSampling = 0;
    } else {

    	//Disable Timer interconnect to SAAD Interrupt
    	nrf_drv_timer_disable(&amp;amp;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(&amp;amp;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(&amp;quot;Start&amp;quot;);
	NRF_LOG_PROCESS();

	timers_start();

	while(true){
		power_manage();
	}
}

&lt;/pre&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: [Strategy] Multiple Tasks (SoftDevice + Scheduler + App Timer)</title><link>https://devzone.nordicsemi.com/thread/257389?ContentTypeID=1</link><pubDate>Mon, 29 Jun 2020 12:56:02 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:c3609cb7-1117-4767-9814-3965d6a3644a</guid><dc:creator>J&amp;#248;rgen Holmefjord</dc:creator><description>&lt;p&gt;Hi,&lt;/p&gt;
[quote user=""]Can i do this with app_timer ?[/quote]
&lt;p&gt;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&amp;nbsp;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:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;// &amp;lt;o&amp;gt; APP_TIMER_CONFIG_RTC_FREQUENCY  - Configure RTC prescaler.
 
// &amp;lt;0=&amp;gt; 32768 Hz 
// &amp;lt;1=&amp;gt; 16384 Hz 
// &amp;lt;3=&amp;gt; 8192 Hz 
// &amp;lt;7=&amp;gt; 4096 Hz 
// &amp;lt;15=&amp;gt; 2048 Hz 
// &amp;lt;31=&amp;gt; 1024 Hz 

#ifndef APP_TIMER_CONFIG_RTC_FREQUENCY
#define APP_TIMER_CONFIG_RTC_FREQUENCY 0
#endif&lt;/pre&gt;&lt;/p&gt;
[quote user=""]Do I need to use the scheduler ? [/quote]
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Best regards,&lt;br /&gt;Jørgen&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item></channel></rss>