\r
\r
***************************************************************************\r
- * *\r
- * Looking for a quick start? Then check out the FreeRTOS eBook! *\r
- * See http://www.FreeRTOS.org/Documentation for details *\r
- * *\r
+ * *\r
+ * Looking for a quick start? Then check out the FreeRTOS eBook! *\r
+ * See http://www.FreeRTOS.org/Documentation for details *\r
+ * *\r
***************************************************************************\r
\r
1 tab == 4 spaces!\r
licensing and training services.\r
*/\r
\r
-\r
-/*\r
- * Creates all the demo application tasks, then starts the scheduler. The WEB\r
- * documentation provides more details of the standard demo application tasks.\r
- * In addition to the standard demo tasks, the following tasks and tests are\r
- * defined and/or created within this file:\r
- *\r
- * "Fast Interrupt Test" - A high frequency periodic interrupt is generated\r
- * using a free running timer to demonstrate the use of the\r
- * configKERNEL_INTERRUPT_PRIORITY configuration constant. The interrupt\r
- * service routine measures the number of processor clocks that occur between\r
- * each interrupt - and in so doing measures the jitter in the interrupt timing.\r
- * The maximum measured jitter time is latched in the ulMaxJitter variable, and\r
- * displayed on the OLED display by the 'OLED' task as described below. The\r
- * fast interrupt is configured and handled in the timertest.c source file.\r
- *\r
- * "OLED" task - the OLED task is a 'gatekeeper' task. It is the only task that\r
- * is permitted to access the display directly. Other tasks wishing to write a\r
- * message to the OLED send the message on a queue to the OLED task instead of\r
- * accessing the OLED themselves. The OLED task just blocks on the queue waiting\r
- * for messages - waking and displaying the messages as they arrive.\r
- *\r
- * "Check" hook - This only executes every five seconds from the tick hook.\r
- * Its main function is to check that all the standard demo tasks are still\r
- * operational. Should any unexpected behaviour within a demo task be discovered\r
- * the tick hook will write an error to the OLED (via the OLED task). If all the\r
- * demo tasks are executing with their expected behaviour then the check task\r
- * writes PASS to the OLED (again via the OLED task), as described above.\r
- *\r
- * "uIP" task - This is the task that handles the uIP stack. All TCP/IP\r
- * processing is performed in this task.\r
- */\r
-\r
-\r
-\r
-\r
-/*************************************************************************\r
- * Please ensure to read http://www.freertos.org/portLM3Sxxxx_Eclipse.html\r
- * which provides information on configuring and running this demo for the\r
- * various Luminary Micro EKs.\r
- *************************************************************************/\r
-\r
-\r
-\r
-\r
/* Standard includes. */\r
-#include <stdio.h>\r
+#include <string.h>\r
+#include <__cross_studio_io.h>\r
\r
/* Scheduler includes. */\r
#include "FreeRTOS.h"\r
#include "semphr.h"\r
\r
/* Hardware library includes. */\r
-#include "hw_memmap.h"\r
#include "hw_types.h"\r
#include "hw_sysctl.h"\r
#include "sysctl.h"\r
-#include "gpio.h"\r
-#include "grlib.h"\r
-#include "rit128x96x4.h"\r
-#include "osram128x64x4.h"\r
-#include "formike128x128x16.h"\r
-\r
-/* Demo app includes. */\r
-#include "BlockQ.h"\r
-#include "death.h"\r
-#include "integer.h"\r
-#include "blocktim.h"\r
-#include "flash.h"\r
-#include "partest.h"\r
-#include "semtest.h"\r
-#include "PollQ.h"\r
-#include "lcd_message.h"\r
-#include "bitmap.h"\r
-#include "GenQTest.h"\r
-#include "QPeek.h"\r
-#include "recmutex.h"\r
-#include "IntQueue.h"\r
+\r
+/*\r
+ * This file demonstrates the use of MPU using just three tasks - two 'reg test'\r
+ * tasks and one 'check' task. Read the comments above the\r
+ * function prototypes for more information.\r
+ */\r
\r
/*-----------------------------------------------------------*/\r
\r
-/* The time between cycles of the 'check' functionality (defined within the\r
-tick hook. */\r
-#define mainCHECK_DELAY ( ( portTickType ) 5000 / portTICK_RATE_MS )\r
+/* Misc constants. */\r
+#define mainDONT_BLOCK ( 0 )\r
\r
-/* Size of the stack allocated to the uIP task. */\r
-#define mainBASIC_WEB_STACK_SIZE ( configMINIMAL_STACK_SIZE * 3 )\r
+/* Definitions for the messages that can be sent to the check task. */\r
+#define mainREG_TEST_1_STILL_EXECUTING ( 0 )\r
+#define mainREG_TEST_2_STILL_EXECUTING ( 1 )\r
+#define mainPRINT_SYSTEM_STATUS ( 2 )\r
\r
-/* The OLED task uses the sprintf function so requires a little more stack too. */\r
-#define mainOLED_TASK_STACK_SIZE ( configMINIMAL_STACK_SIZE + 50 )\r
+/* GCC specifics. */\r
+#define mainALIGN_TO( x ) __attribute__((aligned(x)))\r
\r
-/* Task priorities. */\r
-#define mainQUEUE_POLL_PRIORITY ( tskIDLE_PRIORITY + 2 )\r
-#define mainCHECK_TASK_PRIORITY ( tskIDLE_PRIORITY + 3 )\r
-#define mainSEM_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 )\r
-#define mainBLOCK_Q_PRIORITY ( tskIDLE_PRIORITY + 2 )\r
-#define mainCREATOR_TASK_PRIORITY ( tskIDLE_PRIORITY + 3 )\r
-#define mainINTEGER_TASK_PRIORITY ( tskIDLE_PRIORITY )\r
-#define mainGEN_QUEUE_TASK_PRIORITY ( tskIDLE_PRIORITY )\r
\r
-/* The maximum number of message that can be waiting for display at any one\r
-time. */\r
-#define mainOLED_QUEUE_SIZE ( 3 )\r
+/*-----------------------------------------------------------*/\r
+/* Prototypes for functions that implement tasks. -----------*/\r
+/*-----------------------------------------------------------*/\r
\r
-/* Dimensions the buffer into which the jitter time is written. */\r
-#define mainMAX_MSG_LEN 25\r
+/* \r
+ * Prototype for the reg test tasks. Amongst other things, these fill the CPU\r
+ * registers with known values before checking that the registers still contain\r
+ * the expected values. Each of the two tasks use different values so an error\r
+ * in the context switch mechanism can be caught. Both reg test tasks execute\r
+ * at the idle priority so will get preempted regularly.\r
+ */\r
+static void prvRegTest1Task( void *pvParameters );\r
+static void prvRegTest2Task( void *pvParameters );\r
\r
-/* The period of the system clock in nano seconds. This is used to calculate\r
-the jitter time in nano seconds. */\r
-#define mainNS_PER_CLOCK ( ( unsigned portLONG ) ( ( 1.0 / ( double ) configCPU_CLOCK_HZ ) * 1000000000.0 ) )\r
+/*\r
+ * Prototype for the check task. The check task demonstrates various features\r
+ * of the MPU before entering a loop where it waits for commands to arrive on a\r
+ * queue.\r
+ *\r
+ * The check task will periodically be commanded to print out a status message.\r
+ * If both the reg tests tasks are executing as expected the check task will\r
+ * print "PASS" to the debug port, otherwise it will print 'FAIL'. Debug port\r
+ * messages can be viewed within the CrossWorks IDE.\r
+ */\r
+static void prvCheckTask( void *pvParameters );\r
\r
-/* Constants used when writing strings to the display. */\r
-#define mainCHARACTER_HEIGHT ( 9 )\r
-#define mainMAX_ROWS_128 ( mainCHARACTER_HEIGHT * 14 )\r
-#define mainMAX_ROWS_96 ( mainCHARACTER_HEIGHT * 10 )\r
-#define mainMAX_ROWS_64 ( mainCHARACTER_HEIGHT * 7 )\r
-#define mainFULL_SCALE ( 15 )\r
-#define ulSSI_FREQUENCY ( 3500000UL )\r
\r
+\r
+/*-----------------------------------------------------------*/\r
+/* Prototypes for other misc functions. --------------------*/\r
/*-----------------------------------------------------------*/\r
\r
/*\r
- * The task that handles the uIP stack. All TCP/IP processing is performed in\r
- * this task.\r
+ * Just configures any clocks and IO necessary.\r
*/\r
-extern void vuIP_Task( void *pvParameters );\r
+static void prvSetupHardware( void );\r
\r
/*\r
- * The display is written two by more than one task so is controlled by a\r
- * 'gatekeeper' task. This is the only task that is actually permitted to\r
- * access the display directly. Other tasks wanting to display a message send\r
- * the message to the gatekeeper.\r
+ * Simply deletes the calling task. The function is provided only because it\r
+ * is simpler to call from asm code than the normal vTaskDelete() API function.\r
+ * It has the noinline attribute because it is called from asm code.\r
*/\r
-static void vOLEDTask( void *pvParameters );\r
+static void prvDeleteMe( void ) __attribute__((noinline));\r
\r
/*\r
- * Configure the hardware for the demo.\r
+ * Used by both reg test tasks to send messages to the check task. The message\r
+ * just lets the check task know that the sending is still functioning correctly.\r
+ * If a reg test task detects an error it will delete itself, and in so doing\r
+ * prevent itself from sending any more 'I'm Alive' messages to the check task.\r
*/\r
-static void prvSetupHardware( void );\r
+static void prvSendImAlive( xQueueHandle xHandle, unsigned long ulTaskNumber );\r
\r
/*\r
- * Configures the high frequency timers - those used to measure the timing\r
- * jitter while the real time kernel is executing.\r
+ * The check task is created with access to three memory regions (plus its\r
+ * stack). Each memory region is configured with different parameters and\r
+ * prvTestMemoryRegions() demonstrates what can and cannot be accessed for each\r
+ * region. prvTestMemoryRegions() also demonstrates a task that was created\r
+ * as a privileged task settings its own privilege level down to that of a user\r
+ * task.\r
*/\r
-extern void vSetupHighFrequencyTimer( void );\r
+static void prvTestMemoryRegions( void );\r
\r
-/*\r
- * The idle hook is used to run a test of the scheduler context switch\r
- * mechanism.\r
- */\r
-void vApplicationIdleHook( void ) __attribute__((naked));\r
/*-----------------------------------------------------------*/\r
\r
-/* The queue used to send messages to the OLED task. */\r
-xQueueHandle xOLEDQueue;\r
+/* The handle of the queue used to communicate between tasks and between tasks\r
+and interrupts. Note that this is a file scope variable that falls outside of\r
+any MPU region. As such other techniques have to be used to allow the tasks\r
+to gain access to the queue. See the comments in the tasks themselves for \r
+further information. */\r
+static xQueueHandle xFileScopeCheckQueue = NULL;\r
\r
-/* The welcome text. */\r
-const portCHAR * const pcWelcomeMessage = " www.FreeRTOS.org";\r
\r
-/* Variables used to detect the test in the idle hook failing. */\r
-unsigned portLONG ulIdleError = pdFALSE;\r
+\r
+/*-----------------------------------------------------------*/\r
+/* Data used by the 'check' task. ---------------------------*/\r
+/*-----------------------------------------------------------*/\r
+\r
+/* Define the constants used to allocate the check task stack. Note that the\r
+stack size is defined in words, not bytes. */\r
+#define mainCHECK_TASK_STACK_SIZE_WORDS 128\r
+#define mainCHECK_TASK_STACK_ALIGNMENT ( mainCHECK_TASK_STACK_SIZE_WORDS * sizeof( portSTACK_TYPE ) )\r
+\r
+/* Declare the stack that will be used by the check task. The kernel will\r
+ automatically create an MPU region for the stack. The stack alignment must \r
+ match its size, so if 128 words are reserved for the stack then it must be \r
+ aligned to ( 128 * 4 ) bytes. */\r
+static portSTACK_TYPE xCheckTaskStack[ mainCHECK_TASK_STACK_SIZE_WORDS ] mainALIGN_TO( mainCHECK_TASK_STACK_ALIGNMENT );\r
+\r
+/* Declare three arrays - an MPU region will be created for each array\r
+ using the xTaskParameters structure below. Note that the arrays allocate \r
+slightly more RAM than is actually assigned to the MPU region. This is to \r
+permit writes off the end of the array to be detected even when the arrays are \r
+placed in adjacent memory locations (with no gaps between them). The align \r
+size must be a power of two. */\r
+#define mainREAD_WRITE_ARRAY_SIZE 130\r
+#define mainREAD_WRITE_ALIGN_SIZE 128\r
+char cReadWriteArray[ mainREAD_WRITE_ARRAY_SIZE ] mainALIGN_TO( mainREAD_WRITE_ALIGN_SIZE );\r
+\r
+#define mainREAD_ONLY_ARRAY_SIZE 260\r
+#define mainREAD_ONLY_ALIGN_SIZE 256\r
+char cReadOnlyArray[ mainREAD_ONLY_ARRAY_SIZE ] mainALIGN_TO( mainREAD_ONLY_ALIGN_SIZE );\r
+\r
+#define mainPRIVILEGED_ONLY_ACCESS_ARRAY_SIZE 130\r
+#define mainPRIVILEGED_ONLY_ACCESS_ALIGN_SIZE 128\r
+char cPrivilegedOnlyAccessArray[ mainPRIVILEGED_ONLY_ACCESS_ALIGN_SIZE ] mainALIGN_TO( mainPRIVILEGED_ONLY_ACCESS_ALIGN_SIZE );\r
+\r
+/* Fill in a xTaskParameters structure to define the check task. */\r
+static const xTaskParameters xCheckTaskParameters =\r
+{\r
+ prvCheckTask, /* pvTaskCode - the function that implements the task. */\r
+ ( signed char * ) "Check", /* pcName */\r
+ mainCHECK_TASK_STACK_SIZE_WORDS, /* usStackDepth - defined in words, not bytes. */\r
+ ( void * ) 0x12121212, /* pvParameters - this value is just to test that the parameter is being passed into the task correctly. */\r
+ ( tskIDLE_PRIORITY + 1 ) | portPRIVILEGE_BIT,/* uxPriority - this is the highest priority task in the system. The task is created in privileged mode to demonstrate accessing the privileged only data. */\r
+ xCheckTaskStack, /* puxStackBuffer - the array to use as the task stack, as declared above. */\r
+\r
+ /* xRegions - In this case the xRegions array is used to create MPU regions\r
+ for all three of the arrays declared directly above. Each MPU region is\r
+ created with different parameters. */\r
+ { \r
+ /* Base address Length Parameters */\r
+ { cReadWriteArray, mainREAD_WRITE_ALIGN_SIZE, portMPU_REGION_READ_WRITE },\r
+ { cReadOnlyArray, mainREAD_ONLY_ALIGN_SIZE, portMPU_REGION_READ_ONLY },\r
+ { cPrivilegedOnlyAccessArray, mainPRIVILEGED_ONLY_ACCESS_ALIGN_SIZE, portMPU_REGION_PRIVILEGED_READ_WRITE }\r
+ }\r
+};\r
+\r
+/* Three MPU regions are defined for use by the 'check' task when the task is \r
+created. These are only used to demonstrate the MPU features and are not\r
+actually necessary for the check task to fulfill its primary purpose. Instead\r
+the MPU regions are replaced with those defined by xAltRegions prior to the \r
+check task receiving any data on the queue or printing any messages to the\r
+debug console. The region configured by xAltRegions just gives the check task\r
+access to the debug variables that form part of the Rowley library, and are\r
+accessed within the debug_printf() function. */\r
+extern unsigned long dbgCntrlWord_mempoll;\r
+static const xMemoryRegion xAltRegions[ portNUM_CONFIGURABLE_REGIONS ] =\r
+{ \r
+ /* Base address Length Parameters */\r
+ { ( void * ) &dbgCntrlWord_mempoll, 32, portMPU_REGION_READ_WRITE },\r
+ { 0, 0, 0 },\r
+ { 0, 0, 0 }\r
+};\r
+\r
+\r
+\r
+/*-----------------------------------------------------------*/\r
+/* Data used by the 'reg test' tasks. -----------------------*/\r
+/*-----------------------------------------------------------*/\r
+\r
+/* Define the constants used to allocate the reg test task stacks. Note that\r
+that stack size is defined in words, not bytes. */\r
+#define mainREG_TEST_STACK_SIZE_WORDS 128\r
+#define mainREG_TEST_STACK_ALIGNMENT ( mainREG_TEST_STACK_SIZE_WORDS * sizeof( portSTACK_TYPE ) )\r
+\r
+/* Declare the stacks that will be used by the reg test tasks. The kernel will\r
+automatically create an MPU region for the stack. The stack alignment must \r
+match its size, so if 128 words are reserved for the stack then it must be \r
+aligned to ( 128 * 4 ) bytes. */\r
+static portSTACK_TYPE xRegTest1Stack[ mainREG_TEST_STACK_SIZE_WORDS ] mainALIGN_TO( mainREG_TEST_STACK_ALIGNMENT );\r
+static portSTACK_TYPE xRegTest2Stack[ mainREG_TEST_STACK_SIZE_WORDS ] mainALIGN_TO( mainREG_TEST_STACK_ALIGNMENT );\r
+\r
+/* Fill in a xTaskParameters structure per reg test task to define the tasks. */\r
+static const xTaskParameters xRegTest1Parameters =\r
+{\r
+ prvRegTest1Task, /* pvTaskCode - the function that implements the task. */\r
+ ( signed char * ) "RegTest1", /* pcName */\r
+ mainREG_TEST_STACK_SIZE_WORDS, /* usStackDepth */\r
+ ( void * ) 0x12345678, /* pvParameters - this value is just to test that the parameter is being passed into the task correctly. */\r
+ tskIDLE_PRIORITY | portPRIVILEGE_BIT, /* uxPriority - note that this task is created with privileges to demonstrate one method of passing a queue handle into the task. */\r
+ xRegTest1Stack, /* puxStackBuffer - the array to use as the task stack, as declared above. */\r
+ { /* xRegions - this task does not use any non-stack data. */\r
+ /* Base address Length Parameters */\r
+ { 0x00, 0x00, 0x00 },\r
+ { 0x00, 0x00, 0x00 },\r
+ { 0x00, 0x00, 0x00 }\r
+ }\r
+};\r
+/*-----------------------------------------------------------*/\r
+\r
+static xTaskParameters xRegTest2Parameters =\r
+{\r
+ prvRegTest2Task, /* pvTaskCode - the function that implements the task. */\r
+ ( signed char * ) "RegTest2", /* pcName */\r
+ mainREG_TEST_STACK_SIZE_WORDS, /* usStackDepth */\r
+ ( void * ) NULL, /* pvParameters - this task uses the parameter to pass in a queue handle, but the queue is not created yet. */\r
+ tskIDLE_PRIORITY, /* uxPriority */\r
+ xRegTest2Stack, /* puxStackBuffer - the array to use as the task stack, as declared above. */\r
+ { /* xRegions - this task does not use any non-stack data. */\r
+ /* Base address Length Parameters */\r
+ { 0x00, 0x00, 0x00 },\r
+ { 0x00, 0x00, 0x00 },\r
+ { 0x00, 0x00, 0x00 }\r
+ }\r
+};\r
\r
/*-----------------------------------------------------------*/\r
\r
-/*************************************************************************\r
- * Please ensure to read http://www.freertos.org/portLM3Sxxxx_Eclipse.html\r
- * which provides information on configuring and running this demo for the\r
- * various Luminary Micro EKs.\r
- *************************************************************************/\r
int main( void )\r
{\r
prvSetupHardware();\r
\r
- /* Create the queue used by the OLED task. Messages for display on the OLED\r
- are received via this queue. */\r
- xOLEDQueue = xQueueCreate( mainOLED_QUEUE_SIZE, sizeof( xOLEDMessage ) );\r
+ /* Create the queue used to pass "I'm alive" messages to the check task. */\r
+ xFileScopeCheckQueue = xQueueCreate( 1, sizeof( unsigned long ) );\r
\r
- /* Create the uIP task if running on a processor that includes a MAC and\r
- PHY. */\r
- if( SysCtlPeripheralPresent( SYSCTL_PERIPH_ETH ) )\r
- {\r
- xTaskCreate( vuIP_Task, ( signed portCHAR * ) "uIP", mainBASIC_WEB_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY - 1, NULL );\r
- }\r
+ /* One check task uses the task parameter to receive the queue handle.\r
+ This allows the file scope variable to be accessed from within the task.\r
+ The pvParameters member of xRegTest2Parameters can only be set after the\r
+ queue has been created. */\r
+ xRegTest2Parameters.pvParameters = xFileScopeCheckQueue;\r
\r
- /* Start the standard demo tasks. */\r
- vStartBlockingQueueTasks( mainBLOCK_Q_PRIORITY );\r
- vCreateBlockTimeTasks();\r
- vStartSemaphoreTasks( mainSEM_TEST_PRIORITY );\r
- vStartPolledQueueTasks( mainQUEUE_POLL_PRIORITY );\r
- vStartIntegerMathTasks( mainINTEGER_TASK_PRIORITY );\r
- vStartGenericQueueTasks( mainGEN_QUEUE_TASK_PRIORITY );\r
- vStartQueuePeekTasks();\r
- vStartRecursiveMutexTasks();\r
- vStartInterruptQueueTasks();\r
-\r
- /* Start the tasks defined within this file/specific to this demo. */\r
- xTaskCreate( vOLEDTask, ( signed portCHAR * ) "OLED", mainOLED_TASK_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );\r
-\r
- /* The suicide tasks must be created last as they need to know how many\r
- tasks were running prior to their creation in order to ascertain whether\r
- or not the correct/expected number of tasks are running at any given time. */\r
- vCreateSuicidalTasks( mainCREATOR_TASK_PRIORITY );\r
-\r
- /* Configure the high frequency interrupt used to measure the interrupt\r
- jitter time. */\r
- vSetupHighFrequencyTimer();\r
+ /* Create the three test tasks. Handles to the created tasks are not\r
+ required, hence the second parameter is NULL. */\r
+ xTaskCreateRestricted( &xRegTest1Parameters, NULL );\r
+ xTaskCreateRestricted( &xRegTest2Parameters, NULL );\r
+ xTaskCreateRestricted( &xCheckTaskParameters, NULL );\r
\r
/* Start the scheduler. */\r
vTaskStartScheduler();\r
\r
- /* Will only get here if there was insufficient memory to create the idle\r
- task. */\r
+ /* Will only get here if there was insufficient memory to create the idle\r
+ task. */\r
for( ;; );\r
return 0;\r
}\r
/*-----------------------------------------------------------*/\r
\r
-void prvSetupHardware( void )\r
+static void prvCheckTask( void *pvParameters )\r
{\r
- /* If running on Rev A2 silicon, turn the LDO voltage up to 2.75V. This is\r
- a workaround to allow the PLL to operate reliably. */\r
- if( DEVICE_IS_REVA2 )\r
- {\r
- SysCtlLDOSet( SYSCTL_LDO_2_75V );\r
- }\r
-\r
- /* Set the clocking to run from the PLL at 50 MHz */\r
- SysCtlClockSet( SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_8MHZ );\r
-\r
- /* Enable Port F for Ethernet LEDs\r
- LED0 Bit 3 Output\r
- LED1 Bit 2 Output */\r
- SysCtlPeripheralEnable( SYSCTL_PERIPH_GPIOF );\r
- GPIODirModeSet( GPIO_PORTF_BASE, (GPIO_PIN_2 | GPIO_PIN_3), GPIO_DIR_MODE_HW );\r
- GPIOPadConfigSet( GPIO_PORTF_BASE, (GPIO_PIN_2 | GPIO_PIN_3 ), GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD );\r
-\r
- vParTestInitialise();\r
+/* This task is created in privileged mode so can access the file scope\r
+queue variable. Take a stack copy of this before the task is set into user\r
+mode. Once that task is in user mode the file scope queue variable will no\r
+longer be accessible but the stack copy will. */\r
+xQueueHandle xQueue = xFileScopeCheckQueue;\r
+long lMessage;\r
+unsigned long ulStillAliveCounts[ 2 ] = { 0 };\r
+const char *pcStatusMessage = "PASS\r\n";\r
+\r
+ /* Just to remove compiler warning. */\r
+ ( void ) pvParameters;\r
+\r
+ /* Demonstrate how the various memory regions can and can't be accessed. \r
+ The task privilege is set down to user mode within this function. */\r
+ prvTestMemoryRegions();\r
+\r
+ /* Change the memory regions allocated to this task to those initially\r
+ set up for demonstration purposes to those actually required by the task. */\r
+ vTaskAllocateMPURegions( NULL, xAltRegions );\r
+\r
+ /* This loop performs the main function of the task, which is blocking\r
+ on a message queue then processing each message as it arrives. */\r
+ for( ;; )\r
+ {\r
+ /* Wait for the next message to arrive. */\r
+ xQueueReceive( xQueue, &lMessage, portMAX_DELAY );\r
+ \r
+ switch( lMessage )\r
+ {\r
+ case mainREG_TEST_1_STILL_EXECUTING : \r
+ /* Message from task 1, so task 1 must still be executing. */\r
+ ( ulStillAliveCounts[ 0 ] )++;\r
+ break;\r
+\r
+ case mainREG_TEST_2_STILL_EXECUTING : \r
+ /* Message from task 2, so task 2 must still be executing. */\r
+ ( ulStillAliveCounts[ 1 ] )++;\r
+ break;\r
+\r
+ case mainPRINT_SYSTEM_STATUS : \r
+ /* Message from tick hook, time to print out the system\r
+ status. If messages has stopped arriving from either reg\r
+ test task then the status must be set to fail. */\r
+ if( ( ulStillAliveCounts[ 0 ] == 0 ) || ( ulStillAliveCounts[ 1 ] == 0 ) )\r
+ {\r
+ /* One or both of the test tasks are no longer sending \r
+ 'still alive' messages. */\r
+ pcStatusMessage = "FAIL\r\n";\r
+ }\r
+\r
+ /* Print a pass/fail message to the terminal. This will be\r
+ visible in the CrossWorks IDE. */\r
+ debug_printf( pcStatusMessage );\r
+\r
+ /* Reset the count of 'still alive' messages. */\r
+ memset( ulStillAliveCounts, 0x00, sizeof( ulStillAliveCounts ) );\r
+ break;\r
+\r
+ default :\r
+ /* Something unexpected happened. Delete this task so the \r
+ error is apparent (no output will be displayed). */\r
+ prvDeleteMe();\r
+ break;\r
+ }\r
+ }\r
}\r
/*-----------------------------------------------------------*/\r
\r
-void vApplicationTickHook( void )\r
+static void prvTestMemoryRegions( void )\r
{\r
-static xOLEDMessage xMessage = { "PASS" };\r
-static unsigned portLONG ulTicksSinceLastDisplay = 0;\r
-portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;\r
-\r
- /* Called from every tick interrupt. Have enough ticks passed to make it\r
- time to perform our health status check again? */\r
- ulTicksSinceLastDisplay++;\r
- if( ulTicksSinceLastDisplay >= mainCHECK_DELAY )\r
+long l;\r
+char cTemp;\r
+\r
+ /* The check task is created in the privileged mode. The privileged array \r
+ can be both read from and written to while this task is privileged. */\r
+ cPrivilegedOnlyAccessArray[ 0 ] = 'a';\r
+ if( cPrivilegedOnlyAccessArray[ 0 ] != 'a' )\r
{\r
- ulTicksSinceLastDisplay = 0;\r
+ /* Something unexpected happened. Delete this task so the error is\r
+ apparent (no output will be displayed). */\r
+ prvDeleteMe();\r
+ }\r
\r
- /* Has an error been found in any task? */\r
- if( xAreGenericQueueTasksStillRunning() != pdTRUE )\r
- {\r
- xMessage.pcMessage = "ERROR IN GEN Q";\r
- }\r
- else if( xAreQueuePeekTasksStillRunning() != pdTRUE )\r
- {\r
- xMessage.pcMessage = "ERROR IN PEEK Q";\r
- }\r
- else if( xAreBlockingQueuesStillRunning() != pdTRUE )\r
- {\r
- xMessage.pcMessage = "ERROR IN BLOCK Q";\r
- }\r
- else if( xAreBlockTimeTestTasksStillRunning() != pdTRUE )\r
- {\r
- xMessage.pcMessage = "ERROR IN BLOCK TIME";\r
- }\r
- else if( xAreSemaphoreTasksStillRunning() != pdTRUE )\r
- {\r
- xMessage.pcMessage = "ERROR IN SEMAPHORE";\r
- }\r
- else if( xArePollingQueuesStillRunning() != pdTRUE )\r
- {\r
- xMessage.pcMessage = "ERROR IN POLL Q";\r
- }\r
- else if( xIsCreateTaskStillRunning() != pdTRUE )\r
- {\r
- xMessage.pcMessage = "ERROR IN CREATE";\r
- }\r
- else if( xAreIntegerMathsTaskStillRunning() != pdTRUE )\r
- {\r
- xMessage.pcMessage = "ERROR IN MATH";\r
- }\r
- else if( xAreRecursiveMutexTasksStillRunning() != pdTRUE )\r
- {\r
- xMessage.pcMessage = "ERROR IN REC MUTEX";\r
- }\r
- else if( ulIdleError != pdFALSE )\r
- {\r
- xMessage.pcMessage = "ERROR IN HOOK";\r
- }\r
- else if( xAreIntQueueTasksStillRunning() != pdTRUE )\r
+ /* Writing off the end of the RAM allocated to this task will *NOT* cause a\r
+ protection fault because the task is still executing in a privileged mode. \r
+ Uncomment the following to test. */\r
+ /*cPrivilegedOnlyAccessArray[ mainPRIVILEGED_ONLY_ACCESS_ALIGN_SIZE ] = 'a';*/\r
+\r
+ /* Now set the task into user mode. */\r
+ portSWITCH_TO_USER_MODE();\r
+ \r
+ /* Accessing the privileged only array will now cause a fault. Uncomment \r
+ the following line to test. */ \r
+ /*cPrivilegedOnlyAccessArray[ 0 ] = 'a';*/\r
+\r
+ /* The read/write array can still be successfully read and written. */\r
+ for( l = 0; l < mainREAD_WRITE_ALIGN_SIZE; l++ )\r
+ {\r
+ cReadWriteArray[ l ] = 'a';\r
+ if( cReadWriteArray[ l ] != 'a' )\r
{\r
- xMessage.pcMessage = "ERROR IN INT QUEUE";\r
+ /* Something unexpected happened. Delete this task so the error is\r
+ apparent (no output will be displayed). */\r
+ prvDeleteMe();\r
}\r
+ }\r
\r
+ /* But attempting to read or write off the end of the RAM allocated to this\r
+ task will cause a fault. Uncomment either of the following two lines to \r
+ test. */\r
+ /* cReadWriteArray[ 0 ] = cReadWriteArray[ -1 ]; */\r
+ /* cReadWriteArray[ mainREAD_WRITE_ALIGN_SIZE ] = 0x00; */\r
\r
- /* Send the message to the OLED gatekeeper for display. */\r
- xHigherPriorityTaskWoken = pdFALSE;\r
- xQueueSendFromISR( xOLEDQueue, &xMessage, &xHigherPriorityTaskWoken );\r
+ /* The read only array can be successfully read... */\r
+ for( l = 0; l < mainREAD_ONLY_ALIGN_SIZE; l++ )\r
+ {\r
+ cTemp = cReadOnlyArray[ l ];\r
}\r
+\r
+ /* ...but cannot be written. Uncomment the following line to test. */\r
+ /* cReadOnlyArray[ 0 ] = 'a'; */\r
+\r
+ /* Writing to the first and last locations in the stack array should not \r
+ cause a protection fault. Note that doing this will cause the kernel to\r
+ detect a stack overflow if configCHECK_FOR_STACK_OVERFLOW is greater than \r
+ 1. */\r
+ xCheckTaskStack[ 0 ] = 0;\r
+ xCheckTaskStack[ mainCHECK_TASK_STACK_SIZE_WORDS - 1 ] = 0;\r
+\r
+ /* Writing off either end of the stack array should cause a protection \r
+ fault, uncomment either of the following two lines to test. */\r
+ /* xCheckTaskStack[ -1 ] = 0; */\r
+ /* xCheckTaskStack[ mainCHECK_TASK_STACK_SIZE_WORDS ] = 0; */\r
}\r
/*-----------------------------------------------------------*/\r
\r
-void vOLEDTask( void *pvParameters )\r
+static void prvRegTest1Task( void *pvParameters )\r
{\r
-xOLEDMessage xMessage;\r
-unsigned portLONG ulY, ulMaxY;\r
-static portCHAR cMessage[ mainMAX_MSG_LEN ];\r
-extern volatile unsigned portLONG ulMaxJitter;\r
-unsigned portBASE_TYPE uxUnusedStackOnEntry, uxUnusedStackNow;\r
-const unsigned portCHAR *pucImage;\r
-\r
-/* Functions to access the OLED. The one used depends on the dev kit\r
-being used. */\r
-void ( *vOLEDInit )( unsigned portLONG ) = NULL;\r
-void ( *vOLEDStringDraw )( const portCHAR *, unsigned portLONG, unsigned portLONG, unsigned portCHAR ) = NULL;\r
-void ( *vOLEDImageDraw )( const unsigned portCHAR *, unsigned portLONG, unsigned portLONG, unsigned portLONG, unsigned portLONG ) = NULL;\r
-void ( *vOLEDClear )( void ) = NULL;\r
-\r
- /* Just for demo purposes. */\r
- uxUnusedStackOnEntry = uxTaskGetStackHighWaterMark( NULL );\r
-\r
- /* Map the OLED access functions to the driver functions that are appropriate\r
- for the evaluation kit being used. */\r
- switch( HWREG( SYSCTL_DID1 ) & SYSCTL_DID1_PRTNO_MASK )\r
+/* This task is created in privileged mode so can access the file scope\r
+queue variable. Take a stack copy of this before the task is set into user\r
+mode. Once that task is in user mode the file scope queue variable will no\r
+longer be accessible but the stack copy will. */\r
+xQueueHandle xQueue = xFileScopeCheckQueue;\r
+\r
+ /* Now the queue handle has been obtained the task can switch to user \r
+ mode. This is just one method of passing a handle into a protected\r
+ task, the other reg test task uses the task parameter instead. */\r
+ portSWITCH_TO_USER_MODE();\r
+\r
+ /* First check that the parameter value is as expected. */\r
+ if( pvParameters != ( void * ) 0x12345678 )\r
{\r
- case SYSCTL_DID1_PRTNO_6965 :\r
- case SYSCTL_DID1_PRTNO_2965 : vOLEDInit = OSRAM128x64x4Init;\r
- vOLEDStringDraw = OSRAM128x64x4StringDraw;\r
- vOLEDImageDraw = OSRAM128x64x4ImageDraw;\r
- vOLEDClear = OSRAM128x64x4Clear;\r
- ulMaxY = mainMAX_ROWS_64;\r
- pucImage = pucBasicBitmap;\r
- break;\r
-\r
- case SYSCTL_DID1_PRTNO_1968 :\r
- case SYSCTL_DID1_PRTNO_8962 : vOLEDInit = RIT128x96x4Init;\r
- vOLEDStringDraw = RIT128x96x4StringDraw;\r
- vOLEDImageDraw = RIT128x96x4ImageDraw;\r
- vOLEDClear = RIT128x96x4Clear;\r
- ulMaxY = mainMAX_ROWS_96;\r
- pucImage = pucBasicBitmap;\r
- break;\r
-\r
- default : vOLEDInit = vFormike128x128x16Init;\r
- vOLEDStringDraw = vFormike128x128x16StringDraw;\r
- vOLEDImageDraw = vFormike128x128x16ImageDraw;\r
- vOLEDClear = vFormike128x128x16Clear;\r
- ulMaxY = mainMAX_ROWS_128;\r
- pucImage = pucGrLibBitmap;\r
- break;\r
+ /* Error detected. Delete the task so it stops communicating with\r
+ the check task. */\r
+ prvDeleteMe();\r
}\r
\r
- ulY = ulMaxY;\r
\r
- /* Initialise the OLED and display a startup message. */\r
- vOLEDInit( ulSSI_FREQUENCY );\r
- vOLEDStringDraw( "POWERED BY FreeRTOS", 0, 0, mainFULL_SCALE );\r
- vOLEDImageDraw( pucImage, 0, mainCHARACTER_HEIGHT + 1, bmpBITMAP_WIDTH, bmpBITMAP_HEIGHT );\r
+ for( ;; )\r
+ { \r
+ /* This task tests the kernel context switch mechanism by reading and\r
+ writing directly to registers - which requires the test to be written\r
+ in assembly code. */\r
+ __asm volatile \r
+ ( \r
+ " MOV R4, #104 \n" /* Set registers to a known value. R0 to R1 are done in the loop below. */\r
+ " MOV R5, #105 \n"\r
+ " MOV R6, #106 \n"\r
+ " MOV R8, #108 \n"\r
+ " MOV R9, #109 \n"\r
+ " MOV R10, #110 \n"\r
+ " MOV R11, #111 \n"\r
+ "reg1loop: \n"\r
+ " MOV R0, #100 \n" /* Set the scratch registers to known values - done inside the loop as they get clobbered. */\r
+ " MOV R1, #101 \n"\r
+ " MOV R2, #102 \n"\r
+ " MOV R3, #103 \n"\r
+ " MOV R12, #112 \n"\r
+ " SVC #1 \n" /* Yield just to increase test coverage. */\r
+ " CMP R0, #100 \n" /* Check all the registers still contain their expected values. */\r
+ " BNE prvDeleteMe \n" /* Value was not as expected, delete the task so it stops communicating with the check task. */\r
+ " CMP R1, #101 \n"\r
+ " BNE prvDeleteMe \n"\r
+ " CMP R2, #102 \n"\r
+ " BNE prvDeleteMe \n"\r
+ " CMP R3, #103 \n"\r
+ " BNE prvDeleteMe \n"\r
+ " CMP R4, #104 \n" \r
+ " BNE prvDeleteMe \n" \r
+ " CMP R5, #105 \n"\r
+ " BNE prvDeleteMe \n"\r
+ " CMP R6, #106 \n"\r
+ " BNE prvDeleteMe \n"\r
+ " CMP R8, #108 \n"\r
+ " BNE prvDeleteMe \n"\r
+ " CMP R9, #109 \n"\r
+ " BNE prvDeleteMe \n"\r
+ " CMP R10, #110 \n"\r
+ " BNE prvDeleteMe \n"\r
+ " CMP R11, #111 \n"\r
+ " BNE prvDeleteMe \n"\r
+ " CMP R12, #112 \n"\r
+ " BNE prvDeleteMe \n"\r
+ );\r
+\r
+ /* Send mainREG_TEST_1_STILL_EXECUTING to the check task to indicate that this \r
+ task is still functioning. */\r
+ prvSendImAlive( xQueue, mainREG_TEST_1_STILL_EXECUTING );\r
+\r
+ /* Go back to check all the register values again. */\r
+ __asm volatile( " B reg1loop " );\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvRegTest2Task( void *pvParameters )\r
+{\r
+/* The queue handle is passed in as the task parameter. This is one method of\r
+passing data into a protected task, the other check task uses a different \r
+method. */\r
+xQueueHandle xQueue = ( xQueueHandle ) pvParameters;\r
\r
for( ;; )\r
{\r
- /* Wait for a message to arrive that requires displaying. */\r
- xQueueReceive( xOLEDQueue, &xMessage, portMAX_DELAY );\r
+ /* This task tests the kernel context switch mechanism by reading and\r
+ writing directly to registers - which requires the test to be written\r
+ in assembly code. */\r
+ __asm volatile \r
+ ( \r
+ " MOV R4, #4 \n" /* Set registers to a known value. R0 to R1 are done in the loop below. */\r
+ " MOV R5, #5 \n"\r
+ " MOV R6, #6 \n"\r
+ " MOV R8, #8 \n" /* Frame pointer is omitted as it must not be changed. */\r
+ " MOV R9, #9 \n"\r
+ " MOV R10, 10 \n"\r
+ " MOV R11, #11 \n" \r
+ "reg2loop: \n"\r
+ " MOV R0, #13 \n" /* Set the scratch registers to known values - done inside the loop as they get clobbered. */\r
+ " MOV R1, #1 \n"\r
+ " MOV R2, #2 \n"\r
+ " MOV R3, #3 \n"\r
+ " MOV R12, #12 \n"\r
+ " CMP R0, #13 \n" /* Check all the registers still contain their expected values. */\r
+ " BNE prvDeleteMe \n" /* Value was not as expected, delete the task so it stops communicating with the check task */\r
+ " CMP R1, #1 \n"\r
+ " BNE prvDeleteMe \n"\r
+ " CMP R2, #2 \n"\r
+ " BNE prvDeleteMe \n"\r
+ " CMP R3, #3 \n"\r
+ " BNE prvDeleteMe \n"\r
+ " CMP R4, #4 \n"\r
+ " BNE prvDeleteMe \n"\r
+ " CMP R5, #5 \n"\r
+ " BNE prvDeleteMe \n"\r
+ " CMP R6, #6 \n"\r
+ " BNE prvDeleteMe \n"\r
+ " CMP R8, #8 \n"\r
+ " BNE prvDeleteMe \n"\r
+ " CMP R9, #9 \n"\r
+ " BNE prvDeleteMe \n"\r
+ " CMP R10, #10 \n"\r
+ " BNE prvDeleteMe \n"\r
+ " CMP R11, #11 \n"\r
+ " BNE prvDeleteMe \n"\r
+ " CMP R12, #12 \n"\r
+ " BNE prvDeleteMe \n"\r
+ );\r
+\r
+ /* Send mainREG_TEST_2_STILL_EXECUTING to the check task to indicate that this \r
+ task is still functioning. */\r
+ prvSendImAlive( xQueue, mainREG_TEST_2_STILL_EXECUTING );\r
+\r
+ /* Go back to check all the register values again. */\r
+ __asm volatile( " B reg2loop " );\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
\r
- /* Write the message on the next available row. */\r
- ulY += mainCHARACTER_HEIGHT;\r
- if( ulY >= ulMaxY )\r
- {\r
- ulY = mainCHARACTER_HEIGHT;\r
- vOLEDClear();\r
- vOLEDStringDraw( pcWelcomeMessage, 0, 0, mainFULL_SCALE );\r
- }\r
+static void prvDeleteMe( void )\r
+{\r
+ vTaskDelete( NULL );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvSendImAlive( xQueueHandle xHandle, unsigned long ulTaskNumber )\r
+{\r
+ if( xHandle != NULL )\r
+ {\r
+ xQueueSend( xHandle, &ulTaskNumber, mainDONT_BLOCK );\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
\r
- /* Display the message along with the maximum jitter time from the\r
- high priority time test. */\r
- sprintf( cMessage, "%s [%uns]", xMessage.pcMessage, ulMaxJitter * mainNS_PER_CLOCK );\r
- vOLEDStringDraw( cMessage, 0, ulY, mainFULL_SCALE );\r
+static void prvSetupHardware( void )\r
+{\r
+ /* If running on Rev A2 silicon, turn the LDO voltage up to 2.75V. This is\r
+ a workaround to allow the PLL to operate reliably. */\r
+ if( DEVICE_IS_REVA2 )\r
+ {\r
+ SysCtlLDOSet( SYSCTL_LDO_2_75V );\r
+ }\r
+\r
+ /* Set the clocking to run from the PLL at 50 MHz */\r
+ SysCtlClockSet( SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_8MHZ );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vApplicationTickHook( void )\r
+{\r
+static unsigned long ulCallCount;\r
+const unsigned long ulCallsBetweenSends = 5000 / portTICK_RATE_MS;\r
+const unsigned long ulMessage = mainPRINT_SYSTEM_STATUS;\r
+portBASE_TYPE xDummy;\r
+\r
+ /* If configUSE_TICK_HOOK is set to 1 then this function will get called\r
+ from each RTOS tick. It is called from the tick interrupt and therefore\r
+ will be executing in the privileged state. */\r
+\r
+ ulCallCount++;\r
+\r
+ /* Is it time to print out the pass/fail message again? */\r
+ if( ulCallCount >= ulCallsBetweenSends )\r
+ {\r
+ ulCallCount = 0;\r
+\r
+ /* Send a message to the check task to command it to check that all\r
+ the tasks are still running then print out the status. \r
+ \r
+ This is running in an ISR so has to use the "FromISR" version of\r
+ xQueueSend(). Because it is in an ISR it is running with privileges\r
+ so can access xFileScopeCheckQueue directly. */\r
+ xQueueSendFromISR( xFileScopeCheckQueue, &ulMessage, &xDummy );\r
}\r
}\r
/*-----------------------------------------------------------*/\r
\r
void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed portCHAR *pcTaskName )\r
{\r
+ /* If configCHECK_FOR_STACK_OVERFLOW is set to either 1 or 2 then this \r
+ function will automatically get called if a task overflows its stack. */\r
+ ( void ) pxTask;\r
+ ( void ) pcTaskName;\r
for( ;; );\r
}\r
/*-----------------------------------------------------------*/\r
\r
void vApplicationMallocFailedHook( void )\r
{\r
+ /* If configUSE_MALLOC_FAILED_HOOK is set to 1 then this function will\r
+ be called automatically if a call to pvPortMalloc() fails. pvPortMalloc()\r
+ is called automatically when a task, queue or semaphore is created. */\r
for( ;; );\r
}\r
/*-----------------------------------------------------------*/\r
/* Just to keep the linker happy. */\r
void __error__( char *pcFilename, unsigned long ulLine )\r
{\r
+ ( void ) pcFilename;\r
+ ( void ) ulLine;\r
for( ;; );\r
}\r
+/*-----------------------------------------------------------*/\r
\r
+/* Just to keep the linker happy. */\r
int uipprintf( const char *fmt, ... )\r
{\r
+ ( void ) fmt;\r
return( 0 );\r
}\r
+/*-----------------------------------------------------------*/\r
+\r
+void hard_fault_handler(unsigned int * hardfault_args)\r
+{\r
+unsigned int stacked_r0;\r
+unsigned int stacked_r1;\r
+unsigned int stacked_r2;\r
+unsigned int stacked_r3;\r
+unsigned int stacked_r12;\r
+unsigned int stacked_lr;\r
+unsigned int stacked_pc;\r
+unsigned int stacked_psr;\r
+\r
+ stacked_r0 = ((unsigned long) hardfault_args[0]);\r
+ stacked_r1 = ((unsigned long) hardfault_args[1]);\r
+ stacked_r2 = ((unsigned long) hardfault_args[2]);\r
+ stacked_r3 = ((unsigned long) hardfault_args[3]);\r
+\r
+ stacked_r12 = ((unsigned long) hardfault_args[4]);\r
+ stacked_lr = ((unsigned long) hardfault_args[5]);\r
+ stacked_pc = ((unsigned long) hardfault_args[6]);\r
+ stacked_psr = ((unsigned long) hardfault_args[7]);\r
+\r
+ /* Inspect stacked_pc to locate the offending instruction. */\r
+ for( ;; );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void Fault_ISR( void ) __attribute__((naked));\r
+void Fault_ISR( void )\r
+{\r
+ __asm volatile\r
+ (\r
+ " tst lr, #4 \n"\r
+ " ite eq \n"\r
+ " mrseq r0, msp \n"\r
+ " mrsne r0, psp \n"\r
+ " ldr r1, [r0, #24] \n"\r
+ " ldr r2, handler_address_const \n"\r
+ " bx r2 \n"\r
+ " handler_address_const: .word hard_fault_handler \n"\r
+ );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void MPU_Fault_ISR( void ) __attribute__((naked));\r
+void MPU_Fault_ISR( void )\r
+{\r
+ __asm volatile\r
+ (\r
+ " tst lr, #4 \n"\r
+ " ite eq \n"\r
+ " mrseq r0, msp \n"\r
+ " mrsne r0, psp \n"\r
+ " ldr r1, [r0, #24] \n"\r
+ " ldr r2, handler_address_const \n"\r
+ " bx r2 \n"\r
+ " handler2_address_const: .word hard_fault_handler \n"\r
+ );\r
+}\r
+/*-----------------------------------------------------------*/
\ No newline at end of file