Quality RTOS & Embedded Software

 Real time embedded FreeRTOS RSS feed 
Real time embedded FreeRTOS mailing list 
Quick Start Supported MCUs PDF Books Trace Tools Ecosystem TCP & FAT Training




Loading

How to insert multiple items in a Queue?

Posted by Jaroslav Fojtik on May 28, 2010
Is there any effective way, how to insert many messages into a Queue?

I have found only a way to call "xQueueSendToBack" repeatedly. But this causes some overhead, because implementation of
"xQueueSendToBack" is quite complex.
On the other side the Queue is emptied from IRQ char by char and it is convenient to have message with size 1 Byte.

regards
Jara


/** Stream send buffer. Function sends buffer via stream defined.
@param PStreampointer to a stream handle.
@param pbuffbeginbegin of buffer to send.
@param bufflenlength of buffer to send.
@return0 / -err. */
INT32 SendBlock(TStream *PStream, const UINT8 *pbuffbegin, UINT16 bufflen)
{
if(PStream==NULL) return -1;
if(PStream->Tx_QueueHandle==NULL) return -2;
while(bufflen--)
{
if(xQueueSendToBack(PStream->Tx_QueueHandle,pbuffbegin++,clib_STREAM_OSqueueTxTicksToWait) != pdPASS )
{
/// @TODO: unsuccessfull sending of whole buff - do an action
return(-1);
}
PStream->ActivateTransfer();
}

return(0);
}

RE: How to insert multiple items in a Queue?

Posted by Richard Damon on May 28, 2010
I don't know of a faster way, if you really are going to use a queue and don't want to write your own xQueueSendToBackMultiple function. As Richard has pointed out, the demos do this because it is easy, and also somewhat because it is a bit inefficient so it stresses the system a bit better.

If you want to improve the transfer speed, you can probably do better with mutex to acquire access to a plain circular buffer and maybe a semaphore to handle waiting if the buffer fills. (And if only 1 task will be writing to the buffer the mutex can be eliminated).

A second method is to actually send pointers to buffers of data to the queue, and the interrupt pops the pointer off and remembers it, drawing out of the buffer until empty, then returning the buffer back to the program and getting the next buffer from the queue.

I will point out that your implementation has a few weaknesses, If multiple tasks send to the same queue, their outputs can get intermixed (might not be a problem in your given case, but is in general, you may want to wrap it with a mutex), and that the queue needs to be as long as the longest message that might ever be sent (or you will fill the buffer and block till timeout and then error return without calling your ActivateTransfer function), and without the mutex, it needs to be longer to handle rare case where one task is sending a message, and just before putting in the last character it gets swapped out, and the next task sends more data, and so on (it can be hard to figure the real exact maximum that might get cued up).

RE: How to insert multiple items in a Queue?

Posted by Jaroslav Fojtik on May 28, 2010
The big advantage of RTOS Queue is that somebody solved putting messages from task and receiving messages within IRQ.

My particular queue usage serves for logging messages to a serial line.
Locking of queue would damage real time process. If there is no space in a queue, then it is better to thrash message.

xQueueSendToBackMultiple would help. But I am afraid that I will need to rewrite nearly whole RTOS core functionality.

Yes, messages could get intermixed, but it is still better than nothing. I am using around 512 bytes of queue and I hope that it would be sufficient enough for minimally 5 messages. xQueueSendToBackMultiple would solve even this. When the queue
has enough free space, it would copy everything into a FIFO.




RE: How to insert multiple items in a Queue?

Posted by Richard on May 28, 2010
As richard_damon says, placing characters in a simple circular buffer, then using a semaphore to indicate when a complete message has arrived is a very common technique. Circular buffer implementation can be very fast, and provided the read pointer is only modified from a task, and the write pointer is only modified from the interrupt, then there is normally no need for any locking.

Another common technique is to use a dma to move data around without [much] cpu overhead. Then you can use a single dma interrupt to give a semaphore to unblock a task that is waiting for the data.

Regards.

RE: How to insert multiple items in a Queue?

Posted by Richard Damon on May 29, 2010
I think you may find less impact than you think. If you make the mutex aquire have a timeout of 1, then if a lower priority task was suspended in the middle of sending a message, it will be priority elevated, finish and return back. If the buffer fills it will time out and you just trash your message. If you can't tolerate the 1 tick possible delay, you can either use a 0 tick delay and lose the occasional message because the lower priority task had the queue, or you could replace the mutex with a critical section. Especially if you are using the simple circular buffer, this should be a very short critical section (of course, if the buffer fills, you need to handle this and leave the critical section.)

The concept of queuing up "message buffers" also works very well for this sort of thing, messages by their nature are kept together. It does add complexity, but does improve efficiency by a fair amount.

RE: How to insert multiple items in a Queue?

Posted by Jaroslav Fojtik on May 29, 2010
I posted this message to probe whether "xQueueSendToBackMultiple" is planned.

Thank you for hints. It is not a good ides to cache buffers in my particular case, because they are internally used inside Clib and it is not good idea to rewrite whole IAR Clib - see below.

DMA is a "gun shooting of a sparrow" (just Czech proverb). It will surely work, but I am afraid that 128kbit/s UART line cannot emit more than 12000 interrupts per second. For my particular architecture it is less than 3000 ints/s - 4 byte HW FIFO on UART.
When I write my own FIFO, DMA could point into it. But I am afraid that overhead would be pretty big. It would be necessary to check even DMA transfer position, just because the transfer is slow and DMA area could occupy significant amount of buffer.

DMA is a good for ethernet or SSI, where transfer rates are from 10Mbit/s to 100Mbit/s.



/* If the __write implementation uses internal buffering, uncomment
* the following line to ensure that we are called with "buffer" as 0
* (i.e. flush) when the application terminates. */
size_t __write(int handle, const unsigned char *buffer, size_t size)
{
size_t nChars;

if (buffer == 0)
{ /*
* This means that we should flush internal buffers. Since we
* don't we just return. (Remember, "handle" == -1 means that all
* handles should be flushed.) */
return 0;
}

/* This template only writes to "standard out" and "standard err",
* for all other file handles it returns failure. */
if (handle != _LLIO_STDOUT && handle != _LLIO_STDERR)
{
return _LLIO_ERROR;
}

nChars = 0;
for (/* Empty */; size != 0; --size)
{
if(xQueueSendToBack(LOG2STREAM->Tx_QueueHandle,&(*buffer++),clib_STREAM_OSqueueTxTicksToWait) != pdPASS )
{
return _LLIO_ERROR;
}
LOG2STREAM->ActivateTransfer();
++nChars;
}

return nChars;
}


[ Back to the top ]    [ About FreeRTOS ]    [ Sitemap ]    [ ]




Copyright (C) 2004-2010 Richard Barry. Copyright (C) 2010-2016 Real Time Engineers Ltd.
Any and all data, files, source code, html content and documentation included in the FreeRTOSTM distribution or available on this site are the exclusive property of Real Time Engineers Ltd.. See the files license.txt (included in the distribution) and this copyright notice for more information. FreeRTOSTM and FreeRTOS.orgTM are trade marks of Real Time Engineers Ltd.

Latest News:

FreeRTOS V9.0.0 is now available for download.


Free TCP/IP and file system demos for the RTOS


Sponsored Links

⇓ Now With No Code Size Limit! ⇓
⇑ Free Download Without Registering ⇑


FreeRTOS Partners

ARM Connected RTOS partner for all ARM microcontroller cores

Renesas Electronics Gold Alliance RTOS Partner.jpg

Microchip Premier RTOS Partner

RTOS partner of NXP for all NXP ARM microcontrollers

Atmel RTOS partner supporting ARM Cortex-M3 and AVR32 microcontrollers

STMicro RTOS partner supporting ARM7, ARM Cortex-M3, ARM Cortex-M4 and ARM Cortex-M0

Xilinx Microblaze and Zynq partner

Silicon Labs low power RTOS partner

Altera RTOS partner for Nios II and Cortex-A9 SoC

Freescale Alliance RTOS Member supporting ARM and ColdFire microcontrollers

Infineon ARM Cortex-M microcontrollers

Texas Instruments MCU Developer Network RTOS partner for ARM and MSP430 microcontrollers

Cypress RTOS partner supporting ARM Cortex-M3

Fujitsu RTOS partner supporting ARM Cortex-M3 and FM3

Microsemi (previously Actel) RTOS partner supporting ARM Cortex-M3

Atollic Partner

IAR Partner

Keil ARM Partner

Embedded Artists