Add xQueueOverwriteFromISR() and update the QueueOverwrite.c to demonstrate its use.

This commit is contained in:
Richard Barry 2013-06-27 14:25:17 +00:00
parent 671949ad78
commit 3b02b4c8f8
5 changed files with 165 additions and 13 deletions

View File

@ -98,18 +98,33 @@ static void prvQueueOverwriteTask( void *pvParameters );
prvQueueOverwriteTask() has not found any errors. */ prvQueueOverwriteTask() has not found any errors. */
static unsigned long ulLoopCounter = 0; static unsigned long ulLoopCounter = 0;
/* Set to pdFALSE if an error is discovered by the
vQueueOverwritePeriodicISRDemo() function. */
static portBASE_TYPE xISRTestStatus = pdPASS;
/* The queue that is accessed from the ISR. The queue accessed by the task is
created inside the task itself. */
static xQueueHandle xISRQueue = NULL;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vStartQueueOverwriteTask( unsigned portBASE_TYPE uxPriority ) void vStartQueueOverwriteTask( unsigned portBASE_TYPE uxPriority )
{ {
/* Create the test task. */ const unsigned portBASE_TYPE uxQueueLength = 1;
/* Create the queue used by the ISR. xQueueOverwriteFromISR() should only
be used on queues that have a length of 1. */
xISRQueue = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( unsigned long ) );
/* Create the test task. The queue used by the test task is created inside
the task itself. */
xTaskCreate( prvQueueOverwriteTask, ( signed char * ) "QOver", configMINIMAL_STACK_SIZE, NULL, uxPriority, ( xTaskHandle * ) NULL ); xTaskCreate( prvQueueOverwriteTask, ( signed char * ) "QOver", configMINIMAL_STACK_SIZE, NULL, uxPriority, ( xTaskHandle * ) NULL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvQueueOverwriteTask( void *pvParameters ) static void prvQueueOverwriteTask( void *pvParameters )
{ {
xQueueHandle xQueue; xQueueHandle xTaskQueue;
const unsigned portBASE_TYPE uxQueueLength = 1; const unsigned portBASE_TYPE uxQueueLength = 1;
unsigned long ulValue, ulStatus = pdPASS, x; unsigned long ulValue, ulStatus = pdPASS, x;
@ -118,18 +133,18 @@ unsigned long ulValue, ulStatus = pdPASS, x;
/* Create the queue. xQueueOverwrite() should only be used on queues that /* Create the queue. xQueueOverwrite() should only be used on queues that
have a length of 1. */ have a length of 1. */
xQueue = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( unsigned long ) ); xTaskQueue = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( unsigned long ) );
configASSERT( xQueue ); configASSERT( xTaskQueue );
for( ;; ) for( ;; )
{ {
/* The queue is empty. Writing to the queue then reading from the queue /* The queue is empty. Writing to the queue then reading from the queue
should return the item written. */ should return the item written. */
ulValue = 10; ulValue = 10;
xQueueOverwrite( xQueue, &ulValue ); xQueueOverwrite( xTaskQueue, &ulValue );
ulValue = 0; ulValue = 0;
xQueueReceive( xQueue, &ulValue, qoDONT_BLOCK ); xQueueReceive( xTaskQueue, &ulValue, qoDONT_BLOCK );
if( ulValue != 10 ) if( ulValue != 10 )
{ {
@ -141,27 +156,27 @@ unsigned long ulValue, ulStatus = pdPASS, x;
for( x = 0; x < qoLOOPS; x++ ) for( x = 0; x < qoLOOPS; x++ )
{ {
/* Write to the queue. */ /* Write to the queue. */
xQueueOverwrite( xQueue, &x ); xQueueOverwrite( xTaskQueue, &x );
/* Check the value in the queue is that written, even though the /* Check the value in the queue is that written, even though the
queue was not necessarily empty. */ queue was not necessarily empty. */
xQueuePeek( xQueue, &ulValue, qoDONT_BLOCK ); xQueuePeek( xTaskQueue, &ulValue, qoDONT_BLOCK );
if( ulValue != x ) if( ulValue != x )
{ {
ulStatus = pdFAIL; ulStatus = pdFAIL;
} }
/* There should always be one item in the queue. */ /* There should always be one item in the queue. */
if( uxQueueMessagesWaiting( xQueue ) != uxQueueLength ) if( uxQueueMessagesWaiting( xTaskQueue ) != uxQueueLength )
{ {
ulStatus = pdFAIL; ulStatus = pdFAIL;
} }
} }
/* Empty the queue again. */ /* Empty the queue again. */
xQueueReceive( xQueue, &ulValue, qoDONT_BLOCK ); xQueueReceive( xTaskQueue, &ulValue, qoDONT_BLOCK );
if( uxQueueMessagesWaiting( xQueue ) != 0 ) if( uxQueueMessagesWaiting( xTaskQueue ) != 0 )
{ {
ulStatus = pdFAIL; ulStatus = pdFAIL;
} }
@ -180,7 +195,11 @@ portBASE_TYPE xIsQueueOverwriteTaskStillRunning( void )
{ {
portBASE_TYPE xReturn; portBASE_TYPE xReturn;
if( ulLoopCounter > 0 ) if( xISRTestStatus != pdPASS )
{
xReturn = pdFAIL;
}
else if( ulLoopCounter > 0 )
{ {
xReturn = pdPASS; xReturn = pdPASS;
} }
@ -194,4 +213,54 @@ portBASE_TYPE xReturn;
return xReturn; return xReturn;
} }
/*-----------------------------------------------------------*/
void vQueueOverwritePeriodicISRDemo( void )
{
static unsigned long ulCallCount = 0;
const unsigned long ulTx1 = 10UL, ulTx2 = 20UL, ulNumberOfSwitchCases = 3UL;
unsigned long ulRx;
/* This function should be called from an interrupt, such as the tick hook
function vApplicationTickHook(). */
configASSERT( xISRQueue );
switch( ulCallCount )
{
case 0:
/* The queue is empty. Write ulTx1 to the queue. In this demo the
last parameter is not used because there are no tasks blocked on
this queue. */
xQueueOverwriteFromISR( xISRQueue, &ulTx1, NULL );
break;
case 1:
/* The queue already holds ulTx1. Overwrite the value in the queue
with ulTx2. */
xQueueOverwriteFromISR( xISRQueue, &ulTx2, NULL );
break;
case 2:
/* Read from the queue to empty the queue again. The value read
should be ulTx2. */
xQueueReceiveFromISR( xISRQueue, &ulRx, NULL );
if( ulRx != ulTx2 )
{
xISRTestStatus = pdFAIL;
}
break;
}
/* Run the next case in the switch statement above next time this function
is called. */
ulCallCount++;
if( ulCallCount >= ulNumberOfSwitchCases )
{
/* Go back to the start. */
ulCallCount = 0;
}
}

View File

@ -77,6 +77,7 @@
void vStartQueueOverwriteTask( unsigned portBASE_TYPE uxPriority ); void vStartQueueOverwriteTask( unsigned portBASE_TYPE uxPriority );
portBASE_TYPE xIsQueueOverwriteTaskStillRunning( void ); portBASE_TYPE xIsQueueOverwriteTaskStillRunning( void );
void vQueueOverwritePeriodicISRDemo( void );
#endif /* QUEUE_OVERWRITE_H */ #endif /* QUEUE_OVERWRITE_H */

View File

@ -411,6 +411,9 @@ void vApplicationTickHook( void )
can be called from an ISR. */ can be called from an ISR. */
vTimerPeriodicISRTests(); vTimerPeriodicISRTests();
/* Call the periodic queue overwrite from ISR demo. */
vQueueOverwritePeriodicISRDemo();
/* Write to a queue that is in use as part of the queue set demo to /* Write to a queue that is in use as part of the queue set demo to
demonstrate using queue sets from an ISR. */ demonstrate using queue sets from an ISR. */
vQueueSetAccessQueueSetFromISR(); vQueueSetAccessQueueSetFromISR();

View File

@ -1053,6 +1053,84 @@ void vQueueDelete( xQueueHandle xQueue ) PRIVILEGED_FUNCTION;
*/ */
#define xQueueSendToBackFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK ) #define xQueueSendToBackFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK )
/**
* queue. h
* <pre>
portBASE_TYPE xQueueOverwriteFromISR(
xQueueHandle xQueue,
const void * pvItemToQueue,
portBASE_TYPE *pxHigherPriorityTaskWoken
);
* </pre>
*
* A version of xQueueOverwrite() that can be used from an interrupt service
* routine (ISR).
*
* Only for use with queues that can hold a single item - so the queue is either
* empty or full.
*
* Post an item on a queue. If the queue is already full then overwrite the
* value held in the queue. The item is queued by copy, not by reference.
*
* @param xQueue The handle to the queue on which the item is to be posted.
*
* @param pvItemToQueue A pointer to the item that is to be placed on the
* queue. The size of the items the queue will hold was defined when the
* queue was created, so this many bytes will be copied from pvItemToQueue
* into the queue storage area.
*
* @param pxHigherPriorityTaskWoken xQueueOverwriteFromISR() will set
* *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task
* to unblock, and the unblocked task has a priority higher than the currently
* running task. If xQueueSendFromISR() sets this value to pdTRUE then
* a context switch should be requested before the interrupt is exited.
*
* @return xQueueOverwriteFromISR() is a macro that calls
* xQueueGenericSendFromISR(), and therefore has the same return values as
* xQueueSendToFrontFromISR(). However, as xQueueOverwriteFromISR() will write
* to the queue even when the queue is full pdPASS will be returned in all cases
* (errQUEUE_FULL will never be returned).
*
* Example usage:
<pre>
xQueueHandle xQueue;
void vFunction( void *pvParameters )
{
// Create a queue to hold one unsigned long value. It is strongly
// recommended *not* to use xQueueOverwrite() on queues that can
// contain more than one value, and doing so will trigger an assertion
// if configASSERT() is defined.
xQueue = xQueueCreate( 1, sizeof( unsigned long ) );
}
void vAnInterruptHandler( void )
{
// xHigherPriorityTaskWoken must be set to pdFALSE before it is used.
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
unsigned long ulVarToSend, ulValReceived;
// Write the value 10 to the queue using xQueueOverwriteFromISR().
ulVarToSend = 10;
xQueueOverwriteFromISR( xQueue, &ulVarToSend, &xHigherPriorityTaskWoken );
// The queue is full, but calling xQueueOverwriteFromISR() again will still
// pass because the value held in the queue will be overwritten with the
// new value.
ulVarToSend = 100;
xQueueOverwrite( xQueue, &ulVarToSend, &xHigherPriorityTaskWoken );
// Reading from the queue will now return 100.
// ...
}
</pre>
* \defgroup xQueueOverwriteFromISR xQueueOverwriteFromISR
* \ingroup QueueManagement
*/
#define xQueueOverwriteFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueOVERWRITE )
/** /**
* queue. h * queue. h
* <pre> * <pre>

View File

@ -939,6 +939,7 @@ xQUEUE *pxQueue;
pxQueue = ( xQUEUE * ) xQueue; pxQueue = ( xQUEUE * ) xQueue;
configASSERT( pxQueue ); configASSERT( pxQueue );
configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );
configASSERT( !( ( xCopyPosition == queueOVERWRITE ) && ( pxQueue->uxLength != 1 ) ) );
/* Similar to xQueueGenericSend, except we don't block if there is no room /* Similar to xQueueGenericSend, except we don't block if there is no room
in the queue. Also we don't directly wake a task that was blocked on a in the queue. Also we don't directly wake a task that was blocked on a
@ -947,7 +948,7 @@ xQUEUE *pxQueue;
by this post). */ by this post). */
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
{ {
if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) )
{ {
traceQUEUE_SEND_FROM_ISR( pxQueue ); traceQUEUE_SEND_FROM_ISR( pxQueue );