]> git.sur5r.net Git - freertos/blob - Demo/Cygnal/main.c
Update version numbers to V4.8.0
[freertos] / Demo / Cygnal / main.c
1 /*\r
2         FreeRTOS.org V4.8.0 - Copyright (C) 2003-2008 Richard Barry.\r
3 \r
4         This file is part of the FreeRTOS.org distribution.\r
5 \r
6         FreeRTOS.org is free software; you can redistribute it and/or modify\r
7         it under the terms of the GNU General Public License as published by\r
8         the Free Software Foundation; either version 2 of the License, or\r
9         (at your option) any later version.\r
10 \r
11         FreeRTOS.org is distributed in the hope that it will be useful,\r
12         but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14         GNU General Public License for more details.\r
15 \r
16         You should have received a copy of the GNU General Public License\r
17         along with FreeRTOS.org; if not, write to the Free Software\r
18         Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
19 \r
20         A special exception to the GPL can be applied should you wish to distribute\r
21         a combined work that includes FreeRTOS.org, without being obliged to provide\r
22         the source code for any proprietary components.  See the licensing section \r
23         of http://www.FreeRTOS.org for full details of how and when the exception\r
24         can be applied.\r
25 \r
26         ***************************************************************************\r
27         ***************************************************************************\r
28         *                                                                                                                                                 *\r
29         * SAVE TIME AND MONEY!  Why not get us to quote to get FreeRTOS.org               *\r
30         * running on your hardware - or even write all or part of your application*\r
31         * for you?  See http://www.OpenRTOS.com for details.                                      *\r
32         *                                                                                                                                                 *\r
33         ***************************************************************************\r
34         ***************************************************************************\r
35 \r
36         Please ensure to read the configuration and relevant port sections of the\r
37         online documentation.\r
38 \r
39         http://www.FreeRTOS.org - Documentation, latest information, license and \r
40         contact details.\r
41 \r
42         http://www.SafeRTOS.com - A version that is certified for use in safety \r
43         critical systems.\r
44 \r
45         http://www.OpenRTOS.com - Commercial support, development, porting, \r
46         licensing and training services.\r
47 */\r
48 \r
49 /*\r
50  * Creates the demo application tasks, then starts the scheduler.  The WEB\r
51  * documentation provides more details of the demo application tasks.\r
52  * \r
53  * Main. c also creates four other tasks:\r
54  * \r
55  * 1) vErrorChecks()\r
56  * This only executes every few seconds but has the highest priority so is \r
57  * guaranteed to get processor time.  Its main function is to check that all \r
58  * the standard demo application tasks are still operational and have not\r
59  * experienced any errors.  vErrorChecks() will toggle the on board LED\r
60  * every mainNO_ERROR_FLASH_PERIOD milliseconds if none of the demo application\r
61  * tasks have reported an error.  Should any task report an error at any time\r
62  * the rate at which the on board LED is toggled is increased to \r
63  * mainERROR_FLASH_PERIOD - providing visual feedback that something has gone\r
64  * wrong.\r
65  *\r
66  * 2) vRegisterCheck()\r
67  * This is a very simple task that checks that all the registers are always\r
68  * in their expected state.  The task only makes use of the A register, so\r
69  * all the other registers should always contain their initial values.\r
70  * An incorrect value indicates an error in the context switch mechanism.\r
71  * The task operates at the idle priority so will be preempted regularly.\r
72  * Any error will cause the toggle rate of the on board LED to increase to\r
73  * mainERROR_FLASH_PERIOD milliseconds.\r
74  *\r
75  * 3 and 4) vFLOPCheck1() and vFLOPCheck2()\r
76  * These are very basic versions of the standard FLOP tasks.  They are good\r
77  * at detecting errors in the context switch mechanism, and also check that\r
78  * the floating point libraries are correctly built to be re-enterant.  The\r
79  * stack restrictions of the 8051 prevent the use of the standard FLOP demo\r
80  * tasks.\r
81  */\r
82 \r
83 /* Standard includes. */\r
84 #include <stdlib.h>\r
85 \r
86 /* Scheduler includes. */\r
87 #include "FreeRTOS.h"\r
88 #include "task.h"\r
89 \r
90 /* Demo application includes. */\r
91 #include "partest.h"\r
92 #include "flash.h"\r
93 #include "integer.h"\r
94 #include "PollQ.h"\r
95 #include "comtest2.h"\r
96 #include "semtest.h"\r
97 \r
98 /* Demo task priorities. */\r
99 #define mainLED_TASK_PRIORITY           ( tskIDLE_PRIORITY + 1 )\r
100 #define mainQUEUE_POLL_PRIORITY         ( tskIDLE_PRIORITY + 2 )\r
101 #define mainCOM_TEST_PRIORITY           ( tskIDLE_PRIORITY + 2 )\r
102 #define mainCHECK_TASK_PRIORITY         ( tskIDLE_PRIORITY + 3 )\r
103 #define mainSEM_TEST_PRIORITY           ( tskIDLE_PRIORITY + 2 )\r
104 #define mainINTEGER_PRIORITY            tskIDLE_PRIORITY\r
105 \r
106 /* Constants required to disable the watchdog. */\r
107 #define mainDISABLE_BYTE_1                      ( ( unsigned portCHAR ) 0xde )\r
108 #define mainDISABLE_BYTE_2                      ( ( unsigned portCHAR ) 0xad )\r
109 \r
110 /* Constants to setup and use the on board LED. */\r
111 #define ucLED_BIT                                       ( ( unsigned portCHAR ) 0x40 )\r
112 #define mainPORT_1_BIT_6                        ( ( unsigned portCHAR ) 0x40 )\r
113 #define mainENABLE_CROSS_BAR            ( ( unsigned portCHAR ) 0x40 )\r
114 \r
115 /* Constants to set the clock frequency. */\r
116 #define mainSELECT_INTERNAL_OSC         ( ( unsigned portCHAR ) 0x80 )\r
117 #define mainDIVIDE_CLOCK_BY_1           ( ( unsigned portCHAR ) 0x03 )\r
118 #define mainPLL_USES_INTERNAL_OSC       ( ( unsigned portCHAR ) 0x04 )\r
119 #define mainFLASH_READ_TIMING           ( ( unsigned portCHAR ) 0x30 )\r
120 #define mainPLL_POWER_ON                        ( ( unsigned portCHAR ) 0x01 )\r
121 #define mainPLL_NO_PREDIVIDE            ( ( unsigned portCHAR ) 0x01 )\r
122 #define mainPLL_FILTER                          ( ( unsigned portCHAR ) 0x01 )\r
123 #define mainPLL_MULTIPLICATION          ( ( unsigned portCHAR ) 0x04 )\r
124 #define mainENABLE_PLL                          ( ( unsigned portCHAR ) 0x02 )\r
125 #define mainPLL_LOCKED                          ( ( unsigned portCHAR ) 0x10 )\r
126 #define mainSELECT_PLL_AS_SOURCE        ( ( unsigned portCHAR ) 0x02 )\r
127 \r
128 /* Toggle rate for the on board LED - which is dependent on whether or not\r
129 an error has been detected. */\r
130 #define mainNO_ERROR_FLASH_PERIOD       ( ( portTickType ) 5000 )\r
131 #define mainERROR_FLASH_PERIOD          ( ( portTickType ) 250 )\r
132 \r
133 /* Baud rate used by the serial port tasks. */\r
134 #define mainCOM_TEST_BAUD_RATE          ( ( unsigned portLONG ) 115200 )\r
135 \r
136 /* Pass an invalid LED number to the COM test task as we don't want it to flash\r
137 an LED.  There are only 8 LEDs (excluding the on board LED) wired in and these\r
138 are all used by the flash tasks. */\r
139 #define mainCOM_TEST_LED                        ( 200 )\r
140 \r
141 /* We want the Cygnal to act as much as possible as a standard 8052. */\r
142 #define mainAUTO_SFR_OFF                        ( ( unsigned portCHAR ) 0 )\r
143 \r
144 /* Constants required to setup the IO pins for serial comms. */\r
145 #define mainENABLE_COMS                         ( ( unsigned portCHAR ) 0x04 )\r
146 #define mainCOMS_LINES_TO_PUSH_PULL ( ( unsigned portCHAR ) 0x03 )\r
147 \r
148 /* Pointer passed as a parameter to vRegisterCheck() just so it has some know\r
149 values to check for in the DPH, DPL and B registers. */\r
150 #define mainDUMMY_POINTER               ( ( xdata void * ) 0xabcd )\r
151 \r
152 /* Macro that lets vErrorChecks() know that one of the tasks defined in\r
153 main. c has detected an error.  A critical region is used around xLatchError\r
154 as it is accessed from vErrorChecks(), which has a higher priority. */ \r
155 #define mainLATCH_ERROR()                       \\r
156 {                                                                       \\r
157         portENTER_CRITICAL();                   \\r
158                 xLatchedError = pdTRUE;         \\r
159         portEXIT_CRITICAL();                    \\r
160 }\r
161 \r
162 /*\r
163  * Setup the Cygnal microcontroller for its fastest operation. \r
164  */\r
165 static void prvSetupSystemClock( void );\r
166 \r
167 /*\r
168  * Setup the peripherals, including the on board LED. \r
169  */\r
170 static void prvSetupHardware( void );\r
171 \r
172 /*\r
173  * Toggle the state of the on board LED. \r
174  */\r
175 static void prvToggleOnBoardLED( void );\r
176 \r
177 /*\r
178  * See comments at the top of the file for details. \r
179  */\r
180 static void vErrorChecks( void *pvParameters );\r
181 \r
182 /*\r
183  * See comments at the top of the file for details. \r
184  */\r
185 static void vRegisterCheck( void *pvParameters );\r
186 \r
187 /*\r
188  * See comments at the top of the file for details. \r
189  */\r
190 static void vFLOPCheck1( void *pvParameters );\r
191 \r
192 /*\r
193  * See comments at the top of the file for details. \r
194  */\r
195 static void vFLOPCheck2( void *pvParameters );\r
196 \r
197 /* File scope variable used to communicate the occurrence of an error between\r
198 tasks. */\r
199 static portBASE_TYPE xLatchedError = pdFALSE;\r
200 \r
201 /*-----------------------------------------------------------*/\r
202 \r
203 /*\r
204  * Starts all the other tasks, then starts the scheduler. \r
205  */\r
206 void main( void )\r
207 {\r
208         /* Initialise the hardware including the system clock and on board\r
209         LED. */\r
210         prvSetupHardware();\r
211 \r
212         /* Initialise the port that controls the external LED's utilized by the\r
213         flash tasks. */\r
214         vParTestInitialise();\r
215 \r
216         /* Start the used standard demo tasks. */\r
217         vStartLEDFlashTasks( mainLED_TASK_PRIORITY );\r
218         vStartPolledQueueTasks( mainQUEUE_POLL_PRIORITY );\r
219         vStartIntegerMathTasks( mainINTEGER_PRIORITY );\r
220         vAltStartComTestTasks( mainCOM_TEST_PRIORITY, mainCOM_TEST_BAUD_RATE, mainCOM_TEST_LED );\r
221         vStartSemaphoreTasks( mainSEM_TEST_PRIORITY );\r
222 \r
223         /* Start the tasks defined in this file.  The first three never block so\r
224         must not be used with the co-operative scheduler. */\r
225         #if configUSE_PREEMPTION == 1\r
226         {\r
227                 xTaskCreate( vRegisterCheck, "RegChck", configMINIMAL_STACK_SIZE, mainDUMMY_POINTER, tskIDLE_PRIORITY, ( xTaskHandle * ) NULL );\r
228                 xTaskCreate( vFLOPCheck1, "FLOP", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, ( xTaskHandle * ) NULL );\r
229                 xTaskCreate( vFLOPCheck2, "FLOP", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, ( xTaskHandle * ) NULL );\r
230         }\r
231         #endif \r
232 \r
233         xTaskCreate( vErrorChecks, "Check", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY, ( xTaskHandle * ) NULL );\r
234 \r
235         /* Finally kick off the scheduler.  This function should never return. */\r
236         vTaskStartScheduler();\r
237 \r
238         /* Should never reach here as the tasks will now be executing under control\r
239         of the scheduler. */\r
240 }\r
241 /*-----------------------------------------------------------*/\r
242 \r
243 /*\r
244  * Setup the hardware prior to using the scheduler.  Most of the Cygnal\r
245  * specific initialisation is performed here leaving standard 8052 setup\r
246  * only in the driver code.\r
247  */\r
248 static void prvSetupHardware( void )\r
249 {\r
250 unsigned portCHAR ucOriginalSFRPage;\r
251 \r
252         /* Remember the SFR page before it is changed so it can get set back\r
253         before the function exits. */\r
254         ucOriginalSFRPage = SFRPAGE;\r
255 \r
256         /* Setup the SFR page to access the config SFR's. */\r
257         SFRPAGE = CONFIG_PAGE;\r
258 \r
259         /* Don't allow the microcontroller to automatically switch SFR page, as the\r
260         SFR page is not stored as part of the task context. */\r
261         SFRPGCN = mainAUTO_SFR_OFF;\r
262 \r
263         /* Disable the watchdog. */\r
264         WDTCN = mainDISABLE_BYTE_1;\r
265         WDTCN = mainDISABLE_BYTE_2;\r
266 \r
267         /* Set the on board LED to push pull. */\r
268         P1MDOUT |= mainPORT_1_BIT_6;\r
269 \r
270         /* Setup the cross bar to enable serial comms here as it is not part of the \r
271         standard 8051 setup and therefore is not in the driver code. */\r
272         XBR0 |= mainENABLE_COMS;\r
273         P0MDOUT |= mainCOMS_LINES_TO_PUSH_PULL;\r
274 \r
275         /* Enable the cross bar so our hardware setup takes effect. */\r
276         XBR2 = mainENABLE_CROSS_BAR;\r
277 \r
278         /* Setup a fast system clock. */\r
279         prvSetupSystemClock();\r
280 \r
281         /* Return the SFR page. */\r
282         SFRPAGE = ucOriginalSFRPage;\r
283 }\r
284 /*-----------------------------------------------------------*/\r
285 \r
286 static void prvSetupSystemClock( void )\r
287 {\r
288 volatile unsigned portSHORT usWait;\r
289 const unsigned portSHORT usWaitTime = ( unsigned portSHORT ) 0x2ff;\r
290 unsigned portCHAR ucOriginalSFRPage;\r
291 \r
292         /* Remember the SFR page so we can set it back at the end. */\r
293         ucOriginalSFRPage = SFRPAGE;\r
294         SFRPAGE = CONFIG_PAGE;\r
295 \r
296         /* Use the internal oscillator set to its fasted frequency. */\r
297         OSCICN = mainSELECT_INTERNAL_OSC | mainDIVIDE_CLOCK_BY_1;\r
298 \r
299         /* Ensure the clock is stable. */\r
300         for( usWait = 0; usWait < usWaitTime; usWait++ );\r
301 \r
302         /* Setup the clock source for the PLL. */\r
303         PLL0CN &= ~mainPLL_USES_INTERNAL_OSC;\r
304 \r
305         /* Change the read timing for the flash ready for the fast clock. */\r
306         SFRPAGE = LEGACY_PAGE;\r
307         FLSCL |= mainFLASH_READ_TIMING;\r
308 \r
309         /* Turn on the PLL power. */\r
310         SFRPAGE = CONFIG_PAGE;\r
311         PLL0CN |= mainPLL_POWER_ON;\r
312 \r
313         /* Don't predivide the clock. */\r
314         PLL0DIV = mainPLL_NO_PREDIVIDE;\r
315 \r
316         /* Set filter for fastest clock. */\r
317         PLL0FLT = mainPLL_FILTER;\r
318         PLL0MUL = mainPLL_MULTIPLICATION;\r
319 \r
320         /* Ensure the clock is stable. */\r
321         for( usWait = 0; usWait < usWaitTime; usWait++ );\r
322 \r
323         /* Enable the PLL and wait for it to lock. */\r
324         PLL0CN |= mainENABLE_PLL;\r
325         for( usWait = 0; usWait < usWaitTime; usWait++ )\r
326         {\r
327                 if( PLL0CN & mainPLL_LOCKED )\r
328                 {\r
329                         break;\r
330                 }\r
331         }\r
332 \r
333         /* Select the PLL as the clock source. */\r
334         CLKSEL |= mainSELECT_PLL_AS_SOURCE;\r
335 \r
336         /* Return the SFR back to its original value. */\r
337         SFRPAGE = ucOriginalSFRPage;\r
338 }\r
339 /*-----------------------------------------------------------*/\r
340 \r
341 static void prvToggleOnBoardLED( void )\r
342 {\r
343         /* If the on board LED is on, turn it off and visa versa. */\r
344         if( P1 & ucLED_BIT )\r
345         {\r
346                 P1 &= ~ucLED_BIT;\r
347         }\r
348         else\r
349         {\r
350                 P1 |= ucLED_BIT;\r
351         }\r
352 }\r
353 /*-----------------------------------------------------------*/\r
354 \r
355 /*\r
356  * See the documentation at the top of this file. \r
357  */\r
358 static void vErrorChecks( void *pvParameters )\r
359 {\r
360 portBASE_TYPE xErrorHasOccurred = pdFALSE;\r
361         \r
362         /* Just to prevent compiler warnings. */\r
363         ( void ) pvParameters;\r
364         \r
365         /* Cycle for ever, delaying then checking all the other tasks are still\r
366         operating without error.   The delay period depends on whether an error\r
367         has ever been detected. */\r
368         for( ;; )\r
369         {\r
370                 if( xLatchedError == pdFALSE )\r
371                 {               \r
372                         /* No errors have been detected so delay for a longer period.  The\r
373                         on board LED will get toggled every mainNO_ERROR_FLASH_PERIOD ms. */\r
374                         vTaskDelay( mainNO_ERROR_FLASH_PERIOD );\r
375                 }\r
376                 else\r
377                 {\r
378                         /* We have at some time recognised an error in one of the demo\r
379                         application tasks, delay for a shorter period.  The on board LED\r
380                         will get toggled every mainERROR_FLASH_PERIOD ms. */\r
381                         vTaskDelay( mainERROR_FLASH_PERIOD );\r
382                 }\r
383 \r
384                 \r
385                 \r
386                 /* Check the demo application tasks for errors. */\r
387 \r
388                 if( xAreIntegerMathsTaskStillRunning() != pdTRUE )\r
389                 {\r
390                         xErrorHasOccurred = pdTRUE;\r
391                 }\r
392 \r
393                 if( xArePollingQueuesStillRunning() != pdTRUE )\r
394                 {\r
395                         xErrorHasOccurred = pdTRUE;\r
396                 }\r
397 \r
398                 if( xAreComTestTasksStillRunning() != pdTRUE )\r
399                 {\r
400                         xErrorHasOccurred = pdTRUE;\r
401                 }\r
402 \r
403                 if( xAreSemaphoreTasksStillRunning() != pdTRUE )\r
404                 {\r
405                         xErrorHasOccurred = pdTRUE;\r
406                 }\r
407 \r
408                 /* If an error has occurred, latch it to cause the LED flash rate to \r
409                 increase. */\r
410                 if( xErrorHasOccurred == pdTRUE )\r
411                 {\r
412                         xLatchedError = pdTRUE;\r
413                 }\r
414 \r
415                 /* Toggle the LED to indicate the completion of a check cycle.  The\r
416                 frequency of check cycles is dependent on whether or not we have \r
417                 latched an error. */\r
418                 prvToggleOnBoardLED();\r
419         }\r
420 }\r
421 /*-----------------------------------------------------------*/\r
422 \r
423 /*\r
424  * See the documentation at the top of this file.  Also see the standard FLOP\r
425  * demo task documentation for the rationale of these tasks.\r
426  */\r
427 static void vFLOPCheck1( void *pvParameters )\r
428 {\r
429 volatile portFLOAT fVal1, fVal2, fResult;\r
430 \r
431         ( void ) pvParameters;\r
432 \r
433         for( ;; )\r
434         {\r
435                 fVal1 = ( portFLOAT ) -1234.5678;\r
436                 fVal2 = ( portFLOAT ) 2345.6789;\r
437 \r
438                 fResult = fVal1 + fVal2;\r
439                 if( ( fResult > ( portFLOAT )  1111.15 ) || ( fResult < ( portFLOAT ) 1111.05 ) )\r
440                 {\r
441                         mainLATCH_ERROR();\r
442                 }\r
443 \r
444                 fResult = fVal1 / fVal2;\r
445                 if( ( fResult > ( portFLOAT ) -0.51 ) || ( fResult < ( portFLOAT ) -0.53 ) )\r
446                 {\r
447                         mainLATCH_ERROR();\r
448                 }\r
449         }\r
450 }\r
451 /*-----------------------------------------------------------*/\r
452 \r
453 /*\r
454  * See the documentation at the top of this file.\r
455  */\r
456 static void vFLOPCheck2( void *pvParameters )\r
457 {\r
458 volatile portFLOAT fVal1, fVal2, fResult;\r
459 \r
460         ( void ) pvParameters;\r
461 \r
462         for( ;; )\r
463         {\r
464                 fVal1 = ( portFLOAT ) -12340.5678;\r
465                 fVal2 = ( portFLOAT ) 23450.6789;\r
466 \r
467                 fResult = fVal1 + fVal2;\r
468                 if( ( fResult > ( portFLOAT ) 11110.15 ) || ( fResult < ( portFLOAT ) 11110.05 ) )\r
469                 {\r
470                         mainLATCH_ERROR();\r
471                 }\r
472 \r
473                 fResult = fVal1 / -fVal2;\r
474                 if( ( fResult > ( portFLOAT ) 0.53 ) || ( fResult < ( portFLOAT ) 0.51 ) )\r
475                 {\r
476                         mainLATCH_ERROR();\r
477                 }\r
478         }\r
479 }\r
480 /*-----------------------------------------------------------*/\r
481 \r
482 /*\r
483  * See the documentation at the top of this file. \r
484  */\r
485 static void vRegisterCheck( void *pvParameters )\r
486 {\r
487         ( void ) pvParameters;\r
488 \r
489         for( ;; )\r
490         {\r
491                 if( SP != configSTACK_START )\r
492                 {\r
493                         mainLATCH_ERROR();\r
494                 }\r
495 \r
496                 _asm\r
497                         MOV ACC, ar0\r
498                 _endasm;\r
499 \r
500                 if( ACC != 0 )\r
501                 {\r
502                         mainLATCH_ERROR();\r
503                 }\r
504 \r
505                 _asm\r
506                         MOV ACC, ar1\r
507                 _endasm;\r
508 \r
509                 if( ACC != 1 )\r
510                 {\r
511                         mainLATCH_ERROR();\r
512                 }\r
513                 _asm\r
514                         MOV ACC, ar2\r
515                 _endasm;\r
516 \r
517                 if( ACC != 2 )\r
518                 {\r
519                         mainLATCH_ERROR();\r
520                 }\r
521                 _asm\r
522                         MOV ACC, ar3\r
523                 _endasm;\r
524 \r
525                 if( ACC != 3 )\r
526                 {\r
527                         mainLATCH_ERROR();\r
528                 }\r
529                 _asm\r
530                         MOV ACC, ar4\r
531                 _endasm;\r
532 \r
533                 if( ACC != 4 )\r
534                 {\r
535                         mainLATCH_ERROR();\r
536                 }\r
537                 _asm\r
538                         MOV ACC, ar5\r
539                 _endasm;\r
540 \r
541                 if( ACC != 5 )\r
542                 {\r
543                         mainLATCH_ERROR();\r
544                 }\r
545                 _asm\r
546                         MOV ACC, ar6\r
547                 _endasm;\r
548 \r
549                 if( ACC != 6 )\r
550                 {\r
551                         mainLATCH_ERROR();\r
552                 }\r
553                 _asm\r
554                         MOV ACC, ar7\r
555                 _endasm;\r
556 \r
557                 if( ACC != 7 )\r
558                 {\r
559                         mainLATCH_ERROR();\r
560                 }\r
561 \r
562                 if( DPL != 0xcd )\r
563                 {\r
564                         mainLATCH_ERROR();\r
565                 }\r
566 \r
567                 if( DPH != 0xab )\r
568                 {\r
569                         mainLATCH_ERROR();\r
570                 }\r
571 \r
572                 if( B != 0x01 )\r
573                 {\r
574                         mainLATCH_ERROR();\r
575                 }                       \r
576         }\r
577 }\r
578 \r
579 \r