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

blinky_rtc_freertos task switching not working when nrf_drv_rtc_init is disable

HW: nrf52840

SW: nRF5_SDK_15.2.0_9412b96

source code: blinky_rtc_freertos example

Q1:

I read freeRTOS xtaskcreate operation on the web, it seem that I just need to call xtaskcreate function and link to a function and it should able to switching between multiple task with the right priority been set. But I notice when RTC function in the blinky_rtc_freertos example is removed the task will stop switching.

Expected xtaskcreate coding that is not working.

/**
 * @brief Reference to LED0 toggling FreeRTOS task.
 */
static TaskHandle_t  m_led_toggle_task_handle;

/**
 * @brief Reference to LED0 toggling FreeRTOS task.
 */
static TaskHandle_t  m_led_toggle_task_handle2;

static void led_toggle_task_function (void * pvParameter)
{
    ret_code_t err_code;

    UNUSED_PARAMETER(pvParameter);
    while (true)
    {
        bsp_board_led_invert(BSP_BOARD_LED_0);

        /* Wait for the event from the RTC */
        UNUSED_RETURN_VALUE(xSemaphoreTake(m_led_semaphore, portMAX_DELAY));
    }

    /* Tasks must be implemented to never return... */
}

static void led_toggle_task_function2 (void * pvParameter)
{
    UNUSED_PARAMETER(pvParameter);
    while (true)
    {
        bsp_board_led_invert(BSP_BOARD_LED_2);

        /* Wait for the event from the RTC */
        UNUSED_RETURN_VALUE(xSemaphoreTake(m_led_semaphore, portMAX_DELAY));
    }

    /* Tasks must be implemented to never return... */
}

int main(void)
{
    m_led_semaphore = xSemaphoreCreateBinary();
    ASSERT(NULL != m_led_semaphore);
    /* Create task for LED0 blinking with priority set to 2 */
    UNUSED_VARIABLE(xTaskCreate(led_toggle_task_function, "LED0", configMINIMAL_STACK_SIZE + 200, NULL, 2, &m_led_toggle_task_handle));

   /* Create task for LED0 blinking with priority set to 2 */
    UNUSED_VARIABLE(xTaskCreate(led_toggle_task_function2, "LED1", configMINIMAL_STACK_SIZE + 200, NULL, 3, &m_led_toggle_task_handle2));
}

Q2:

I still not very clear with how softdevices <> FreeRTOS interact and how do RTC vs systick and how RTC or systick can influence the task scheduling. As I know RTC can still operate when the device in deep sleep which I can use RTC interrupt to wake the device from Tickless idle mode but I not sure how nordic softdevices + FreeRTOS works.

Parents
  • A1)  You need to start the scheduler after creating tasks. Just creating tasks is not enough to make the scheduler work. Please add the below code at the end of the main file.

        // Start FreeRTOS scheduler.
        vTaskStartScheduler();
    
        for (;;)
        {
            APP_ERROR_HANDLER(NRF_ERROR_FORBIDDEN);
        }

    Q2) Nordic port of FreeRTOS does not use softdevice reserved interrupt IRQs and priorities. It follows all softdevice rules that is set for the application. In simple terms, FreeRTOS port for Nordic works as another application on top of softdevice. The softdevice will be able to interrupt the scheduler anytime it wants. We have added special handling that if softdevice steams the MCU from FreeRTOS for multiple ticks, then the RTC1 handler will be able to recover from this by correcting the missing ticks. You can see that in port_cmsis_nrf52.c

  • Hi Aryan,

    The blinky rtos example already have the vTaskStartScheduler(); called. Still not functioning for the switching part, it only able to enter the first task while loop and struck there forever.

  • The main function code snippet you attached does not have vTaskStartScheduler. So not sure where you are starting it. 

    Both tasks are doing xSemaphoreTake, who is Giving the semaphore? isn't that a deadlock? In blinky_rtos example the rtc handler was configured to run after the certain time which would call xSemaphoreGiveFromISR. But you never initialized RTC like below

        /* Initialize clock driver for better time accuracy in FREERTOS */
        err_code = nrf_drv_clock_init();
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_rtc_init(&m_rtc, &m_rtc_config, blink_rtc_handler);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_rtc_cc_set(&m_rtc, BLINK_RTC_CC, BLINK_RTC_TICKS, true);
        APP_ERROR_CHECK(err_code);
        nrf_drv_rtc_enable(&m_rtc);

    I ran your tasks as below and everything works as it should

    /**
     * Copyright (c) 2017 - 2018, 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 blinky_rtc_freertos_example_main main.c
     * @{
     * @ingroup blinky_rtc_freertos_example
     *
     * @brief Blinky FreeRTOS Example Application main file.
     *
     * This file contains the source code for a sample application using FreeRTOS to blink LEDs.
     *
     */
    
    #include <stdbool.h>
    #include <stdint.h>
    
    #include "FreeRTOS.h"
    #include "semphr.h"
    #include "timers.h"
    #include "bsp.h"
    #include "nordic_common.h"
    #include "nrf_drv_clock.h"
    #include "sdk_errors.h"
    #include "app_error.h"
    #include "nrf_drv_rtc.h"
    
    
    #if LEDS_NUMBER <= 2
    #error "Board is not equipped with enough amount of LEDs"
    #endif
    
    /**
     * @brief RTC instance number used for blinking
     *
     */
    #define BLINK_RTC 2
    
    /**
     * @brief RTC compare channel used
     *
     */
    #define BLINK_RTC_CC 0
    
    /**
     * @brief Number of RTC ticks between interrupts
     */
    #define BLINK_RTC_TICKS   (RTC_US_TO_TICKS(500000ULL, RTC_DEFAULT_CONFIG_FREQUENCY))
    
    /**
     * @brief Reference to LED0 toggling FreeRTOS task.
     */
    static TaskHandle_t  m_led_toggle_task_handle;
    
    /**
     * @brief Semaphore set in RTC event
     */
    static SemaphoreHandle_t m_led_semaphore;
    
    /**
     * @brief RTC configuration
     */
    static nrf_drv_rtc_config_t const m_rtc_config = NRF_DRV_RTC_DEFAULT_CONFIG;
    
    /**
     * @brief RTC instance
     *
     * Instance of the RTC used for led blinking
     */
    static nrf_drv_rtc_t const m_rtc = NRF_DRV_RTC_INSTANCE(BLINK_RTC);
    
    
    static void blink_rtc_handler(nrf_drv_rtc_int_type_t int_type)
    {
        BaseType_t yield_req = pdFALSE;
        ret_code_t err_code;
        bsp_board_led_invert(BSP_BOARD_LED_1);
        err_code = nrf_drv_rtc_cc_set(
            &m_rtc,
            BLINK_RTC_CC,
            (nrf_rtc_cc_get(m_rtc.p_reg, BLINK_RTC_CC) + BLINK_RTC_TICKS) & RTC_COUNTER_COUNTER_Msk,
            true);
        APP_ERROR_CHECK(err_code);
    
       /* The returned value may be safely ignored, if error is returned it only means that
        * the semaphore is already given (raised). */
       UNUSED_VARIABLE(xSemaphoreGiveFromISR(m_led_semaphore, &yield_req));
       portYIELD_FROM_ISR(yield_req);
    }
    
    
    static TaskHandle_t  m_led_toggle_task_handle2;
    
    static void led_toggle_task_function (void * pvParameter)
    {
        ret_code_t err_code;
    
        UNUSED_PARAMETER(pvParameter);
        while (true)
        {
            bsp_board_led_invert(BSP_BOARD_LED_0);
    
            /* Wait for the event from the RTC */
            UNUSED_RETURN_VALUE(xSemaphoreTake(m_led_semaphore, portMAX_DELAY));
        }
    
        /* Tasks must be implemented to never return... */
    }
    
    static void led_toggle_task_function2 (void * pvParameter)
    {
        UNUSED_PARAMETER(pvParameter);
        while (true)
        {
            bsp_board_led_invert(BSP_BOARD_LED_2);
    
            /* Wait for the event from the RTC */
            UNUSED_RETURN_VALUE(xSemaphoreTake(m_led_semaphore, portMAX_DELAY));
        }
    
        /* Tasks must be implemented to never return... */
    }
    
    int main(void)
    {
        ret_code_t err_code;
    
        /* Initialize clock driver for better time accuracy in FREERTOS */
        err_code = nrf_drv_clock_init();
        APP_ERROR_CHECK(err_code);
    
        /* Configure LED-pins as outputs */
        bsp_board_init(BSP_INIT_LEDS);
    
        err_code = nrf_drv_rtc_init(&m_rtc, &m_rtc_config, blink_rtc_handler);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_rtc_cc_set(&m_rtc, BLINK_RTC_CC, BLINK_RTC_TICKS, true);
        APP_ERROR_CHECK(err_code);
        nrf_drv_rtc_enable(&m_rtc);
        m_led_semaphore = xSemaphoreCreateBinary();
        ASSERT(NULL != m_led_semaphore);
        /* Create task for LED0 blinking with priority set to 2 */
        UNUSED_VARIABLE(xTaskCreate(led_toggle_task_function, "LED0", configMINIMAL_STACK_SIZE + 200, NULL, 2, &m_led_toggle_task_handle));
    
       /* Create task for LED0 blinking with priority set to 2 */
        UNUSED_VARIABLE(xTaskCreate(led_toggle_task_function2, "LED1", configMINIMAL_STACK_SIZE + 200, NULL, 3, &m_led_toggle_task_handle2));
    
    
        /* Activate deep sleep mode */
        SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
    
        /* Start FreeRTOS scheduler. */
        vTaskStartScheduler();
    
        while (true)
        {
            ASSERT(false);
            /* FreeRTOS should not be here... FreeRTOS goes back to the start of stack
             * in vTaskStartScheduler function. */
        }
    }
    
    /**
     * @}
     */
    

  • Hi Aryan,

    Thanks. Which means the xTaskCreate required the semaphore to allow task to shared time space within task and those timing will required rtc to be initialized only it can operate.

    And the rtc handler will act as an agent to scan the priorities and choose the right task for example led_toggle_task_function or led_toggle_task_function2 to be executed.

    ISR rtc interrupt -> (blink_rtc_handler -> get next priority task from xSemaphoreGiveFromISR - > call led_toggle_task_function / led_toggle_task_function2  task using portYIELD_FROM_ISR) -> (led_toggle_task_function / led_toggle_task_function2 -> run code -> xSemaphoreTake (release semaphore for next IRQ to call another function)

    Here is my previous full code, I was trying to have the task working without RTC. But now I understand that RTC is a must to have in order for the task to able to switch, Please confirm whether am I right?

    /**
     * Copyright (c) 2017 - 2018, 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 blinky_rtc_freertos_example_main main.c
     * @{
     * @ingroup blinky_rtc_freertos_example
     *
     * @brief Blinky FreeRTOS Example Application main file.
     *
     * This file contains the source code for a sample application using FreeRTOS to blink LEDs.
     *
     */
    
    #include <stdbool.h>
    #include <stdint.h>
    
    #include "FreeRTOS.h"
    #include "semphr.h"
    #include "timers.h"
    #include "bsp.h"
    #include "nordic_common.h"
    #include "nrf_drv_clock.h"
    #include "sdk_errors.h"
    #include "app_error.h"
    #include "nrf_drv_rtc.h"
    
    
    #if LEDS_NUMBER <= 2
    #error "Board is not equipped with enough amount of LEDs"
    #endif
    
    /**
     * @brief RTC instance number used for blinking
     *
     */
    #define BLINK_RTC 2
    
    /**
     * @brief RTC compare channel used
     *
     */
    #define BLINK_RTC_CC 0
    
    /**
     * @brief Number of RTC ticks between interrupts
     */
    #define BLINK_RTC_TICKS   (RTC_US_TO_TICKS(500000ULL, RTC_DEFAULT_CONFIG_FREQUENCY))
    
    /**
     * @brief Reference to LED0 toggling FreeRTOS task.
     */
    static TaskHandle_t  m_led_toggle_task_handle;
    
    /**
     * @brief Reference to LED0 toggling FreeRTOS task.
     */
    static TaskHandle_t  m_led_toggle_task_handle2;
    /**
     * @brief Semaphore set in RTC event
     */
    static SemaphoreHandle_t m_led_semaphore;
    
    /**
     * @brief RTC configuration
     */
    static nrf_drv_rtc_config_t const m_rtc_config = NRF_DRV_RTC_DEFAULT_CONFIG;
    
    /**
     * @brief RTC instance
     *
     * Instance of the RTC used for led blinking
     */
    static nrf_drv_rtc_t const m_rtc = NRF_DRV_RTC_INSTANCE(BLINK_RTC);
    
    //static void blink_rtc_handler(nrf_drv_rtc_int_type_t int_type)
    //{
    //    BaseType_t yield_req = pdFALSE;
    //    ret_code_t err_code;
    //    bsp_board_led_invert(BSP_BOARD_LED_1);
    //    err_code = nrf_drv_rtc_cc_set(
    //        &m_rtc,
    //        BLINK_RTC_CC,
    //        (nrf_rtc_cc_get(m_rtc.p_reg, BLINK_RTC_CC) + BLINK_RTC_TICKS) & RTC_COUNTER_COUNTER_Msk,
    //        true);
    //    APP_ERROR_CHECK(err_code);
    //
    //   /* The returned value may be safely ignored, if error is returned it only means that
    //    * the semaphore is already given (raised). */
    //   UNUSED_VARIABLE(xSemaphoreGiveFromISR(m_led_semaphore, &yield_req));
    //   portYIELD_FROM_ISR(yield_req);
    //}
    
    /**
     * @brief LED0 task entry function.
     *
     * @param[in] pvParameter   Pointer that will be used as the parameter for the task.
     */
    static void led_toggle_task_function (void * pvParameter)
    {
        ret_code_t err_code;
    
    //    err_code = nrf_drv_rtc_init(&m_rtc, &m_rtc_config, blink_rtc_handler);
    //    APP_ERROR_CHECK(err_code);
    //    err_code = nrf_drv_rtc_cc_set(&m_rtc, BLINK_RTC_CC, BLINK_RTC_TICKS, true);
    //    APP_ERROR_CHECK(err_code);
    //    nrf_drv_rtc_enable(&m_rtc);
    
    
    
        UNUSED_PARAMETER(pvParameter);
        while (true)
        {
            bsp_board_led_invert(BSP_BOARD_LED_0);
    
            /* Wait for the event from the RTC */
            UNUSED_RETURN_VALUE(xSemaphoreTake(m_led_semaphore, portMAX_DELAY));
        }
    
        /* Tasks must be implemented to never return... */
    }
    
    static void led_toggle_task_function2 (void * pvParameter)
    {
        UNUSED_PARAMETER(pvParameter);
        while (true)
        {
            bsp_board_led_invert(BSP_BOARD_LED_2);
    
            /* Wait for the event from the RTC */
            UNUSED_RETURN_VALUE(xSemaphoreTake(m_led_semaphore, portMAX_DELAY));
        }
    
        /* Tasks must be implemented to never return... */
    }
    
    int main(void)
    {
        ret_code_t err_code;
    
        /* Initialize clock driver for better time accuracy in FREERTOS */
        err_code = nrf_drv_clock_init();
        APP_ERROR_CHECK(err_code);
    
        /* Configure LED-pins as outputs */
        bsp_board_init(BSP_INIT_LEDS);
    
    //    err_code = nrf_drv_rtc_init(&m_rtc, &m_rtc_config, blink_rtc_handler);
    //    APP_ERROR_CHECK(err_code);
    //    err_code = nrf_drv_rtc_cc_set(&m_rtc, BLINK_RTC_CC, BLINK_RTC_TICKS, true);
    //    APP_ERROR_CHECK(err_code);
    //    nrf_drv_rtc_enable(&m_rtc);
        m_led_semaphore = xSemaphoreCreateBinary();
        ASSERT(NULL != m_led_semaphore);
        /* Create task for LED0 blinking with priority set to 2 */
        UNUSED_VARIABLE(xTaskCreate(led_toggle_task_function, "LED0", configMINIMAL_STACK_SIZE + 200, NULL, 2, &m_led_toggle_task_handle));
    
       /* Create task for LED0 blinking with priority set to 2 */
        UNUSED_VARIABLE(xTaskCreate(led_toggle_task_function2, "LED1", configMINIMAL_STACK_SIZE + 200, NULL, 2, &m_led_toggle_task_handle2));
    
        /* Activate deep sleep mode */
        SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
    
        /* Start FreeRTOS scheduler. */
        vTaskStartScheduler();
    
        while (true)
        {
            ASSERT(false);
            /* FreeRTOS should not be here... FreeRTOS goes back to the start of stack
             * in vTaskStartScheduler function. */
        }
    }
    
    /**
     * @}
     */
    

  • in your program, i see both tasks are always trying to take the semaphore. Where in your program are you giving the semaphore? your code will not work until you give the semaphore from somewhere to unblock the tasks.

    In my code, i was using rtc driver to set a timer to give the semaphore at a particular frequency to unblock any tasks that are being blocked on taking that semaphore. Its a simple serialization of code using a semaphore.

  • Thanks for your confirmation, I will continue to use RTC in my application.

Reply Children
No Data
Related