Event Groups Question

Hello all,

I’ve been having some difficulty controlling my tasks using event groups. To begin, there are 5 main tasks:

Task WD - A watchdog task. This is not controlled by the event group and is to run periodically.

Task A1 - This is one of the main detection tasks. It is used to compute data for IO to determine if some condition is met.

Task A2 - This is the self check task that is used to verify the hardware that Task A1 is using. It is only meant to be schedulable when Task A1 has determined that the condition has been met.

Task B1 - This task is very similar to Task A1, but will be evaluating a different set of IO info.

Task B2 - This behaves the same as Task A2 and will only be schedulable when Task B1 determines a condition is true.

My plan to deal with the control flow of these tasks was to assign have Task A1 toggle on and off bit 0x1 and Task B1 toggle bit 0x2 in the event group. Both of the self check tasks begin with the xEventGroupWaitBits() being set to wait until their bit is set to run. This xEventGroupWaitBits() function is called at the beginning of the infinite loop within each self check task to check if the condition is still being met within Tasks A1 and B1.

At power on time, a value from a rotary dip will be saved and used to set 1 of 3 operation modes which will change which if Task A1 will run, if Task A2 will run or if both will run. I have included the xEventGroupWaitBits() at the beginning of Task A1 and B1’s infinite loop to check on which mode has been set to allow the correct Tasks to begin running.

I have build and flashed this onto my dev board and I have set the operation mode manually to only run Task A1. At the beginning Task A1 will run once and then freeze indefinitely and then when Task WD is put in the ready state it is starved of a time slice and the program freezes. I might be misunderstanding something here because I am new to using event groups, please feel free to ask for any other information you need.

Thanks.

Can you show the code.

When the Task A1 freezes indefinitely, what is it doing. It doesn’t sound like it is frozen if it is preventing lower priority tasks from running. If you stop the debugger, what is running? Are you just looping in an assert or in an undefined interrupt handler?

Unfortunately I am not able to post the code itself for IP reasons but I can describe where it gets stuck in the debugger. When I pause the debugger It seems like a memory check is being performed in a continuous loop. I am using a processor that is using an MPU so I believe that is what is being checked here. I am using tracealyzer, but as this processor is using an MPU the user space information is limited. I have attached some images of the current tracalyzer output below:

It sounds like you have a task running continuously that is starving lower priority tasks of cpu time. Is that the case? I can’t view the trace on my phone.

I was thinking the same thing originally. All of the tasks begin running and are blocked, with the exception of Task A1 (which is expected) task A1 runs until it reaches its first vTaskDelay() which is set to delay for 100ms. Nothing happens for a while (which is expected) until the WD task is set to the ready state. It is then put in the running state and the program freezes. This task never ends up executing. This WD task is the only task that is not using the event group to control its execution. Could that be a problem?

If it is the highest priority task, then it is problematic. You can quickly verify that by lowering its priority (have all the tasks at the same priority) or by calling vTaskDelay to put in blocked state for a while.

Thanks.

Thanks for the reply. I set all tasks to the highest priority and I am having the same issue.

I just changed the initial set up of the event group so that none of the event group bits are set, blocking all tasks except the WD task. After doing this the WD task is working properly and executing periodically.

Glad that it worked for you.

I think there might be a misunderstanding. My issue isn’t fixed, I was just demonstrating the the issue isn’t with the WD task itself but rather the even group functions

Sorry for the misunderstanding. Can you remove your proprietary code and share a sample which just uses FreeRTOS constructs and demonstrates the problem?

I can do that. I’ll that to you as soon as I can

Please see attached code. I tried to comment it well but please let me know if you would like clarification. I have also posted a screenshot of the tracealyzer output below. I believe I may have been mistaken in my previous message about the WD task not running at all. I believe it is running once and then the program freezes after.



/******************************** system and platform files */
#include <stdint.h>             /* Variable type definitions */
#include <stdbool.h>

#include "FreeRTOS.h"
#include "os_queue.h"
#include "os_task.h"
#include "os_semphr.h"
#include "os_timer.h"
#include "os_event_groups.h"

#include "HALCoGEN.h"



/* Function prototypes */

SAFETY_FUNCTION portBaseType A1TaskCreate( portUnsignedBaseType priority );
SAFETY_FUNCTION portBaseType A2TaskCreate( portUnsignedBaseType priority );
SAFETY_FUNCTION portBaseType WDTaskCreate( portUnsignedBaseType priority );
SAFETY_FUNCTION portBaseType B1TaskCreate( portUnsignedBaseType priority );


SAFETY_FUNCTION void A1Task ( void *parameters );
SAFETY_FUNCTION void A2Task ( void *parameters );
SAFETY_FUNCTION void WDTask ( void *parameters );
SAFETY_FUNCTION void B1Task ( void *parameters );

SAFETY_FUNCTION static void mainInit( void );

/* Event group bits */

#define A1_PASS                                ( 1UL << 0UL )
#define B1_PASS                                ( 1UL << 1UL )
#define A1_ONLY_MODE                           ( 1UL << 2UL )
#define B1_ONLY_MODE                           ( 1UL << 3UL )
#define OR_MODE                                ( 1UL << 4UL )

/* Task priorities */

#define A1_TASK_PRIORITY                       ( tskIDLE_PRIORITY + 2 )
#define A2_TASK_PRIORIT                        ( tskIDLE_PRIORITY + 1 )
#define WD_TASK_PRIORITY                       ( tskIDLE_PRIORITY + 7 )
#define B1_TASK_PRIORITY                       ( tskIDLE_PRIORITY + 2 )

/* Task stack size */

const unsigned int A1STACK_SIZE = 50u;
const unsigned int A2STACK_SIZE = 20u;
const unsigned int WDSTACK_SIZE = 200u;
const unsigned int B1STACK_SIZE = 100u;

/* Task handles */

static portTaskHandleType A1TaskHandle = NULL;
static portTaskHandleType A2TaskHandle = NULL;
static portTaskHandleType WDTaskHandle = NULL;
static portTaskHandleType B1TaskHandle = NULL;

/* Event group declaration  */

EventGroupHandle_t xTaskControlBits;

int32_t VD2Main(void)
{
    portBaseType xStatus = pdPASS;
    mainInit();
    _enable_IRQ();

    vTraceEnable(TRC_START);


    /* Initialize FreeRTOS Kernel Scheduler */

    xStatus = A1TaskCreate(A1_TASK_PRIORITY);

    if (xStatus == pdPASS)
    {
        xStatus = A2TaskCreate(A2_TASK_PRIORIT);
    }
    if (xStatus == pdPASS)
    {
        xStatus = WDTaskCreate(WD_TASK_PRIORITY);
    }
    if (xStatus == pdPASS)
    {
        xStatus = B1TaskCreate(B1_TASK_PRIORITY);
    }

    xTaskControlBits = xEventGroupCreate();

    /* Configure Event Group so only A1 is running. WD should also run as it is not in the event group */
    xEventGroupSetBits( xTaskControlBits, A1_ONLY_MODE );

    vTaskStartScheduler();

    /* Should never rear here*/
    while(LOOP_FOREVER)
    {

    }
}
/* Creation of tasks */
portBaseType  A1TaskCreate (
        portUnsignedBaseType priority   /* Priority level for this task */
)
{

    portBaseType xCreateResult;
    /* Spawn the task */
    xCreateResult = xTaskCreate(
                        A1Task,
                        "A1Task",
                        A1STACK_SIZE,
                        NULL,
                        priority,
                        &A1TaskHandle);

    return xCreateResult;
}

portBaseType  A2TaskCreate (
        portUnsignedBaseType priority   /* Priority level for this task */
)
{

    portBaseType xCreateResult;
    /* Spawn the task */
    xCreateResult = xTaskCreate(
                        A2Task,
                        "A2Task",
                        A2STACK_SIZE,
                        NULL,
                        priority,
                        &A2TaskHandle);

    return xCreateResult;
}

portBaseType  WDTaskCreate (
        portUnsignedBaseType priority   /* Priority level for this task */
)
{

    portBaseType xCreateResult;
    /* Spawn the task */
    xCreateResult = xTaskCreate(
                        WDTask,
                        "WDTask",
                        WDSTACK_SIZE,
                        NULL,
                        priority,
                        &WDTaskHandle);

    return xCreateResult;
}

portBaseType  B1TaskCreate (
        portUnsignedBaseType priority   /* Priority level for this task */
)
{

    portBaseType xCreateResult;
    /* Spawn the task */
    xCreateResult = xTaskCreate(
                        B1Task,
                        "B1Task",
                        B1STACK_SIZE,
                        NULL,
                        priority,
                        &B1TaskHandle);

    return xCreateResult;
}
/* Should run periodically */
void A1Task(
    void *parameters            /* Task startup parameters */
)
{

    ( void ) parameters;
    static EventBits_t xTCBits;

    /* Will run if OR mode or A1 Only is selected. A1 Only mode is hardcoded as selected for testing */
    EventBits_t FR_Control = ( A1_ONLY_MODE | OR_MODE );
    while(LOOP_FOREVER)
    {
        xTCBits = xEventGroupWaitBits(
                        xTaskControlBits,
                        FR_Control,
                        pdFALSE,
                        pdFALSE,
                        portMAX_DELAY );
        /* Added to give easier to read output in tracealyzer. */
        vTaskDelay(100/portTICK_PERIOD_MS);


    }
}

/* Should never run */
void B1Task(
    void *parameters            /* Task startup parameters */
)
{

    ( void ) parameters;
    static EventBits_t xTCBits;

    /* Will run if OR mode or B1 Only is selected. A1 Only mode is hardcoded as selected for testing */
    EventBits_t FR_Control =( B1_ONLY_MODE | OR_MODE );
    while(LOOP_FOREVER)
    {
        xTCBits = xEventGroupWaitBits(
                        xTaskControlBits,
                        FR_Control,
                        pdFALSE,
                        pdFALSE,
                        portMAX_DELAY );

        /* Added to give easier to read output in tracealyzer. */
        vTaskDelay(100/portTICK_PERIOD_MS);

    }
}
/* Should run periodically, regardless of state of event group*/
void WDTask(
    void *parameters            /* Task startup parameters */
)
{

    ( void ) parameters;
    static EventBits_t xTCBits;


    while(LOOP_FOREVER)
    {
        /* Added to give easier to read output in tracealyzer. */
        vTaskDelay(30/portTICK_PERIOD_MS);

    }
}
/* Should never run*/
void A2Task(
    void *parameters            /* Task startup parameters */
)
{

    ( void ) parameters;
    static EventBits_t xTCBits;

    EventBits_t FR_Control =( A1_PASS );
    while(LOOP_FOREVER)
    {
        xTCBits = xEventGroupWaitBits(
                        xTaskControlBits,
                        FR_Control,
                        pdFALSE,
                        pdFALSE,
                        portMAX_DELAY );
        /* Added to give easier to read output in tracealyzer. */
        vTaskDelay(60/portTICK_PERIOD_MS);

    }
}
#if 0
SAFETY_FUNCTION static void mainInit( void )
{
    /* HET1 I/O required in order to set CPU error flags */

    gioInit();
    sciInit();
    adcInit();
    hetInit();


}
#endif

Your stack sizes were too small and were resulting in memory corruption because of stack overflow. I increased them and the code now runs as expected. Here is the updated code - app_main.c (6.5 KB)

Note that I made some changes to make it compile and I tested it on a Cortex-M7. Here is the sequence -

  1. WD Tasks runs first as it is the highest priority ready task. It gets blocked on vTaskDelay.
  2. A1 runs next and gets blocked on vTaskDelay.
  3. B1 runs next and gets blocked on xEventGroupWaitBits.
  4. A2 runs next and gets blocked on xEventGroupWaitBits.
  5. After this point, B1 and A2 remains blocked forever and WD and A1 run periodically.

Thanks.

Sorry about that, I must have over looked one of the tasks. Thanks for the help everyone