mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-04-19 21:11:57 -04:00
Finish off the Cortus demo application:
+ Add a traceTASK_SWITCHED_OUT macro as part of the RegTest.c. + Add task to test the saving and restoring of the interrupt mask. + Change the serial port interrupt handlers to use naked functions.
This commit is contained in:
parent
f4d8802850
commit
a2b1a64ba1
|
@ -103,8 +103,21 @@ We use --gc-sections when linking, so there is no harm is setting all of these t
|
|||
|
||||
#define BLOCKQ_1 1
|
||||
|
||||
|
||||
|
||||
|
||||
/* A task is created to test the behaviour of the interrupt controller during
|
||||
context switches. This macro is just used to set a variable to true each time
|
||||
the test task is switched out - the task itself needs to know when this happens
|
||||
in order to complete its tests. This macro will slow down the context switch
|
||||
and can normally be removed (just delete the whole macro, although doing so will
|
||||
cause the test task to indicate an error). */
|
||||
extern void *xICTestTask;
|
||||
extern volatile unsigned long ulTaskSwitchedOut;
|
||||
#define traceTASK_SWITCHED_OUT() if( pxCurrentTCB == xICTestTask ) ulTaskSwitchedOut = pdTRUE
|
||||
|
||||
|
||||
|
||||
#endif /* FREERTOS_CONFIG_H */
|
||||
|
||||
// Local Variables:
|
||||
// tab-width:4
|
||||
// End:
|
||||
|
||||
|
|
|
@ -54,17 +54,45 @@
|
|||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/*
|
||||
* Two test tasks that fill the CPU registers with known values before
|
||||
* continuously looping round checking that each register still contains its
|
||||
* expected value. Both tasks use a separate set of values, with an incorrect
|
||||
* value being found at any time being indicative of an error in the context
|
||||
* switch mechanism. One of the tasks uses a yield instruction to increase the
|
||||
* test coverage. The nature of these tasks necessitates that they are written
|
||||
* in assembly code.
|
||||
*/
|
||||
static void vRegTest1( void *pvParameters );
|
||||
static void vRegTest2( void *pvParameters );
|
||||
|
||||
static volatile unsigned long ulRegTest1Counter = 0UL, ulRegTest2Counter = 0UL;
|
||||
/*
|
||||
* A task that tests the management of the Interrupt Controller (IC) during a
|
||||
* context switch. The state of the IC current mask level must be maintained
|
||||
* across context switches. Also, yields must be able to be performed when the
|
||||
* interrupt controller mask is not zero. This task tests both these
|
||||
* requirements.
|
||||
*/
|
||||
static void prvICCheck1Task( void *pvParameters );
|
||||
|
||||
/* Counters used to ensure the tasks are still running. */
|
||||
static volatile unsigned long ulRegTest1Counter = 0UL, ulRegTest2Counter = 0UL, ulICTestCounter = 0UL;
|
||||
|
||||
/* Handle to the task that checks the interrupt controller behaviour. This is
|
||||
used by the traceTASK_SWITCHED_OUT() macro, which is defined in
|
||||
FreeRTOSConfig.h and can be removed - it is just for the purpose of this test. */
|
||||
xTaskHandle xICTestTask = NULL;
|
||||
|
||||
/* Variable that gets set to pdTRUE by traceTASK_SWITCHED_OUT each time
|
||||
is switched out. */
|
||||
volatile unsigned long ulTaskSwitchedOut;
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartRegTestTasks( void )
|
||||
{
|
||||
xTaskCreate( vRegTest1, ( signed char * ) "RTest1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vRegTest2, ( signed char * ) "RTest1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( prvICCheck1Task, ( signed char * ) "ICCheck", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, &xICTestTask );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
|
@ -193,9 +221,61 @@ static void vRegTest2( void *pvParameters )
|
|||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvICCheck1Task( void *pvParameters )
|
||||
{
|
||||
long lICCheckStatus = pdPASS;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* At this point the interrupt mask should be zero. */
|
||||
if( ic->cpl != 0 )
|
||||
{
|
||||
lICCheckStatus = pdFAIL;
|
||||
}
|
||||
|
||||
/* If we yield here, it should still be 0 when the task next runs.
|
||||
ulTaskSwitchedOut is just used to check that a switch does actually
|
||||
happen. */
|
||||
ulTaskSwitchedOut = pdFALSE;
|
||||
taskYIELD();
|
||||
if( ( ulTaskSwitchedOut != pdTRUE ) || ( ic->cpl != 0 ) )
|
||||
{
|
||||
lICCheckStatus = pdFAIL;
|
||||
}
|
||||
|
||||
/* Set the interrupt mask to portSYSTEM_INTERRUPT_PRIORITY_LEVEL + 1,
|
||||
before checking it is as expected. */
|
||||
taskENTER_CRITICAL();
|
||||
if( ic->cpl != ( portSYSTEM_INTERRUPT_PRIORITY_LEVEL + 1 ) )
|
||||
{
|
||||
lICCheckStatus = pdFAIL;
|
||||
}
|
||||
|
||||
/* If we yield here, it should still be
|
||||
portSYSTEM_INTERRUPT_PRIORITY_LEVEL + 10 when the task next runs. */
|
||||
ulTaskSwitchedOut = pdFALSE;
|
||||
taskYIELD();
|
||||
if( ( ulTaskSwitchedOut != pdTRUE ) || ( ic->cpl != ( portSYSTEM_INTERRUPT_PRIORITY_LEVEL + 1 ) ) )
|
||||
{
|
||||
lICCheckStatus = pdFAIL;
|
||||
}
|
||||
|
||||
/* Return the interrupt mask to its default state. */
|
||||
taskEXIT_CRITICAL();
|
||||
|
||||
/* Just increment a loop counter so the check task knows if this task
|
||||
is still running or not. */
|
||||
if( lICCheckStatus == pdPASS )
|
||||
{
|
||||
ulICTestCounter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
portBASE_TYPE xAreRegTestTasksStillRunning( void )
|
||||
{
|
||||
static unsigned long ulLastCounter1 = 0UL, ulLastCounter2 = 0UL;
|
||||
static unsigned long ulLastCounter1 = 0UL, ulLastCounter2 = 0UL, ulLastICTestCounter = 0UL;
|
||||
long lReturn;
|
||||
|
||||
/* Check that both loop counters are still incrementing, indicating that
|
||||
|
@ -208,6 +288,10 @@ long lReturn;
|
|||
{
|
||||
lReturn = pdFAIL;
|
||||
}
|
||||
else if( ulLastICTestCounter == ulICTestCounter )
|
||||
{
|
||||
lReturn = pdFAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
lReturn = pdPASS;
|
||||
|
@ -215,6 +299,7 @@ long lReturn;
|
|||
|
||||
ulLastCounter1 = ulRegTest1Counter;
|
||||
ulLastCounter2 = ulRegTest2Counter;
|
||||
ulLastICTestCounter = ulICTestCounter;
|
||||
|
||||
return lReturn;
|
||||
}
|
||||
|
|
|
@ -71,6 +71,16 @@
|
|||
#define comBLOCK_RETRY_TIME 10
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The interrupt handlers are naked functions that call C handlers. The C
|
||||
handlers are marked as noinline to ensure they work correctly when the
|
||||
optimiser is on. */
|
||||
void interrupt5_handler( void ) __attribute__((naked));
|
||||
static void prvTxHandler( void ) __attribute__((noinline));
|
||||
void interrupt6_handler( void ) __attribute__((naked));
|
||||
static void prvRxHandler( void ) __attribute__((noinline));
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Queues used to hold received characters, and characters waiting to be
|
||||
transmitted. */
|
||||
static xQueueHandle xRxedChars;
|
||||
|
@ -116,7 +126,6 @@ signed portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, signed char *pcRxedC
|
|||
return pdFALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vSerialPutString( xComPortHandle pxPort, const signed char * const pcString, unsigned short usStringLength )
|
||||
|
@ -132,7 +141,6 @@ void vSerialPutString( xComPortHandle pxPort, const signed char * const pcString
|
|||
while( xSerialPutChar( pxPort, *pChNext, comBLOCK_RETRY_TIME ) != pdTRUE ); pChNext++;
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
signed portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, signed char cOutChar, portTickType xBlockTime )
|
||||
|
@ -162,12 +170,20 @@ void vSerialClose( xComPortHandle xPort )
|
|||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void interrupt_handler( IRQ_UART1_TX )
|
||||
/* UART Tx interrupt handler. */
|
||||
void interrupt5_handler( void )
|
||||
{
|
||||
static signed char cChar;
|
||||
static portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
|
||||
|
||||
/* This is a naked function. */
|
||||
portSAVE_CONTEXT();
|
||||
prvTxHandler();
|
||||
portRESTORE_CONTEXT();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvTxHandler( void )
|
||||
{
|
||||
signed char cChar;
|
||||
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
|
||||
|
||||
/* The interrupt was caused by the transmit fifo having space for at least one
|
||||
character. Are there any more characters to transmit? */
|
||||
|
@ -186,36 +202,34 @@ static portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
|
|||
ensure that the unblocked task is the task that executes when the interrupt
|
||||
completes if the unblocked task has a priority higher than the interrupted
|
||||
task. */
|
||||
if( xHigherPriorityTaskWoken )
|
||||
{
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* UART Rx interrupt. */
|
||||
void interrupt6_handler( void )
|
||||
{
|
||||
portSAVE_CONTEXT();
|
||||
prvRxHandler();
|
||||
portRESTORE_CONTEXT();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void interrupt_handler( IRQ_UART1_RX )
|
||||
static void prvRxHandler( void )
|
||||
{
|
||||
static signed char cChar;
|
||||
static portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
|
||||
|
||||
portSAVE_CONTEXT();
|
||||
signed char cChar;
|
||||
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
|
||||
|
||||
/* The interrupt was caused by the receiver getting data. */
|
||||
cChar = uart1->rx_data;
|
||||
|
||||
(void)xQueueSendFromISR(xRxedChars, &cChar, &xHigherPriorityTaskWoken);
|
||||
xQueueSendFromISR(xRxedChars, &cChar, &xHigherPriorityTaskWoken );
|
||||
|
||||
/* If an event caused a task to unblock then we call "Yield from ISR" to
|
||||
ensure that the unblocked task is the task that executes when the interrupt
|
||||
completes if the unblocked task has a priority higher than the interrupted
|
||||
task. */
|
||||
if( xHigherPriorityTaskWoken )
|
||||
{
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
|
||||
portRESTORE_CONTEXT();
|
||||
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
|
|
Loading…
Reference in a new issue