FreeRtos taskCRITICAL example not working as expected

Hi everyone,

I am working with freertos10_xilinx and trying to solve a challenge presented (Digikey freertos challenge, video 7 on youtube)

In short, I need to create N Producer tasks that store their task number 3 times, in common global buffer and M Consumer tasks that print whatever there is in the global buffer.

Following is the code I am using

//To implement problem from DigiKey Introduction to RTOS Part 7.
//https://www.youtube.com/watch?v=95yUbClyf3E&list=PLEBQazB0HUyQ4hAPU1cJED6t3DU0h34bz&index=7
/* Task 1,2,3,4:
 * 	Send task number to a queue
 * Task 5,6:
 * 	Receive data from the same queue and print it
 */

/****************************************** Application specific includes ******************************************/
#include "RtosUtil.h"
#include "app.h"

/****************************************** 'Main' specific ******************************************/
//Task Related
#define TASK_STACK_SIZE	(1024)
#define BUFFER_SIZE		(100)
#define NUM_OF_PROD_TASKS	(5)
#define NUM_OF_CONS_TASKS	(2)

//Semaphore Related
SemaphoreHandle_t SemCount;

//Queue Related
QueueHandle_t queue1;
QueueHandle_t queue2;

//Task Related
TaskHandle_t TaskProdHandle[NUM_OF_PROD_TASKS];
TaskHandle_t TaskConsHandle[NUM_OF_CONS_TASKS];

static void TaskProd(void *);
static void TaskCons();

//UART related
char* rcvstr=NULL;
char UartByte;
char dumbuf[BUFFER_SIZE];
uint32_t head=0,tail=0;

unsigned int i_ind;

/* Task 1,2,3,4:
 * 	Send task number to a queue
 */
static void TaskProd(void *pvParameters){

	//Use to load global buffer and control UART
	taskENTER_CRITICAL();
	for(int i=0;i<3;i++){
		dumbuf[head]=*(uint32_t *)pvParameters;
		head=(head+1) % BUFFER_SIZE;
	}
	xil_printf("Received in TaskProd :%d\r\n",*(uint8_t *)pvParameters);
	taskEXIT_CRITICAL();

	xSemaphoreGive(SemCount);
//	vTaskDelete(TaskProdHandle[*(uint32_t *)pvParameters]);

}

/* Task 5,6:
 * 	Receive data from the same queue and print it
 */
static void TaskCons(){

	while(1){
		xSemaphoreTake(SemCount,0);

		//Use to load global buffer and control UART
		taskENTER_CRITICAL();
		xil_printf("Task number %d\r\n",dumbuf[tail]);
		tail=(tail+1) % BUFFER_SIZE;
		taskEXIT_CRITICAL();

		//Add delay for the task
		vTaskDelay(1000/portTICK_RATE_MS);
	}
}

int main(){

	xil_printf("Application started\r\n");

	AllInit();

	//Create Semaphores
	SemCount=xSemaphoreCreateCounting(NUM_OF_PROD_TASKS,0);
	if(SemCount!=NULL){
		xil_printf("Counting Semaphore Created\r\n");
	}

	//Create Queues to send parameters among tasks
	queue1=xQueueCreate(MAX_QUEUE_LEN,
						sizeof(int));
	queue2=xQueueCreate(MAX_QUEUE_LEN,
						sizeof(int));

	if(queue1==NULL && queue2==NULL)
		xil_printf("Queues NOT created\r\n");

	//Create Producer tasks
	for(i_ind=0;i_ind<NUM_OF_PROD_TASKS;i_ind++){
		sprintf(dumbuf,"Producer Task %d\r\n",i_ind);
		//Create Task to send the task number.
		xTaskCreate(TaskProd,
					dumbuf,
					TASK_STACK_SIZE,
					(void *)&i_ind,
					1,
					&TaskProdHandle[i_ind]);

//		xSemaphoreTake(SemCount, 0);

	}

	//Create Consumer tasks
	for(i_ind=0;i_ind<NUM_OF_CONS_TASKS;i_ind++){
		sprintf(dumbuf,"Consumer Task %d\r\n",i_ind);
		//Create task to send task number
		xTaskCreate(TaskCons,
					dumbuf,
					TASK_STACK_SIZE,
					NULL,
					1,
					&TaskConsHandle[i_ind]);
	}

	//Start scheduler
	vTaskStartScheduler();

	return 0;
}


This is the output I am getting.

Application started
XGpio_CfgInitialize successful
Counting Semaphore Created
Received in TaskProd :2
Received in TaskProd :2
Received in TaskProd :2
Received in TaskProd :2
Received in TaskProd :2
Task number 2
Task number 2

I don’t see what I am doing wrong. Can someone guide me here?

Thanks in advance,

-ZoroIchimonji

A task cannot exit - it must call vTaskDelete( NULL ); to delete itself.

1 Like

Hi @aggarg ,

Yes just corrected that and also made some more changes.

//To implement problem from DigiKey Introduction to RTOS Part 7.
//https://www.youtube.com/watch?v=95yUbClyf3E&list=PLEBQazB0HUyQ4hAPU1cJED6t3DU0h34bz&index=7
/* Task 1,2,3,4:
 * 	Send task number to a queue
 * Task 5,6:
 * 	Receive data from the same queue and print it
 */

/****************************************** Application specific includes ******************************************/
#include "RtosUtil.h"
#include "app.h"

/****************************************** 'Main' specific ******************************************/
//Task Related
#define TASK_STACK_SIZE	(1024)
#define BUFFER_SIZE		(100)
#define NUM_OF_PROD_TASKS	(5)
#define NUM_OF_CONS_TASKS	(2)

//Semaphore Related
SemaphoreHandle_t SemCount;

//Queue Related
QueueHandle_t queue1;
QueueHandle_t queue2;

//Task Related
TaskHandle_t TaskProdHandle[NUM_OF_PROD_TASKS];
TaskHandle_t TaskConsHandle[NUM_OF_CONS_TASKS];

static void TaskProd(void *);
static void TaskCons();

//UART related
char* rcvstr=NULL;
char UartByte;
char dumbuf[BUFFER_SIZE];
char ProdTaskDat[BUFFER_SIZE];

uint32_t head=0,tail=0;

//unsigned int i_ind;

/* Task 1,2,3,4:
 * 	Send task number to a queue
 */
static void TaskProd(void *pvParameters){

	//Use to load global buffer and control UART
	taskENTER_CRITICAL();
	xil_printf("Received in TaskProd :%d\r\n",*(uint8_t *)pvParameters);
	taskEXIT_CRITICAL();

	for(int i=0;i<3;i++){
		xSemaphoreGive(SemCount);

		taskENTER_CRITICAL();
		dumbuf[head]=*(uint8_t *)pvParameters;
		head=(head+1) % BUFFER_SIZE;
		taskEXIT_CRITICAL();
	}

	vTaskDelete(TaskProdHandle[*(uint8_t *)pvParameters]);
	TaskProdHandle[*(uint8_t *)pvParameters]=NULL;

}

/* Task 5,6:
 * 	Receive data from the same queue and print it
 */
static void TaskCons(){

	while(1){
		xSemaphoreTake(SemCount,portMAX_DELAY);

		//Use to load global buffer and control UART
		taskENTER_CRITICAL();
		xil_printf("Task number %d\r\n",dumbuf[tail]);
		tail=(tail+1) % BUFFER_SIZE;
		taskEXIT_CRITICAL();

		//Add delay for the task
		vTaskDelay(100/portTICK_RATE_MS);
	}
}

int main(){

	xil_printf("Application started\r\n");

	AllInit();

	//Create Semaphores
	SemCount=xSemaphoreCreateCounting(NUM_OF_PROD_TASKS*3,0);
	if(SemCount!=NULL){
		xil_printf("Counting Semaphore Created\r\n");
	}

	//Create Queues to send parameters among tasks
	queue1=xQueueCreate(MAX_QUEUE_LEN,
						sizeof(int));
	queue2=xQueueCreate(MAX_QUEUE_LEN,
						sizeof(int));

	if(queue1==NULL && queue2==NULL)
		xil_printf("Queues NOT created\r\n");

	//Create Producer tasks
	for(int i_ind=0;i_ind<NUM_OF_PROD_TASKS;i_ind++){
		ProdTaskDat[i_ind]=i_ind;
		sprintf(dumbuf,"Producer Task %d\r\n",i_ind);
		//Create Task to send the task number.
		xTaskCreate(TaskProd,
					dumbuf,
					TASK_STACK_SIZE,
					(void *)&ProdTaskDat[i_ind],
					1,
					&TaskProdHandle[i_ind]);

//		xSemaphoreTake(SemCount, 0);

	}

	//Create Consumer tasks
	for(int i_ind=0;i_ind<NUM_OF_CONS_TASKS;i_ind++){
		sprintf(dumbuf,"Consumer Task %d\r\n",i_ind);
		//Create task to send task number
		xTaskCreate(TaskCons,
					dumbuf,
					TASK_STACK_SIZE,
					NULL,
					1,
					&TaskConsHandle[i_ind]);
	}

	//Start scheduler
	vTaskStartScheduler();

	return 0;
}


Thank you for sharing changes. Does it solve your problem?

1 Like

Note that a task can delete itself by just using vTaskDelete(NULL); and I’d recommend that this should be the very last statement in the task code even though the effective deletion is deferred to the idle task.

1 Like

also make sure to check the return value of each FreeRTOS API call, in particular xTaskCreate().

1 Like

Yes

To be specific, the problem was I think that tasks were suspended. Because of two reasons.

  1. I was improperly type casting the Handle to vTaskDelete() resulting in some error. Proper type casting and assigning the Handle value to NULL after, solved the problem.
  2. As per problem statement, I needed to hand different value in the pvParameters in the xTaskCreate(). Because I am sharing the address of a global variable/variable out of scope, and because all tasks start after a call to vTaskStartScheduler(), they were printing same number.

Hi @hs2
Ok! I tried to search for if it does that. Probably got unlucky there.

Hi @RAc
Yep! Will do that from next time.

Thank you everyone!

See the API doc here:

Parameters:

  • xTask The handle of the task to be deleted. Passing NULL will cause the calling task to be deleted.
1 Like