/*\r
- FreeRTOS.org V5.1.1 - Copyright (C) 2003-2008 Richard Barry.\r
+ FreeRTOS V7.1.0 - Copyright (C) 2011 Real Time Engineers Ltd.\r
+ \r
\r
- This file is part of the FreeRTOS.org distribution.\r
+ ***************************************************************************\r
+ * *\r
+ * FreeRTOS tutorial books are available in pdf and paperback. *\r
+ * Complete, revised, and edited pdf reference manuals are also *\r
+ * available. *\r
+ * *\r
+ * Purchasing FreeRTOS documentation will not only help you, by *\r
+ * ensuring you get running as quickly as possible and with an *\r
+ * in-depth knowledge of how to use FreeRTOS, it will also help *\r
+ * the FreeRTOS project to continue with its mission of providing *\r
+ * professional grade, cross platform, de facto standard solutions *\r
+ * for microcontrollers - completely free of charge! *\r
+ * *\r
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
+ * *\r
+ * Thank you for using FreeRTOS, and thank you for your support! *\r
+ * *\r
+ ***************************************************************************\r
\r
- FreeRTOS.org is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU General Public License as published by\r
- the Free Software Foundation; either version 2 of the License, or\r
- (at your option) any later version.\r
\r
- FreeRTOS.org is distributed in the hope that it will be useful,\r
- but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- GNU General Public License for more details.\r
+ This file is part of the FreeRTOS distribution.\r
\r
- You should have received a copy of the GNU General Public License\r
- along with FreeRTOS.org; if not, write to the Free Software\r
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+ FreeRTOS is free software; you can redistribute it and/or modify it under\r
+ the terms of the GNU General Public License (version 2) as published by the\r
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
+ >>>NOTE<<< The modification to the GPL is included to allow you to\r
+ distribute a combined work that includes FreeRTOS without being obliged to\r
+ provide the source code for proprietary components outside of the FreeRTOS\r
+ kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
+ more details. You should have received a copy of the GNU General Public\r
+ License and the FreeRTOS license exception along with FreeRTOS; if not it\r
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
+ by writing to Richard Barry, contact details for whom are available on the\r
+ FreeRTOS WEB site.\r
\r
- A special exception to the GPL can be applied should you wish to distribute\r
- a combined work that includes FreeRTOS.org, without being obliged to provide\r
- the source code for any proprietary components. See the licensing section \r
- of http://www.FreeRTOS.org for full details of how and when the exception\r
- can be applied.\r
+ 1 tab == 4 spaces!\r
\r
- ***************************************************************************\r
- ***************************************************************************\r
- * *\r
- * SAVE TIME AND MONEY! We can port FreeRTOS.org to your own hardware, *\r
- * and even write all or part of your application on your behalf. *\r
- * See http://www.OpenRTOS.com for details of the services we provide to *\r
- * expedite your project. *\r
- * *\r
- ***************************************************************************\r
- ***************************************************************************\r
+ http://www.FreeRTOS.org - Documentation, latest information, license and\r
+ contact details.\r
\r
- Please ensure to read the configuration and relevant port sections of the\r
- online documentation.\r
+ http://www.SafeRTOS.com - A version that is certified for use in safety\r
+ critical systems.\r
\r
- http://www.FreeRTOS.org - Documentation, latest information, license and \r
- contact details.\r
+ http://www.OpenRTOS.com - Commercial support, development, porting,\r
+ licensing and training services.\r
+*/\r
\r
- http://www.SafeRTOS.com - A version that is certified for use in safety \r
- critical systems.\r
\r
- http://www.OpenRTOS.com - Commercial support, development, porting, \r
- licensing and training services.\r
-*/\r
+/* \r
+ * Defines the 'dice' tasks as described at the top of main.c\r
+ */\r
\r
+\r
+/* Kernel includes. */\r
#include "FreeRTOS.h"\r
#include "task.h"\r
#include "semphr.h"\r
\r
-#define diceMIN 1\r
-#define diceMAX 6\r
-#define diceRUN_MIN 600000L\r
-#define diceRUN_MAX 1200000L\r
-\r
-#define diceSTATE_STOPPED 0\r
-#define diceSTATE_STARTUP 1\r
-#define diceSTATE_RUNNING 2\r
+/* Delays used within the dice functionality. All delays are defined in milliseconds. */\r
+#define diceDELAY_BETWEEN_RANDOM_NUMBERS_ms ( 20 / portTICK_RATE_MS )\r
+#define diceSHAKE_TIME ( ( 2000 / portTICK_RATE_MS ) / diceDELAY_BETWEEN_RANDOM_NUMBERS_ms )\r
+#define diceSHORT_PAUSE_BEFORE_SHAKE ( 250 / portTICK_RATE_MS )\r
+#define diceDELAY_WHILE_DISPLAYING_RESULT ( 5000 / portTICK_RATE_MS )\r
\r
-#define diceEND_DELAY ( 5000 / portTICK_RATE_MS )\r
-\r
-#define dice7SEG_Value( x ) *( pucDisplayOutput[ x ] )\r
+/* Macro to access the display ports. */\r
+#define dice7SEG_Value( x ) ( *( pucDisplayOutput[ x ] ) )\r
\r
+/* Checks the semaphore use to communicate button push events. A block time\r
+can be specified - this is the time to wait for a button push to occur should\r
+one have not already occurred. */\r
#define prvButtonHit( ucIndex, xTicksToWait ) xSemaphoreTake( xSemaphores[ ucIndex ], xTicksToWait )\r
\r
+/* Defines the outputs required for each digit on the display. */\r
static const char cDisplaySegments[ 2 ][ 11 ] =\r
{\r
- { 0x48, 0xeb, 0x8c, 0x89, 0x2b, 0x19, 0x18, 0xcb, 0x08, 0x09, 0xf7 },\r
- { 0xa0, 0xf3, 0xc4, 0xc1, 0x93, 0x89, 0x88, 0xe3, 0x80, 0x81, 0x7f }\r
+ { 0x48, 0xeb, 0x8c, 0x89, 0x2b, 0x19, 0x18, 0xcb, 0x08, 0x09, 0xf7 }, /* Left display. */\r
+ { 0xa0, 0xf3, 0xc4, 0xc1, 0x93, 0x89, 0x88, 0xe3, 0x80, 0x81, 0x7f } /* Right display. */\r
};\r
\r
+/* The semaphores used to communicate button push events between the button\r
+input interrupt handlers and the dice tasks. Two dice tasks are created so two\r
+semaphores are required. */\r
static xSemaphoreHandle xSemaphores[ 2 ] = { 0 };\r
\r
+/* Defines the ports used to write to the display. This variable is defined in\r
+partest.c, which contains the LED set/clear/toggle functions. */\r
extern volatile unsigned char *pucDisplayOutput[ 2 ];\r
\r
/*-----------------------------------------------------------*/\r
\r
+/* \r
+ * Defines the 'dice' tasks as described at the top of main.c\r
+ */\r
void vDiceTask( void *pvParameters )\r
{\r
-char cDiceState = diceSTATE_STOPPED;\r
unsigned char ucDiceValue, ucIndex;\r
-unsigned long ulDiceRunTime, ulDiceDelay, ulDiceDelayReload;\r
-extern void vToggleFlashTaskSuspendState( void );\r
+unsigned long ulDiceRunTime;\r
+extern void vSuspendFlashTasks( unsigned char ucIndex, short sSuspendTasks );\r
+\r
\r
+\r
+ /* Two instances of this task are created so the task parameter is used\r
+ to pass in a constant that indicates whether this task is controlling\r
+ the left side or right side display. The constant is used as an index\r
+ into the arrays defined at file scope within this file. */\r
ucIndex = ( unsigned char ) pvParameters;\r
+ \r
+ /* A binary semaphore is used to signal button push events. Create the\r
+ semaphore before it is used. */\r
vSemaphoreCreateBinary( xSemaphores[ ucIndex ] );\r
- srand( ( unsigned char ) diceRUN_MIN );\r
\r
+ /* Make sure the semaphore starts in the wanted state - no button pushes \r
+ pending. This call will just clear any button pushes that are latched.\r
+ Passing in 0 as the block time means the call will not wait for any further\r
+ button pushes but instead return immediately. */\r
+ prvButtonHit( ucIndex, 0 );\r
+\r
+ /* Seed the random number generator. */\r
+ srand( ( unsigned char ) diceSHAKE_TIME );\r
+\r
+\r
+\r
+\r
+ /* Start the task proper. A loop will be performed each time a button is\r
+ pushed. The task will remain in the blocked state (sleeping) until a \r
+ button is pushed. */\r
for( ;; )\r
{\r
- switch( cDiceState )\r
+ /* Wait for a button push. This task will enter the Blocked state\r
+ (will not run again) until after a button has been pushed. */\r
+ prvButtonHit( ucIndex, portMAX_DELAY );\r
+ \r
+ /* The next line will only execute after a button has been pushed -\r
+ initialise the variable used to control the time the dice is shaken\r
+ for. */\r
+ ulDiceRunTime = diceSHAKE_TIME; \r
+\r
+ /* Suspend the flash tasks so this task has exclusive access to the\r
+ display. */\r
+ vSuspendFlashTasks( ucIndex, pdTRUE );\r
+\r
+ /* Clear the display and pause for a short time, before starting to\r
+ shake. */\r
+ *pucDisplayOutput[ ucIndex ] = 0xff;\r
+ vTaskDelay( diceSHORT_PAUSE_BEFORE_SHAKE );\r
+\r
+ /* Keep generating and displaying random numbers until the shake time\r
+ expires. */\r
+ while( ulDiceRunTime > 0 )\r
{\r
- case diceSTATE_STOPPED:\r
-\r
- prvButtonHit( ucIndex, portMAX_DELAY );\r
- ulDiceRunTime = diceRUN_MIN; \r
- cDiceState = diceSTATE_RUNNING;\r
- ulDiceDelay = 1;\r
- ulDiceDelayReload = 1;\r
- cDiceState = diceSTATE_RUNNING;\r
- if( ucIndex == 0 )\r
- {\r
- vToggleFlashTaskSuspendState();\r
- }\r
-\r
- break;\r
-\r
- case diceSTATE_RUNNING:\r
-\r
- ulDiceRunTime--;\r
- ulDiceDelay--;\r
-\r
- if( !ulDiceDelay )\r
- {\r
- ucDiceValue = rand() % 6 + 1;\r
- dice7SEG_Value( ucIndex ) = ( dice7SEG_Value( ucIndex ) | 0xf7 ) & cDisplaySegments[ ucIndex ][ ucDiceValue ];\r
- ulDiceDelayReload = ulDiceDelayReload + 100;\r
- ulDiceDelay = ulDiceDelayReload;\r
- }\r
-\r
- if( ulDiceRunTime == 0 )\r
- {\r
- dice7SEG_Value( ucIndex ) = ( dice7SEG_Value( ucIndex ) | 0xf7 ) & cDisplaySegments[ ucIndex ][ rand() % 6 + 1 ];\r
- cDiceState = diceSTATE_STOPPED;\r
-\r
- if( ucIndex == 0 )\r
- {\r
- vTaskDelay( diceEND_DELAY );\r
- *pucDisplayOutput[ ucIndex ] = 0xff;\r
- vToggleFlashTaskSuspendState();\r
- }\r
- }\r
-\r
- break;\r
+ ulDiceRunTime--;\r
+\r
+ /* Generate and display a random number. */\r
+ ucDiceValue = rand() % 6 + 1;\r
+ dice7SEG_Value( ucIndex ) = ( dice7SEG_Value( ucIndex ) | 0xf7 ) & cDisplaySegments[ ucIndex ][ ucDiceValue ];\r
+\r
+ /* Block/sleep for a very short time before generating the next\r
+ random number. */\r
+ vTaskDelay( diceDELAY_BETWEEN_RANDOM_NUMBERS_ms );\r
}\r
+\r
+\r
+\r
+ /* Clear any button pushes that are pending because a button bounced, or\r
+ was pressed while the dice were shaking. Again a block time of zero is \r
+ used so the function does not wait for any pushes but instead returns\r
+ immediately. */\r
+ prvButtonHit( ucIndex, 0 );\r
+\r
+ /* Delay for a short while to display the dice shake result. Use a queue\r
+ peek here instead of a vTaskDelay() allows the delay to be interrupted by\r
+ a button push. If a button is pressed xQueuePeek() will return but the\r
+ button push will remain pending to be read again at the top of this for\r
+ loop. It is safe to uses a queue function on a semaphore handle as\r
+ semaphores are implemented as macros that uses queues, so the two are \r
+ basically the same thing. */\r
+ xQueuePeek( xSemaphores[ ucIndex ], NULL, diceDELAY_WHILE_DISPLAYING_RESULT );\r
+\r
+ /* Clear the display then resume the tasks or co-routines that were using\r
+ the segments of the display. */\r
+ *pucDisplayOutput[ ucIndex ] = 0xff;\r
+ vSuspendFlashTasks( ucIndex, pdFALSE );\r
}\r
}\r
/*-----------------------------------------------------------*/\r
\r
+/* Handler for the SW2 button push interrupt. */\r
__interrupt void vExternalInt8Handler( void )\r
{\r
short sHigherPriorityTaskWoken = pdFALSE;\r
/* Reset the interrupt. */\r
EIRR1_ER8 = 0;\r
\r
- xSemaphoreGiveFromISR( xSemaphores[ 0 ], &sHigherPriorityTaskWoken );\r
+ /* Check the semaphore has been created before attempting to use it. */\r
+ if( xSemaphores[ configLEFT_DISPLAY ] != NULL )\r
+ {\r
+ /* Send a message via the semaphore to the dice task that controls the\r
+ left side display. This will unblock the task if it is blocked waiting\r
+ for a button push. */\r
+ xSemaphoreGiveFromISR( xSemaphores[ configLEFT_DISPLAY ], &sHigherPriorityTaskWoken );\r
+ }\r
\r
+ /* If sending the semaphore unblocked a task, and the unblocked task has a\r
+ priority that is higher than the currently running task, then force a context\r
+ switch. */\r
if( sHigherPriorityTaskWoken != pdFALSE )\r
{\r
portYIELD_FROM_ISR();\r
}\r
/*-----------------------------------------------------------*/\r
\r
+/* As per vExternalInt8Handler(), but for SW3 and the right side display. */\r
__interrupt void vExternalInt9Handler( void )\r
{\r
short sHigherPriorityTaskWoken = pdFALSE;\r
/* Reset the interrupt. */\r
EIRR1_ER9 = 0;\r
\r
- xSemaphoreGiveFromISR( xSemaphores[ 1 ], &sHigherPriorityTaskWoken );\r
+ if( xSemaphores[ configRIGHT_DISPLAY ] != NULL )\r
+ {\r
+ xSemaphoreGiveFromISR( xSemaphores[ configRIGHT_DISPLAY ], &sHigherPriorityTaskWoken );\r
+ }\r
\r
if( sHigherPriorityTaskWoken != pdFALSE )\r
{\r