http://www.OpenRTOS.com - Commercial support, development, porting,\r
licensing and training services.\r
*/\r
+\r
+/* Standard includes. */\r
#include <stdio.h>\r
\r
+/* FreeRTOS includes. */\r
#include "FreeRTOS.h"\r
#include "task.h"\r
#include "queue.h"\r
\r
+/* Hardware includes. */\r
#include "msp430.h"\r
#include "hal_MSP-EXP430F5438.h"\r
\r
-/* The rate at which mainCHECK_LED will toggle when all the tasks are running\r
-without error. Controlled by the check task as described at the top of this\r
-file. */\r
-#define mainNO_ERROR_CYCLE_TIME ( 5000 / portTICK_RATE_MS )\r
-\r
-/* The rate at which mainCHECK_LED will toggle when an error has been reported\r
-by at least one task. Controlled by the check task as described at the top of\r
-this file. */\r
-#define mainERROR_CYCLE_TIME ( 200 / portTICK_RATE_MS )\r
+/* Standard demo includes. */\r
+#include "ParTest.h"\r
+#include "dynamic.h"\r
+#include "comtest2.h"\r
+#include "GenQTest.h"\r
\r
/* Codes sent within messages to the LCD task so the LCD task can interpret\r
exactly what the message it just received was. These are sent in the\r
#define mainMESSAGE_STATUS ( 3 )\r
\r
/* When the cMessageID member of the message sent to the LCD task is\r
-mainMESSAGE_STATUS then these definitions are sent in the cMessageValue member\r
+mainMESSAGE_STATUS then these definitions are sent in the ulMessageValue member\r
of the same message and indicate what the status actually is. */\r
#define mainERROR_DYNAMIC_TASKS ( pdPASS + 1 )\r
#define mainERROR_COM_TEST ( pdPASS + 2 )\r
#define mainERROR_GEN_QUEUE_TEST ( pdPASS + 3 )\r
+#define mainERROR_REG_TEST ( pdPASS + 4 )\r
\r
/* The length of the queue (the number of items the queue can hold) that is used\r
to send messages from tasks and interrupts the the LCD task. */\r
#define mainQUEUE_LENGTH ( 5 )\r
\r
#define mainLCD_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 )\r
+#define mainCOM_TEST_PRIORITY ( tskIDLE_PRIORITY + 2 )\r
+#define mainGENERIC_QUEUE_TEST_PRIORITY ( tskIDLE_PRIORITY )\r
\r
+/* The LED used by the comtest tasks. See the comtest.c file for more\r
+information. In this case it is deliberately out of range as there are only\r
+two LEDs, and they are both already in use. */\r
+#define mainCOM_TEST_LED ( 3 )\r
+\r
+/* The baud rate used by the comtest tasks described at the top of this file. */\r
+#define mainCOM_TEST_BAUD_RATE ( 9600 )\r
/*-----------------------------------------------------------*/\r
\r
extern void vRegTest1Task( void *pvParameters );\r
extern void vRegTest2Task( void *pvParameters );\r
-static void prvCheckTask( void *pvParameters );\r
static void prvSetupHardware( void );\r
static void prvTerminalIOTask( void *pvParameters );\r
static void prvButtonPollTask( void *pvParameters );\r
/*-----------------------------------------------------------*/\r
\r
volatile unsigned short usRegTest1Counter = 0, usRegTest2Counter = 0;\r
+volatile unsigned long ulStatsOverflowCount = 0;\r
\r
/* The handle of the queue used to send messages from tasks and interrupts to\r
the LCD task. */\r
typedef struct\r
{\r
char cMessageID; /* << States what the message is. */\r
- char cMessageValue; /* << States the message value (can be an integer, string pointer, etc. depending on the value of cMessageID. */\r
+ unsigned long ulMessageValue; /* << States the message value (can be an integer, string pointer, etc. depending on the value of cMessageID. */\r
} xQueueMessage;\r
/*-----------------------------------------------------------*/\r
\r
void main( void )\r
{\r
prvSetupHardware();\r
- \r
+\r
/* Create the queue used by tasks and interrupts to send strings to the LCD\r
task. */\r
xLCDQueue = xQueueCreate( mainQUEUE_LENGTH, sizeof( xQueueMessage ) );\r
- \r
+\r
if( xLCDQueue != NULL )\r
{\r
/* Add the created queue to the queue registry so it can be viewed in\r
the IAR FreeRTOS state viewer plug-in. */\r
vQueueAddToRegistry( xLCDQueue, "LCDQueue" );\r
\r
+ /* Create the standard demo tasks. */\r
+ vAltStartComTestTasks( mainCOM_TEST_PRIORITY, mainCOM_TEST_BAUD_RATE, mainCOM_TEST_LED );\r
+ vStartDynamicPriorityTasks();\r
+ vStartGenericQueueTasks( mainGENERIC_QUEUE_TEST_PRIORITY );\r
+ \r
/* Create the terminal IO and button poll tasks, as described at the top\r
of this file. */\r
- xTaskCreate( prvTerminalIOTask, ( signed char * ) "LCD", configMINIMAL_STACK_SIZE, NULL, mainLCD_TASK_PRIORITY, NULL );\r
- xTaskCreate( prvButtonPollTask, ( signed char * ) "ButPoll", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );\r
+ xTaskCreate( prvTerminalIOTask, ( signed char * ) "IO", configMINIMAL_STACK_SIZE * 2, NULL, mainLCD_TASK_PRIORITY, NULL );\r
+ xTaskCreate( prvButtonPollTask, ( signed char * ) "BPoll", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );\r
\r
- xTaskCreate( vRegTest1Task, "RegTest1", configMINIMAL_STACK_SIZE, NULL, 0, NULL );\r
- xTaskCreate( vRegTest2Task, "RegTest2", configMINIMAL_STACK_SIZE, NULL, 0, NULL );\r
- xTaskCreate( prvCheckTask, "Check", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL );\r
+ /* Create the register test tasks as described at the top of this file. */\r
+ xTaskCreate( vRegTest1Task, "Reg1", configMINIMAL_STACK_SIZE, NULL, 0, NULL );\r
+ xTaskCreate( vRegTest2Task, "Reg2", configMINIMAL_STACK_SIZE, NULL, 0, NULL );\r
vTaskStartScheduler();\r
}\r
+ \r
for( ;; );\r
}\r
/*-----------------------------------------------------------*/\r
stack, which is too small to hold such a variable. The stack size is configured\r
when the task is created. */\r
static char cBuffer[ 512 ];\r
+unsigned char ucLine = 1;\r
+\r
\r
/* This function is the only function that uses printf(). If printf() is\r
used from any other function then some sort of mutual exclusion on stdout\r
has been received. */\r
xQueueReceive( xLCDQueue, &xReceivedMessage, portMAX_DELAY );\r
\r
+ /* Clear the LCD if no room remains for any more text output. */\r
+ if( ucLine > 8 )\r
+ {\r
+ halLcdClearScreen();\r
+ ucLine = 0;\r
+ }\r
+ \r
/* What is this message? What does it contain? */\r
switch( xReceivedMessage.cMessageID )\r
{\r
informed this task that the up\r
button on the joystick input has\r
been pressed or released. */\r
- sprintf( cBuffer, "Button up = %d", xReceivedMessage.cMessageValue );\r
+ sprintf( cBuffer, "Button up = %d", ( int ) xReceivedMessage.ulMessageValue );\r
break;\r
\r
case mainMESSAGE_BUTTON_SEL : /* The select button interrupt\r
the terminal IO window in the IAR\r
embedded workbench. */\r
printf( "\nTask\t Abs Time\t %%Time\n*****************************************" );\r
-// vTaskGetRunTimeStats( ( signed char * ) cBuffer );\r
-// printf( cBuffer );\r
+ fflush( stdout );\r
+ vTaskGetRunTimeStats( ( signed char * ) cBuffer );\r
+ printf( cBuffer );\r
+ fflush( stdout );\r
+ \r
+ /* Also print out a message to\r
+ the LCD - in this case the\r
+ pointer to the string to print\r
+ is sent directly in the\r
+ lMessageValue member of the\r
+ message. This just demonstrates\r
+ a different communication\r
+ technique. */\r
+ sprintf( cBuffer, "%s", ( char * ) xReceivedMessage.ulMessageValue );\r
break;\r
\r
case mainMESSAGE_STATUS : /* The tick interrupt hook\r
task of the system status.\r
Generate a string in accordance\r
with the status value. */\r
- prvGenerateStatusMessage( cBuffer, xReceivedMessage.cMessageValue );\r
+ prvGenerateStatusMessage( cBuffer, xReceivedMessage.ulMessageValue );\r
break;\r
\r
default : sprintf( cBuffer, "Unknown message" );\r
break;\r
}\r
\r
- /* Output the message that was placed into the cBuffer array within the\r
- switch statement above. */\r
- printf( "%s", cBuffer );\r
+ halLcdPrintLine( cBuffer, ucLine, OVERWRITE_TEXT );\r
+ ucLine++;\r
}\r
}\r
/*-----------------------------------------------------------*/\r
string for output onto the LCD. */\r
switch( lStatusValue )\r
{\r
- case pdPASS : sprintf( pcBuffer, "Task status = PASS" );\r
+ case pdPASS : sprintf( pcBuffer, "Status = PASS" );\r
break;\r
- case mainERROR_DYNAMIC_TASKS : sprintf( pcBuffer, "Error: Dynamic tasks" );\r
+ case mainERROR_DYNAMIC_TASKS : sprintf( pcBuffer, "Err: Dynamic tsks" );\r
break;\r
- case mainERROR_COM_TEST : sprintf( pcBuffer, "Err: loop connected?" ); /* Error in COM test - is the Loopback connector connected? */ \r
+ case mainERROR_COM_TEST : sprintf( pcBuffer, "Err: COM test" ); /* Error in COM test - is the Loopback connector connected? */ \r
break;\r
case mainERROR_GEN_QUEUE_TEST : sprintf( pcBuffer, "Error: Gen Q test" );\r
break;\r
+ case mainERROR_REG_TEST : sprintf( pcBuffer, "Error: Reg test" );\r
+ break;\r
default : sprintf( pcBuffer, "Unknown status" );\r
break;\r
}\r
{\r
/* Check the button state. */\r
ucState = ( halButtonsPressed() & BUTTON_UP );\r
+ \r
+ if( ucState != 0 )\r
+ {\r
+ ucState = pdTRUE;\r
+ }\r
+ \r
if( ucState != ucLastState )\r
{\r
/* The state has changed, send a message to the LCD task. */\r
xMessage.cMessageID = mainMESSAGE_BUTTON_UP;\r
- xMessage.cMessageValue = ucState;\r
+ xMessage.ulMessageValue = ( unsigned long ) ucState;\r
ucLastState = ucState;\r
xQueueSend( xLCDQueue, &xMessage, portMAX_DELAY );\r
}\r
\r
static void prvSetupHardware( void )\r
{\r
- halBoardInit();\r
- halButtonsInit( BUTTON_ALL );\r
- halButtonsInterruptEnable( BUTTON_SELECT );\r
- LFXT_Start (XT1DRIVE_0);\r
- Init_FLL_Settle( 25000, 488 );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvCheckTask( void *pvParameters )\r
-{\r
-volatile unsigned short usLastRegTest1Counter = 0, usLastRegTest2Counter = 0;\r
-portTickType xNextWakeTime, xCycleFrequency = mainNO_ERROR_CYCLE_TIME;\r
-const char *pcStatusMessage = "OK";\r
-\r
- /* Initialise xNextWakeTime - this only needs to be done once. */\r
- xNextWakeTime = xTaskGetTickCount();\r
-\r
- for( ;; )\r
- {\r
- /* Place this task in the blocked state until it is time to run again. */\r
- vTaskDelayUntil( &xNextWakeTime, xCycleFrequency );\r
+unsigned long ulCPU_Clock_KHz = ( configCPU_CLOCK_HZ / 1000UL );\r
\r
- /* Check the reg test tasks are still cycling. They will stop incrementing\r
- their loop counters if they encounter an error. */\r
- if( usRegTest1Counter == usLastRegTest1Counter )\r
- {\r
- pcStatusMessage = "Error: RegTest1";\r
- }\r
+ halBoardInit();\r
\r
- if( usRegTest2Counter == usLastRegTest2Counter )\r
- {\r
- pcStatusMessage = "Error: RegTest2";\r
- }\r
+ LFXT_Start( XT1DRIVE_0 );\r
+ Init_FLL_Settle( ( unsigned short ) ulCPU_Clock_KHz, 488 );\r
\r
- usLastRegTest1Counter = usRegTest1Counter;\r
- usLastRegTest2Counter = usRegTest2Counter;\r
- \r
- printf( "%s, tick count = %u\n", pcStatusMessage, ( unsigned int ) xTaskGetTickCount() );\r
- fflush( stdout );\r
- }\r
+ halButtonsInit( BUTTON_ALL );\r
+ halButtonsInterruptEnable( BUTTON_SELECT );\r
+ halLcdInit();\r
+ halLcdBackLightInit();\r
+ halLcdSetBackLight( 0 );\r
+ halLcdSetContrast( 100 );\r
+ halLcdClearScreen();\r
+ \r
+ halLcdPrintLine( " www.FreeRTOS.org", 0, OVERWRITE_TEXT );\r
+ \r
+while( ( halButtonsPressed() & BUTTON_UP ) == 0 );\r
}\r
/*-----------------------------------------------------------*/\r
\r
/* Ensure the timer is stopped. */\r
TA0CTL = 0;\r
\r
- /* Run the timer of the ACLK. */\r
+ /* Run the timer from the ACLK. */\r
TA0CTL = TASSEL_1;\r
\r
/* Clear everything to start with. */\r
\r
void vApplicationIdleHook( void )\r
{\r
- __bis_SR_register( LPM3_bits + GIE );\r
+ /* Want to leave the SMCLK running so the COMTest tasks don't fail. */\r
+ __bis_SR_register( LPM1_bits + GIE );\r
}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vApplicationTickHook( void )\r
+{\r
+static unsigned short usLastRegTest1Counter = 0, usLastRegTest2Counter = 0;\r
+static unsigned long ulCounter = 0;\r
+static const unsigned long ulCheckFrequency = 5000UL / portTICK_RATE_MS;\r
+portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;\r
+\r
+/* Define the status message that is sent to the LCD task. By default the\r
+status is PASS. */\r
+static xQueueMessage xStatusMessage = { mainMESSAGE_STATUS, pdPASS };\r
+\r
+ /* This is called from within the tick interrupt and performs the 'check'\r
+ functionality as described in the comments at the top of this file.\r
+\r
+ Is it time to perform the 'check' functionality again? */\r
+ ulCounter++;\r
+ if( ulCounter >= ulCheckFrequency )\r
+ {\r
+ /* See if the standard demo tasks are executing as expected, changing\r
+ the message that is sent to the LCD task from PASS to an error code if\r
+ any tasks set reports an error. */\r
+ if( xAreComTestTasksStillRunning() != pdPASS )\r
+ {\r
+ xStatusMessage.ulMessageValue = mainERROR_COM_TEST;\r
+ }\r
+\r
+ if( xAreDynamicPriorityTasksStillRunning() != pdPASS )\r
+ {\r
+ xStatusMessage.ulMessageValue = mainERROR_DYNAMIC_TASKS;\r
+ }\r
+ \r
+ if( xAreGenericQueueTasksStillRunning() != pdPASS )\r
+ {\r
+ xStatusMessage.ulMessageValue = mainERROR_GEN_QUEUE_TEST;\r
+ } \r
+\r
+ /* Check the reg test tasks are still cycling. They will stop incrementing\r
+ their loop counters if they encounter an error. */\r
+ if( usRegTest1Counter == usLastRegTest1Counter )\r
+ {\r
+ xStatusMessage.ulMessageValue = mainERROR_REG_TEST;\r
+ }\r
+\r
+ if( usRegTest2Counter == usLastRegTest2Counter )\r
+ {\r
+ xStatusMessage.ulMessageValue = mainERROR_REG_TEST;\r
+ }\r
+\r
+ usLastRegTest1Counter = usRegTest1Counter;\r
+ usLastRegTest2Counter = usRegTest2Counter;\r
+ \r
+ /* As this is the tick hook the lHigherPriorityTaskWoken parameter is not\r
+ needed (a context switch is going to be performed anyway), but it must\r
+ still be provided. */\r
+ xQueueSendFromISR( xLCDQueue, &xStatusMessage, &xHigherPriorityTaskWoken );\r
+ ulCounter = 0;\r
+ }\r
+\r
+ if( ( ulCounter & 0xff ) == 0 )\r
+ {\r
+ if( ( LED_PORT_OUT & LED_1 ) == 0 )\r
+ {\r
+ LED_PORT_OUT |= LED_1;\r
+ LED_PORT_OUT &= ~LED_2;\r
+ }\r
+ else\r
+ {\r
+ LED_PORT_OUT &= ~LED_1;\r
+ LED_PORT_OUT |= LED_2;\r
+ }\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+#pragma vector=PORT2_VECTOR\r
+__interrupt static void prvSelectButtonInterrupt(void)\r
+{\r
+/* Define the message sent to the LCD task from this interrupt. */\r
+static const xQueueMessage xMessage = { mainMESSAGE_BUTTON_SEL, ( unsigned long ) "Select Interrupt" };\r
+portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;\r
+\r
+ /* This is the interrupt handler for the joystick select button input.\r
+ The button has been pushed, write a message to the LCD via the LCD task. */\r
+ xQueueSendFromISR( xLCDQueue, &xMessage, &xHigherPriorityTaskWoken );\r
+\r
+ P2IFG = 0;\r
+ \r
+ /* If writing to xLCDQueue caused a task to unblock, and the unblocked task\r
+ has a priority equal to or above the task that this interrupt interrupted,\r
+ then lHigherPriorityTaskWoken will have been set to pdTRUE internally within\r
+ xQueuesendFromISR(), and portEND_SWITCHING_ISR() will ensure that this\r
+ interrupt returns directly to the higher priority unblocked task. */\r
+ portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vConfigureTimerForRunTimeStats( void )\r
+{\r
+ /* Ensure the timer is stopped. */\r
+ TA1CTL = 0;\r
+\r
+ /* Run the timer from the ACLK/4. */\r
+ TA1CTL = TASSEL_1 | ID__4;\r
+\r
+ /* Clear everything to start with. */\r
+ TA1CTL |= TACLR;\r
+\r
+ /* Enable the interrupts. */\r
+ TA1CCTL0 = CCIE;\r
+\r
+ /* Start up clean. */\r
+ TA1CTL |= TACLR;\r
+\r
+ /* Continuous mode. */\r
+ TA1CTL |= MC__CONTINOUS;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+#pragma vector=TIMER1_A0_VECTOR\r
+static __interrupt void prvRunTimeStatsOverflowISR( void )\r
+{\r
+ ulStatsOverflowCount++;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+inline unsigned long ulGetRunTimeStatsTime( void )\r
+{\r
+unsigned long ulReturn;\r
+\r
+ TA1CTL &= ~MC__CONTINOUS;\r
+ ulReturn = ( ( ulStatsOverflowCount << 16UL ) | ( unsigned long ) TA1R );\r
+ TA1CTL |= MC__CONTINOUS;\r
+ \r
+ return ulReturn;\r
+}\r
+\r
\r
\r
\r