Receive char array in Queue from UART ISR

Hi!

I’m relatively new using RTOS in embedded sistems.
My problem is that I have implemented a Queue send from ISR after receive one message via UART and when the code runs to the task where I receive that message from de Queue, I only receive the first character of the message.
My code implementation :

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) //UART ISR
{
		HAL_UART_Receive_IT(&huart3, &rxCnsl, 1);

		consoleCMD [cnt]= rxCnsl; //I receive chars one by one, the buffer is defined in a .h file to avoid redefinition each UART reception

		cnt++;

		if (rxCnsl == '~') //When I receive this character, the message is complete and would be processed
		{

			BaseType_t xHigherPriorityTaskWoken = pdFALSE;

			if (xQueueSendFromISR(ConsoleQueue, &consoleCMD, &xHigherPriorityTaskWoken) == pdPASS)
			{
				DEBUG("Sendindg string to QUEUE %s", consoleCMD); // Here the message is printed correctly (the buffer has the truth message)
			}

			portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
			memset(consoleCMD,0,sizeof(consoleCMD));
		}

}


void HandleConsoleData_init(void *pvParameters)
{
	char *rxConsoleCmd;
	rxConsoleCmd = pvPortMalloc(64*sizeof(char));
//	char *ptr;
	while(1)
	{


		if (xQueueReceive(ConsoleQueue, rxConsoleCmd, portMAX_DELAY) != pdTRUE) 
// In this point, if I pass the pointer rxConsoleCmd by reference (&), the code gets stuck in vPortFree function, I don't know why
		{
			ERROR("Error in Receiving from Queue\n\n");
		}
		else
		{

			DEBUG("Successfully RECEIVED the string %s\n",rxConsoleCmd); // here I just see one character of the message.
			vPortFree(rxConsoleCmd); //free the pointer 
			rxConsoleCmd = pvPortMalloc(64*sizeof(char)); //re-malloc to receive the next msg

		}
		vTaskDelay(5);
	}
}

Caan anyone help me or suggest another way to implement this? I just want to receive messages from the console in my MCU via UART ISR and process it into a task.

Thanks in advance.

It is not completely clear what you are trying to do - is the interrupt supposed to be filling the buffer that is allocated in HandleConsoleData_init()? Why is rxConsoleCmd being freed and then immediately re-allocated rather than just reused? What is consoleCMD pointing to? Is the the same buffer as allocated in the task?

consoleCMD looks like it is a char*, so a pointer to an array of characters. Therefore consoleCMD[0] and *consoleCMD both dereference the pointer to return the first character in the string. As you don’t show the code that created the queue I don’t know what sending &consoleCMD to the queue will do - if the queue was created to hold char * then what it will do is copy the value held in the consoleCMD variable (i.e. the value of the pointer, basically the address it is pointing to) into the queue…

…then calling xQueueReceive() also using a char * (rxConsoleCmd) will copy that queued char* value into the address pointed to by rxConsoleCmd - so I think - just from inspection - rxConsoleCmd will no longer be pointing to the allocated buffer.

Hi Richard!
Thanks for your quick response, this is my first time at the FreeRTOS forum and I’m working with this RTOS just for one month.

What I want to do is to fill a global buffer (char [])declared in the interrupt routine file until I receive the character ‘~’, when I receive this character it means that the message is complete and that’s the moment when I send it to the Queue from ISR and receives it in the HandleConsoleData_Init(). At the moment I only want to print the received buffer in the Queue receive task and after that Free the pointer and reMalloc for wait to another message.

I think that the best way to do this is by using pointers to a declared struct that contains a char *. I have modified the code and now it works better, but when I try to print the content of the pointer before send to the Queue and after receive from the Queue, I only see garbage values…

Here is where I declare the Queue:

ConsoleQueue = xQueueCreate(64,sizeof(char));
if(ConsoleQueue == NULL) ERROR(“Unable to Create ConsoleQueue\r\n”);
else INFO(“Binary Semaphore created successfully\r\n”);
Struct declaration and definition
typedef struct
{
char *str;

}QueueCMD;

QueueCMD *consoleCMD; // I make the Mallok out of the ISR routine, because malloc is limitant function and cannot do it inside the ISR

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
HAL_UART_Receive_IT(&huart3, &rxCnsl, 1);

	consoleCMD->str += rxCnsl;

	if (rxCnsl == '~')
	{

		BaseType_t xHigherPriorityTaskWoken = pdFALSE;

		if (xQueueSendFromISR(ConsoleQueue, &consoleCMD, 
                &xHigherPriorityTaskWoken) == pdPASS)
		{
			DEBUG("Sendindg string to QUEUE %s", consoleCMD->str);
		}


		portYIELD_FROM_ISR( xHigherPriorityTaskWoken );

	}

}

The Task function:

void HandleConsoleData_init(void *pvParameters)
{
QueueCMD *rxConsoleCmd;

while(1)
{
	if (xQueueReceive(ConsoleQueue, &rxConsoleCmd, portMAX_DELAY) != pdTRUE)
	{
		ERROR("Error in Receiving from Queue\n\n");
	}
	else
	{
		DEBUG("Successfully RECEIVED the string %s\n",rxConsoleCmd->str);
		vPortFree(rxConsoleCmd);
		mallocConsoleBuff();
	}


	vTaskDelay(5);
}

}

You think the problem becomes from using a global pointer in the ISR routine?

Thanks in advance Richard.

You are defining that your Queue has 64 slots that each can hold 1 character.
You then send the address of the buffer, which is a pointer to character which will be bigger than a character, so not all of the address will be put into the queue.
If you did this right, and defined the queue to hold pointers to characters instead of characters then you would have the issue that the ISR and the receiver will use the same buffer, so the receiver needs to process the buffer before the next character comes in.

The other option would be to have a loop that puts each character in the buffer into your queue one by one, and receive the characters out of the queue one by one.

You might also want to look at the StreamBuffer object, which is more designed for this sort of thing.

Also, consoleCMD->str += rxCnsl; doesn’t store the character rxCnsl into your buffer, but just increments the str pointer by the value of rxCnsl.

Better follow Richard Damon’s proposal and just forward the raw serial data from the ISR to the post-processing task. This keeps the ISR as short as possible and simplifies your overly complex design a lot. Preferably make use of the streambuffer feature. But also a queue (of characters) would be fine. It just has a slightly higher overhead.