]> git.sur5r.net Git - freertos/blobdiff - Demo/MB96350_Softune_Dice_Kit/DiceTask.c
Add STM32F0 demo.
[freertos] / Demo / MB96350_Softune_Dice_Kit / DiceTask.c
index 849b4b723fd53dc014c722a7fa202dc5b0d65bbc..4fcc0efecc7ebf12bf059b58e37a972f7eb82872 100644 (file)
 /*\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
@@ -147,8 +198,18 @@ short sHigherPriorityTaskWoken = pdFALSE;
        /* 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
@@ -156,6 +217,7 @@ short sHigherPriorityTaskWoken = pdFALSE;
 }\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
@@ -163,7 +225,10 @@ short sHigherPriorityTaskWoken = pdFALSE;
        /* 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