]> git.sur5r.net Git - freertos/commitdiff
Finish off the Cortus demo application:
authorrichardbarry <richardbarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Mon, 29 Mar 2010 14:04:11 +0000 (14:04 +0000)
committerrichardbarry <richardbarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Mon, 29 Mar 2010 14:04:11 +0000 (14:04 +0000)
+ 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.

git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@1010 1d2547de-c912-0410-9cb9-b8ca96c0e9e2

Demo/CORTUS_APS3_GCC/Demo/FreeRTOSConfig.h
Demo/CORTUS_APS3_GCC/Demo/RegTest.c
Demo/CORTUS_APS3_GCC/Demo/serial.c

index 33110da7c5042eb0615f8a4cbce669710b3ce498..d3b6a2851c5f5cc1f6e5bbbb1f4abaf97f14efe0 100644 (file)
@@ -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:
+
index 21a4040ce35419e3d6cc02c460bbf831a77d50fd..7719e9a3a86dcb2215d5e06270302914572f6ba3 100644 (file)
 #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;
 }
index 90cf9528ae81bbd0db83849bce57ff459085261e..95dd142b1f16817aee56a734406117ffa4a1d1a6 100644 (file)
 #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();
-       }
-       portRESTORE_CONTEXT();
+       portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
 }
 /*-----------------------------------------------------------*/
 
-void interrupt_handler( IRQ_UART1_RX )
+/* UART Rx interrupt. */
+void interrupt6_handler( void )
 {
-static signed char cChar;
-static portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
-
        portSAVE_CONTEXT();
+       prvRxHandler();
+       portRESTORE_CONTEXT();
+}
+/*-----------------------------------------------------------*/
+
+static void prvRxHandler( void )
+{
+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 );
 }
 /*-----------------------------------------------------------*/