I can't achieve required task execution time

I have already added TICK_HOOK_PIN (toggle) and enabled the Tick Hook IRQ in the settings. Tomorrow I will have a look at it by oscilloscope.

The logic in your APP_STATE_WRITE_WAIT doesn’t look quite right. As per the code you posted above, vTaskDelayUntil() will be called repeatedly until either the transfer has completed or an error has occurred. Presumably the transfer will not have completed on the first entry into this state (unless DRV_AT25DF_Write() is blocking?), so it seems likely that vTaskDelayUntil() will be called at least twice.

If you want a 100ms task period then the vTaskDelayUntil() call should be performed once, either at the completion of your state machine (appData.state = APP_STATE_INIT_DONE) or at it’s start. Putting the delay in your initial state can make for cleaner code if you have multiple paths back to this state.

Hi Mike,
Thank you for your advice. I will move the vTaskDelayUntil () till the end of the state machine and I will see.

Picture of the tick hook function and detail. GPIO pin toggle.

This comment seems to indicate that there is a misunderstanding about the way FreeRTOS tasks work. A FreeRTOS task is an independent thread of execution which can be roughly in one the following state:

  1. Running - The processor is executing the task’s code.
  2. Ready - The task is able to run but not running currently.
  3. Blocked - The task is not able to run and waiting for an event.

At any point in time, the FreeRTOS scheduler selects the highest priority Ready task and schedules it to run (thereby changing its state from Ready to Running). If an event causes a task with priority higher than the currently running task’s priority to become Ready, the scheduler swaps out the currently running task (i.e. changes its state from Running to Ready) and swaps in the new task (i.e. changes its state from Ready to Running). If the currently executing task enters Blocked state to wait for an event, the scheduler swaps it out and swaps in the highest priority Ready task.

Tasks can enter the Blocked state to wait for two different types of event:

  1. Temporal (time-related) events - the delay period specified using vTaskDelay, vTaskDelayUntil APIs.
  2. Synchronization events from FreeRTOS queues, semaphores, mutexes, event groups and direct to task notifications etc.

If you want to have your own timer and call some functions periodically from
that timer’s ISR, you should be able to and that does not need anything from
FreeRTOS.

/* ISR for the timer which is programmed to fire every 100 ms. */
void Timer_100ms_ISR( void )
{
    /* Perform action here. */
}

When using FreeRTOS tasks, vTaskDelayUntil can be used to achieve periodic
execution in the following way:

/* Perform an action every 100 miliseconds. */
 void vTaskFunction( void * pvParameters )
 {
 TickType_t xLastWakeTime;
 const TickType_t xFrequency = pdMS_TO_TICKS( 100 );

     /* Initialise the xLastWakeTime variable with the current time. */
     xLastWakeTime = xTaskGetTickCount();

     for( ;; )
     {
        /* Wait for the next cycle. */
        vTaskDelayUntil( &xLastWakeTime, xFrequency );

        /* Perform action here. */
     }
 }

I am still unclear which of the above two are you trying to achieve. Would you please elaborate what are you trying to achieve?

1 Like

I would like to make an on-board computer for an amateur rocket that can reach an altitude of 3 km (10,000 feet). A Bosch 6DoF IMU BMI160 will provide 100 Hz data cca 1.4 ms (see the IRQ data ready pulse) which I will use to control the flight of the rocket with 4 aileron actuated servo motors (PWM). I will simultaneously store the data in memory for later flight evaluation (data transmission by means of Bluetooth to mobile phone) and sending them to the ground using telemetry (LoRaWAN).

Maybe I will use affordable Winbond 2G-bit Serial NAND flash (W25N02KVZEIR). 128KB Block Erase Time: 2ms, 2KB Page Program Time: 250µs.

Assuming that this is a response to my question, I am interested in knowing what you want to achieve from the FreeRTOS perspective. In other words, do you want to have a FreeRTOS task that executes every 100 ms OR do you want to have a function that is called from your timer ISR which fires every 100 ms OR something else?
Also, have you read my previous response and are we on the same page regarding the understanding about FreeRTOS tasks?

My goal was to use FreeRTOS (automatically added in the Microchip MPLAB X IDE, Harmony, Project Graph after adding the Flash Memory driver AT25DF) to simulate writing to flash memory each 100 ms before I will use Bosch IMU BMI160 IRQ triggered writing.

If I was to create a simulation like that, I would have the flash writing task not do a “delay”, but have it take the data from a IMU simulation task that works off a 10 ms repeating vTaskDelayUntil loop that creates simulated IMU data and sends that to the flash writing task.

The following is a rough translation of @richard-damon’s suggestion to code -

/* Initialized when the FlashWritingTask is created. */
TaskHandle_t FlashWritingTaskHandle;

void FlashWritingTask( void * params )
{
    ( void ) params;

    for( ;; )
    {
        /* Wait for a notification to write to flash. */
        ulTaskNotifyTake( pdTRUE, portMAX_DELAY  );

        /* Write to flash. */
    }
}

/* Simulation - Kick off the FlashWritingTask every 100 ms. */
void SimulationTask( void * params )
{
    TickType_t xLastWakeTime;
    const TickType_t xFrequency = pdMS_TO_TICKS( 100 );

    ( void ) params;

     /* Initialise the xLastWakeTime variable with the current time. */
     xLastWakeTime = xTaskGetTickCount();

    for( ;; )
    {
        /* Wait for the next cycle. */
        vTaskDelayUntil( &xLastWakeTime, xFrequency );

        /* Kick off the FlashWritingTask. */
        xTaskNotifyGive( FlashWritingTaskHandle );
    }
}

/* Bosch IMU BMI160 IRQ - Kick off the FlashWritingTask every 100 ms. */
void Bosch_IMU_BMI160_ISR( void )
{
    xHigherPriorityTaskWoken = pdFALSE;

    vTaskNotifyGiveFromISR( FlashWritingTaskHandle, &( xHigherPriorityTaskWoken ) );

    portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}

1 Like

Thank you for the code. I need to familiarize myself with it and understand how it works.

The problem is that the Bosch IMU BMI160 IRQ is set to 100 Hz i.e. 10 ms and writing to flash takes 82.3 ms. I would like to keep Bosch at 100 Hz so I may use Winbond 2Gb Serial NAND Flash Memory (Block Erase Time: 2ms, Page Program Time: 250µs, Block is 64x 2KB Pages, see pdf page 12).

For each Bosch IMU BMI160 IRQ, I need to write just 256 bytes to flash memory.

What 256 bytes of data are you getting from the IMU every 10 ms? Typically for each reading you get 2 bytes of data x 6 axis of reading (3 accelerometer, 3 gyroscopic), which is what your scope trace is showing.

You can gather 10 lots of this data to make a single write to the flash every 100ms, which will be only 120 byte from the IMU, giving you room for additional payload, depending on the write buffer size (or you just write less often).

I would have one task doing the data collection, and a seperate task doing the writes (so the writing doesn’t block the collection operation). It sounds like you also may have another task doing navigation control operations. This might be able to be combined with the collection task, but making it seperate means you can be sure not to lose any of the data being collected if the nav task slows down. (It might just skip some input data)

1 Like

@aggarg

I am having troubles how to pass TaskHandle_t FlashWritingTaskHandle;
from flashwritingtask

void FLASHWRITINGTASK_Initialize ( void )
{
    /* Place the App state machine in its initial state. */
    flashwritingtaskData.state = FLASHWRITINGTASK_STATE_INIT;



    /* TODO: Initialize your application's state machine and other
     * parameters.
     */
    
    TaskHandle_t FlashWritingTaskHandle;
}

to simulationtask. If I use in simulationtask

TaskHandle_t FlashWritingTaskHandle = TaskGetHandle("flashwritingtask");

I will get error in flashwritingtask FlashWritingTaskHandle is not used and in simulationtask initializer element is not constant.

Do I need to define TaskHandle_t FlashWritingTaskHandle in flashwritingtask.h and include it in simulationtask.c?

No need to pass anything yourself manually when using xTaskGetHandle.
As the API docs tell you it returns the handle of the named task if found.
I don’t understand the purpose of the local, uninitialized TaskHandle_t FlashWritingTaskHandle; variable in FLASHWRITINGTASK_Initialize.

To pass a handle between files in C, you need to declare them as global externals in files (normally done in a header file) and then a definition in one, and you then typically set that variable when you create the object.

Something like:
in flash.h

extern TaskHandle_t FlashWritingTaskHandle;

Then in flash.c

TaskHandle_t FlashWritingTaskHandle = 0;

Then set the Handle when you create the task (and not some local variable).

You can also use TaskGetHandle in a function to get the handle for a task by name if it haddn’t been created as a global.

I did it, but now I don’t know how “to set” it. The program compiles without any errors now.

I have in flashwritingtask.c

#include "flashwritingtask.h"
#include "config/default/peripheral/port/plib_port.h"   // LED_Toggle()
#include "FreeRTOS.h"
#include "task.h"

// Section: Global Data Definitions
FLASHWRITINGTASK_DATA flashwritingtaskData;

TaskHandle_t FlashWritingTaskHandle = 0;

// Section: Application Initialization and State Machine Functions
void FLASHWRITINGTASK_Initialize ( void )
{
    /* Place the App state machine in its initial state. */
    flashwritingtaskData.state = FLASHWRITINGTASK_STATE_INIT;


    /* TODO: Initialize your application's state machine and other
     * parameters.
     */
    
//    TaskHandle_t FlashWritingTaskHandle;
}

void FLASHWRITINGTASK_Tasks ( void )
{

    /* Check the application's current state. */
    switch ( flashwritingtaskData.state )
    {
        /* Application's initial state. */
        case FLASHWRITINGTASK_STATE_INIT:
        {
            bool appInitialized = true;


            if (appInitialized)
            {

                flashwritingtaskData.state = FLASHWRITINGTASK_STATE_SERVICE_TASKS;
            }
            break;
        }

        case FLASHWRITINGTASK_STATE_SERVICE_TASKS:
        {
            /* Wait for a notification to write to flash. */
            ulTaskNotifyTake( pdTRUE, portMAX_DELAY  );
            
            /* Write to flash. */
            LED_Toggle();
            break;
        }

        /* TODO: implement your application state machine.*/


        /* The default state should never be executed. */
        default:
        {
            /* TODO: Handle error in application's state machine. */
            break;
        }
    }
}

flashwritingtask.h

#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include "configuration.h"
#include "FreeRTOS.h"
#include "task.h"

// Section: Type Definitions
typedef enum
{
    /* Application's state machine's initial state. */
    FLASHWRITINGTASK_STATE_INIT=0,
    FLASHWRITINGTASK_STATE_SERVICE_TASKS,
    /* TODO: Define states used by the application state machine. */

} FLASHWRITINGTASK_STATES;

extern TaskHandle_t FlashWritingTaskHandle;

/* Application Data */
typedef struct
{
    /* The application's current state */
    FLASHWRITINGTASK_STATES state;

    /* TODO: Define any additional data used by the application. */

} FLASHWRITINGTASK_DATA;

// Section: Application Initialization and State Machine Functions
void FLASHWRITINGTASK_Initialize ( void );

void FLASHWRITINGTASK_Tasks( void );

That code appears to be useless.

What exactly do you expect as a response to that fragmentary code skeleton? I still do not see how that would address your throughput issues.

Where are you creating the “Task” (not just defining the function that performs that task). There should be a call to vTaskCreate (or one of the variants of it) to setup the task. That call will take as a parameter a pointer to the handle to fill it in when the task is created.

The code is generated automatically in the Microchip MPLAB X IDE, Harmony. I slightly modified the program for the required purpose.

I found xTaskCreate in FreeRTOS.h, FreeRTOS_task.c and in some other system files (task.h, mpu_prototypes.h, mpu_wrappers.h, task.c and timers.c).

task.c

void SYS_Tasks ( void )
{
    /* Maintain system services */
    

    /* Maintain Device Drivers */
    

    /* Maintain Middleware & Other Libraries */
    

    /* Maintain the application's state machine. */
        /* Create OS Thread for SIMULATIONTASK_Tasks. */
    (void) xTaskCreate((TaskFunction_t) lSIMULATIONTASK_Tasks,
                "SIMULATIONTASK_Tasks",
                128,
                NULL,
                1,
                &xSIMULATIONTASK_Tasks);

    /* Create OS Thread for FLASHWRITINGTASK_Tasks. */
    (void) xTaskCreate((TaskFunction_t) lFLASHWRITINGTASK_Tasks,
                "FLASHWRITINGTASK_Tasks",
                128,
                NULL,
                2,
                &xFLASHWRITINGTASK_Tasks);




    /* Start RTOS Scheduler. */
    
     /**********************************************************************
     * Create all Threads for APP Tasks before starting FreeRTOS Scheduler *
     ***********************************************************************/
    vTaskStartScheduler(); /* This function never returns. */

}

This is also my answer to @RAc

See the Project Graph

So that code is showing that the handle for the flash writing task was put into a variable called xFLASHWRITTINGTASK_Task. Hopefully the framework put a declaration for that in some header you could include get a reference to it.

One problem with auto-generated code like this is you tend to not understand what is happening unless you really study it, and often it would have been quicker to study the library documentation and worked straight from it, as there is better help for the library than the code-generator.

I finally get it to compile without problems and I am going to test it.

flashwritingtask.c, I set the flag in FreeRTOSConfig.h to 1

/* undefined reference to `xTaskGetHandle'"
     INCLUDE_xTaskGetHandle must be set to 1 in FreeRTOSConfig.h for xTaskGetHandle() to be available.
     */
    FlashWritingTaskHandle = xTaskGetHandle( "FLASHWRITINGTASK_Tasks" );

Thank you all for your help, I’ll let you know if it works.