From: richardbarry Date: Tue, 12 Feb 2013 10:09:36 +0000 (+0000) Subject: Improve QueueSet.c test coverage by reading the queue set from an ISR to force paths... X-Git-Tag: V7.4.0~9 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=debb00813774c36bd953c2182f26e1681f42bee2;p=freertos Improve QueueSet.c test coverage by reading the queue set from an ISR to force paths through the queue locking and unlocking. Add the FreeRTOS+Trace recorder into the Win32 MSVC demo. Added more functions, including the queue set functions, to the MPU port. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@1822 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- diff --git a/FreeRTOS/Demo/Common/Minimal/QueueSet.c b/FreeRTOS/Demo/Common/Minimal/QueueSet.c index 809aff1ed..59dbcd3d2 100644 --- a/FreeRTOS/Demo/Common/Minimal/QueueSet.c +++ b/FreeRTOS/Demo/Common/Minimal/QueueSet.c @@ -67,7 +67,7 @@ */ /* - * Demonstrates the creation an use of queue sets. + * Tests the use of queue sets. * * A receive task creates a number of queues and adds them to a queue set before * blocking on the queue set receive. A transmit task and (optionally) an @@ -76,11 +76,12 @@ * the queues and flags an error if the received message does not match that * expected. The task sends values in the range 0 to * queuesetINITIAL_ISR_TX_VALUE, and the ISR sends value in the range - * queuesetINITIAL_ISR_TX_VALUE to 0xffffffffUL; + * queuesetINITIAL_ISR_TX_VALUE to ULONG_MAX. */ /* Standard includes. */ #include +#include /* Kernel includes. */ #include "FreeRTOS.h" @@ -102,7 +103,7 @@ /* Messages are sent in incrementing order from both a task and an interrupt. The task sends values in the range 0 to 0xfffe, and the interrupt sends values -in the range of 0xffff to 0xffffffff; */ +in the range of 0xffff to ULONG_MAX. */ #define queuesetINITIAL_ISR_TX_VALUE 0xffffUL /* The priorities used in this demo. */ @@ -115,8 +116,13 @@ queuesetPRIORITY_CHANGE_LOOPS number of values are sent to a queue. */ #define queuesetPRIORITY_CHANGE_LOOPS 100UL /* The ISR sends to the queue every queuesetISR_TX_PERIOD ticks. */ -#define queuesetISR_TX_PERIOD ( 100UL ) +#define queuesetISR_TX_PERIOD 2//( 100UL ) +/* The allowable maximum deviation between a received value and the expected +received value. A deviation will occur when data is received from a queue +inside an ISR in between a task receiving from a queue and the task checking +the received value. */ +#define queuesetALLOWABLE_RX_DEVIATION 5 /* * The task that periodically sends to the queue set. */ @@ -127,6 +133,35 @@ static void prvQueueSetSendingTask( void *pvParameters ); */ static void prvQueueSetReceivingTask( void *pvParameters ); +/* + * Check the value received from a queue is the expected value. Some values + * originate from the send task, some values originate from the ISR, with the + * range of the value being used to distinguish between the two message + * sources. + */ +static void prvCheckReceivedValue( unsigned long ulReceived ); + +/* + * For purposes of test coverage, functions that read from and write to a + * queue set from an ISR respectively. + */ +static void prvReceiveFromQueueInSetFromISR( void ); +static void prvSendToQueueInSetFromISR( void ); + +/* + * Create the queues and add them to a queue set before resuming the Tx + * task. + */ +static void prvSetupTest( xTaskHandle xQueueSetSendingTask ); + +/* + * Checks a value received from a queue falls within the range of expected + * values. + */ +static portBASE_TYPE prvCheckReceivedValueWithinExpectedRange( unsigned long ulReceived, unsigned long ulExpectedReceived ); + +/*-----------------------------------------------------------*/ + /* The queues that are added to the set. */ static xQueueHandle xQueues[ queuesetNUM_QUEUES_IN_SET ] = { 0 }; @@ -166,8 +201,8 @@ xTaskHandle xQueueSetSendingTask; /* Create the two queues. The handle of the sending task is passed into the receiving task using the task parameter. The receiving task uses the handle to resume the sending task after it has created the queues. */ - xTaskCreate( prvQueueSetSendingTask, ( signed char * ) "Check", configMINIMAL_STACK_SIZE, NULL, queuesetMEDIUM_PRIORITY, &xQueueSetSendingTask ); - xTaskCreate( prvQueueSetReceivingTask, ( signed char * ) "Check", configMINIMAL_STACK_SIZE, ( void * ) xQueueSetSendingTask, queuesetMEDIUM_PRIORITY, NULL ); + xTaskCreate( prvQueueSetSendingTask, ( signed char * ) "SetTx", configMINIMAL_STACK_SIZE, NULL, queuesetMEDIUM_PRIORITY, &xQueueSetSendingTask ); + xTaskCreate( prvQueueSetReceivingTask, ( signed char * ) "SetRx", configMINIMAL_STACK_SIZE, ( void * ) xQueueSetSendingTask, queuesetMEDIUM_PRIORITY, NULL ); /* It is important that the sending task does not attempt to write to a queue before the queue has been created. It is therefore placed into the @@ -226,48 +261,6 @@ portBASE_TYPE xReturn = pdPASS, x; } /*-----------------------------------------------------------*/ -void vQueueSetWriteToQueueFromISR( void ) -{ -portBASE_TYPE x = 0; -static unsigned long ulCallCount = 0; - - /* xSetupComplete is set to pdTRUE when the queues have been created and - are available for use. */ - if( xSetupComplete == pdTRUE ) - { - /* It is intended that this function is called from the tick hook - function, so each call is one tick period apart. */ - ulCallCount++; - if( ulCallCount > queuesetISR_TX_PERIOD ) - { - ulCallCount = 0; - - /* Look for a queue that can be written to. */ - for( x = 0; x < queuesetNUM_QUEUES_IN_SET; x++ ) - { - if( xQueues[ x ] != NULL ) - { - /* xQueues[ x ] can be written to. Send the next value. */ - if( xQueueSendFromISR( xQueues[ x ], ( void * ) &ulISRTxValue, NULL ) == pdPASS ) - { - ulISRTxValue++; - - /* If the Tx value has wrapped then set it back to its - initial value. */ - if( ulISRTxValue == 0UL ) - { - ulISRTxValue = queuesetINITIAL_ISR_TX_VALUE; - } - } - - break; - } - } - } - } -} -/*-----------------------------------------------------------*/ - static void prvQueueSetSendingTask( void *pvParameters ) { unsigned long ulTaskTxValue = 0; @@ -299,41 +292,6 @@ unsigned portBASE_TYPE uxPriority = queuesetMEDIUM_PRIORITY, ulLoops = 0; xQueueSetTasksStatus = pdFAIL; } - /* Attempt to remove the queue from a queue set it does not belong - to (NULL being passed as the queue set in this case). */ - if( xQueueRemoveFromQueueSet( xQueueInUse, NULL ) != pdFAIL ) - { - /* It is not possible to successfully remove a queue from a queue - set it does not belong to. */ - xQueueSetTasksStatus = pdFAIL; - } - - /* Mark the space in the array of queues as being empty before actually - removing the queue from the queue set. This is to prevent the code - that accesses the queue set from an interrupt from attempting to access - a queue that is no longer in the set. */ - xQueues[ xQueueToWriteTo ] = 0; - - /* Attempt to remove the queue from the queue set it does belong to. */ - if( xQueueRemoveFromQueueSet( xQueueInUse, xQueueSet ) != pdPASS ) - { - /* It should be possible to remove the queue from the queue set it - does belong to. */ - xQueueSetTasksStatus = pdFAIL; - } - - /* Add the queue back before cycling back to run again. */ - if( xQueueAddToQueueSet( xQueueInUse, xQueueSet ) != pdPASS ) - { - /* If the queue was successfully removed from the queue set then it - should be possible to add it back in again. */ - xQueueSetTasksStatus = pdFAIL; - } - - /* Now the queue is back in the set it is ok for the interrupt that - writes to the queues to access it again. */ - xQueues[ xQueueToWriteTo ] = xQueueInUse; - ulTaskTxValue++; /* If the Tx value has reached the range used by the ISR then set it @@ -363,56 +321,21 @@ unsigned portBASE_TYPE uxPriority = queuesetMEDIUM_PRIORITY, ulLoops = 0; static void prvQueueSetReceivingTask( void *pvParameters ) { -unsigned long ulReceived, ulExpectedReceivedFromTask = 0, ulExpectedReceivedFromISR = queuesetINITIAL_ISR_TX_VALUE; +unsigned long ulReceived; xQueueHandle xActivatedQueue; -portBASE_TYPE x; xTaskHandle xQueueSetSendingTask; /* The handle to the sending task is passed in using the task parameter. */ xQueueSetSendingTask = ( xTaskHandle ) pvParameters; - /* Ensure the queues are created and the queue set configured before the - sending task is unsuspended. - - First Create the queue set such that it will be able to hold a message for - every space in every queue in the set. */ - xQueueSet = xQueueSetCreate( queuesetNUM_QUEUES_IN_SET * queuesetQUEUE_LENGTH ); - - for( x = 0; x < queuesetNUM_QUEUES_IN_SET; x++ ) - { - /* Create the queue and add it to the set. The queue is just holding - unsigned long value. */ - xQueues[ x ] = xQueueCreate( queuesetQUEUE_LENGTH, sizeof( unsigned long ) ); - configASSERT( xQueues[ x ] ); - if( xQueueAddToQueueSet( xQueues[ x ], xQueueSet ) != pdPASS ) - { - xQueueSetTasksStatus = pdFAIL; - } - - /* The queue has now been added to the queue set and cannot be added to - another. */ - if( xQueueAddToQueueSet( xQueues[ x ], xQueueSet ) != pdFAIL ) - { - xQueueSetTasksStatus = pdFAIL; - } - } - - /* The task that sends to the queues is not running yet, so attempting to - read from the queue set should fail, resulting in xActivatedQueue being set - to NULL. */ - xActivatedQueue = xQueueBlockMultiple( xQueueSet, queuesetSHORT_DELAY ); - configASSERT( xActivatedQueue == NULL ); - - /* Resume the task that writes to the queues. */ - vTaskResume( xQueueSetSendingTask ); - - /* Let the ISR access the queues also. */ - xSetupComplete = pdTRUE; + /* Create the queues and add them to the queue set before resuming the Tx + task. */ + prvSetupTest( xQueueSetSendingTask ); for( ;; ) { /* Wait for a message to arrive on one of the queues in the set. */ - xActivatedQueue = xQueueBlockMultiple( xQueueSet, portMAX_DELAY ); + xActivatedQueue = xQueueSelectFromSet( xQueueSet, portMAX_DELAY ); configASSERT( xActivatedQueue ); if( xActivatedQueue == NULL ) @@ -430,58 +353,266 @@ xTaskHandle xQueueSetSendingTask; xQueueSetTasksStatus = pdFAIL; } - /* If the received value is equal to or greater than - queuesetINITIAL_ISR_TX_VALUE then it was sent by an ISR. */ - if( ulReceived >= queuesetINITIAL_ISR_TX_VALUE ) + /* Ensure the value received was the value expected. This function + manipulates file scope data and is also called from an ISR, hence + the critical section. */ + taskENTER_CRITICAL(); { - /* The value was sent from the ISR. Check it against its - expected value. */ - configASSERT( ulReceived == ulExpectedReceivedFromISR ); - if( ulReceived != ulExpectedReceivedFromISR ) - { - xQueueSetTasksStatus = pdFAIL; - } - else - { - /* It is expected to receive an incrementing value. */ - ulExpectedReceivedFromISR++; - - /* If the expected value has wrapped then set it back to - its initial value. */ - if( ulExpectedReceivedFromISR == 0 ) - { - ulExpectedReceivedFromISR = queuesetINITIAL_ISR_TX_VALUE; - } - } + prvCheckReceivedValue( ulReceived ); + } + taskEXIT_CRITICAL(); + } + + if( xQueueSetTasksStatus == pdPASS ) + { + ulCycleCounter++; + } + } +} +/*-----------------------------------------------------------*/ + +void vQueueSetAccessQueueSetFromISR( void ) +{ +static unsigned long ulCallCount = 0; + + /* xSetupComplete is set to pdTRUE when the queues have been created and + are available for use. */ + if( xSetupComplete == pdTRUE ) + { + /* It is intended that this function is called from the tick hook + function, so each call is one tick period apart. */ + ulCallCount++; + if( ulCallCount > queuesetISR_TX_PERIOD ) + { + ulCallCount = 0; + + /* First attempt to read from the queue set. */ + prvReceiveFromQueueInSetFromISR(); + + /* Then write to the queue set. */ + prvSendToQueueInSetFromISR(); + } + } +} +/*-----------------------------------------------------------*/ + +static void prvCheckReceivedValue( unsigned long ulReceived ) +{ +static unsigned long ulExpectedReceivedFromTask = 0, ulExpectedReceivedFromISR = queuesetINITIAL_ISR_TX_VALUE; + + /* Values are received in tasks and interrupts. It is likely that the + receiving task will sometimes get preempted by the receiving interrupt + between reading a value from the queue and calling this function. When + that happens, if the receiving interrupt calls this function the values + will get passed into this function slightly out of order. For that + reason the value passed in is tested against a small range of expected + values, rather than a single absolute value. To make the range testing + easier values in the range limits are ignored. */ + + /* If the received value is equal to or greater than + queuesetINITIAL_ISR_TX_VALUE then it was sent by an ISR. */ + if( ulReceived >= queuesetINITIAL_ISR_TX_VALUE ) + { + /* The value was sent from the ISR. */ + if( ( ulReceived - queuesetINITIAL_ISR_TX_VALUE ) < queuesetALLOWABLE_RX_DEVIATION ) + { + /* The value received is at the lower limit of the expected range. + Don't test it and expect to receive one higher next time. */ + ulExpectedReceivedFromISR++; + } + else if( ( ULONG_MAX - ulReceived ) <= queuesetALLOWABLE_RX_DEVIATION ) + { + /* The value received is at the higher limit of the expected range. + Don't test it and expect to wrap soon. */ + ulExpectedReceivedFromISR = queuesetINITIAL_ISR_TX_VALUE; + } + else + { + /* Check the value against its expected value range. */ + if( prvCheckReceivedValueWithinExpectedRange( ulReceived, ulExpectedReceivedFromISR ) != pdPASS ) + { + xQueueSetTasksStatus = pdFAIL; + } + else + { + /* It is expected to receive an incrementing value. */ + ulExpectedReceivedFromISR++; + } + } + } + else + { + /* The value was sent from the Tx task. */ + if( ulReceived < queuesetALLOWABLE_RX_DEVIATION ) + { + /* The value received is at the lower limit of the expected range. + Don't test it, and expect to receive one higher next time. */ + ulExpectedReceivedFromTask++; + } + else if( ( ( queuesetINITIAL_ISR_TX_VALUE - 1 ) - ulReceived ) <= queuesetALLOWABLE_RX_DEVIATION ) + { + /* The value received is at the higher limit of the expected range. + Don't test it and expect to wrap soon. */ + ulExpectedReceivedFromTask = 0; + } + else + { + /* Check the value against its expected value range. */ + if( prvCheckReceivedValueWithinExpectedRange( ulReceived, ulExpectedReceivedFromTask ) != pdPASS ) + { + xQueueSetTasksStatus = pdFAIL; } else { - /* The value was sent from the Tx task. Check it against its - expected value. */ - configASSERT( ulReceived == ulExpectedReceivedFromTask ); - if( ulReceived != ulExpectedReceivedFromTask ) - { - xQueueSetTasksStatus = pdFAIL; - } - else - { - /* It is expected to receive an incrementing value. */ - ulExpectedReceivedFromTask++; - - /* If the expected value has reached the range of values - used by the ISR then set it back to 0. */ - if( ulExpectedReceivedFromTask >= queuesetINITIAL_ISR_TX_VALUE ) - { - ulExpectedReceivedFromTask = 0; - } - } + /* It is expected to receive an incrementing value. */ + ulExpectedReceivedFromTask++; } } + } +} +/*-----------------------------------------------------------*/ + +static portBASE_TYPE prvCheckReceivedValueWithinExpectedRange( unsigned long ulReceived, unsigned long ulExpectedReceived ) +{ +portBASE_TYPE xReturn = pdPASS; + + if( ulReceived > ulExpectedReceived ) + { + configASSERT( ( ulReceived - ulExpectedReceived ) <= queuesetALLOWABLE_RX_DEVIATION ); + if( ( ulReceived - ulExpectedReceived ) > queuesetALLOWABLE_RX_DEVIATION ) + { + xReturn = pdFALSE; + } + } + else + { + configASSERT( ( ulExpectedReceived - ulReceived ) <= queuesetALLOWABLE_RX_DEVIATION ); + if( ( ulExpectedReceived - ulReceived ) > queuesetALLOWABLE_RX_DEVIATION ) + { + xReturn = pdFALSE; + } + } - if( xQueueSetTasksStatus == pdPASS ) + return xReturn; +} +/*-----------------------------------------------------------*/ + +static void prvReceiveFromQueueInSetFromISR( void ) +{ +xQueueSetMemberHandle xActivatedQueue; +unsigned long ulReceived; + + /* See if any of the queues in the set contain data. */ + xActivatedQueue = xQueueSelectFromSetFromISR( xQueueSet ); + + if( xActivatedQueue != NULL ) + { + /* Reading from the queue for test purposes only. */ + if( xQueueReceiveFromISR( xActivatedQueue, &ulReceived, NULL ) != pdPASS ) { - ulCycleCounter++; + /* Data should have been available as the handle was returned from + xQueueSelectFromSetFromISR(). */ + xQueueSetTasksStatus = pdFAIL; + } + + /* Ensure the value received was the value expected. */ + prvCheckReceivedValue( ulReceived ); + } +} +/*-----------------------------------------------------------*/ + +static void prvSendToQueueInSetFromISR( void ) +{ +static portBASE_TYPE xQueueToWriteTo = 0; + + if( xQueueSendFromISR( xQueues[ xQueueToWriteTo ], ( void * ) &ulISRTxValue, NULL ) == pdPASS ) + { + ulISRTxValue++; + + /* If the Tx value has wrapped then set it back to its + initial value. */ + if( ulISRTxValue == 0UL ) + { + ulISRTxValue = queuesetINITIAL_ISR_TX_VALUE; + } + + /* Use a different queue next time. */ + xQueueToWriteTo++; + if( xQueueToWriteTo >= queuesetNUM_QUEUES_IN_SET ) + { + xQueueToWriteTo = 0; } } } +/*-----------------------------------------------------------*/ + +static void prvSetupTest( xTaskHandle xQueueSetSendingTask ) +{ +portBASE_TYPE x; +xQueueSetMemberHandle xActivatedQueue; + + /* Ensure the queues are created and the queue set configured before the + sending task is unsuspended. + + First Create the queue set such that it will be able to hold a message for + every space in every queue in the set. */ + xQueueSet = xQueueCreateSet( queuesetNUM_QUEUES_IN_SET * queuesetQUEUE_LENGTH ); + + for( x = 0; x < queuesetNUM_QUEUES_IN_SET; x++ ) + { + /* Create the queue and add it to the set. The queue is just holding + unsigned long value. */ + xQueues[ x ] = xQueueCreate( queuesetQUEUE_LENGTH, sizeof( unsigned long ) ); + configASSERT( xQueues[ x ] ); + if( xQueueAddToSet( xQueues[ x ], xQueueSet ) != pdPASS ) + { + xQueueSetTasksStatus = pdFAIL; + } + else + { + /* The queue has now been added to the queue set and cannot be added to + another. */ + if( xQueueAddToSet( xQueues[ x ], xQueueSet ) != pdFAIL ) + { + xQueueSetTasksStatus = pdFAIL; + } + } + } + + /* Attempt to remove a queue from a queue set it does not belong + to (NULL being passed as the queue set in this case). */ + if( xQueueRemoveFromSet( xQueues[ 0 ], NULL ) != pdFAIL ) + { + /* It is not possible to successfully remove a queue from a queue + set it does not belong to. */ + xQueueSetTasksStatus = pdFAIL; + } + + /* Attempt to remove a queue from the queue set it does belong to. */ + if( xQueueRemoveFromSet( xQueues[ 0 ], xQueueSet ) != pdPASS ) + { + /* It should be possible to remove the queue from the queue set it + does belong to. */ + xQueueSetTasksStatus = pdFAIL; + } + /* Add the queue back again before starting the dynamic tests. */ + if( xQueueAddToSet( xQueues[ 0 ], xQueueSet ) != pdPASS ) + { + /* If the queue was successfully removed from the queue set then it + should be possible to add it back in again. */ + xQueueSetTasksStatus = pdFAIL; + } + + /* The task that sends to the queues is not running yet, so attempting to + read from the queue set should fail, resulting in xActivatedQueue being set + to NULL. */ + xActivatedQueue = xQueueSelectFromSet( xQueueSet, queuesetSHORT_DELAY ); + configASSERT( xActivatedQueue == NULL ); + + /* Resume the task that writes to the queues. */ + vTaskResume( xQueueSetSendingTask ); + + /* Let the ISR access the queues also. */ + xSetupComplete = pdTRUE; +} diff --git a/FreeRTOS/Demo/Common/include/QueueSet.h b/FreeRTOS/Demo/Common/include/QueueSet.h index eb203ec0e..afd4839c1 100644 --- a/FreeRTOS/Demo/Common/include/QueueSet.h +++ b/FreeRTOS/Demo/Common/include/QueueSet.h @@ -71,7 +71,7 @@ void vStartQueueSetTasks( void ); portBASE_TYPE xAreQueueSetTasksStillRunning( void ); -void vQueueSetWriteToQueueFromISR( void ); +void vQueueSetAccessQueueSetFromISR( void ); #endif /* QUEUE_WAIT_MULTIPLE_H */ diff --git a/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h b/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h index 0c548e3d5..31bb3115e 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h +++ b/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h @@ -92,7 +92,6 @@ #define configIDLE_SHOULD_YIELD 1 #define configUSE_CO_ROUTINES 0 #define configUSE_MUTEXES 1 -#define configGENERATE_RUN_TIME_STATS 0 #define configCHECK_FOR_STACK_OVERFLOW 0 #define configUSE_RECURSIVE_MUTEXES 1 #define configQUEUE_REGISTRY_SIZE 0 @@ -111,6 +110,13 @@ #define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) +/* Run time stats gathering definitions. */ +unsigned long ulGetRunTimeCounterValue( void ); +void vConfigureTimerForRunTimeStats( void ); +#define configGENERATE_RUN_TIME_STATS 1 +#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() vConfigureTimerForRunTimeStats() +#define portGET_RUN_TIME_COUNTER_VALUE() ulGetRunTimeCounterValue() + /* Co-routine definitions. */ #define configUSE_CO_ROUTINES 0 #define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) @@ -140,5 +146,7 @@ version of the Win32 simulator projects. It will be ignored in the GCC version. */ #define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +/* Include the FreeRTOS+Trace recorder hooks. */ +#include "trcHooks.h" #endif /* FREERTOS_CONFIG_H */ diff --git a/FreeRTOS/Demo/WIN32-MSVC/Run-time-stats-utils.c b/FreeRTOS/Demo/WIN32-MSVC/Run-time-stats-utils.c new file mode 100644 index 000000000..7f7a80b06 --- /dev/null +++ b/FreeRTOS/Demo/WIN32-MSVC/Run-time-stats-utils.c @@ -0,0 +1,143 @@ +/* + FreeRTOS V7.3.0 - Copyright (C) 2012 Real Time Engineers Ltd. + + FEATURES AND PORTS ARE ADDED TO FREERTOS ALL THE TIME. PLEASE VISIT + http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS tutorial books are available in pdf and paperback. * + * Complete, revised, and edited pdf reference manuals are also * + * available. * + * * + * Purchasing FreeRTOS documentation will not only help you, by * + * ensuring you get running as quickly as possible and with an * + * in-depth knowledge of how to use FreeRTOS, it will also help * + * the FreeRTOS project to continue with its mission of providing * + * professional grade, cross platform, de facto standard solutions * + * for microcontrollers - completely free of charge! * + * * + * >>> See http://www.FreeRTOS.org/Documentation for details. <<< * + * * + * Thank you for using FreeRTOS, and thank you for your support! * + * * + *************************************************************************** + + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation AND MODIFIED BY the FreeRTOS exception. + >>>NOTE<<< The modification to the GPL is included to allow you to + distribute a combined work that includes FreeRTOS without being obliged to + provide the source code for proprietary components outside of the FreeRTOS + kernel. FreeRTOS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. You should have received a copy of the GNU General Public + License and the FreeRTOS license exception along with FreeRTOS; if not it + can be viewed here: http://www.freertos.org/a00114.html and also obtained + by writing to Richard Barry, contact details for whom are available on the + FreeRTOS WEB site. + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + + http://www.FreeRTOS.org - Documentation, training, latest versions, license + and contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool. + + Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell + the code with commercial support, indemnification, and middleware, under + the OpenRTOS brand: http://www.OpenRTOS.com. High Integrity Systems also + provide a safety engineered and independently SIL3 certified version under + the SafeRTOS brand: http://www.SafeRTOS.com. +*/ + +/* + * Utility functions required to gather run time statistics. See: + * http://www.freertos.org/rtos-run-time-stats.html + * + * Note that this is a simulated port, where simulated time is a lot slower than + * real time, therefore the run time counter values have no real meaningful + * units. + * + * Also note that it is assumed this demo is going to be used for short periods + * of time only, and therefore timer overflows are not handled. +*/ + +/* FreeRTOS includes. */ +#include + +/* FreeRTOS+Trace includes. */ +#include "trcUser.h" + +/* Variables used in the creation of the run time stats time base. Run time +stats record how much time each task spends in the Running state. */ +static long long llInitialRunTimeCounterValue = 0LL, llTicksPerHundedthMillisecond = 0LL; + +/*-----------------------------------------------------------*/ + +void vConfigureTimerForRunTimeStats( void ) +{ +LARGE_INTEGER liPerformanceCounterFrequency, liInitialRunTimeValue; + + /* Initialise the variables used to create the run time stats time base. + Run time stats record how much time each task spends in the Running + state. */ + + if( QueryPerformanceFrequency( &liPerformanceCounterFrequency ) == 0 ) + { + llTicksPerHundedthMillisecond = 1; + } + else + { + /* How many times does the performance counter increment in 1/100th + millisecond. */ + llTicksPerHundedthMillisecond = liPerformanceCounterFrequency.QuadPart / 100000LL; + + /* What is the performance counter value now, this will be subtracted + from readings taken at run time. */ + QueryPerformanceCounter( &liInitialRunTimeValue ); + llInitialRunTimeCounterValue = liInitialRunTimeValue.QuadPart; + } +} +/*-----------------------------------------------------------*/ + +unsigned long ulGetRunTimeCounterValue( void ) +{ +LARGE_INTEGER liCurrentCount; +unsigned long ulReturn; + + /* What is the performance counter value now? */ + QueryPerformanceCounter( &liCurrentCount ); + + /* Subtract the performance counter value reading taken when the + application started to get a count from that reference point, then + scale to (simulated) 1/100ths of a millisecond. */ + if( llTicksPerHundedthMillisecond == 0 ) + { + /* The trace macros are probably calling this function before the + scheduler has been started. */ + ulReturn = 0; + } + else + { + ulReturn = ( unsigned long ) ( ( liCurrentCount.QuadPart - llInitialRunTimeCounterValue ) / llTicksPerHundedthMillisecond ); + } + + return ulReturn; +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Demo/WIN32-MSVC/Trace_Recorder_Configuration/trcConfig.h b/FreeRTOS/Demo/WIN32-MSVC/Trace_Recorder_Configuration/trcConfig.h new file mode 100644 index 000000000..19b38d729 --- /dev/null +++ b/FreeRTOS/Demo/WIN32-MSVC/Trace_Recorder_Configuration/trcConfig.h @@ -0,0 +1,411 @@ +/******************************************************************************* + * FreeRTOS+Trace v2.2.2 Recorder Library + * Percepio AB, www.percepio.se + * + * trcConfig.h + * + * Configuration parameters for the trace recorder library. Before using the + * trace recorder library, please check that the default settings are + * appropriate for your system, and if necessary adjust these. Most likely, you + * will need to adjust the NTask, NISR, NQueue, NMutex and NSemaphore values to + * reflect the number of such objects in your system. These may be + * overapproximated, although larger values values implies more RAM usage. + * + * Terms of Use + * This software is copyright Percepio AB. The recorder library is free for + * use together with Percepio products. You may distribute the recorder library + * in its original form, including modifications in trcPort.c and trcPort.h + * given that these modification are clearly marked as your own modifications + * and documented in the initial comment section of these source files. + * This software is the intellectual property of Percepio AB and may not be + * sold or in other ways commercially redistributed without explicit written + * permission by Percepio AB. + * + * Disclaimer + * The trace tool and recorder library is being delivered to you AS IS and + * Percepio AB makes no warranty as to its use or performance. Percepio AB does + * not and cannot warrant the performance or results you may obtain by using the + * software or documentation. Percepio AB make no warranties, express or + * implied, as to noninfringement of third party rights, merchantability, or + * fitness for any particular purpose. In no event will Percepio AB, its + * technology partners, or distributors be liable to you for any consequential, + * incidental or special damages, including any lost profits or lost savings, + * even if a representative of Percepio AB has been advised of the possibility + * of such damages, or for any claim by any third party. Some jurisdictions do + * not allow the exclusion or limitation of incidental, consequential or special + * damages, or the exclusion of implied warranties or limitations on how long an + * implied warranty may last, so the above limitations may not apply to you. + * + * FreeRTOS+Trace is available as Free Edition and in two premium editions. + * You may use the premium features during 30 days for evaluation. + * Download FreeRTOS+Trace at http://www.percepio.se/index.php?page=downloads + * + * Copyright Percepio AB, 2012. + * www.percepio.se + ******************************************************************************/ + +#ifndef TRCCONFIG_H +#define TRCCONFIG_H + +/******************************************************************************* + * CONFIGURATION RELATED TO CAPACITY AND ALLOCATION + ******************************************************************************/ + +/******************************************************************************* + * EVENT_BUFFER_SIZE + * + * Macro which should be defined as an integer value. + * + * This defines the capacity of the event buffer, i.e., the number of records + * it may store. Each registered event typically use one record (4 byte), but + * vTracePrintF may use multiple records depending on the number of data args. + ******************************************************************************/ + +#if WIN32 + #define EVENT_BUFFER_SIZE 3000 +#else + #define EVENT_BUFFER_SIZE 1000 /* Adjust wrt. to available RAM */ +#endif + +/******************************************************************************* + * SYMBOL_TABLE_SIZE + * + * Macro which should be defined as an integer value. + * + * This defines the capacity of the symbol table, in bytes. This symbol table + * stores User Events labels and names of deleted tasks, queues, or other kernel + * objects. Note that the names of active objects not stored here but in the + * Object Table. Thus, if you don't use User Events or delete any kernel + * objects you set this to zero (0) to minimize RAM usage. + ******************************************************************************/ +#define SYMBOL_TABLE_SIZE 1000 + +/******************************************************************************* + * NTask, NISR, NQueue, NSemaphore, NMutex + * + * A group of Macros which should be defined as an integer value of zero (0) + * or larger. + * + * This defines the capacity of the Object Property Table - the maximum number + * of objects active at any given point within each object class. + * + * NOTE: In case objects are deleted and created during runtime, this setting + * does not limit the total amount of objects, only the number of concurrently + * active objects. + * + * Using too small values will give an error message through the vTraceError + * routine, which makes the error message appear when opening the trace data + * in FreeRTOS+Trace. If you are using the recorder status monitor task, + * any error messages are displayed in console prints, assuming that the + * print macro has been defined properly (vConsolePrintMessage). + * + * NOTE 2: If you include the monitor task (USE_TRACE_PROGRESS_MONITOR_TASK) + * make sure to dimension NTask with this task accounted for. + * + * Also remember to account for all tasks created by FreeRTOS, such as the + * IDLE task, the FreeRTOS timer task, and any tasks created by other 3rd party + * software components, such as communication stacks. + * Moreover, one task slot is used to indicate "(startup)", i.e., a "task" that + * represent the time before the first task starts. NTask should thus be at + * least 2-3 slots larger than your application task count. + * + * NOTE 3: The FreeRTOS timer task creates a Queue, that should be accounted + * for in NQueue. + ******************************************************************************/ +#define NTask 500 +#define NISR 500 +#define NQueue 500 +#define NSemaphore 500 +#define NMutex 500 + +/* Maximum object name length for each class (includes zero termination) */ +#define NameLenTask configMAX_TASK_NAME_LEN +#define NameLenISR 10 +#define NameLenQueue 15 +#define NameLenSemaphore 15 +#define NameLenMutex 15 + +/****************************************************************************** + * TRACE_DESCRIPTION + * + * Macro which should be defined as a string. + * + * This string is stored in the trace and displayed in FreeRTOS+Trace. Can be + * used to store, e.g., system version or build date. This is also used to store + * internal error messages from the recorder, which if occurs overwrites the + * value defined here. This may be maximum 256 chars. + *****************************************************************************/ +#define TRACE_DESCRIPTION "FreeRTOS+Trace Demo" + +/****************************************************************************** + * TRACE_DESCRIPTION_MAX_LENGTH + * + * The maximum length (including zero termination) for the TRACE_DESCRIPTION + * string. Since this string also is used for internal error messages from the + * recorder do not make it too short, as this may truncate the error messages. + * Default is 80. + * Maximum allowed length is 256 - the trace will fail to load if longer. + *****************************************************************************/ +#define TRACE_DESCRIPTION_MAX_LENGTH 80 + + +/****************************************************************************** + * TRACE_DATA_ALLOCATION + * + * This defines how to allocate the recorder data structure, i.e., using a + * static declaration or using a dynamic allocation in runtime (malloc). + * + * Should be one of these two options: + * - TRACE_DATA_ALLOCATION_STATIC (default) + * - TRACE_DATA_ALLOCATION_DYNAMIC + * + * Using static allocation has the benefits of compile-time errors if the buffer + * is too large (too large constants in trcConfig.h) and no need to call the + * initialization routine (xTraceInitTraceData). + * + * Using dynamic allocation may give more flexibility in some cases. + *****************************************************************************/ + +#define TRACE_DATA_ALLOCATION TRACE_DATA_ALLOCATION_STATIC + + +/****************************************************************************** + * CONFIGURATION REGARDING WHAT CODE/FEATURES TO INCLUDE + *****************************************************************************/ + +/****************************************************************************** + * INCLUDE_USER_EVENTS + * + * Macro which should be defined as either zero (0) or one (1). + * Default is 1. + * + * If this is zero (0) the code for creating User Events is excluded to + * reduce code size. User Events are application-generated events, like + * "printf" but for the trace log instead of console output. User Events are + * much faster than a printf and can therefore be used in timing critical code. + * See vTraceUserEvent() and vTracePrintF() in trcUser.h + * + * Note that FreeRTOS+Trace Standard Edition or Professional Edition is required + * for User Events, they are not displayed in FreeRTOS+Trace Free Edition. + *****************************************************************************/ +#define INCLUDE_USER_EVENTS 1 + +/***************************************************************************** + * INCLUDE_ISR_TRACING + * + * Macro which should be defined as either zero (0) or one (1). + * Default is 1. + * + * If this is zero (0), the code for recording Interrupt Service Routines is + * excluded to reduce code size. Note, recording ISRs require that you insert + * calls to vTraceStoreISRBegin and vTraceStoreISREnd in your interrupt handlers. + * There is no automatic recording of ISRs like for task scheduling, since + * FreeRTOS does not have a central interrupt dispatcher. + *****************************************************************************/ +#define INCLUDE_ISR_TRACING 1 + +/****************************************************************************** + * INCLUDE_OBJECT_DELETE + * + * Macro which should be defined as either zero (0) or one (1). + * Default is 1. + * + * This must be enabled (1) if tasks, queues or other + * traced kernel objects are deleted at runtime, e.g., using vTaskDelete or + * vQueueDelete. If no deletes are made, this can be set to 0 in order to + * exclude the delete-handling code. + *****************************************************************************/ +#define INCLUDE_OBJECT_DELETE 1 + +/****************************************************************************** + * CONFIGURATION RELATED TO BEHAVIOR + *****************************************************************************/ + +/****************************************************************************** + * RECORDER_STORE_MODE + * + * Macro which should be defined as one of: + * - STORE_MODE_RING_BUFFER + * - STORE_MODE_STOP_WHEN_FULL + * Default is STORE_MODE_RING_BUFFER. + * + * With RECORDER_STORE_MODE set to STORE_MODE_RING_BUFFER, the events are stored + * in a ring buffer, i.e., where the oldest events are overwritten when the + * buffer becomes full. This allows you to get the last events leading up to an + * interesting state, e.g., an error, without having a large trace buffer for + * string the whole run since startup. In this mode, the recorder can run + * "forever" as the buffer never gets full, i.e., in the sense that it always + * has room for more events. + * + * To fetch the trace in mode STORE_MODE_RING_BUFFER, you need to first halt the + * system using your debugger and then do a RAM dump, or to explicitly stop the + * recorder using vTraceStop() and then store/upload the trace data using a + * FreeRTOS task that you need to provide yourself. The trace data is found in + * the struct RecorderData, initialized in trcBase.c. + * + * Note that, if you upload the trace using a RAM dump, i.e., when the system is + * halted on a breakpoint or by a debugger command, there is no need to stop the + * recorder first. + * + * When RECORDER_STORE_MODE is STORE_MODE_STOP_WHEN_FULL, the recording is + * stopped when the buffer becomes full. When the recorder stops itself this way + * vTracePortEnd() is called which allows for custom actions, such as triggering + * a task that stores the trace buffer, i.e., in case taking a RAM dump + * using an on-chip debugger is not possible. In the Windows port, vTracePortEnd + * saves the trace to file directly, but this is not recommended in a real-time + * system since the scheduler is blocked during the processing of vTracePortEnd. + *****************************************************************************/ +#define RECORDER_STORE_MODE STORE_MODE_RING_BUFFER +/*#define RECORDER_STORE_MODE STORE_MODE_STOP_WHEN_FULL*/ + +/****************************************************************************** + * STOP_AFTER_N_EVENTS + * + * Macro which should be defined as an integer value, or not defined. + * Default is -1 + * + * STOP_AFTER_N_EVENTS is intended for tests of the ring buffer mode (when + * RECORDER_STORE_MODE is STORE_MODE_RING_BUFFER). It stops the recording when + * the specified number of events has been observed. This value can be larger + * than the buffer size, to allow for test of the "wrapping around" that occurs + * in ring buffer mode . A negative value (or no definition of this macro) + * disables this feature. + *****************************************************************************/ +#define STOP_AFTER_N_EVENTS -1 + +/****************************************************************************** + * USE_IMPLICIT_IFE_RULES + * + * Macro which should be defined as either zero (0) or one (1). + * Default is 1. + * + * ### Instance Finish Events (IFE) ### + * + * For tasks with "infinite" main loops (non-terminating tasks), the concept + * of a task instance has no clear definition, it is an application-specific + * thing. FreeRTOS+Trace allows you to define Instance Finish Events (IFEs), + * which marks the point in a cyclic task when the "task instance" ends. + * The IFE is a blocking kernel call, typically in the main loop of a task + * which typically reads a message queue, waits for a semaphore or performs + * an explicit delay. + * + * If USE_IMPLICIT_IFE_RULES is one (1), the following FreeRTOS kernel calls + * are considered by default to be IFEs (Implicit IFEs): + * - vTaskDelay + * - vTaskDelayUntil + * - vTaskSuspend + * - xQueueReceive (blocking cases only) + * - xSemaphoreTake (blocking cases only) + * + * However, Implicit IFEs only applies to blocking kernel calls. If an + * xQueueReceive reads a message without blocking, it does not create a new + * instance since no blocking occurred. + * + * Moreover, the actual IFE might sometimes be another blocking call such as + * xQueueSend or xSemaphoreGive. We therefore allow for user-defined + * Explicit IFEs by calling + * + * vTraceTaskInstanceIsFinished() + * + * right before the kernel call considered as IFE. This does not create an + * additional event but instead stores the service code and object handle + * of the IFE call as properties of the task. + * + * If using Explicit IFEs and the task also calls an Implicit IFE like + * vTaskDelay, this may result in additional incorrect task instances. + * This is solved by disabling the Implicit IFEs for the task, by adding + * a call to + * + * vTraceTaskSkipDefaultInstanceFinishedEvents() + * + * in the very beginning of that task. This allows you to combine Explicit IFEs + * for some tasks with Implicit IFEs for the rest of the tasks, if + * USE_IMPLICIT_IFE_RULES is 1. + * + * By setting USE_IMPLICIT_IFE_RULES to zero (0), the implicit IFEs are disabled + * for all tasks. Tasks will then be considered to have a single instance only, + * covering all execution fragments, unless you define an explicit IFE in each + * task by calling vTraceTaskInstanceIsFinished before the blocking call. + *****************************************************************************/ +#define USE_IMPLICIT_IFE_RULES 1 + +/****************************************************************************** + * INCLUDE_SAVE_TO_FILE + * + * Macro which should be defined as either zero (0) or one (1). + * Default is 0. + * + * If enabled (1), the recorder will include code for saving the trace + * to a local file system. + ******************************************************************************/ +#ifdef WIN32 + #define INCLUDE_SAVE_TO_FILE 1 +#else + #define INCLUDE_SAVE_TO_FILE 0 +#endif + +/****************************************************************************** + * TRACE_PROGRESS_MONITOR_TASK_PRIORITY + * + * Macro which sets the priority of the "recorder status monitor" task. + * + * This task, vTraceMonitorTask in trcUser.c, periodically writes + * the recorder status using the vTraceConsoleMessage macro, which is to + * be mapped to your console "printf" routine. The task is named TraceMon but + * is intentionally excluded from the demo trace. + * + * Default is tskIDLE_PRIORITY + 1 + * Note that if your system constantly has a high CPU load from high-priority + * tasks, this might not be get a chance to execute. + * + * See vTraceMonitorTask in trcUser.c + *****************************************************************************/ +#define TRACE_PROGRESS_MONITOR_TASK_PRIORITY (tskIDLE_PRIORITY + 3) + +/****************************************************************************** + * TRACE_PROGRESS_MONITOR_TASK_STACKSIZE + * + * Macro which sets the stack size of the "recorder status monitor" task. + * + * This task, vTraceMonitorTask in trcUser.c, periodically writes + * the recorder status using the vTraceConsoleMessage macro, which is to + * be mapped to your console "printf" routine. The task is intentionally + * excluded from the demo trace. + * + * See vTraceMonitorTask in trcUser.c + *****************************************************************************/ +#define TRACE_PROGRESS_MONITOR_TASK_STACKSIZE 500 + +/****************************************************************************** + * TRACE_PROGRESS_MONITOR_TASK_PERIOD + * + * Macro which sets the period of the "recorder status monitor" task. + * + * This task, vTraceMonitorTask in trcUser.c, periodically writes + * the recorder status using the vTraceConsoleMessage macro, which is to + * be mapped to your console "printf" routine. The task is named TraceMon but + * is intentionally excluded from the demo trace. + * + * Default is 1000 FreeRTOS ticks (typically 1 second). On the Windows port, a + * lower value is suggested since the Windows port runs very slowly, often 20-40 + * times slower than the simulated FreeRTOS time. + * + * See vTraceMonitorTask in trcUser.c + *****************************************************************************/ +#if WIN32 + #define TRACE_PROGRESS_MONITOR_TASK_PERIOD 100 +#else + #define TRACE_PROGRESS_MONITOR_TASK_PERIOD 1000 +#endif + +/****************************************************************************** + * TEAM_LICENSE_CODE + * + * Macro which defines a string - the team license code. + * If no team license is available, this should be an empty string "". + * This should be maximum 32 chars, including zero-termination. + *****************************************************************************/ +#define TEAM_LICENSE_CODE "" + +#endif + diff --git a/FreeRTOS/Demo/WIN32-MSVC/Trace_Recorder_Configuration/trcPort.h b/FreeRTOS/Demo/WIN32-MSVC/Trace_Recorder_Configuration/trcPort.h new file mode 100644 index 000000000..c343d5134 --- /dev/null +++ b/FreeRTOS/Demo/WIN32-MSVC/Trace_Recorder_Configuration/trcPort.h @@ -0,0 +1,492 @@ +/******************************************************************************* + * FreeRTOS+Trace v2.3.0 Recorder Library + * Percepio AB, www.percepio.com + * + * trcPort.h + * + * Contains together with trcPort.c all portability issues of the trace recorder + * library. + * + * Terms of Use + * This software is copyright Percepio AB. The recorder library is free for + * use together with Percepio products. You may distribute the recorder library + * in its original form, including modifications in trcPort.c and trcPort.h + * given that these modification are clearly marked as your own modifications + * and documented in the initial comment section of these source files. + * This software is the intellectual property of Percepio AB and may not be + * sold or in other ways commercially redistributed without explicit written + * permission by Percepio AB. + * + * Disclaimer + * The trace tool and recorder library is being delivered to you AS IS and + * Percepio AB makes no warranty as to its use or performance. Percepio AB does + * not and cannot warrant the performance or results you may obtain by using the + * software or documentation. Percepio AB make no warranties, express or + * implied, as to noninfringement of third party rights, merchantability, or + * fitness for any particular purpose. In no event will Percepio AB, its + * technology partners, or distributors be liable to you for any consequential, + * incidental or special damages, including any lost profits or lost savings, + * even if a representative of Percepio AB has been advised of the possibility + * of such damages, or for any claim by any third party. Some jurisdictions do + * not allow the exclusion or limitation of incidental, consequential or special + * damages, or the exclusion of implied warranties or limitations on how long an + * implied warranty may last, so the above limitations may not apply to you. + * + * FreeRTOS+Trace is available as Free Edition and in two premium editions. + * You may use the premium features during 30 days for evaluation. + * Download FreeRTOS+Trace at http://www.percepio.com/products/downloads/ + * + * Copyright Percepio AB, 2012. + * www.percepio.com + ******************************************************************************/ + +#ifndef TRCPORT_H +#define TRCPORT_H + +/* If FreeRTOS Win32 port */ +#ifdef WIN32 + + #undef _WIN32_WINNT + #define _WIN32_WINNT 0x0600 + + /* Standard includes. */ + #include + #include + #include + +/******************************************************************************* + * The Win32 port by default saves the trace to file and then kills the + * program when the recorder is stopped, to facilitate quick, simple tests + * of the recorder. + ******************************************************************************/ + #define WIN32_PORT_SAVE_WHEN_STOPPED 1 + #define WIN32_PORT_EXIT_WHEN_STOPPED 1 +#else + #define WIN32_PORT_SAVE_WHEN_STOPPED 0 + #define WIN32_PORT_EXIT_WHEN_STOPPED 0 +#endif + +#define DIRECTION_INCREMENTING 1 +#define DIRECTION_DECREMENTING 2 + +/****************************************************************************** + * Supported ports + * + * PORT_HWIndependent + * A hardware independent fallback option for event timestamping. Provides low + * resolution timestamps based on the OS tick. + * This may be used on the Win32 port, but may also be used on embedded hardware + * platforms. Note that this gives suboptimal display in FreeRTOS+Trace. All + * time durations will be truncated to the OS tick frequency, typically 1 KHz. + * This means that a task or ISR that executes in less than 1 ms get an exection + * time of zero. They are however still visible in FreeRTOS+Trace. + * + * PORT_Win32 + * "Accurate" timestamping based on the Windows permance counter. Note that + * this gives the host machine time, not the simulated FreeRTOS time (tick + * count). The timing of the Win32 FreeRTOS build is not real-time, since it + * depends on the scheduling and tick rate of Windows, which is very slow. + * + * Officially supported hardware timer ports: + * - PORT_Atmel_AT91SAM7 + * - PORT_Atmel_UC3A0 + * - PORT_ARM_CortexM + * - PORT_Renesas_RX600 + * - PORT_Microchip_dsPIC_AND_PIC24 + * + * We also provide several "unofficial" hardware-specific ports. There have + * been developed by external contributors, and have not yet been verified + * by Percepio AB. Let us know if you have problems getting these to work. + * + * Unoffical hardware specific ports provided are: + * - PORT_TEXAS_INSTRUMENTS_TMS570 + * - PORT_TEXAS_INSTRUMENTS_MSP430 + * - PORT_MICROCHIP_PIC32 + * - PORT_XILINX_PPC405 + * - PORT_XILINX_PPC440 + * - PORT_XILINX_MICROBLAZE + * - PORT_NXP_LPC210X + * + *****************************************************************************/ + +#define PORT_NOT_SET -1 + +/*** Officially supported hardware timer ports *******************************/ +#define PORT_HWIndependent 0 +#define PORT_Win32 1 +#define PORT_Atmel_AT91SAM7 2 +#define PORT_Atmel_UC3A0 3 +#define PORT_ARM_CortexM 4 +#define PORT_Renesas_RX600 5 +#define PORT_Microchip_dsPIC_AND_PIC24 6 + +/*** Unofficial ports, provided by external developers, not yet verified *****/ +#define PORT_TEXAS_INSTRUMENTS_TMS570 7 +#define PORT_TEXAS_INSTRUMENTS_MSP430 8 +#define PORT_MICROCHIP_PIC32 9 +#define PORT_XILINX_PPC405 10 +#define PORT_XILINX_PPC440 11 +#define PORT_XILINX_MICROBLAZE 12 +#define PORT_NXP_LPC210X 13 + +/*** Select your port here! **************************************************/ +#define SELECTED_PORT PORT_Win32 +/*****************************************************************************/ + +#if (SELECTED_PORT == PORT_NOT_SET) +#error "You need to define SELECTED_PORT here!" +#endif + +/******************************************************************************* + * IRQ_PRIORITY_ORDER + * + * Macro which should be defined as an integer of 0 or 1. + * + * This should be 0 if lower irq priority values implies higher priority + * levels, such as on ARM Cortex M. If the opposite scheme is used, i.e., + * if higher irq priority values means higher priority, this should be 1. + * + * This setting is not critical. It is used only to sort and colorize the + * interrupts in priority order, in case you record interrupts using + * the vTraceStoreISRBegin and vTraceStoreISREnd routines. + * + * We provide this setting for some hardware architectures below: + * - ARM Cortex M: 0 (lower irq priority values are more significant) + * - Atmel AT91SAM7x: 1 (higher irq priority values are more significant) + * - Atmel AVR32: 1 (higher irq priority values are more significant) + * - Renesas RX600: 1 (higher irq priority values are more significant) + * - Microchip PIC24: 0 (lower irq priority values are more significant) + * - Microchip dsPIC: 0 (lower irq priority values are more significant) + * - TI TMS570: 0 (lower irq priority values are more significant) + * - Freescale HCS08: 0 (lower irq priority values are more significant) + * - Freescale HCS12: 0 (lower irq priority values are more significant) + * - PowerPC 405: 0 (lower irq priority values are more significant) + * - PowerPC 440: 0 (lower irq priority values are more significant) + * - Freescale ColdFire: 1 (higher irq priority values are more significant) + * - NXP LPC210x: 0 (lower irq priority values are more significant) + * - MicroBlaze: 0 (lower irq priority values are more significant) + * + * If your chip is not on the above list, and you perhaps know this detail by + * heart, please inform us by e-mail to support@percepio.com. + * + ****************************************************************************** + * + * HWTC Macros + * + * These four HWTC macros provides a hardware isolation layer representing a + * generic hardware timer/counter used for driving the operating system tick, + * such as the SysTick feature of ARM Cortex M3/M4, or the PIT of the Atmel + * AT91SAM7X. + * + * HWTC_COUNT: The current value of the counter. This is expected to be reset + * a each tick interrupt. Thus, when the tick handler starts, the counter has + * already wrapped. + * + * HWTC_COUNT_DIRECTION: Should be one of: + * - DIRECTION_INCREMENTING - for hardware timer/counters of incrementing type + * such as the PIT on Atmel AT91SAM7X. + * When the counter value reach HWTC_PERIOD, it is reset to zero and the + * interrupt is signaled. + * - DIRECTION_DECREMENTING - for hardware timer/counters of decrementing type + * such as the SysTick on ARM Cortex M3/M4 chips. + * When the counter value reach 0, it is reset to HWTC_PERIOD and the + * interrupt is signaled. + * + * HWTC_PERIOD: The number of increments or decrements of HWTC_COUNT between + * two tick interrupts. This should preferably be mapped to the reload + * register of the hardware timer, to make it more portable between chips in the + * same family. The macro should in most cases be (reload register + 1). + * + * HWTC_DIVISOR: If the timer frequency is very high, like on the Cortex M chips + * (where the SysTick runs at the core clock frequency), the "differential + * timestamping" used in the recorder will more frequently insert extra XTS + * events to store the timestamps, which increases the event buffer usage. + * In such cases, to reduce the number of XTS events and thereby get longer + * traces, you use HWTC_DIVISOR to scale down the timestamps and frequency. + * Assuming a OS tick rate of 1 KHz, it is suggested to keep the effective timer + * frequency below 65 MHz to avoid an excessive amount of XTS events. Thus, a + * Cortex M chip running at 72 MHZ should use a HWTC_DIVISOR of 2, while a + * faster chip require a higher HWTC_DIVISOR value. + * + * The HWTC macros and uiTracePortGetTimeStamp is the main porting issue + * or the trace recorder library. Typically you should not need to change + * the code of uiTracePortGetTimeStamp if using the HWTC macros. + * + * FREE LICENSE OFFER FROM PERCEPIO + * + * For silicon companies and non-corporate FreeRTOS users (researchers, students, + * hobbyists or early-phase startups) we have the following offer: + * Provide a hardware port for our FreeRTOS recorder and get a FREE single-user + * license for FreeRTOS+Trace Professional Edition. Read more about this offer + * at www.percepio.com or contact us directly at support@percepio.com. + * + ******************************************************************************/ + +#if (SELECTED_PORT == PORT_Win32) + + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT (ulGetRunTimeCounterValue()) + #define HWTC_PERIOD 0 + #define HWTC_DIVISOR 1 + + #define IRQ_PRIORITY_ORDER 1 // Please update according to your hardware... + +#elif (SELECTED_PORT == PORT_HWIndependent) + + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT 0 + #define HWTC_PERIOD 1 + #define HWTC_DIVISOR 1 + + #define IRQ_PRIORITY_ORDER 1 // Please update according to your hardware... + +#elif (SELECTED_PORT == PORT_Atmel_AT91SAM7) + + /* HWTC_PERIOD is hardcoded for AT91SAM7X256-EK Board (48 MHz) + A more generic solution is to get the period from pxPIT->PITC_PIMR */ + + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT (AT91C_BASE_PITC->PITC_PIIR & 0xFFFFF) + #define HWTC_PERIOD 2995 + #define HWTC_DIVISOR 1 + + #define IRQ_PRIORITY_ORDER 1 // higher irq priority values are more significant + +#elif (SELECTED_PORT == PORT_Atmel_UC3A0) + + /* For Atmel AVR32 (AT32UC3A) */ + + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT sysreg_read(AVR32_COUNT) + #define HWTC_PERIOD ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) + #define HWTC_DIVISOR 1 + + #define IRQ_PRIORITY_ORDER 1 // higher irq priority values are more significant + +#elif (SELECTED_PORT == PORT_ARM_CortexM) + + /* For all chips using ARM Cortex M cores */ + + #define HWTC_COUNT_DIRECTION DIRECTION_DECREMENTING + #define HWTC_COUNT (*((uint32_t*)0xE000E018)) + #define HWTC_PERIOD ((*(uint32_t*)0xE000E014) + 1) + #define HWTC_DIVISOR 2 + + #define IRQ_PRIORITY_ORDER 0 // lower irq priority values are more significant + +#elif (SELECTED_PORT == PORT_Renesas_RX600) + + #include "iodefine.h" + + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT (CMT0.CMCNT) + #define HWTC_PERIOD ((((configPERIPHERAL_CLOCK_HZ/configTICK_RATE_HZ)-1)/8)) + #define HWTC_DIVISOR 1 + + #define IRQ_PRIORITY_ORDER 1 // higher irq priority values are more significant + +#elif (SELECTED_PORT == PORT_Microchip_dsPIC_AND_PIC24) + + /* For Microchip PIC24 and dsPIC (16 bit) */ + + /* Note: The trace library was originally designed for 32-bit MCUs, and is slower + than intended on 16-bit MCUs. Storing an event on a PIC24 takes about 70 µs. + In comparison, 32-bit MCUs are often 10-20 times faster. If recording overhead + becomes a problem on PIC24, use the filters to exclude less interresting tasks + or system calls. */ + + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT (TMR1) + #define HWTC_PERIOD (PR1+1) + #define HWTC_DIVISOR 1 + + #define IRQ_PRIORITY_ORDER 0 // lower irq priority values are more significant + +#elif (SELECTED_PORT == PORT_NXP_LPC210X) + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + + /* Tested with LPC2106, but should work with most LPC21XX chips. + Assumption: prescaler is 1:1 (this setting is hardcoded in + FreeRTOS port for LPC21XX) */ + + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT *((uint32_t *)0xE0004008 ) + #define HWTC_PERIOD ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) + #define HWTC_DIVISOR 1 + + #define IRQ_PRIORITY_ORDER 0 // lower irq priority values are more significant + +#elif (SELECTED_PORT == PORT_TEXAS_INSTRUMENTS_TMS570) + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + + #define RTIFRC0 *((uint32_t *)0xFFFFFC10) + #define RTICOMP0 *((uint32_t *)0xFFFFFC50) + #define RTIUDCP0 *((uint32_t *)0xFFFFFC54) + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT (RTIFRC0 - (RTICOMP0 - RTIUDCP0)) + #define HWTC_PERIOD (RTIUDCP0) + #define HWTC_DIVISOR 1 + + #define IRQ_PRIORITY_ORDER 0 // lower irq priority values are more significant + +#elif (SELECTED_PORT == PORT_TEXAS_INSTRUMENTS_MSP430) + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT (TA0R) + #define HWTC_PERIOD configCPU_CLOCKS_PER_TICK + #define HWTC_DIVISOR 1 + + #define IRQ_PRIORITY_ORDER 1 // higher irq priority values are more significant + +#elif (SELECTED_PORT == PORT_MICROCHIP_PIC32) + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT (ReadTimer1()) /* Should be available in BSP */ + #define HWTC_PERIOD (ReadPeriod1()+1) /* Should be available in BSP */ + #define HWTC_DIVISOR 1 + + #define IRQ_PRIORITY_ORDER 0 // lower irq priority values are more significant + +#elif (SELECTED_PORT == PORT_XILINX_PPC405) + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + + #define HWTC_COUNT_DIRECTION DIRECTION_DECREMENTING + #define HWTC_COUNT mfspr( 0x3db) + #define HWTC_PERIOD ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) + #define HWTC_DIVISOR 1 + + #define IRQ_PRIORITY_ORDER 0 // lower irq priority values are more significant + +#elif (SELECTED_PORT == PORT_XILINX_PPC440) + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + + /* This should work with most PowerPC chips */ + + #define HWTC_COUNT_DIRECTION DIRECTION_DECREMENTING + #define HWTC_COUNT mfspr( 0x016 ) + #define HWTC_PERIOD ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) + #define HWTC_DIVISOR 1 + + #define IRQ_PRIORITY_ORDER 0 // lower irq priority values are more significant + +#elif (SELECTED_PORT == PORT_XILINX_MICROBLAZE) + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + + /* This should work with most Microblaze configurations + * This port is based on the official FreeRTOS Microlaze port and example application. + * It uses the AXI Timer 0 - the tick interrupt source. + * If an AXI Timer 0 peripheral is available on your hardware platform, no modifications are required. + */ + #include "xtmrctr_l.h" + + #define HWTC_COUNT_DIRECTION DIRECTION_DECREMENTING + #define HWTC_COUNT XTmrCtr_GetTimerCounterReg( XPAR_TMRCTR_0_BASEADDR, 0 ) + #define HWTC_PERIOD ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) + #define HWTC_DIVISOR 16 + + #define IRQ_PRIORITY_ORDER 0 // lower irq priority values are more significant + +#elif (SELECTED_PORT != PORT_NOT_SET) + + #error "SELECTED_PORT had unsupported value!" + #define SELECTED_PORT PORT_NOT_SET + +#endif + +#if (SELECTED_PORT != PORT_NOT_SET) + + #ifndef HWTC_COUNT_DIRECTION + #error "HWTC_COUNT_DIRECTION is not set!" + #endif + + #ifndef HWTC_COUNT + #error "HWTC_COUNT is not set!" + #endif + + #ifndef HWTC_PERIOD + #error "HWTC_PERIOD is not set!" + #endif + + #ifndef HWTC_DIVISOR + #error "HWTC_DIVISOR is not set!" + #endif + + #ifndef IRQ_PRIORITY_ORDER + #error "IRQ_PRIORITY_ORDER is not set!" + #elif (IRQ_PRIORITY_ORDER != 0) && (IRQ_PRIORITY_ORDER != 1) + #error "IRQ_PRIORITY_ORDER has bad value!" + #endif + + #if (HWTC_DIVISOR < 1) + #error "HWTC_DIVISOR must be a non-zero positive value!" + #endif + +#endif +/******************************************************************************* + * vTraceConsoleMessage + * + * A wrapper for your system-specific console "printf" console output function. + * This needs to be correctly defined to see status reports from the trace + * status monitor task (this is defined in trcUser.c). + ******************************************************************************/ +#if (SELECTED_PORT == PORT_Atmel_AT91SAM7) +/* Port specific includes */ +#include "console.h" +#endif + +#define vTraceConsoleMessage printf + +/******************************************************************************* + * uiTracePortGetTimeStamp + * + * Returns the current time based on the HWTC macros which provide a hardware + * isolation layer towards the hardware timer/counter. + * + * The HWTC macros and uiTracePortGetTimeStamp is the main porting issue + * or the trace recorder library. Typically you should not need to change + * the code of uiTracePortGetTimeStamp if using the HWTC macros. + * + * OFFER FROM PERCEPIO: + * For silicon companies and non-corporate FreeRTOS users (researchers, + * students, hobbyists or early-phase startups) we have an attractive offer: + * Provide a hardware timer port and get a FREE single-user licence for + * FreeRTOS+Trace Professional Edition. Read more about this offer at + * www.percepio.com or contact us directly at support@percepio.com. + ******************************************************************************/ +void uiTracePortGetTimeStamp(uint32_t *puiTimestamp); + +/******************************************************************************* + * vTracePortEnd + * + * This function is called when the recorder is stopped due to full buffer. + * Mainly intended to show a message in the console. + * This is used by the Win32 port to store the trace to a file. The file path is + * set using vTracePortSetFileName. + ******************************************************************************/ +void vTracePortEnd(void); + +#if (INCLUDE_SAVE_TO_FILE == 1) + +/******************************************************************************* + * vTracePortSetOutFile + * + * Sets the filename/path used in vTracePortSave. + * This is set in a separate function, since the Win32 port calls vTracePortSave + * in vTracePortEnd if WIN32_PORT_SAVE_WHEN_STOPPED is set. + ******************************************************************************/ +void vTracePortSetOutFile(char* path); + +/****************************************************************************** + * vTracePortSave + * + * Saves the trace to a file on a target-side file system. The path is set in a + * separate function, vTracePortSetOutFile, since the Win32 port may call + * vTracePortSave in vTracePortEnd, if using WIN32_PORT_SAVE_WHEN_STOPPED. + ******************************************************************************/ +void vTracePortSave(void); + +#endif + +#endif diff --git a/FreeRTOS/Demo/WIN32-MSVC/WIN32.suo b/FreeRTOS/Demo/WIN32-MSVC/WIN32.suo index 96f9643bf..ca909d394 100644 Binary files a/FreeRTOS/Demo/WIN32-MSVC/WIN32.suo and b/FreeRTOS/Demo/WIN32-MSVC/WIN32.suo differ diff --git a/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj b/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj index 87c8fb15d..5429533dc 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj +++ b/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj @@ -54,7 +54,7 @@ Disabled - ..\..\Source\include;..\..\Source\portable\MSVC-MingW;..\Common\Include;.;%(AdditionalIncludeDirectories) + ..\..\Source\include;..\..\Source\portable\MSVC-MingW;..\Common\Include;..\..\..\FreeRTOS-Plus\FreeRTOS-Plus-Trace\Include;.\Trace_Recorder_Configuration;.;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0500;WINVER=0x400;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true EnableFastChecks @@ -125,6 +125,10 @@ + + + + @@ -166,6 +170,7 @@ %(PreprocessorDefinitions) %(PreprocessorDefinitions) + @@ -180,6 +185,8 @@ + + diff --git a/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj.filters b/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj.filters index bc0d07c7d..bbd24de02 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj.filters +++ b/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj.filters @@ -32,6 +32,9 @@ {19ff1a34-36de-4c48-9d10-3fb1fa0d1fa4} h;hpp;hxx;hm;inl + + {90b56567-bab6-4d92-b319-b514d378329d} + @@ -97,6 +100,21 @@ Demo App Source\Common Demo Tasks + + Demo App Source\FreeRTOS+Trace Recorder + + + Demo App Source\FreeRTOS+Trace Recorder + + + Demo App Source\FreeRTOS+Trace Recorder + + + Demo App Source\FreeRTOS+Trace Recorder + + + Demo App Source + @@ -135,5 +153,11 @@ FreeRTOS Source\Include + + Demo App Source\FreeRTOS+Trace Recorder + + + Demo App Source\FreeRTOS+Trace Recorder + \ No newline at end of file diff --git a/FreeRTOS/Demo/WIN32-MSVC/main.c b/FreeRTOS/Demo/WIN32-MSVC/main.c index d4c972c2f..2cc0a9b04 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/main.c +++ b/FreeRTOS/Demo/WIN32-MSVC/main.c @@ -178,6 +178,10 @@ int main( void ) is done purely to test the use of vSemaphoreDelete(). */ xMutexToDelete = xSemaphoreCreateMutex(); + /* Start the trace recording - the recording is written to a file if + configASSERT() is called. */ + vTraceStart(); + /* Start the scheduler itself. */ vTaskStartScheduler(); @@ -381,7 +385,6 @@ extern unsigned portBASE_TYPE uxTaskGetTaskNumber( xTaskHandle xTask ); pcStatusMessage = "Error: Returned test task state was incorrect 3"; } } - } } /*-----------------------------------------------------------*/ @@ -408,13 +411,19 @@ void vApplicationTickHook( void ) /* Write to a queue that is in use as part of the queue set demo to demonstrate using queue sets from an ISR. */ - vQueueSetWriteToQueueFromISR(); + vQueueSetAccessQueueSetFromISR(); } /*-----------------------------------------------------------*/ void vAssertCalled( void ) { taskDISABLE_INTERRUPTS(); + + /* Stop the trace recording. */ + vTraceStop(); + vTracePortSave(); + for( ;; ); } +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Source/include/mpu_wrappers.h b/FreeRTOS/Source/include/mpu_wrappers.h index b2ded270c..7cb0927d1 100644 --- a/FreeRTOS/Source/include/mpu_wrappers.h +++ b/FreeRTOS/Source/include/mpu_wrappers.h @@ -101,6 +101,7 @@ only for ports that are using the MPU. */ #define uxTaskGetStackHighWaterMark MPU_uxTaskGetStackHighWaterMark #define xTaskGetCurrentTaskHandle MPU_xTaskGetCurrentTaskHandle #define xTaskGetSchedulerState MPU_xTaskGetSchedulerState + #define xTaskGetIdleTaskHandle MPU_xTaskGetIdleTaskHandle #define xQueueGenericCreate MPU_xQueueGenericCreate #define xQueueCreateMutex MPU_xQueueCreateMutex @@ -113,6 +114,11 @@ only for ports that are using the MPU. */ #define xQueueGenericReceive MPU_xQueueGenericReceive #define uxQueueMessagesWaiting MPU_uxQueueMessagesWaiting #define vQueueDelete MPU_vQueueDelete + #define xQueueGenericReset MPU_xQueueGenericReset + #define xQueueCreateSet MPU_xQueueCreateSet + #define xQueueSelectFromSet MPU_xQueueSelectFromSet + #define xQueueAddToSet MPU_xQueueAddToSet + #define xQueueRemoveFromSet MPU_xQueueRemoveFromSet #define pvPortMalloc MPU_pvPortMalloc #define vPortFree MPU_vPortFree diff --git a/FreeRTOS/Source/include/queue.h b/FreeRTOS/Source/include/queue.h index f2b466c21..9118bb766 100644 --- a/FreeRTOS/Source/include/queue.h +++ b/FreeRTOS/Source/include/queue.h @@ -90,8 +90,8 @@ typedef void * xQueueHandle; /** * Type by which queue sets are referenced. For example, a call to - * xQueueSetCreate() returns an xQueueSet variable that can then be used as a - * parameter to xQueueBlockMultiple(), xQueueAddToQueueSet(), etc. + * xQueueCreateSet() returns an xQueueSet variable that can then be used as a + * parameter to xQueueSelectFromSet(), xQueueAddToSet(), etc. */ typedef void * xQueueSetHandle; @@ -1309,10 +1309,10 @@ xQueueHandle xQueueGenericCreate( unsigned portBASE_TYPE uxQueueLength, unsigned * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this * function. * - * A queue set must be explicitly created using a call to xQueueSetCreate() + * A queue set must be explicitly created using a call to xQueueCreateSet() * before it can be used. Once created, standard FreeRTOS queues and semaphores - * can be added to the set using calls to xQueueAddToQueueSet(). - * xQueueBlockMultiple() is then used to determine which, if any, of the queues + * can be added to the set using calls to xQueueAddToSet(). + * xQueueSelectFromSet() is then used to determine which, if any, of the queues * or semaphores contained in the set is in a state where a queue read or * semaphore take operation would be successful. * @@ -1328,6 +1328,10 @@ xQueueHandle xQueueGenericCreate( unsigned portBASE_TYPE uxQueueLength, unsigned * queue added to a queue set. Therefore counting semaphores with large maximum * counts should not be added to queue sets. * + * Note 4: A received (in the case of a queue) or take (in the case of a + * semaphore) operation must not be performed on a member of a queue set unless + * a call to xQueueSelect() has first returned a handle to that set member. + * * @param uxEventQueueLength Queue sets themselves queue events that occur on * the queues and semaphores contained in the set. uxEventQueueLength specifies * the maximum number of events that can be queued at once. To be absolutely @@ -1347,15 +1351,19 @@ xQueueHandle xQueueGenericCreate( unsigned portBASE_TYPE uxQueueLength, unsigned * @return If the queue set is created successfully then a handle to the created * queue set is returned. Otherwise NULL is returned. */ -xQueueSetHandle xQueueSetCreate( unsigned portBASE_TYPE uxEventQueueLength ); +xQueueSetHandle xQueueCreateSet( unsigned portBASE_TYPE uxEventQueueLength ); /* * Adds a queue or semaphore to a queue set that was previously created by a - * call to xQueueSetCreate(). + * call to xQueueCreateSet(). * * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this * function. * + * Note 1: A received (in the case of a queue) or take (in the case of a + * semaphore) operation must not be performed on a member of a queue set unless + * a call to xQueueSelect() has first returned a handle to that set member. + * * @param xQueueOrSemaphore The handle of the queue or semaphore being added to * the queue set (cast to an xQueueSetMemberHandle type). * @@ -1367,10 +1375,11 @@ xQueueSetHandle xQueueSetCreate( unsigned portBASE_TYPE uxEventQueueLength ); * queue set because it is already a member of a different queue set then pdFAIL * is returned. */ -portBASE_TYPE xQueueAddToQueueSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ); +portBASE_TYPE xQueueAddToSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ); /* - * Removes a queue or semaphore from a queue set. + * Removes a queue or semaphore from a queue set. A queue can only be removed + * from a set when it is empty. * * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this * function. @@ -1385,11 +1394,14 @@ portBASE_TYPE xQueueAddToQueueSet( xQueueSetMemberHandle xQueueOrSemaphore, xQue * then pdPASS is returned. If the queue was not in the queue set then pdFAIL * is returned. */ -portBASE_TYPE xQueueRemoveFromQueueSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ); +portBASE_TYPE xQueueRemoveFromSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ); /* - * xQueueBlockMultiple() allows a task to block (pend) on a read operation on - * all the queues and semaphores in a queue set simultaneously. + * xQueueSelectFromSet() selects from the members of a queue set a queue or + * semaphore that either contains data (in the case of a queue) or is available + * to take (in the case of a semaphore). xQueueSelectFromSet() effectively + * allows a task to block (pend) on a read operation on all the queues and + * semaphores in a queue set simultaneously. * * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this * function. @@ -1402,6 +1414,10 @@ portBASE_TYPE xQueueRemoveFromQueueSet( xQueueSetMemberHandle xQueueOrSemaphore, * Note 2: Blocking on a queue set that contains a mutex will not cause the * mutex holder to inherit the priority of the blocked task. * + * Note 3: A received (in the case of a queue) or take (in the case of a + * semaphore) operation must not be performed on a member of a queue set unless + * a call to xQueueSelect() has first returned a handle to that set member. + * * @param xQueueSet The queue set on which the task will (potentially) block. * * @param xBlockTimeTicks The maximum time, in ticks, that the calling task will @@ -1409,13 +1425,18 @@ portBASE_TYPE xQueueRemoveFromQueueSet( xQueueSetMemberHandle xQueueOrSemaphore, * of the queue set to be ready for a successful queue read or semaphore take * operation. * - * @return xQueueBlockMultiple() will return the handle of a queue (cast to + * @return xQueueSelectFromSet() will return the handle of a queue (cast to * a xQueueSetMemberHandle type) contained in the queue set that contains data, * or the handle of a semaphore (cast to a xQueueSetMemberHandle type) contained * in the queue set that is available, or NULL if no such queue or semaphore * exists before before the specified block time expires. */ -xQueueSetMemberHandle xQueueBlockMultiple( xQueueSetHandle xQueueSet, portTickType xBlockTimeTicks ); +xQueueSetMemberHandle xQueueSelectFromSet( xQueueSetHandle xQueueSet, portTickType xBlockTimeTicks ); + +/* + * A version of xQueueSelectFromSet() that can be used from an ISR. + */ +xQueueSetMemberHandle xQueueSelectFromSetFromISR( xQueueSetHandle xQueueSet ); /* Not public API functions. */ void vQueueWaitForMessageRestricted( xQueueHandle pxQueue, portTickType xTicksToWait ); diff --git a/FreeRTOS/Source/portable/GCC/ARM_CM3_MPU/port.c b/FreeRTOS/Source/portable/GCC/ARM_CM3_MPU/port.c index 1118ec500..5c3dff1c3 100644 --- a/FreeRTOS/Source/portable/GCC/ARM_CM3_MPU/port.c +++ b/FreeRTOS/Source/portable/GCC/ARM_CM3_MPU/port.c @@ -196,8 +196,10 @@ portBASE_TYPE MPU_xTaskCallApplicationTaskHook( xTaskHandle xTask, void *pvParam unsigned portBASE_TYPE MPU_uxTaskGetStackHighWaterMark( xTaskHandle xTask ); xTaskHandle MPU_xTaskGetCurrentTaskHandle( void ); portBASE_TYPE MPU_xTaskGetSchedulerState( void ); +xTaskHandle MPU_xTaskGetIdleTaskHandle( void ); xQueueHandle MPU_xQueueGenericCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize, unsigned char ucQueueType ); signed portBASE_TYPE MPU_xQueueGenericSend( xQueueHandle xQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ); +portBASE_TYPE MPU_xQueueGenericReset( xQueueHandle pxQueue, portBASE_TYPE xNewQueue ); unsigned portBASE_TYPE MPU_uxQueueMessagesWaiting( const xQueueHandle pxQueue ); signed portBASE_TYPE MPU_xQueueGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ); xQueueHandle MPU_xQueueCreateMutex( void ); @@ -212,6 +214,10 @@ void *MPU_pvPortMalloc( size_t xSize ); void MPU_vPortFree( void *pv ); void MPU_vPortInitialiseBlocks( void ); size_t MPU_xPortGetFreeHeapSize( void ); +xQueueSetHandle MPU_xQueueCreateSet( unsigned portBASE_TYPE uxEventQueueLength ); +xQueueSetMemberHandle MPU_xQueueSelectFromSet( xQueueSetHandle xQueueSet, portTickType xBlockTimeTicks ); +portBASE_TYPE MPU_xQueueAddToSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ); +portBASE_TYPE MPU_xQueueRemoveFromSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ); /*-----------------------------------------------------------*/ @@ -749,6 +755,19 @@ portBASE_TYPE xRunningPrivileged = prvRaisePrivilege(); #endif /*-----------------------------------------------------------*/ +#if ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) + xTaskHandle MPU_xTaskGetIdleTaskHandle( void ) + { + xTaskHandle xReturn; + portBASE_TYPE xRunningPrivileged = prvRaisePrivilege(); + + xReturn = xTaskGetIdleTaskHandle(); + portRESET_PRIVILEGE( xRunningPrivileged ); + return eReturn; + } +#endif +/*-----------------------------------------------------------*/ + #if ( INCLUDE_vTaskSuspend == 1 ) void MPU_vTaskSuspend( xTaskHandle pxTaskToSuspend ) { @@ -935,6 +954,17 @@ portBASE_TYPE xRunningPrivileged = prvRaisePrivilege(); } /*-----------------------------------------------------------*/ +portBASE_TYPE MPU_xQueueGenericReset( xQueueHandle pxQueue, portBASE_TYPE xNewQueue ) +{ +portBASE_TYPE xReturn; +portBASE_TYPE xRunningPrivileged = prvRaisePrivilege(); + + xReturn = xQueueGenericReset( pxQueue, xNewQueue ); + portRESET_PRIVILEGE( xRunningPrivileged ); + return xReturn; +} +/*-----------------------------------------------------------*/ + signed portBASE_TYPE MPU_xQueueGenericSend( xQueueHandle xQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ) { signed portBASE_TYPE xReturn; @@ -1020,6 +1050,58 @@ signed portBASE_TYPE xReturn; #endif /*-----------------------------------------------------------*/ +#if ( configUSE_QUEUE_SETS == 1 ) + xQueueSetHandle MPU_xQueueCreateSet( unsigned portBASE_TYPE uxEventQueueLength ) + { + xQueueSetHandle xReturn; + portBASE_TYPE xRunningPrivileged = prvRaisePrivilege(); + + xReturn = xQueueCreateSet( uxEventQueueLength ); + portRESET_PRIVILEGE( xRunningPrivileged ); + return xReturn; + } +#endif +/*-----------------------------------------------------------*/ + +#if ( configUSE_QUEUE_SETS == 1 ) + xQueueSetMemberHandle MPU_xQueueSelectFromSet( xQueueSetHandle xQueueSet, portTickType xBlockTimeTicks ) + { + xQueueSetMemberHandle xReturn; + portBASE_TYPE xRunningPrivileged = prvRaisePrivilege(); + + xReturn = xQueueSelectFromSet( xQueueSet, xBlockTimeTicks ); + portRESET_PRIVILEGE( xRunningPrivileged ); + return xReturn; + } +#endif +/*-----------------------------------------------------------*/ + +#if ( configUSE_QUEUE_SETS == 1 ) + portBASE_TYPE MPU_xQueueAddToSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ) + { + portBASE_TYPE xReturn; + portBASE_TYPE xRunningPrivileged = prvRaisePrivilege(); + + xReturn = xQueueAddToSet( xQueueOrSemaphore, xQueueSet ); + portRESET_PRIVILEGE( xRunningPrivileged ); + return xReturn; + } +#endif +/*-----------------------------------------------------------*/ + +#if ( configUSE_QUEUE_SETS == 1 ) + portBASE_TYPE MPU_xQueueRemoveFromSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ) + { + portBASE_TYPE xReturn; + portBASE_TYPE xRunningPrivileged = prvRaisePrivilege(); + + xReturn = xQueueRemoveFromSet( xQueueOrSemaphore, xQueueSet ); + portRESET_PRIVILEGE( xRunningPrivileged ); + return xReturn; + } +#endif +/*-----------------------------------------------------------*/ + #if configUSE_ALTERNATIVE_API == 1 signed portBASE_TYPE MPU_xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ) { diff --git a/FreeRTOS/Source/queue.c b/FreeRTOS/Source/queue.c index 2cc676cf7..f78591ad1 100644 --- a/FreeRTOS/Source/queue.c +++ b/FreeRTOS/Source/queue.c @@ -111,7 +111,7 @@ zero. */ #define queueQUEUE_TYPE_COUNTING_SEMAPHORE ( 2U ) #define queueQUEUE_TYPE_BINARY_SEMAPHORE ( 3U ) #define queueQUEUE_TYPE_RECURSIVE_MUTEX ( 4U ) -#define queueQUEUE_TYPE_SET ( 5U ) +#define queueQUEUE_TYPE_SET ( 0U ) /* * Definition of the queue used by the scheduler. @@ -191,10 +191,10 @@ void vQueueSetQueueNumber( xQueueHandle pxQueue, unsigned char ucQueueNumber ) P unsigned char ucQueueGetQueueType( xQueueHandle pxQueue ) PRIVILEGED_FUNCTION; portBASE_TYPE xQueueGenericReset( xQueueHandle pxQueue, portBASE_TYPE xNewQueue ) PRIVILEGED_FUNCTION; xTaskHandle xQueueGetMutexHolder( xQueueHandle xSemaphore ) PRIVILEGED_FUNCTION; -xQueueSetHandle xQueueSetCreate( unsigned portBASE_TYPE uxEventQueueLength ) PRIVILEGED_FUNCTION; -xQueueSetMemberHandle xQueueBlockMultiple( xQueueSetHandle xQueueSet, portTickType xBlockTimeTicks ) PRIVILEGED_FUNCTION; -portBASE_TYPE xQueueAddToQueueSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ) PRIVILEGED_FUNCTION; -portBASE_TYPE xQueueRemoveFromQueueSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ) PRIVILEGED_FUNCTION; +xQueueSetHandle xQueueCreateSet( unsigned portBASE_TYPE uxEventQueueLength ) PRIVILEGED_FUNCTION; +xQueueSetMemberHandle xQueueSelectFromSet( xQueueSetHandle xQueueSet, portTickType xBlockTimeTicks ) PRIVILEGED_FUNCTION; +portBASE_TYPE xQueueAddToSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ) PRIVILEGED_FUNCTION; +portBASE_TYPE xQueueRemoveFromSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ) PRIVILEGED_FUNCTION; /* * Co-routine queue functions differ from task queue functions. Co-routines are @@ -630,36 +630,52 @@ xTimeOutType xTimeOut; traceQUEUE_SEND( pxQueue ); prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); - /* If there was a task waiting for data to arrive on the - queue then unblock it now. */ - if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + #if ( configUSE_QUEUE_SETS == 1 ) { - if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE ) + if( pxQueue->pxQueueSetContainer != NULL ) { - /* The unblocked task has a priority higher than - our own so yield immediately. Yes it is ok to do - this from within the critical section - the kernel - takes care of that. */ - portYIELD_WITHIN_API(); + if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) == pdTRUE ) + { + /* The queue is a member of a queue set, and posting + to the queue set caused a higher priority task to + unblock. A context switch is required. */ + portYIELD_WITHIN_API(); + } } - } - else - { - #if ( configUSE_QUEUE_SETS == 1 ) + else { - if( pxQueue->pxQueueSetContainer != NULL ) + /* If there was a task waiting for data to arrive on the + queue then unblock it now. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { - if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) == pdTRUE ) + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE ) { - /* The queue is a member of a queue set, and posting to - the queue set caused a higher priority task to unblock. - A context switch is required. */ + /* The unblocked task has a priority higher than + our own so yield immediately. Yes it is ok to + do this from within the critical section - the + kernel takes care of that. */ portYIELD_WITHIN_API(); } } } - #endif /* configUSE_QUEUE_SETS */ } + #else /* configUSE_QUEUE_SETS */ + { + /* If there was a task waiting for data to arrive on the + queue then unblock it now. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE ) + { + /* The unblocked task has a priority higher than + our own so yield immediately. Yes it is ok to do + this from within the critical section - the kernel + takes care of that. */ + portYIELD_WITHIN_API(); + } + } + } + #endif /* configUSE_QUEUE_SETS */ taskEXIT_CRITICAL(); @@ -977,29 +993,29 @@ unsigned portBASE_TYPE uxSavedInterruptStatus; be done when the queue is unlocked later. */ if( pxQueue->xTxLock == queueUNLOCKED ) { - if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + #if ( configUSE_QUEUE_SETS == 1 ) { - if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + if( pxQueue->pxQueueSetContainer != NULL ) { - /* The task waiting has a higher priority so record that a - context switch is required. */ - if( pxHigherPriorityTaskWoken != NULL ) + if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) == pdTRUE ) { - *pxHigherPriorityTaskWoken = pdTRUE; + /* The queue is a member of a queue set, and posting + to the queue set caused a higher priority task to + unblock. A context switch is required. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } } } - } - else - { - #if ( configUSE_QUEUE_SETS == 1 ) + else { - if( pxQueue->pxQueueSetContainer != NULL ) + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { - if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) == pdTRUE ) + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) { - /* The queue is a member of a queue set, and posting - to the queue set caused a higher priority task to - unblock. A context switch is required. */ + /* The task waiting has a higher priority so record that a + context switch is required. */ if( pxHigherPriorityTaskWoken != NULL ) { *pxHigherPriorityTaskWoken = pdTRUE; @@ -1007,8 +1023,23 @@ unsigned portBASE_TYPE uxSavedInterruptStatus; } } } - #endif /* configUSE_QUEUE_SETS */ } + #else /* configUSE_QUEUE_SETS */ + { + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority so record that a + context switch is required. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + } + } + } + #endif /* configUSE_QUEUE_SETS */ } else { @@ -1371,52 +1402,58 @@ static void prvUnlockQueue( xQueueHandle pxQueue ) { /* Data was posted while the queue was locked. Are any tasks blocked waiting for data to become available? */ - if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + #if ( configUSE_QUEUE_SETS == 1 ) { - /* Tasks that are removed from the event list will get added to - the pending ready list as the scheduler is still suspended. */ - if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + if( pxQueue->pxQueueSetContainer != NULL ) { - /* The task waiting has a higher priority so record that a - context switch is required. */ - vTaskMissedYield(); + if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) == pdTRUE ) + { + /* The queue is a member of a queue set, and posting to + the queue set caused a higher priority task to unblock. + A context switch is required. */ + vTaskMissedYield(); + } } else { - #if ( configUSE_QUEUE_SETS == 1 ) + /* Tasks that are removed from the event list will get added to + the pending ready list as the scheduler is still suspended. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { - /* It is highly unlikely that this code will ever run, - for the following reason: - + A task will only lock a queue that is part of a - queue set when it is blocking on a write to the - queue. - + An interrupt can only add something to a queue - while the queue is locked (resulting in the - following code executing when the queue is unlocked) - if the queue is not full, meaning a task will never - have blocked on a write in the first place. - The code could execute if an interrupt is also removing - items from a queue. */ - if( pxQueue->pxQueueSetContainer != NULL ) + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) { - if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) == pdTRUE ) - { - /* The queue is a member of a queue set, and posting to - the queue set caused a higher priority task to unblock. - A context switch is required. */ - vTaskMissedYield(); - } + /* The task waiting has a higher priority so record that a + context switch is required. */ + vTaskMissedYield(); } } - #endif /* configUSE_QUEUE_SETS */ + else + { + break; + } } - - --( pxQueue->xTxLock ); } - else + #else /* configUSE_QUEUE_SETS */ { - break; + /* Tasks that are removed from the event list will get added to + the pending ready list as the scheduler is still suspended. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority so record that a + context switch is required. */ + vTaskMissedYield(); + } + } + else + { + break; + } } + #endif /* configUSE_QUEUE_SETS */ + + --( pxQueue->xTxLock ); } pxQueue->xTxLock = queueUNLOCKED; @@ -1791,7 +1828,7 @@ signed portBASE_TYPE xReturn; #if ( configUSE_QUEUE_SETS == 1 ) - xQueueSetHandle xQueueSetCreate( unsigned portBASE_TYPE uxEventQueueLength ) + xQueueSetHandle xQueueCreateSet( unsigned portBASE_TYPE uxEventQueueLength ) { xQUEUE *pxQueue; @@ -1805,7 +1842,7 @@ signed portBASE_TYPE xReturn; #if ( configUSE_QUEUE_SETS == 1 ) - portBASE_TYPE xQueueAddToQueueSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ) + portBASE_TYPE xQueueAddToSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ) { portBASE_TYPE xReturn; @@ -1831,18 +1868,27 @@ signed portBASE_TYPE xReturn; #if ( configUSE_QUEUE_SETS == 1 ) - portBASE_TYPE xQueueRemoveFromQueueSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ) + portBASE_TYPE xQueueRemoveFromSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ) { portBASE_TYPE xReturn; if( xQueueOrSemaphore->pxQueueSetContainer != xQueueSet ) { + /* The queue was not a member of the set. */ + xReturn = pdFAIL; + } + else if( xQueueOrSemaphore->uxMessagesWaiting != 0 ) + { + /* It is dangerous to remove a queue from a set when the queue is + not empty because the queue set will still hold pending events for + the queue. */ xReturn = pdFAIL; } else { taskENTER_CRITICAL(); { + /* The queue is no longer contained in the set. */ xQueueOrSemaphore->pxQueueSetContainer = NULL; } taskEXIT_CRITICAL(); @@ -1857,7 +1903,7 @@ signed portBASE_TYPE xReturn; #if ( configUSE_QUEUE_SETS == 1 ) - xQueueSetMemberHandle xQueueBlockMultiple( xQueueSetHandle xQueueSet, portTickType xBlockTimeTicks ) + xQueueSetMemberHandle xQueueSelectFromSet( xQueueSetHandle xQueueSet, portTickType xBlockTimeTicks ) { xQueueSetMemberHandle xReturn = NULL; @@ -1868,6 +1914,19 @@ signed portBASE_TYPE xReturn; #endif /* configUSE_QUEUE_SETS */ /*-----------------------------------------------------------*/ +#if ( configUSE_QUEUE_SETS == 1 ) + + xQueueSetMemberHandle xQueueSelectFromSetFromISR( xQueueSetHandle xQueueSet ) + { + xQueueSetMemberHandle xReturn = NULL; + + xQueueReceiveFromISR( ( xQueueHandle ) xQueueSet, &xReturn, NULL ); + return xReturn; + } + +#endif /* configUSE_QUEUE_SETS */ +/*-----------------------------------------------------------*/ + #if ( configUSE_QUEUE_SETS == 1 ) static portBASE_TYPE prvNotifyQueueSetContainer( xQUEUE *pxQueue, portBASE_TYPE xCopyPosition ) @@ -1880,6 +1939,8 @@ signed portBASE_TYPE xReturn; if( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength ) { + traceQUEUE_SEND( pxQueueSetContainer ); + /* The data copies is the handle of the queue that contains data. */ prvCopyDataToQueue( pxQueueSetContainer, &pxQueue, xCopyPosition ); if( listLIST_IS_EMPTY( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) == pdFALSE ) { diff --git a/FreeRTOS/Source/tasks.c b/FreeRTOS/Source/tasks.c index 6284a56ff..ba7d37dcf 100644 --- a/FreeRTOS/Source/tasks.c +++ b/FreeRTOS/Source/tasks.c @@ -974,7 +974,11 @@ tskTCB * pxNewTCB; /* Remember the ready list the task might be referenced from before its uxPriority member is changed so the taskRESET_READY_PRIORITY() macro can function correctly. */ - uxPriorityUsedOnEntry = pxTCB->uxPriority; + #if ( configUSE_PORT_OPTIMISED_TASK_SELECTION != 0 ) + { + uxPriorityUsedOnEntry = pxTCB->uxPriority; + } + #endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ #if ( configUSE_MUTEXES == 1 ) { @@ -1274,11 +1278,13 @@ portBASE_TYPE xReturn; /* Should only reach here if a task calls xTaskEndScheduler(). */ } } - - /* This line will only be reached if the kernel could not be started, or - vTaskEndScheduler() was called (vTaskEndScheduler() is not implemented for - most ports). */ - configASSERT( xReturn ); + else + { + /* This line will only be reached if the kernel could not be started, + because there was not enough FreeRTOS heap to create the idle task + or the timer task. */ + configASSERT( xReturn ); + } } /*-----------------------------------------------------------*/