From b3eb5c74f6471267135bdb4609905cf32107d5e3 Mon Sep 17 00:00:00 2001 From: richardbarry Date: Thu, 27 Jun 2013 14:25:17 +0000 Subject: [PATCH] Add xQueueOverwriteFromISR() and update the QueueOverwrite.c to demonstrate its use. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@1954 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- FreeRTOS/Demo/Common/Minimal/QueueOverwrite.c | 93 ++++++++++++++++--- FreeRTOS/Demo/Common/include/QueueOverwrite.h | 1 + FreeRTOS/Demo/WIN32-MSVC/main.c | 3 + FreeRTOS/Source/include/queue.h | 78 ++++++++++++++++ FreeRTOS/Source/queue.c | 3 +- 5 files changed, 165 insertions(+), 13 deletions(-) diff --git a/FreeRTOS/Demo/Common/Minimal/QueueOverwrite.c b/FreeRTOS/Demo/Common/Minimal/QueueOverwrite.c index e554201bd..e33dcdbff 100644 --- a/FreeRTOS/Demo/Common/Minimal/QueueOverwrite.c +++ b/FreeRTOS/Demo/Common/Minimal/QueueOverwrite.c @@ -98,18 +98,33 @@ static void prvQueueOverwriteTask( void *pvParameters ); prvQueueOverwriteTask() has not found any errors. */ 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 ) { - /* 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 ); } /*-----------------------------------------------------------*/ static void prvQueueOverwriteTask( void *pvParameters ) { -xQueueHandle xQueue; +xQueueHandle xTaskQueue; const unsigned portBASE_TYPE uxQueueLength = 1; 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 have a length of 1. */ - xQueue = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( unsigned long ) ); - configASSERT( xQueue ); + xTaskQueue = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( unsigned long ) ); + configASSERT( xTaskQueue ); for( ;; ) { /* The queue is empty. Writing to the queue then reading from the queue should return the item written. */ ulValue = 10; - xQueueOverwrite( xQueue, &ulValue ); + xQueueOverwrite( xTaskQueue, &ulValue ); ulValue = 0; - xQueueReceive( xQueue, &ulValue, qoDONT_BLOCK ); + xQueueReceive( xTaskQueue, &ulValue, qoDONT_BLOCK ); if( ulValue != 10 ) { @@ -141,27 +156,27 @@ unsigned long ulValue, ulStatus = pdPASS, x; for( x = 0; x < qoLOOPS; x++ ) { /* Write to the queue. */ - xQueueOverwrite( xQueue, &x ); + xQueueOverwrite( xTaskQueue, &x ); /* Check the value in the queue is that written, even though the queue was not necessarily empty. */ - xQueuePeek( xQueue, &ulValue, qoDONT_BLOCK ); + xQueuePeek( xTaskQueue, &ulValue, qoDONT_BLOCK ); if( ulValue != x ) { ulStatus = pdFAIL; } /* There should always be one item in the queue. */ - if( uxQueueMessagesWaiting( xQueue ) != uxQueueLength ) + if( uxQueueMessagesWaiting( xTaskQueue ) != uxQueueLength ) { ulStatus = pdFAIL; } } /* Empty the queue again. */ - xQueueReceive( xQueue, &ulValue, qoDONT_BLOCK ); + xQueueReceive( xTaskQueue, &ulValue, qoDONT_BLOCK ); - if( uxQueueMessagesWaiting( xQueue ) != 0 ) + if( uxQueueMessagesWaiting( xTaskQueue ) != 0 ) { ulStatus = pdFAIL; } @@ -180,7 +195,11 @@ portBASE_TYPE xIsQueueOverwriteTaskStillRunning( void ) { portBASE_TYPE xReturn; - if( ulLoopCounter > 0 ) + if( xISRTestStatus != pdPASS ) + { + xReturn = pdFAIL; + } + else if( ulLoopCounter > 0 ) { xReturn = pdPASS; } @@ -194,4 +213,54 @@ portBASE_TYPE 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; + } +} diff --git a/FreeRTOS/Demo/Common/include/QueueOverwrite.h b/FreeRTOS/Demo/Common/include/QueueOverwrite.h index c4fba5ffb..fc1231229 100644 --- a/FreeRTOS/Demo/Common/include/QueueOverwrite.h +++ b/FreeRTOS/Demo/Common/include/QueueOverwrite.h @@ -77,6 +77,7 @@ void vStartQueueOverwriteTask( unsigned portBASE_TYPE uxPriority ); portBASE_TYPE xIsQueueOverwriteTaskStillRunning( void ); +void vQueueOverwritePeriodicISRDemo( void ); #endif /* QUEUE_OVERWRITE_H */ diff --git a/FreeRTOS/Demo/WIN32-MSVC/main.c b/FreeRTOS/Demo/WIN32-MSVC/main.c index 0dc4dcd45..b57938c7b 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/main.c +++ b/FreeRTOS/Demo/WIN32-MSVC/main.c @@ -411,6 +411,9 @@ void vApplicationTickHook( void ) can be called from an ISR. */ 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 demonstrate using queue sets from an ISR. */ vQueueSetAccessQueueSetFromISR(); diff --git a/FreeRTOS/Source/include/queue.h b/FreeRTOS/Source/include/queue.h index f81a91fae..915e2ab99 100644 --- a/FreeRTOS/Source/include/queue.h +++ b/FreeRTOS/Source/include/queue.h @@ -1053,6 +1053,84 @@ void vQueueDelete( xQueueHandle xQueue ) PRIVILEGED_FUNCTION; */ #define xQueueSendToBackFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK ) +/** + * queue. h + *
+ portBASE_TYPE xQueueOverwriteFromISR(
+							  xQueueHandle xQueue,
+							  const void * pvItemToQueue,
+							  portBASE_TYPE *pxHigherPriorityTaskWoken
+						 );
+ * 
+ * + * 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: +
+
+ 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.
+
+	// ...
+}
+ 
+ * \defgroup xQueueOverwriteFromISR xQueueOverwriteFromISR + * \ingroup QueueManagement + */ +#define xQueueOverwriteFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueOVERWRITE ) + /** * queue. h *
diff --git a/FreeRTOS/Source/queue.c b/FreeRTOS/Source/queue.c
index cd1c8545e..4488169ea 100644
--- a/FreeRTOS/Source/queue.c
+++ b/FreeRTOS/Source/queue.c
@@ -939,6 +939,7 @@ xQUEUE *pxQueue;
 	pxQueue = ( xQUEUE * ) xQueue;
 	configASSERT( pxQueue );
 	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
 	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). */
 	uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
 	{
-		if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
+		if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) )
 		{
 			traceQUEUE_SEND_FROM_ISR( pxQueue );
 
-- 
2.39.5