Semaphore Counter can be used as a counter event, for example, the next code example will create a new event each time that button is pressed. There are tasks in charge of reading the number of events that happened.

Code Example:

#include "bsp.h"

#define MAX_EVENTS      3                           /* Max of events to activate LED */
#define EVENTS_TO_LED   2                           /* Number of necessary events to activate LED */
#define EVENTS_TO_CLEAR 3                           /* Number of events to take again all the semaphores */

static void Task_WaitEvents( void *parameter );     /* Wait to the right number of events */
static void Task_ClearEvents( void *parameter );    /* Wait to the event to take smeaphores */

SemaphoreHandle_t Semph;                            /* Semaphore Handle */

int main( void )
{
    HAL_Init( );
    /*enable RTT and system view*/
    SEGGER_SYSVIEW_Conf( );
    SEGGER_SYSVIEW_Start( );

    HAL_NVIC_SetPriority( EXTI4_15_IRQn, 2, 0 );    /* Set the priority to External Interrupt */
    HAL_NVIC_EnableIRQ( EXTI4_15_IRQn );            /* Enable External Interrupt */

    Semph = xSemaphoreCreateCounting(3,0);          /* Counter Semaphore creation */

    xTaskCreate( Task_WaitEvents, "Task_WaitEvents", 128u, NULL, 1u, NULL );    /* Register in Kernel a task with priority 1 */
    xTaskCreate( Task_ClearEvents, "Task_CkearEvents", 128u, NULL, 1u, NULL );  /* Register in Kernel a task with priority 1 */

    vTaskStartScheduler( );                         /* Initialize the Kernel */

    return 0u;
}

static void Task_WaitEvents( void *parameter )
{
    UNUSED(parameter);

    for(;;)
    {
        if (uxSemaphoreGetCount(Semph) == EVENTS_TO_LED)            /* Check if events matches with the necessary events
                                                                       to turn ON the LED */
        {
            HAL_GPIO_WritePin( GPIOC, GPIO_PIN_0, GPIO_PIN_SET );   /* Execute a function */
            SEGGER_SYSVIEW_PrintfHost( "LED ON" );                  /* Print on Terminal */
        }

        vTaskDelay(500); 
    }
}

static void Task_ClearEvents( void *parameter )
{
    UNUSED(parameter);

    for(;;)
    {
        if (uxSemaphoreGetCount(Semph) >= EVENTS_TO_CLEAR)           /* Check if there are an event more than the MAX_EVENTS */
        {
            HAL_GPIO_WritePin( GPIOC, GPIO_PIN_0, GPIO_PIN_RESET ); /* Deactivate LED */

            for(uint8_t iter = 0; iter <= MAX_EVENTS; iter++)       /* Iterate to take all the samphores */     
            {
                xSemaphoreTake( Semph, 0 );                         /* Function to take a semaphore without tick delay */
            }

            SEGGER_SYSVIEW_PrintfHost( "Conter Semaphore clear" );  /* Print on Terminal */
        }

        vTaskDelay(500); 
    }
}

void HAL_GPIO_EXTI_Rising_Callback( uint16_t GPIO_Pin )     /* Callback of interrupt */
{
    SEGGER_SYSVIEW_RecordEnterISR();                        /* Record enter of IRS on SytemView timeline */
    BaseType_t FreeEvent = pdFALSE;                         /* Variable to indicate if there are semaphores available */

    xSemaphoreGiveFromISR( Semph, &FreeEvent );             /* Give semahpore */

    SEGGER_SYSVIEW_RecordExitISR();                         /* Record exit of IRS on SytemView timeline */
    portEND_SWITCHING_ISR( FreeEvent );                     /* Change context inmediatelly if semaphore is given */
}

There are 2 tasks registered, Task_WaitEvents and Task_ClearEvents, these 2 tasks are in charge of reading the number of events, and if the number of events matches with an expected number of each task, the task executes, for example, the task Task_WaitEvents waits to happen 3 events to after active a LED. The Task Task_ClearEvents waits for another event, which means wait for 4 events to happen to clear the number of events and deactivate the LED.

Events are generated by an external interruption using a button, notice that callback HAL_GPIO_EXTI_Rising_Callback gives a semaphore, to count an event.

SystemView Output

Document

Timeline:

Document

Observe in the Timeline the ISR 23 section, this is the record of the interrupt execution. when the button is pressed the interruption is generated.
To activate a led on "Task_WaitEvents" needs to generate 2 events, this section shows 2 events generated by the button interruption.



This image shows the window event, which presents the behavior of the interruption that gives a semaphore.
Note: semaphores are managed by Queues for this reason the ISR calls the function "xQueueGiveFromISR".

When the task Task_WaitEvents detects 2 events, the code is executed to turn-on an LED and print a message that the LED is enabled.

Next, after 5 seconds the button is pressed again, incrementing the counter event to 3.

The Task "Task_ClearEvents" is executed and takes all the semaphores again, now the counter event is 0 and the LED must be disabled.
Now the application waits for events to happen again.