How to use multiple flags for intra-thread signaling?

Hi,

I am trying to understand how intra-thread signaling work in Mbed RTOS. Multiple functions such as:

uint32_t flags_wait_all (uint32_t flags, bool clear=true)
uint32_t flags_set (uint32_t flags)

accept one uint32_t as parameter as multiple flags.

How does this work? Each flag use one bit of the 32 bit parameter? Or some combination bits?

Will something like the following work?

#define THREAD_SIGNALING_FLAG_1 1
#define THREAD_SIGNALING_FLAG_2 2
#define THREAD_SIGNALING_FLAG_3 4

Please forgive me if I missed something obvious. Thanks.

Hello Li,

How does this work? Each flag use one bit of the 32 bit parameter? Or some combination bits?

Each flag is using one of the last 31 bits of of the EventFlags variable. The most significant is not used.

  • I usually first define the flag’s position within the EventFlags variable, for example:
#define MOTOR_FLAG        (1UL << 0)    // position 0
#define MAX_SPEED_FLAG    (1UL << 1)    // position 1
#define RELAY_ON_FLAG     (1UL << 8)    // position 8
...
  • Then I can set the selected flag(s) in the program like:
EventFlags evenFlags;

...
evenFlags.set(MAX_SPEED_FLAG);
...
evenFlags.set(MOTOR_FLAG | MAX_SPEED_FLAG)
...
  • After that I can wait and block some thread until the selected flag(s) become(s) set:
...
eventFlags.wait_any(MOTOR_FLAG | RELAY_ON_FLAG);
...
eventFlags.wait_all(MOTOR_FLAG | MAX_SPEED_FLAG);
...
  • By default the wait function clears the flags passed to it. If you don’t want the wait function to clear the flag(s) then pass it a second argument defining the wait time in millisecond and third one equal to false:
eventFlags.wait_all(MOTOR_FLAG | MAX_SPEED_FLAG,  osWaitForever, false);
  • Below is an example how to use them in program:
#include "mbed.h"

#define SAMPLE_FLAG1    (1UL << 0)
#define SAMPLE_FLAG2    (1UL << 1)

DigitalOut      led1(LED1, 0);
DigitalOut      led2(LED2, 0);

EventFlags      event_flags;
osThreadId_t    threadId;

uint32_t    flags_read = 0;
Thread      thread_01;
Thread      thread_02;

void task_01()
{
    while (true) {
        led1 = 1;
        event_flags.set(SAMPLE_FLAG1);
        ThisThread::sleep_for(500ms);
        led1 = 0;
        event_flags.set(SAMPLE_FLAG2);
        ThisThread::sleep_for(500ms);
    }
}

void task_02()
{
    while (true) {
        event_flags.wait_all(SAMPLE_FLAG1);
        led2 = 1;
        event_flags.wait_all(SAMPLE_FLAG2);
        led2 = 0;
    }
}

int main()
{
    event_flags.clear();
    thread_01.start(callback(task_01));
    thread_02.start(callback(task_02));

    printf("Waiting for any flag.\r\n");

    while (true) {
        flags_read = event_flags.wait_any(SAMPLE_FLAG1 | SAMPLE_FLAG2, osWaitForever, true);
        printf("Got: 0x%.04x\r\n", flags_read);
        printf("led1 = %d\r\n", led1.read());
        printf("led2 = %d\r\n", led2.read());
    }
}
3 Likes

Can you use constexpr instead of macros to define the flags?

Yes, we can. Actually it’s a better solution because unlike defines constant expressions are check at compile time:

const uint32_t MOTOR_FLAG     = (1UL << 0);    // position 0
const uint32_t MAX_SPEED_FLAG = (1UL << 1);    // position 1
const uint32_t RELAY_ON_FLAG  = (1UL << 8);    // position 8
...

EventFlags can also be very effectively used to handle interrupts:

// Define event flags.
const uint32_t INTERRUPT_FLAG = (1UL << 0);  // position 0

// Define global variables
EventFlags  evenFlags;
InterruptIn button(p22);

// The following function is called on interrupt. 
// It is as short as possible (to not blocking) .
void  on_iterrupt()
{
    eventFlags.set(INTERRUPT_FLAG);
}

// The next task is an Interrupt Service Routine and
// it is running in a high priority task.
// It is blocking/waiting for the INTERRUPT_FLAG to become set.
void interrupt_service_routine()
{
    while (1) {
        eventFlags.wait_all(INTERRUPT_FLAG);
        // serving the interrupt
        ...
    }
}

Thread thread_isr(osPriorityHigh);

int main()
{
    // Start the interrupt service routine task 
    // in a high priority task.
    thread_isr.start(callback(interrupt_service_routine);

    // Attach a callback to the interrupt.
    button.fall(on_iterrupt);
    ...
    // The main thread
    while(1) {
        ...
    }
}

Have a look also at API Can lose messages - #2 by hudakz .