Phipps Electronics

Order within the next 

FREE SHIPPING OVER $199

50,000+ ORDERS

WORLDWIDE SHIPPING

SSL SECURED

FreeRTOS Queue Multiple Receivers Example

Contents

Read this article for more examples about using a FreeRTOS queue multiple receivers setups.

Introduction

Last time, the last blog introduced queues. It provided at least a straightforward example. You’ll learn another example to enhance your understanding of this subject. The following discussion continues from the GPIO ports example last time. This application demonstrates a FreeRTOS queue multiple receivers setups.

Example Queue Application 2

Here, you’ll use all three LED strips from the previous exercises. Each LED strip represents a queue receive task. Additionally, each task will blink the strip’s LEDs several times based on the data item received from the queue. Push Button 1, when pushed, sends the data item (corresponding to the number of LED blinks) coming from an integer array into the queue. 

This example demonstrates a single sender, multiple receiver queue setup, which is relatively common. You can find a similar application in TCP/IP where a stream of data packets is sent to a queue. Multiple tasks then receive these packets to work on them in a multi-threaded way.

The complete code is below:

				
					#include <stdio.h>
#include <driver\gpio.h>
#include <freertos\FreeRTOS.h>
#include <freertos\task.h>
#include <freertos\queue.h>

#define LED_STRIP1_G GPIO_NUM_32
#define LED_STRIP1_R GPIO_NUM_33
#define LED_STRIP1_B GPIO_NUM_25

#define LED_STRIP2_G GPIO_NUM_26
#define LED_STRIP2_R GPIO_NUM_27
#define LED_STRIP2_B GPIO_NUM_2

#define LED_STRIP3_G GPIO_NUM_13
#define LED_STRIP3_R GPIO_NUM_14
#define LED_STRIP3_B GPIO_NUM_15

#define LED_STRIP1_BIT_MASK (1ULL << LED_STRIP1_G | 1ULL << LED_STRIP1_R | 1ULL << LED_STRIP1_B)
#define LED_STRIP2_BIT_MASK (1ULL << LED_STRIP2_G | 1ULL << LED_STRIP2_R | 1ULL << LED_STRIP2_B)
#define LED_STRIP3_BIT_MASK (1ULL << LED_STRIP3_G | 1ULL << LED_STRIP3_R | 1ULL << LED_STRIP3_B)

#define PUSH_BUTTON_1 GPIO_NUM_4
#define PUSH_BUTTON_2 GPIO_NUM_35
#define PUSH_BUTTON_3 GPIO_NUM_36

#define PUSH_BUTTON_1_BIT_MASK (1ULL << PUSH_BUTTON_1)
#define PUSH_BUTTON_2_BIT_MASK (1ULL << PUSH_BUTTON_2)
#define PUSH_BUTTON_3_BIT_MASK (1ULL << PUSH_BUTTON_3)

#define NUM_OF_DATA 15

gpio_config_t myGPIOconfig;

void config_ports(void);

void Led_strip_task1(void *parameter);
void Led_strip_task2(void *parameter);
void Led_strip_task3(void *parameter);

void Send_to_Strip(void *paramters);

// create an array to pass values to the LED strips. Each value corressponds to the number of blinks to be made.
int blink_led_values[NUM_OF_DATA] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};


QueueHandle_t myQueue;


void app_main(void)
{
    config_ports();

    myQueue = xQueueCreate(10, sizeof(int));

    xTaskCreate(Led_strip_task1, "led_strip1_task", 1048, NULL, 1, NULL);
    xTaskCreate(Led_strip_task2, "led_strip2_task", 1048, NULL, 1, NULL);
    xTaskCreate(Led_strip_task3, "led_strip3_task", 1048, NULL, 1, NULL);

    xTaskCreate(Send_to_Strip, "send delay to strip",1048, NULL, 2, NULL);

    for(;;)
    {
        // should not reach this point.
    }
}

void config_ports(void)
{
    // Configure Digital I/O for LEDs
    myGPIOconfig.pin_bit_mask = (LED_STRIP1_BIT_MASK | LED_STRIP2_BIT_MASK | LED_STRIP3_BIT_MASK);
    myGPIOconfig.pull_down_en = GPIO_PULLDOWN_DISABLE;
    myGPIOconfig.pull_up_en = GPIO_PULLUP_DISABLE;
    myGPIOconfig.mode = GPIO_MODE_OUTPUT;
    myGPIOconfig.intr_type = GPIO_INTR_DISABLE;

    gpio_config(&myGPIOconfig);

    myGPIOconfig.pin_bit_mask = (PUSH_BUTTON_2_BIT_MASK | PUSH_BUTTON_3_BIT_MASK);
    myGPIOconfig.pull_down_en = GPIO_PULLDOWN_DISABLE;
    myGPIOconfig.pull_up_en = GPIO_PULLUP_DISABLE;
    myGPIOconfig.mode = GPIO_MODE_INPUT;
    myGPIOconfig.intr_type = GPIO_INTR_DISABLE;

    gpio_config(&myGPIOconfig);

    gpio_set_direction(PUSH_BUTTON_1, GPIO_MODE_INPUT);
    gpio_set_pull_mode(PUSH_BUTTON_1, GPIO_PULLUP_ONLY);

}


void Led_strip_task1(void *parameter)
{
    int led_blink = 0;
    int i;

    for(;;)
    {

        if(xQueueReceive(myQueue, &led_blink, 0) == pdTRUE)
        {

            for(i=0;i<led_blink;i++)
            {

                gpio_set_level(LED_STRIP1_G, 1);
                vTaskDelay(300/portTICK_PERIOD_MS);
                gpio_set_level(LED_STRIP1_G, 0);

                gpio_set_level(LED_STRIP1_R, 1);
                vTaskDelay(300/portTICK_PERIOD_MS);
                gpio_set_level(LED_STRIP1_R, 0);

                gpio_set_level(LED_STRIP1_B, 1);
                vTaskDelay(300/portTICK_PERIOD_MS);
                gpio_set_level(LED_STRIP1_B, 0);

                vTaskDelay(300/portTICK_PERIOD_MS);
            }
        }else{
            led_blink = 0;
        }

        vTaskDelay(100/portTICK_PERIOD_MS);

              
    }
}

void Led_strip_task2(void *parameter)
{
    int led_blink = 0;
    int i;

    for(;;)
    {

        if(xQueueReceive(myQueue, &led_blink, 0) == pdTRUE)
        {

            for(i=0;i<led_blink;i++)
            {

                gpio_set_level(LED_STRIP2_G, 1);
                vTaskDelay(300/portTICK_PERIOD_MS);
                gpio_set_level(LED_STRIP2_G, 0);

                gpio_set_level(LED_STRIP2_R, 1);
                vTaskDelay(300/portTICK_PERIOD_MS);
                gpio_set_level(LED_STRIP2_R, 0);

                gpio_set_level(LED_STRIP2_B, 1);
                vTaskDelay(300/portTICK_PERIOD_MS);
                gpio_set_level(LED_STRIP2_B, 0);

                vTaskDelay(300/portTICK_PERIOD_MS);
            }

        }else{
            led_blink = 0;
        }

        vTaskDelay(100/portTICK_PERIOD_MS);
   
    }
}

void Led_strip_task3(void *parameter)
{
    int led_blink = 0;
    int i;

    for(;;)
    {

        if(xQueueReceive(myQueue, &led_blink, 0) == pdTRUE)
        {

            for(i=0;i<led_blink;i++)
            {

                gpio_set_level(LED_STRIP3_G, 1);
                vTaskDelay(300/portTICK_PERIOD_MS);
                gpio_set_level(LED_STRIP3_G, 0);

                gpio_set_level(LED_STRIP3_R, 1);
                vTaskDelay(300/portTICK_PERIOD_MS);
                gpio_set_level(LED_STRIP3_R, 0);

                gpio_set_level(LED_STRIP3_B, 1);
                vTaskDelay(300/portTICK_PERIOD_MS);
                gpio_set_level(LED_STRIP3_B, 0);

                vTaskDelay(300/portTICK_PERIOD_MS);
            }

        }else{
            led_blink = 0;
        }

        vTaskDelay(100/portTICK_PERIOD_MS);
           
    }
}

void Send_to_Strip(void *paramters)
{
    int i = 0;

    for(;;)
    {

        if((gpio_get_level(PUSH_BUTTON_1) == 0))
        {   
            if(i < NUM_OF_DATA)
            {
                xQueueSend(myQueue, &blink_led_values[i], 10);
            
                // debounce
                vTaskDelay(300/portTICK_PERIOD_MS);

                i++;
            }else{
                i = 0;
            }

        }


        vTaskDelay(10);
        
    }
}


				
			

Below, you’ll see the three function prototypes for the LED tasks, Led_strip_taskn( ). The Send_to_Strip( ) function prototype sends data to the queue through a push button.

An integer array is declared to pass on these blink data to the queue while the myQueue handle is declared as a QueueHandle_t. The array data is only filled with a blink value of 1 for demonstration purposes.

				
					void Led_strip_task1(void *parameter);
void Led_strip_task2(void *parameter);
void Led_strip_task3(void *parameter);

void Send_to_Strip(void *paramters);

// create an array to pass values to the LED strips. Each value corressponds to the number of blinks to be made.
int blink_led_values[NUM_OF_DATA] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};

QueueHandle_t myQueue;
				
			

Like the previous example, the queue and the tasks are created in this code section below. Note that the LED strip tasks have the same priority. This means these tasks receive and processes data on equal CPU time slices compared with each other. The Send_to_Strip task has a lower priority, which means it’s only processed when the LED tasks are blocking.

				
					    myQueue = xQueueCreate(10, sizeof(int));

    xTaskCreate(Led_strip_task1, "led_strip1_task", 1048, NULL, 1, NULL);
    xTaskCreate(Led_strip_task2, "led_strip2_task", 1048, NULL, 1, NULL);
    xTaskCreate(Led_strip_task3, "led_strip3_task", 1048, NULL, 1, NULL);

    xTaskCreate(Send_to_Strip, "send delay to strip",1048, NULL, 2, NULL);

				
			

Take a look at one of the LED tasks below.  You’ll see that myQueue is checked for data. If there is, that data becomes the number of times the LED strip should blink. Else, a continuous pass is done to check myQueue again.

				
					void Led_strip_task1(void *parameter)
{
    int led_blink = 0;
    int i;

    for(;;)
    {

        if(xQueueReceive(myQueue, &led_blink, 0) == pdTRUE)
        {

            for(i=0;i<led_blink;i++)
            {

                gpio_set_level(LED_STRIP1_G, 1);
                vTaskDelay(300/portTICK_PERIOD_MS);
                gpio_set_level(LED_STRIP1_G, 0);

                gpio_set_level(LED_STRIP1_R, 1);
                vTaskDelay(300/portTICK_PERIOD_MS);
                gpio_set_level(LED_STRIP1_R, 0);

                gpio_set_level(LED_STRIP1_B, 1);
                vTaskDelay(300/portTICK_PERIOD_MS);
                gpio_set_level(LED_STRIP1_B, 0);

                vTaskDelay(300/portTICK_PERIOD_MS);
            }
        }else{
            led_blink = 0;
        }

        vTaskDelay(100/portTICK_PERIOD_MS);

              
    }
}
				
			

The sending task is below. If a button is pressed, the corresponding array data is sent to the queue.

				
					void Send_to_Strip(void *paramters)
{
    int i = 0;

    for(;;)
    {

        if((gpio_get_level(PUSH_BUTTON_1) == 0))
        {   
            if(i < NUM_OF_DATA)
            {
                xQueueSend(myQueue, &blink_led_values[i], 10);
            
                // debounce
                vTaskDelay(300/portTICK_PERIOD_MS);

                i++;
            }else{
                i = 0;
            }

        }


        vTaskDelay(10);
        
    }
}

				
			

Check the video demonstration of the actual behavior of the circuit below. As you’ll see, when you press the button once, an LED strip task blinks once. When you press the button several times with significant gaps in between, each LED strip task may be able to receive and process the blink data from the queue separately. Also, the queue will only have one position filled during this time.  

However, pressing the buttons faster creates an overlap between receiving queue data and each LED strip task processing it. With this, the queue begins to fill up. The faster data enters the queue and fills it; the more threads become available to receive and process the data. You’ll also notice the LED strip tasks now run seemingly simultaneously in a multithreaded manner. This process demonstrates the usefulness of a single sender multiple receiver queue setup.

SUBSCRIBE FOR NEW POST ALERTS

Subscribe to be the first to know when we publish a new article!
List Subscriptions(Required)

POPULAR POSTS

Scroll to Top