Complete LPC11xx demo functionality. The batch file to copy the code over is not written yet.
parent
b0a6d939f4
commit
f8d15bfaf5
@ -1,572 +0,0 @@
|
|||||||
/*
|
|
||||||
FreeRTOS V7.1.0 - Copyright (C) 2011 Real Time Engineers Ltd.
|
|
||||||
|
|
||||||
|
|
||||||
***************************************************************************
|
|
||||||
* *
|
|
||||||
* 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!
|
|
||||||
|
|
||||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
|
||||||
contact details.
|
|
||||||
|
|
||||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
|
||||||
critical systems.
|
|
||||||
|
|
||||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
|
||||||
licensing and training services.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Tests the extra queue functionality introduced in FreeRTOS.org V4.5.0 -
|
|
||||||
* including xQueueSendToFront(), xQueueSendToBack(), xQueuePeek() and
|
|
||||||
* mutex behaviour.
|
|
||||||
*
|
|
||||||
* See the comments above the prvSendFrontAndBackTest() and
|
|
||||||
* prvLowPriorityMutexTask() prototypes below for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
/* Scheduler include files. */
|
|
||||||
#include "FreeRTOS.h"
|
|
||||||
#include "task.h"
|
|
||||||
#include "queue.h"
|
|
||||||
#include "semphr.h"
|
|
||||||
|
|
||||||
/* Demo program include files. */
|
|
||||||
#include "GenQTest.h"
|
|
||||||
|
|
||||||
#define genqQUEUE_LENGTH ( 5 )
|
|
||||||
#define genqNO_BLOCK ( 0 )
|
|
||||||
|
|
||||||
#define genqMUTEX_LOW_PRIORITY ( tskIDLE_PRIORITY )
|
|
||||||
#define genqMUTEX_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 )
|
|
||||||
#define genqMUTEX_MEDIUM_PRIORITY ( tskIDLE_PRIORITY + 2 )
|
|
||||||
#define genqMUTEX_HIGH_PRIORITY ( tskIDLE_PRIORITY + 3 )
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Tests the behaviour of the xQueueSendToFront() and xQueueSendToBack()
|
|
||||||
* macros by using both to fill a queue, then reading from the queue to
|
|
||||||
* check the resultant queue order is as expected. Queue data is also
|
|
||||||
* peeked.
|
|
||||||
*/
|
|
||||||
static void prvSendFrontAndBackTest( void *pvParameters );
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The following three tasks are used to demonstrate the mutex behaviour.
|
|
||||||
* Each task is given a different priority to demonstrate the priority
|
|
||||||
* inheritance mechanism.
|
|
||||||
*
|
|
||||||
* The low priority task obtains a mutex. After this a high priority task
|
|
||||||
* attempts to obtain the same mutex, causing its priority to be inherited
|
|
||||||
* by the low priority task. The task with the inherited high priority then
|
|
||||||
* resumes a medium priority task to ensure it is not blocked by the medium
|
|
||||||
* priority task while it holds the inherited high priority. Once the mutex
|
|
||||||
* is returned the task with the inherited priority returns to its original
|
|
||||||
* low priority, and is therefore immediately preempted by first the high
|
|
||||||
* priority task and then the medium prioroity task before it can continue.
|
|
||||||
*/
|
|
||||||
static void prvLowPriorityMutexTask( void *pvParameters );
|
|
||||||
static void prvMediumPriorityMutexTask( void *pvParameters );
|
|
||||||
static void prvHighPriorityMutexTask( void *pvParameters );
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
/* Flag that will be latched to pdTRUE should any unexpected behaviour be
|
|
||||||
detected in any of the tasks. */
|
|
||||||
static portBASE_TYPE xErrorDetected = pdFALSE;
|
|
||||||
|
|
||||||
/* Counters that are incremented on each cycle of a test. This is used to
|
|
||||||
detect a stalled task - a test that is no longer running. */
|
|
||||||
static volatile unsigned portLONG ulLoopCounter = 0;
|
|
||||||
static volatile unsigned portLONG ulLoopCounter2 = 0;
|
|
||||||
|
|
||||||
/* The variable that is guarded by the mutex in the mutex demo tasks. */
|
|
||||||
static volatile unsigned portLONG ulGuardedVariable = 0;
|
|
||||||
|
|
||||||
/* Handles used in the mutext test to suspend and resume the high and medium
|
|
||||||
priority mutex test tasks. */
|
|
||||||
static xTaskHandle xHighPriorityMutexTask, xMediumPriorityMutexTask;
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
void vStartGenericQueueTasks( unsigned portBASE_TYPE uxPriority )
|
|
||||||
{
|
|
||||||
xQueueHandle xQueue;
|
|
||||||
xSemaphoreHandle xMutex;
|
|
||||||
|
|
||||||
/* Create the queue that we are going to use for the
|
|
||||||
prvSendFrontAndBackTest demo. */
|
|
||||||
xQueue = xQueueCreate( genqQUEUE_LENGTH, sizeof( unsigned portLONG ) );
|
|
||||||
|
|
||||||
/* vQueueAddToRegistry() adds the queue to the queue registry, if one is
|
|
||||||
in use. The queue registry is provided as a means for kernel aware
|
|
||||||
debuggers to locate queues and has no purpose if a kernel aware debugger
|
|
||||||
is not being used. The call to vQueueAddToRegistry() will be removed
|
|
||||||
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
|
||||||
defined to be less than 1. */
|
|
||||||
vQueueAddToRegistry( xQueue, ( signed portCHAR * ) "Gen_Queue_Test" );
|
|
||||||
|
|
||||||
/* Create the demo task and pass it the queue just created. We are
|
|
||||||
passing the queue handle by value so it does not matter that it is
|
|
||||||
declared on the stack here. */
|
|
||||||
xTaskCreate( prvSendFrontAndBackTest, ( signed portCHAR * )"GenQ", configMINIMAL_STACK_SIZE, ( void * ) xQueue, uxPriority, NULL );
|
|
||||||
|
|
||||||
/* Create the mutex used by the prvMutexTest task. */
|
|
||||||
xMutex = xSemaphoreCreateMutex();
|
|
||||||
|
|
||||||
/* vQueueAddToRegistry() adds the mutex to the registry, if one is
|
|
||||||
in use. The registry is provided as a means for kernel aware
|
|
||||||
debuggers to locate mutexes and has no purpose if a kernel aware debugger
|
|
||||||
is not being used. The call to vQueueAddToRegistry() will be removed
|
|
||||||
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
|
||||||
defined to be less than 1. */
|
|
||||||
vQueueAddToRegistry( ( xQueueHandle ) xMutex, ( signed portCHAR * ) "Gen_Queue_Mutex" );
|
|
||||||
|
|
||||||
/* Create the mutex demo tasks and pass it the mutex just created. We are
|
|
||||||
passing the mutex handle by value so it does not matter that it is declared
|
|
||||||
on the stack here. */
|
|
||||||
xTaskCreate( prvLowPriorityMutexTask, ( signed portCHAR * )"MuLow", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_LOW_PRIORITY, NULL );
|
|
||||||
xTaskCreate( prvMediumPriorityMutexTask, ( signed portCHAR * )"MuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask );
|
|
||||||
xTaskCreate( prvHighPriorityMutexTask, ( signed portCHAR * )"MuHigh", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_HIGH_PRIORITY, &xHighPriorityMutexTask );
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
static void prvSendFrontAndBackTest( void *pvParameters )
|
|
||||||
{
|
|
||||||
unsigned portLONG ulData, ulData2;
|
|
||||||
xQueueHandle xQueue;
|
|
||||||
|
|
||||||
#ifdef USE_STDIO
|
|
||||||
void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
|
|
||||||
|
|
||||||
const portCHAR * const pcTaskStartMsg = "Queue SendToFront/SendToBack/Peek test started.\r\n";
|
|
||||||
|
|
||||||
/* Queue a message for printing to say the task has started. */
|
|
||||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
xQueue = ( xQueueHandle ) pvParameters;
|
|
||||||
|
|
||||||
for( ;; )
|
|
||||||
{
|
|
||||||
/* The queue is empty, so sending an item to the back of the queue
|
|
||||||
should have the same efect as sending it to the front of the queue.
|
|
||||||
|
|
||||||
First send to the front and check everything is as expected. */
|
|
||||||
xQueueSendToFront( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK );
|
|
||||||
|
|
||||||
if( uxQueueMessagesWaiting( xQueue ) != 1 )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( xQueueReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The data we sent to the queue should equal the data we just received
|
|
||||||
from the queue. */
|
|
||||||
if( ulLoopCounter != ulData )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Then do the same, sending the data to the back, checking everything
|
|
||||||
is as expected. */
|
|
||||||
if( uxQueueMessagesWaiting( xQueue ) != 0 )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
xQueueSendToBack( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK );
|
|
||||||
|
|
||||||
if( uxQueueMessagesWaiting( xQueue ) != 1 )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( xQueueReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( uxQueueMessagesWaiting( xQueue ) != 0 )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The data we sent to the queue should equal the data we just received
|
|
||||||
from the queue. */
|
|
||||||
if( ulLoopCounter != ulData )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if configUSE_PREEMPTION == 0
|
|
||||||
taskYIELD();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Place 2, 3, 4 into the queue, adding items to the back of the queue. */
|
|
||||||
for( ulData = 2; ulData < 5; ulData++ )
|
|
||||||
{
|
|
||||||
xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now the order in the queue should be 2, 3, 4, with 2 being the first
|
|
||||||
thing to be read out. Now add 1 then 0 to the front of the queue. */
|
|
||||||
if( uxQueueMessagesWaiting( xQueue ) != 3 )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
ulData = 1;
|
|
||||||
xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK );
|
|
||||||
ulData = 0;
|
|
||||||
xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK );
|
|
||||||
|
|
||||||
/* Now the queue should be full, and when we read the data out we
|
|
||||||
should receive 0, 1, 2, 3, 4. */
|
|
||||||
if( uxQueueMessagesWaiting( xQueue ) != 5 )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if configUSE_PREEMPTION == 0
|
|
||||||
taskYIELD();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Check the data we read out is in the expected order. */
|
|
||||||
for( ulData = 0; ulData < genqQUEUE_LENGTH; ulData++ )
|
|
||||||
{
|
|
||||||
/* Try peeking the data first. */
|
|
||||||
if( xQueuePeek( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulData != ulData2 )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Now try receiving the data for real. The value should be the
|
|
||||||
same. Clobber the value first so we know we really received it. */
|
|
||||||
ulData2 = ~ulData2;
|
|
||||||
if( xQueueReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulData != ulData2 )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The queue should now be empty again. */
|
|
||||||
if( uxQueueMessagesWaiting( xQueue ) != 0 )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if configUSE_PREEMPTION == 0
|
|
||||||
taskYIELD();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* Our queue is empty once more, add 10, 11 to the back. */
|
|
||||||
ulData = 10;
|
|
||||||
if( xQueueSend( xQueue, &ulData, genqNO_BLOCK ) != pdPASS )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
ulData = 11;
|
|
||||||
if( xQueueSend( xQueue, &ulData, genqNO_BLOCK ) != pdPASS )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( uxQueueMessagesWaiting( xQueue ) != 2 )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now we should have 10, 11 in the queue. Add 7, 8, 9 to the
|
|
||||||
front. */
|
|
||||||
for( ulData = 9; ulData >= 7; ulData-- )
|
|
||||||
{
|
|
||||||
if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now check that the queue is full, and that receiving data provides
|
|
||||||
the expected sequence of 7, 8, 9, 10, 11. */
|
|
||||||
if( uxQueueMessagesWaiting( xQueue ) != 5 )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if configUSE_PREEMPTION == 0
|
|
||||||
taskYIELD();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Check the data we read out is in the expected order. */
|
|
||||||
for( ulData = 7; ulData < ( 7 + genqQUEUE_LENGTH ); ulData++ )
|
|
||||||
{
|
|
||||||
if( xQueueReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulData != ulData2 )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( uxQueueMessagesWaiting( xQueue ) != 0 )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ulLoopCounter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
static void prvLowPriorityMutexTask( void *pvParameters )
|
|
||||||
{
|
|
||||||
xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;
|
|
||||||
|
|
||||||
#ifdef USE_STDIO
|
|
||||||
void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
|
|
||||||
|
|
||||||
const portCHAR * const pcTaskStartMsg = "Mutex with priority inheritance test started.\r\n";
|
|
||||||
|
|
||||||
/* Queue a message for printing to say the task has started. */
|
|
||||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for( ;; )
|
|
||||||
{
|
|
||||||
/* Take the mutex. It should be available now. */
|
|
||||||
if( xSemaphoreTake( xMutex, genqNO_BLOCK ) != pdPASS )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set our guarded variable to a known start value. */
|
|
||||||
ulGuardedVariable = 0;
|
|
||||||
|
|
||||||
/* Our priority should be as per that assigned when the task was
|
|
||||||
created. */
|
|
||||||
if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now unsuspend the high priority task. This will attempt to take the
|
|
||||||
mutex, and block when it finds it cannot obtain it. */
|
|
||||||
vTaskResume( xHighPriorityMutexTask );
|
|
||||||
|
|
||||||
/* We should now have inherited the prioritoy of the high priority task,
|
|
||||||
as by now it will have attempted to get the mutex. */
|
|
||||||
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We can attempt to set our priority to the test priority - between the
|
|
||||||
idle priority and the medium/high test priorities, but our actual
|
|
||||||
prioroity should remain at the high priority. */
|
|
||||||
vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY );
|
|
||||||
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now unsuspend the medium priority task. This should not run as our
|
|
||||||
inherited priority is above that of the medium priority task. */
|
|
||||||
vTaskResume( xMediumPriorityMutexTask );
|
|
||||||
|
|
||||||
/* If the did run then it will have incremented our guarded variable. */
|
|
||||||
if( ulGuardedVariable != 0 )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* When we give back the semaphore our priority should be disinherited
|
|
||||||
back to the priority to which we attempted to set ourselves. This means
|
|
||||||
that when the high priority task next blocks, the medium priority task
|
|
||||||
should execute and increment the guarded variable. When we next run
|
|
||||||
both the high and medium priority tasks will have been suspended again. */
|
|
||||||
if( xSemaphoreGive( xMutex ) != pdPASS )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check that the guarded variable did indeed increment... */
|
|
||||||
if( ulGuardedVariable != 1 )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ... and that our priority has been disinherited to
|
|
||||||
genqMUTEX_TEST_PRIORITY. */
|
|
||||||
if( uxTaskPriorityGet( NULL ) != genqMUTEX_TEST_PRIORITY )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set our priority back to our original priority ready for the next
|
|
||||||
loop around this test. */
|
|
||||||
vTaskPrioritySet( NULL, genqMUTEX_LOW_PRIORITY );
|
|
||||||
|
|
||||||
/* Just to show we are still running. */
|
|
||||||
ulLoopCounter2++;
|
|
||||||
|
|
||||||
#if configUSE_PREEMPTION == 0
|
|
||||||
taskYIELD();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
static void prvMediumPriorityMutexTask( void *pvParameters )
|
|
||||||
{
|
|
||||||
( void ) pvParameters;
|
|
||||||
|
|
||||||
for( ;; )
|
|
||||||
{
|
|
||||||
/* The medium priority task starts by suspending itself. The low
|
|
||||||
priority task will unsuspend this task when required. */
|
|
||||||
vTaskSuspend( NULL );
|
|
||||||
|
|
||||||
/* When this task unsuspends all it does is increment the guarded
|
|
||||||
variable, this is so the low priority task knows that it has
|
|
||||||
executed. */
|
|
||||||
ulGuardedVariable++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
static void prvHighPriorityMutexTask( void *pvParameters )
|
|
||||||
{
|
|
||||||
xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;
|
|
||||||
|
|
||||||
for( ;; )
|
|
||||||
{
|
|
||||||
/* The high priority task starts by suspending itself. The low
|
|
||||||
priority task will unsuspend this task when required. */
|
|
||||||
vTaskSuspend( NULL );
|
|
||||||
|
|
||||||
/* When this task unsuspends all it does is attempt to obtain
|
|
||||||
the mutex. It should find the mutex is not available so a
|
|
||||||
block time is specified. */
|
|
||||||
if( xSemaphoreTake( xMutex, portMAX_DELAY ) != pdPASS )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* When we eventually obtain the mutex we just give it back then
|
|
||||||
return to suspend ready for the next test. */
|
|
||||||
if( xSemaphoreGive( xMutex ) != pdPASS )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
/* This is called to check that all the created tasks are still running. */
|
|
||||||
portBASE_TYPE xAreGenericQueueTasksStillRunning( void )
|
|
||||||
{
|
|
||||||
static unsigned portLONG ulLastLoopCounter = 0, ulLastLoopCounter2 = 0;
|
|
||||||
|
|
||||||
/* If the demo task is still running then we expect the loopcounters to
|
|
||||||
have incremented since this function was last called. */
|
|
||||||
if( ulLastLoopCounter == ulLoopCounter )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulLastLoopCounter2 == ulLoopCounter2 )
|
|
||||||
{
|
|
||||||
xErrorDetected = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ulLastLoopCounter = ulLoopCounter;
|
|
||||||
ulLastLoopCounter2 = ulLoopCounter2;
|
|
||||||
|
|
||||||
/* Errors detected in the task itself will have latched xErrorDetected
|
|
||||||
to true. */
|
|
||||||
|
|
||||||
return !xErrorDetected;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,427 +0,0 @@
|
|||||||
/*
|
|
||||||
FreeRTOS V7.1.0 - Copyright (C) 2011 Real Time Engineers Ltd.
|
|
||||||
|
|
||||||
|
|
||||||
***************************************************************************
|
|
||||||
* *
|
|
||||||
* 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!
|
|
||||||
|
|
||||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
|
||||||
contact details.
|
|
||||||
|
|
||||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
|
||||||
critical systems.
|
|
||||||
|
|
||||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
|
||||||
licensing and training services.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The first test creates three tasks - two counter tasks (one continuous count
|
|
||||||
* and one limited count) and one controller. A "count" variable is shared
|
|
||||||
* between all three tasks. The two counter tasks should never be in a "ready"
|
|
||||||
* state at the same time. The controller task runs at the same priority as
|
|
||||||
* the continuous count task, and at a lower priority than the limited count
|
|
||||||
* task.
|
|
||||||
*
|
|
||||||
* One counter task loops indefinitely, incrementing the shared count variable
|
|
||||||
* on each iteration. To ensure it has exclusive access to the variable it
|
|
||||||
* raises it's priority above that of the controller task before each
|
|
||||||
* increment, lowering it again to it's original priority before starting the
|
|
||||||
* next iteration.
|
|
||||||
*
|
|
||||||
* The other counter task increments the shared count variable on each
|
|
||||||
* iteration of it's loop until the count has reached a limit of 0xff - at
|
|
||||||
* which point it suspends itself. It will not start a new loop until the
|
|
||||||
* controller task has made it "ready" again by calling vTaskResume ().
|
|
||||||
* This second counter task operates at a higher priority than controller
|
|
||||||
* task so does not need to worry about mutual exclusion of the counter
|
|
||||||
* variable.
|
|
||||||
*
|
|
||||||
* The controller task is in two sections. The first section controls and
|
|
||||||
* monitors the continuous count task. When this section is operational the
|
|
||||||
* limited count task is suspended. Likewise, the second section controls
|
|
||||||
* and monitors the limited count task. When this section is operational the
|
|
||||||
* continuous count task is suspended.
|
|
||||||
*
|
|
||||||
* In the first section the controller task first takes a copy of the shared
|
|
||||||
* count variable. To ensure mutual exclusion on the count variable it
|
|
||||||
* suspends the continuous count task, resuming it again when the copy has been
|
|
||||||
* taken. The controller task then sleeps for a fixed period - during which
|
|
||||||
* the continuous count task will execute and increment the shared variable.
|
|
||||||
* When the controller task wakes it checks that the continuous count task
|
|
||||||
* has executed by comparing the copy of the shared variable with its current
|
|
||||||
* value. This time, to ensure mutual exclusion, the scheduler itself is
|
|
||||||
* suspended with a call to vTaskSuspendAll (). This is for demonstration
|
|
||||||
* purposes only and is not a recommended technique due to its inefficiency.
|
|
||||||
*
|
|
||||||
* After a fixed number of iterations the controller task suspends the
|
|
||||||
* continuous count task, and moves on to its second section.
|
|
||||||
*
|
|
||||||
* At the start of the second section the shared variable is cleared to zero.
|
|
||||||
* The limited count task is then woken from it's suspension by a call to
|
|
||||||
* vTaskResume (). As this counter task operates at a higher priority than
|
|
||||||
* the controller task the controller task should not run again until the
|
|
||||||
* shared variable has been counted up to the limited value causing the counter
|
|
||||||
* task to suspend itself. The next line after vTaskResume () is therefore
|
|
||||||
* a check on the shared variable to ensure everything is as expected.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* The second test consists of a couple of very simple tasks that post onto a
|
|
||||||
* queue while the scheduler is suspended. This test was added to test parts
|
|
||||||
* of the scheduler not exercised by the first test.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
/* Scheduler include files. */
|
|
||||||
#include "FreeRTOS.h"
|
|
||||||
#include "task.h"
|
|
||||||
#include "semphr.h"
|
|
||||||
|
|
||||||
/* Demo app include files. */
|
|
||||||
#include "dynamic.h"
|
|
||||||
|
|
||||||
/* Function that implements the "limited count" task as described above. */
|
|
||||||
static portTASK_FUNCTION_PROTO( vLimitedIncrementTask, pvParameters );
|
|
||||||
|
|
||||||
/* Function that implements the "continuous count" task as described above. */
|
|
||||||
static portTASK_FUNCTION_PROTO( vContinuousIncrementTask, pvParameters );
|
|
||||||
|
|
||||||
/* Function that implements the controller task as described above. */
|
|
||||||
static portTASK_FUNCTION_PROTO( vCounterControlTask, pvParameters );
|
|
||||||
|
|
||||||
static portTASK_FUNCTION_PROTO( vQueueReceiveWhenSuspendedTask, pvParameters );
|
|
||||||
static portTASK_FUNCTION_PROTO( vQueueSendWhenSuspendedTask, pvParameters );
|
|
||||||
|
|
||||||
/* Demo task specific constants. */
|
|
||||||
#define priSTACK_SIZE ( configMINIMAL_STACK_SIZE )
|
|
||||||
#define priSLEEP_TIME ( ( portTickType ) 128 / portTICK_RATE_MS )
|
|
||||||
#define priLOOPS ( 5 )
|
|
||||||
#define priMAX_COUNT ( ( unsigned long ) 0xff )
|
|
||||||
#define priNO_BLOCK ( ( portTickType ) 0 )
|
|
||||||
#define priSUSPENDED_QUEUE_LENGTH ( 1 )
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
/* Handles to the two counter tasks. These could be passed in as parameters
|
|
||||||
to the controller task to prevent them having to be file scope. */
|
|
||||||
static xTaskHandle xContinousIncrementHandle, xLimitedIncrementHandle;
|
|
||||||
|
|
||||||
/* The shared counter variable. This is passed in as a parameter to the two
|
|
||||||
counter variables for demonstration purposes. */
|
|
||||||
static unsigned long ulCounter;
|
|
||||||
|
|
||||||
/* Variables used to check that the tasks are still operating without error.
|
|
||||||
Each complete iteration of the controller task increments this variable
|
|
||||||
provided no errors have been found. The variable maintaining the same value
|
|
||||||
is therefore indication of an error. */
|
|
||||||
static volatile unsigned short usCheckVariable = ( unsigned short ) 0;
|
|
||||||
static volatile portBASE_TYPE xSuspendedQueueSendError = pdFALSE;
|
|
||||||
static volatile portBASE_TYPE xSuspendedQueueReceiveError = pdFALSE;
|
|
||||||
|
|
||||||
/* Queue used by the second test. */
|
|
||||||
xQueueHandle xSuspendedTestQueue;
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* Start the three tasks as described at the top of the file.
|
|
||||||
* Note that the limited count task is given a higher priority.
|
|
||||||
*/
|
|
||||||
void vStartDynamicPriorityTasks( void )
|
|
||||||
{
|
|
||||||
xSuspendedTestQueue = xQueueCreate( priSUSPENDED_QUEUE_LENGTH, sizeof( unsigned long ) );
|
|
||||||
|
|
||||||
/* vQueueAddToRegistry() adds the queue to the queue registry, if one is
|
|
||||||
in use. The queue registry is provided as a means for kernel aware
|
|
||||||
debuggers to locate queues and has no purpose if a kernel aware debugger
|
|
||||||
is not being used. The call to vQueueAddToRegistry() will be removed
|
|
||||||
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
|
||||||
defined to be less than 1. */
|
|
||||||
vQueueAddToRegistry( xSuspendedTestQueue, ( signed char * ) "Suspended_Test_Queue" );
|
|
||||||
|
|
||||||
xTaskCreate( vContinuousIncrementTask, ( signed char * ) "CNT_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY, &xContinousIncrementHandle );
|
|
||||||
xTaskCreate( vLimitedIncrementTask, ( signed char * ) "LIM_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY + 1, &xLimitedIncrementHandle );
|
|
||||||
xTaskCreate( vCounterControlTask, ( signed char * ) "C_CTRL", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
|
||||||
xTaskCreate( vQueueSendWhenSuspendedTask, ( signed char * ) "SUSP_TX", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
|
||||||
xTaskCreate( vQueueReceiveWhenSuspendedTask, ( signed char * ) "SUSP_RX", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Just loops around incrementing the shared variable until the limit has been
|
|
||||||
* reached. Once the limit has been reached it suspends itself.
|
|
||||||
*/
|
|
||||||
static portTASK_FUNCTION( vLimitedIncrementTask, pvParameters )
|
|
||||||
{
|
|
||||||
unsigned long *pulCounter;
|
|
||||||
|
|
||||||
/* Take a pointer to the shared variable from the parameters passed into
|
|
||||||
the task. */
|
|
||||||
pulCounter = ( unsigned long * ) pvParameters;
|
|
||||||
|
|
||||||
/* This will run before the control task, so the first thing it does is
|
|
||||||
suspend - the control task will resume it when ready. */
|
|
||||||
vTaskSuspend( NULL );
|
|
||||||
|
|
||||||
for( ;; )
|
|
||||||
{
|
|
||||||
/* Just count up to a value then suspend. */
|
|
||||||
( *pulCounter )++;
|
|
||||||
|
|
||||||
if( *pulCounter >= priMAX_COUNT )
|
|
||||||
{
|
|
||||||
vTaskSuspend( NULL );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Just keep counting the shared variable up. The control task will suspend
|
|
||||||
* this task when it wants.
|
|
||||||
*/
|
|
||||||
static portTASK_FUNCTION( vContinuousIncrementTask, pvParameters )
|
|
||||||
{
|
|
||||||
unsigned long *pulCounter;
|
|
||||||
unsigned portBASE_TYPE uxOurPriority;
|
|
||||||
|
|
||||||
/* Take a pointer to the shared variable from the parameters passed into
|
|
||||||
the task. */
|
|
||||||
pulCounter = ( unsigned long * ) pvParameters;
|
|
||||||
|
|
||||||
/* Query our priority so we can raise it when exclusive access to the
|
|
||||||
shared variable is required. */
|
|
||||||
uxOurPriority = uxTaskPriorityGet( NULL );
|
|
||||||
|
|
||||||
for( ;; )
|
|
||||||
{
|
|
||||||
/* Raise our priority above the controller task to ensure a context
|
|
||||||
switch does not occur while we are accessing this variable. */
|
|
||||||
vTaskPrioritySet( NULL, uxOurPriority + 1 );
|
|
||||||
( *pulCounter )++;
|
|
||||||
vTaskPrioritySet( NULL, uxOurPriority );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Controller task as described above.
|
|
||||||
*/
|
|
||||||
static portTASK_FUNCTION( vCounterControlTask, pvParameters )
|
|
||||||
{
|
|
||||||
unsigned long ulLastCounter;
|
|
||||||
short sLoops;
|
|
||||||
short sError = pdFALSE;
|
|
||||||
|
|
||||||
/* Just to stop warning messages. */
|
|
||||||
( void ) pvParameters;
|
|
||||||
|
|
||||||
for( ;; )
|
|
||||||
{
|
|
||||||
/* Start with the counter at zero. */
|
|
||||||
ulCounter = ( unsigned long ) 0;
|
|
||||||
|
|
||||||
/* First section : */
|
|
||||||
|
|
||||||
/* Check the continuous count task is running. */
|
|
||||||
for( sLoops = 0; sLoops < priLOOPS; sLoops++ )
|
|
||||||
{
|
|
||||||
/* Suspend the continuous count task so we can take a mirror of the
|
|
||||||
shared variable without risk of corruption. */
|
|
||||||
vTaskSuspend( xContinousIncrementHandle );
|
|
||||||
ulLastCounter = ulCounter;
|
|
||||||
vTaskResume( xContinousIncrementHandle );
|
|
||||||
|
|
||||||
/* Now delay to ensure the other task has processor time. */
|
|
||||||
vTaskDelay( priSLEEP_TIME );
|
|
||||||
|
|
||||||
/* Check the shared variable again. This time to ensure mutual
|
|
||||||
exclusion the whole scheduler will be locked. This is just for
|
|
||||||
demo purposes! */
|
|
||||||
vTaskSuspendAll();
|
|
||||||
{
|
|
||||||
if( ulLastCounter == ulCounter )
|
|
||||||
{
|
|
||||||
/* The shared variable has not changed. There is a problem
|
|
||||||
with the continuous count task so flag an error. */
|
|
||||||
sError = pdTRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
xTaskResumeAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Second section: */
|
|
||||||
|
|
||||||
/* Suspend the continuous counter task so it stops accessing the shared variable. */
|
|
||||||
vTaskSuspend( xContinousIncrementHandle );
|
|
||||||
|
|
||||||
/* Reset the variable. */
|
|
||||||
ulCounter = ( unsigned long ) 0;
|
|
||||||
|
|
||||||
/* Resume the limited count task which has a higher priority than us.
|
|
||||||
We should therefore not return from this call until the limited count
|
|
||||||
task has suspended itself with a known value in the counter variable. */
|
|
||||||
vTaskResume( xLimitedIncrementHandle );
|
|
||||||
|
|
||||||
/* Does the counter variable have the expected value? */
|
|
||||||
if( ulCounter != priMAX_COUNT )
|
|
||||||
{
|
|
||||||
sError = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( sError == pdFALSE )
|
|
||||||
{
|
|
||||||
/* If no errors have occurred then increment the check variable. */
|
|
||||||
portENTER_CRITICAL();
|
|
||||||
usCheckVariable++;
|
|
||||||
portEXIT_CRITICAL();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Resume the continuous count task and do it all again. */
|
|
||||||
vTaskResume( xContinousIncrementHandle );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
static portTASK_FUNCTION( vQueueSendWhenSuspendedTask, pvParameters )
|
|
||||||
{
|
|
||||||
static unsigned long ulValueToSend = ( unsigned long ) 0;
|
|
||||||
|
|
||||||
/* Just to stop warning messages. */
|
|
||||||
( void ) pvParameters;
|
|
||||||
|
|
||||||
for( ;; )
|
|
||||||
{
|
|
||||||
vTaskSuspendAll();
|
|
||||||
{
|
|
||||||
/* We must not block while the scheduler is suspended! */
|
|
||||||
if( xQueueSend( xSuspendedTestQueue, ( void * ) &ulValueToSend, priNO_BLOCK ) != pdTRUE )
|
|
||||||
{
|
|
||||||
xSuspendedQueueSendError = pdTRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
xTaskResumeAll();
|
|
||||||
|
|
||||||
vTaskDelay( priSLEEP_TIME );
|
|
||||||
|
|
||||||
++ulValueToSend;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
static portTASK_FUNCTION( vQueueReceiveWhenSuspendedTask, pvParameters )
|
|
||||||
{
|
|
||||||
static unsigned long ulExpectedValue = ( unsigned long ) 0, ulReceivedValue;
|
|
||||||
portBASE_TYPE xGotValue;
|
|
||||||
|
|
||||||
/* Just to stop warning messages. */
|
|
||||||
( void ) pvParameters;
|
|
||||||
|
|
||||||
for( ;; )
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
/* Suspending the scheduler here is fairly pointless and
|
|
||||||
undesirable for a normal application. It is done here purely
|
|
||||||
to test the scheduler. The inner xTaskResumeAll() should
|
|
||||||
never return pdTRUE as the scheduler is still locked by the
|
|
||||||
outer call. */
|
|
||||||
vTaskSuspendAll();
|
|
||||||
{
|
|
||||||
vTaskSuspendAll();
|
|
||||||
{
|
|
||||||
xGotValue = xQueueReceive( xSuspendedTestQueue, ( void * ) &ulReceivedValue, priNO_BLOCK );
|
|
||||||
}
|
|
||||||
if( xTaskResumeAll() )
|
|
||||||
{
|
|
||||||
xSuspendedQueueReceiveError = pdTRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
xTaskResumeAll();
|
|
||||||
|
|
||||||
#if configUSE_PREEMPTION == 0
|
|
||||||
{
|
|
||||||
taskYIELD();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} while( xGotValue == pdFALSE );
|
|
||||||
|
|
||||||
if( ulReceivedValue != ulExpectedValue )
|
|
||||||
{
|
|
||||||
xSuspendedQueueReceiveError = pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
++ulExpectedValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
/* Called to check that all the created tasks are still running without error. */
|
|
||||||
portBASE_TYPE xAreDynamicPriorityTasksStillRunning( void )
|
|
||||||
{
|
|
||||||
/* Keep a history of the check variables so we know if it has been incremented
|
|
||||||
since the last call. */
|
|
||||||
static unsigned short usLastTaskCheck = ( unsigned short ) 0;
|
|
||||||
portBASE_TYPE xReturn = pdTRUE;
|
|
||||||
|
|
||||||
/* Check the tasks are still running by ensuring the check variable
|
|
||||||
is still incrementing. */
|
|
||||||
|
|
||||||
if( usCheckVariable == usLastTaskCheck )
|
|
||||||
{
|
|
||||||
/* The check has not incremented so an error exists. */
|
|
||||||
xReturn = pdFALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( xSuspendedQueueSendError == pdTRUE )
|
|
||||||
{
|
|
||||||
xReturn = pdFALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( xSuspendedQueueReceiveError == pdTRUE )
|
|
||||||
{
|
|
||||||
xReturn = pdFALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
usLastTaskCheck = usCheckVariable;
|
|
||||||
return xReturn;
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
FreeRTOS V7.1.0 - Copyright (C) 2011 Real Time Engineers Ltd.
|
|
||||||
|
|
||||||
|
|
||||||
***************************************************************************
|
|
||||||
* *
|
|
||||||
* 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!
|
|
||||||
|
|
||||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
|
||||||
contact details.
|
|
||||||
|
|
||||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
|
||||||
critical systems.
|
|
||||||
|
|
||||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
|
||||||
licensing and training services.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef BLOCK_Q_H
|
|
||||||
#define BLOCK_Q_H
|
|
||||||
|
|
||||||
void vStartBlockingQueueTasks( unsigned portBASE_TYPE uxPriority );
|
|
||||||
portBASE_TYPE xAreBlockingQueuesStillRunning( void );
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
|||||||
/*
|
|
||||||
FreeRTOS V7.1.0 - Copyright (C) 2011 Real Time Engineers Ltd.
|
|
||||||
|
|
||||||
|
|
||||||
***************************************************************************
|
|
||||||
* *
|
|
||||||
* 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!
|
|
||||||
|
|
||||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
|
||||||
contact details.
|
|
||||||
|
|
||||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
|
||||||
critical systems.
|
|
||||||
|
|
||||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
|
||||||
licensing and training services.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef GEN_Q_TEST_H
|
|
||||||
#define GEN_Q_TEST_H
|
|
||||||
|
|
||||||
void vStartGenericQueueTasks( unsigned portBASE_TYPE uxPriority );
|
|
||||||
portBASE_TYPE xAreGenericQueueTasksStillRunning( void );
|
|
||||||
|
|
||||||
#endif /* GEN_Q_TEST_H */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
FreeRTOS V7.1.0 - Copyright (C) 2011 Real Time Engineers Ltd.
|
|
||||||
|
|
||||||
|
|
||||||
***************************************************************************
|
|
||||||
* *
|
|
||||||
* 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!
|
|
||||||
|
|
||||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
|
||||||
contact details.
|
|
||||||
|
|
||||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
|
||||||
critical systems.
|
|
||||||
|
|
||||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
|
||||||
licensing and training services.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef DYNAMIC_MANIPULATION_H
|
|
||||||
#define DYNAMIC_MANIPULATION_H
|
|
||||||
|
|
||||||
void vStartDynamicPriorityTasks( void );
|
|
||||||
portBASE_TYPE xAreDynamicPriorityTasksStillRunning( void );
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,225 @@
|
|||||||
|
/*
|
||||||
|
FreeRTOS V7.1.0 - Copyright (C) 2011 Real Time Engineers Ltd.
|
||||||
|
|
||||||
|
|
||||||
|
***************************************************************************
|
||||||
|
* *
|
||||||
|
* 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!
|
||||||
|
|
||||||
|
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||||
|
contact details.
|
||||||
|
|
||||||
|
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||||
|
critical systems.
|
||||||
|
|
||||||
|
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||||
|
licensing and training services.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* NOTE 1: This project provides two demo applications. A simple blinky style
|
||||||
|
* project, and a more comprehensive test and demo application. The
|
||||||
|
* mainCREATE_SIMPLE_BLINKY_DEMO_ONLY setting in main.c is used to select
|
||||||
|
* between the two. See the notes on using mainCREATE_SIMPLE_BLINKY_DEMO_ONLY
|
||||||
|
* in main.c. This file implements the simply blinky style version.
|
||||||
|
*
|
||||||
|
* NOTE 2: This file only contains the source code that is specific to the
|
||||||
|
* full demo. Generic functions, such FreeRTOS hook functions, and functions
|
||||||
|
* required to configure the hardware, are defined in main.c.
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* main_blinky() creates one software timer, one queue, and two tasks. It then
|
||||||
|
* starts the scheduler.
|
||||||
|
*
|
||||||
|
* The Queue Send Task:
|
||||||
|
* The queue send task is implemented by the prvQueueSendTask() function in
|
||||||
|
* this file. prvQueueSendTask() sits in a loop that causes it to repeatedly
|
||||||
|
* block for 200 milliseconds, before sending the value 100 to the queue that
|
||||||
|
* was created within main_blinky(). Once the value is sent, the task loops
|
||||||
|
* back around to block for another 200 milliseconds.
|
||||||
|
*
|
||||||
|
* The Queue Receive Task:
|
||||||
|
* The queue receive task is implemented by the prvQueueReceiveTask() function
|
||||||
|
* in this file. prvQueueReceiveTask() sits in a loop where it repeatedly
|
||||||
|
* blocks on attempts to read data from the queue that was created within
|
||||||
|
* main_blinky(). When data is received, the task checks the value of the
|
||||||
|
* data, and if the value equals the expected 100, toggles the LED. The 'block
|
||||||
|
* time' parameter passed to the queue receive function specifies that the
|
||||||
|
* task should be held in the Blocked state indefinitely to wait for data to
|
||||||
|
* be available on the queue. The queue receive task will only leave the
|
||||||
|
* Blocked state when the queue send task writes to the queue. As the queue
|
||||||
|
* send task writes to the queue every 200 milliseconds, the queue receive
|
||||||
|
* task leaves the Blocked state every 200 milliseconds, and therefore toggles
|
||||||
|
* the LED every 200 milliseconds.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Kernel includes. */
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "task.h"
|
||||||
|
#include "queue.h"
|
||||||
|
|
||||||
|
/* Hardware specific includes. */
|
||||||
|
#include "lpc11xx.h"
|
||||||
|
|
||||||
|
/* Priorities at which the tasks are created. */
|
||||||
|
#define mainQUEUE_RECEIVE_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 )
|
||||||
|
#define mainQUEUE_SEND_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 )
|
||||||
|
|
||||||
|
/* The rate at which data is sent to the queue. The 200ms value is converted
|
||||||
|
to ticks using the portTICK_RATE_MS constant. */
|
||||||
|
#define mainQUEUE_SEND_FREQUENCY_MS ( 200 / portTICK_RATE_MS )
|
||||||
|
|
||||||
|
/* The number of items the queue can hold. This is 1 as the receive task
|
||||||
|
will remove items as they are added, meaning the send task should always find
|
||||||
|
the queue empty. */
|
||||||
|
#define mainQUEUE_LENGTH ( 1 )
|
||||||
|
|
||||||
|
/* Values passed to the two tasks just to check the task parameter
|
||||||
|
functionality. */
|
||||||
|
#define mainQUEUE_SEND_PARAMETER ( 0x1111UL )
|
||||||
|
#define mainQUEUE_RECEIVE_PARAMETER ( 0x22UL )
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The tasks as described in the comments at the top of this file.
|
||||||
|
*/
|
||||||
|
static void prvQueueReceiveTask( void *pvParameters );
|
||||||
|
static void prvQueueSendTask( void *pvParameters );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called by main() to create the simply blinky style application if
|
||||||
|
* mainCREATE_SIMPLE_BLINKY_DEMO_ONLY is set to 1.
|
||||||
|
*/
|
||||||
|
void main_blinky( void );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The hardware only has a single LED. Simply toggle it.
|
||||||
|
*/
|
||||||
|
extern void vMainToggleLED( void );
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* The queue used by both tasks. */
|
||||||
|
static xQueueHandle xQueue = NULL;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void main_blinky( void )
|
||||||
|
{
|
||||||
|
/* Create the queue. */
|
||||||
|
xQueue = xQueueCreate( mainQUEUE_LENGTH, sizeof( unsigned long ) );
|
||||||
|
|
||||||
|
if( xQueue != NULL )
|
||||||
|
{
|
||||||
|
/* Start the two tasks as described in the comments at the top of this
|
||||||
|
file. */
|
||||||
|
xTaskCreate( prvQueueReceiveTask, /* The function that implements the task. */
|
||||||
|
( signed char * ) "Rx", /* The text name assigned to the task - for debug only as it is not used by the kernel. */
|
||||||
|
configMINIMAL_STACK_SIZE, /* The size of the stack to allocate to the task. */
|
||||||
|
( void * ) mainQUEUE_RECEIVE_PARAMETER, /* The parameter passed to the task - just to check the functionality. */
|
||||||
|
mainQUEUE_RECEIVE_TASK_PRIORITY, /* The priority assigned to the task. */
|
||||||
|
NULL ); /* The task handle is not required, so NULL is passed. */
|
||||||
|
|
||||||
|
xTaskCreate( prvQueueSendTask, ( signed char * ) "TX", configMINIMAL_STACK_SIZE, ( void * ) mainQUEUE_SEND_PARAMETER, mainQUEUE_SEND_TASK_PRIORITY, NULL );
|
||||||
|
|
||||||
|
/* Start the tasks and timer running. */
|
||||||
|
vTaskStartScheduler();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If all is well, the scheduler will now be running, and the following
|
||||||
|
line will never be reached. If the following line does execute, then
|
||||||
|
there was insufficient FreeRTOS heap memory available for the idle and/or
|
||||||
|
timer tasks to be created. See the memory management section on the
|
||||||
|
FreeRTOS web site for more details. */
|
||||||
|
for( ;; );
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static void prvQueueSendTask( void *pvParameters )
|
||||||
|
{
|
||||||
|
portTickType xNextWakeTime;
|
||||||
|
const unsigned long ulValueToSend = 100UL;
|
||||||
|
|
||||||
|
/* Check the task parameter is as expected. */
|
||||||
|
configASSERT( ( ( unsigned long ) pvParameters ) == mainQUEUE_SEND_PARAMETER );
|
||||||
|
|
||||||
|
/* Initialise xNextWakeTime - this only needs to be done once. */
|
||||||
|
xNextWakeTime = xTaskGetTickCount();
|
||||||
|
|
||||||
|
for( ;; )
|
||||||
|
{
|
||||||
|
/* Place this task in the blocked state until it is time to run again.
|
||||||
|
The block time is specified in ticks, the constant used converts ticks
|
||||||
|
to ms. While in the Blocked state this task will not consume any CPU
|
||||||
|
time. */
|
||||||
|
vTaskDelayUntil( &xNextWakeTime, mainQUEUE_SEND_FREQUENCY_MS );
|
||||||
|
|
||||||
|
/* Send to the queue - causing the queue receive task to unblock and
|
||||||
|
toggle the LED. 0 is used as the block time so the sending operation
|
||||||
|
will not block - it shouldn't need to block as the queue should always
|
||||||
|
be empty at this point in the code. */
|
||||||
|
xQueueSend( xQueue, &ulValueToSend, 0U );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static void prvQueueReceiveTask( void *pvParameters )
|
||||||
|
{
|
||||||
|
unsigned long ulReceivedValue;
|
||||||
|
|
||||||
|
/* Check the task parameter is as expected. */
|
||||||
|
configASSERT( ( ( unsigned long ) pvParameters ) == mainQUEUE_RECEIVE_PARAMETER );
|
||||||
|
|
||||||
|
for( ;; )
|
||||||
|
{
|
||||||
|
/* Wait until something arrives in the queue - this task will block
|
||||||
|
indefinitely provided INCLUDE_vTaskSuspend is set to 1 in
|
||||||
|
FreeRTOSConfig.h. */
|
||||||
|
xQueueReceive( xQueue, &ulReceivedValue, portMAX_DELAY );
|
||||||
|
|
||||||
|
/* To get here something must have been received from the queue, but
|
||||||
|
is it the expected value? If it is, toggle the LED. */
|
||||||
|
if( ulReceivedValue == 100UL )
|
||||||
|
{
|
||||||
|
vMainToggleLED();
|
||||||
|
ulReceivedValue = 0U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -0,0 +1,293 @@
|
|||||||
|
/*
|
||||||
|
FreeRTOS V7.1.0 - Copyright (C) 2011 Real Time Engineers Ltd.
|
||||||
|
|
||||||
|
|
||||||
|
***************************************************************************
|
||||||
|
* *
|
||||||
|
* 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!
|
||||||
|
|
||||||
|
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||||
|
contact details.
|
||||||
|
|
||||||
|
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||||
|
critical systems.
|
||||||
|
|
||||||
|
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||||
|
licensing and training services.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* NOTE 1: This project provides two demo applications. A simple blinky style
|
||||||
|
* project, and a more comprehensive test and demo application. The
|
||||||
|
* mainCREATE_SIMPLE_BLINKY_DEMO_ONLY setting in main.c is used to select
|
||||||
|
* between the two. See the notes on using mainCREATE_SIMPLE_BLINKY_DEMO_ONLY
|
||||||
|
* in main.c. This file implements the comprehensive test and demo version.
|
||||||
|
*
|
||||||
|
* NOTE 2: This file only contains the source code that is specific to the
|
||||||
|
* full demo. Generic functions, such FreeRTOS hook functions, and functions
|
||||||
|
* required to configure the hardware, are defined in main.c.
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* main_full() creates all the demo application tasks (including a set of tasks
|
||||||
|
* that test the interrupt nesting behaviour) and a timer, then starts the
|
||||||
|
* scheduler. The web documentation provides more details of the standard demo
|
||||||
|
* application tasks, which provide no particular functionality, but do provide
|
||||||
|
* a good example of how to use the FreeRTOS API.
|
||||||
|
*
|
||||||
|
* The interrupt nesting test tasks require that two timers are configured to
|
||||||
|
* generate interrupts. The interrupt service routines are defined in
|
||||||
|
* IntQueueTimer.c, and can be used as examples for application writers. They
|
||||||
|
* do not, however, directly demonstrate the use of FreeRTOS safe API functions
|
||||||
|
* (those that end in "FromISR"). Therefore, a dummy interrupt implementation
|
||||||
|
* called Dummy_IRQHandler() is provided at the end of main.c.
|
||||||
|
*
|
||||||
|
* In addition to the standard demo tasks, the following tasks and timer are
|
||||||
|
* defined and/or created within this file:
|
||||||
|
*
|
||||||
|
* "Reg test" tasks - These fill the registers with known values, then check
|
||||||
|
* that each register maintains its expected value for the lifetime of the
|
||||||
|
* task. Each task uses a different set of values. The reg test tasks execute
|
||||||
|
* with a very low priority, so get preempted very frequently. A register
|
||||||
|
* containing an unexpected value is indicative of an error in the context
|
||||||
|
* switching mechanism.
|
||||||
|
*
|
||||||
|
* "Check" software timer - The check timer period is initially set to three
|
||||||
|
* seconds. Its callback function checks that all the standard demo tasks, and
|
||||||
|
* the register check tasks, are not only still executing, but are executing
|
||||||
|
* without reporting any errors. If the check timer callback discovers that a
|
||||||
|
* task has either stalled, or reported an error, then it changes the period of
|
||||||
|
* the check timer from the initial three seconds, to just 200ms. The callback
|
||||||
|
* function also toggles an LED each time it is called. This provides a visual
|
||||||
|
* indication of the system status: If the LED toggles every three seconds,
|
||||||
|
* then no issues have been discovered. If the LED toggles every 200ms, then
|
||||||
|
* an issue has been discovered with at least one task.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Kernel includes. */
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "task.h"
|
||||||
|
#include "queue.h"
|
||||||
|
#include "timers.h"
|
||||||
|
|
||||||
|
/* Common demo includes. */
|
||||||
|
#include "blocktim.h"
|
||||||
|
#include "countsem.h"
|
||||||
|
#include "recmutex.h"
|
||||||
|
#include "IntQueue.h"
|
||||||
|
|
||||||
|
/* Hardware specific includes. */
|
||||||
|
#include "lpc11xx.h"
|
||||||
|
|
||||||
|
/* The period after which the check timer will expire provided no errors have
|
||||||
|
been reported by any of the standard demo tasks. ms are converted to the
|
||||||
|
equivalent in ticks using the portTICK_RATE_MS constant. */
|
||||||
|
#define mainCHECK_TIMER_PERIOD_MS ( 3000UL / portTICK_RATE_MS )
|
||||||
|
|
||||||
|
/* The period at which the check timer will expire if an error has been
|
||||||
|
reported in one of the standard demo tasks. ms are converted to the equivalent
|
||||||
|
in ticks using the portTICK_RATE_MS constant. */
|
||||||
|
#define mainERROR_CHECK_TIMER_PERIOD_MS ( 200UL / portTICK_RATE_MS )
|
||||||
|
|
||||||
|
/* A block time of zero simply means "don't block". */
|
||||||
|
#define mainDONT_BLOCK ( 0UL )
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Register check tasks, as described at the top of this file. The nature of
|
||||||
|
* these files necessitates that they are written in an assembly.
|
||||||
|
*/
|
||||||
|
extern void vRegTest1Task( void *pvParameters );
|
||||||
|
extern void vRegTest2Task( void *pvParameters );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The hardware only has a single LED. Simply toggle it.
|
||||||
|
*/
|
||||||
|
extern void vMainToggleLED( void );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The check timer callback function, as described at the top of this file.
|
||||||
|
*/
|
||||||
|
static void prvCheckTimerCallback( xTimerHandle xTimer );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called by main() to create the comprehensive test/demo application if
|
||||||
|
* mainCREATE_SIMPLE_BLINKY_DEMO_ONLY is not set to 1.
|
||||||
|
*/
|
||||||
|
void main_full( void );
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* The following two variables are used to communicate the status of the
|
||||||
|
register check tasks to the check software timer. If the variables keep
|
||||||
|
incrementing, then the register check tasks has not discovered any errors. If
|
||||||
|
a variable stops incrementing, then an error has been found. */
|
||||||
|
volatile unsigned long ulRegTest1LoopCounter = 0UL, ulRegTest2LoopCounter = 0UL;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void main_full( void )
|
||||||
|
{
|
||||||
|
xTimerHandle xCheckTimer = NULL;
|
||||||
|
/* The register test tasks are asm functions that don't use a stack. The
|
||||||
|
stack allocated just has to be large enough to hold the task context, and
|
||||||
|
for the additional required for the stack overflow checking to work (if
|
||||||
|
configured). */
|
||||||
|
const size_t xRegTestStackSize = 25U;
|
||||||
|
|
||||||
|
/* Create the standard demo tasks, including the interrupt nesting test
|
||||||
|
tasks. */
|
||||||
|
vStartInterruptQueueTasks();
|
||||||
|
vCreateBlockTimeTasks();
|
||||||
|
vStartCountingSemaphoreTasks();
|
||||||
|
vStartRecursiveMutexTasks();
|
||||||
|
|
||||||
|
/* Create the register test tasks as described at the top of this file.
|
||||||
|
These are naked functions that don't use any stack. A stack still has
|
||||||
|
to be allocated to hold the task context. */
|
||||||
|
xTaskCreate( vRegTest1Task, /* Function that implements the task. */
|
||||||
|
( signed char * ) "Reg1", /* Text name of the task. */
|
||||||
|
xRegTestStackSize, /* Stack allocated to the task. */
|
||||||
|
NULL, /* The task parameter is not used. */
|
||||||
|
tskIDLE_PRIORITY, /* The priority to assign to the task. */
|
||||||
|
NULL ); /* Don't receive a handle back, it is not needed. */
|
||||||
|
|
||||||
|
xTaskCreate( vRegTest2Task, /* Function that implements the task. */
|
||||||
|
( signed char * ) "Reg2", /* Text name of the task. */
|
||||||
|
xRegTestStackSize, /* Stack allocated to the task. */
|
||||||
|
NULL, /* The task parameter is not used. */
|
||||||
|
tskIDLE_PRIORITY, /* The priority to assign to the task. */
|
||||||
|
NULL ); /* Don't receive a handle back, it is not needed. */
|
||||||
|
|
||||||
|
/* Create the software timer that performs the 'check' functionality,
|
||||||
|
as described at the top of this file. */
|
||||||
|
xCheckTimer = xTimerCreate( ( const signed char * ) "CheckTimer",/* A text name, purely to help debugging. */
|
||||||
|
( mainCHECK_TIMER_PERIOD_MS ), /* The timer period, in this case 3000ms (3s). */
|
||||||
|
pdTRUE, /* This is an auto-reload timer, so xAutoReload is set to pdTRUE. */
|
||||||
|
( void * ) 0, /* The ID is not used, so can be set to anything. */
|
||||||
|
prvCheckTimerCallback /* The callback function that inspects the status of all the other tasks. */
|
||||||
|
);
|
||||||
|
|
||||||
|
/* If the software timer was created successfully, start it. It won't
|
||||||
|
actually start running until the scheduler starts. A block time of
|
||||||
|
zero is used in this call, although any value could be used as the block
|
||||||
|
time will be ignored because the scheduler has not started yet. */
|
||||||
|
if( xCheckTimer != NULL )
|
||||||
|
{
|
||||||
|
xTimerStart( xCheckTimer, mainDONT_BLOCK );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start the kernel. From here on, only tasks and interrupts will run. */
|
||||||
|
vTaskStartScheduler();
|
||||||
|
|
||||||
|
/* If all is well, the scheduler will now be running, and the following
|
||||||
|
line will never be reached. If the following line does execute, then there
|
||||||
|
was insufficient FreeRTOS heap memory available for the idle and/or timer
|
||||||
|
tasks to be created. See the memory management section on the FreeRTOS web
|
||||||
|
site, or the FreeRTOS tutorial books for more details. */
|
||||||
|
for( ;; );
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* See the description at the top of this file. */
|
||||||
|
static void prvCheckTimerCallback( xTimerHandle xTimer )
|
||||||
|
{
|
||||||
|
static long lChangedTimerPeriodAlready = pdFALSE;
|
||||||
|
static unsigned long ulLastRegTest1Value = 0, ulLastRegTest2Value = 0;
|
||||||
|
unsigned long ulErrorFound = pdFALSE;
|
||||||
|
|
||||||
|
/* Check all the demo and test tasks to ensure that they are all still
|
||||||
|
running, and that none have detected an error. */
|
||||||
|
if( xAreIntQueueTasksStillRunning() != pdPASS )
|
||||||
|
{
|
||||||
|
ulErrorFound |= ( 0x01UL << 0UL );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( xAreBlockTimeTestTasksStillRunning() != pdPASS )
|
||||||
|
{
|
||||||
|
ulErrorFound |= ( 0x01UL << 1UL );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( xAreCountingSemaphoreTasksStillRunning() != pdPASS )
|
||||||
|
{
|
||||||
|
ulErrorFound |= ( 0x01UL << 2UL );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( xAreRecursiveMutexTasksStillRunning() != pdPASS )
|
||||||
|
{
|
||||||
|
ulErrorFound |= ( 0x01UL << 3UL );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that the register test 1 task is still running. */
|
||||||
|
if( ulLastRegTest1Value == ulRegTest1LoopCounter )
|
||||||
|
{
|
||||||
|
ulErrorFound |= ( 0x01UL << 4UL );
|
||||||
|
}
|
||||||
|
ulLastRegTest1Value = ulRegTest1LoopCounter;
|
||||||
|
|
||||||
|
/* Check that the register test 2 task is still running. */
|
||||||
|
if( ulLastRegTest2Value == ulRegTest2LoopCounter )
|
||||||
|
{
|
||||||
|
ulErrorFound |= ( 0x01UL << 5UL );
|
||||||
|
}
|
||||||
|
ulLastRegTest2Value = ulRegTest2LoopCounter;
|
||||||
|
|
||||||
|
/* Toggle the check LED to give an indication of the system status. If
|
||||||
|
the LED toggles every mainCHECK_TIMER_PERIOD_MS milliseconds then
|
||||||
|
everything is ok. A faster toggle indicates an error. */
|
||||||
|
vMainToggleLED();
|
||||||
|
|
||||||
|
/* Have any errors been latched in ulErrorFound? If so, shorten the
|
||||||
|
period of the check timer to mainERROR_CHECK_TIMER_PERIOD_MS milliseconds.
|
||||||
|
This will result in an increase in the rate at which mainCHECK_LED
|
||||||
|
toggles. */
|
||||||
|
if( ulErrorFound != pdFALSE )
|
||||||
|
{
|
||||||
|
if( lChangedTimerPeriodAlready == pdFALSE )
|
||||||
|
{
|
||||||
|
lChangedTimerPeriodAlready = pdTRUE;
|
||||||
|
|
||||||
|
/* This call to xTimerChangePeriod() uses a zero block time.
|
||||||
|
Functions called from inside of a timer callback function must
|
||||||
|
*never* attempt to block. */
|
||||||
|
xTimerChangePeriod( xTimer, ( mainERROR_CHECK_TIMER_PERIOD_MS ), mainDONT_BLOCK );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
Loading…
Reference in New Issue