]> git.sur5r.net Git - freertos/blob - Demo/CORTEX_LM3S316_IAR/main.c
Update to V4.7.2.
[freertos] / Demo / CORTEX_LM3S316_IAR / main.c
1 /*\r
2         FreeRTOS.org V4.7.2 - 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         Please ensure to read the configuration and relevant port sections of the \r
29         online documentation.\r
30 \r
31         +++ http://www.FreeRTOS.org +++\r
32         Documentation, latest information, license and contact details.  \r
33 \r
34         +++ http://www.SafeRTOS.com +++\r
35         A version that is certified for use in safety critical systems.\r
36 \r
37         +++ http://www.OpenRTOS.com +++\r
38         Commercial support, development, porting, licensing and training services.\r
39 \r
40         ***************************************************************************\r
41 */\r
42 \r
43 /* \r
44  * This demo application creates eight co-routines and four tasks (five \r
45  * including the idle task).  The co-routines execute as part of the idle task \r
46  * hook.  The application is limited in size to allow its compilation using\r
47  * the KickStart version of the IAR compiler.\r
48  *\r
49  * Six of the created co-routines are the standard 'co-routine flash' \r
50  * co-routines contained within the Demo/Common/Minimal/crflash.c file and \r
51  * documented on the FreeRTOS.org WEB site.  \r
52  *\r
53  * The 'LCD Task' waits on a message queue for messages informing it what and\r
54  * where to display text.  This is the only task that accesses the LCD\r
55  * so mutual exclusion is guaranteed.\r
56  *\r
57  * The 'LCD Message Task' periodically sends strings to the LCD Task using\r
58  * the message queue.  The strings are rotated to form a short message and\r
59  * are written to the top row of the LCD.\r
60  *\r
61  * The 'ADC Co-routine' periodically reads the ADC input that is connected to\r
62  * the light sensor, forms a short message from the value, and then sends this\r
63  * message to the LCD Task using the same message queue.  The ADC readings are\r
64  * displayed on the bottom row of the LCD.  \r
65  *\r
66  * The eighth co-routine and final task control the transmission and reception\r
67  * of a string to UART 0.  The co-routine periodically sends the first \r
68  * character of the string to the UART, with the UART's TxEnd interrupt being\r
69  * used to transmit the remaining characters.  The UART's RxEnd interrupt \r
70  * receives the characters and places them on a queue to be processed by the \r
71  * 'COMs Rx' task.  An error is latched should an unexpected character be \r
72  * received, or any character be received out of sequence.  \r
73  *\r
74  * A loopback connector is required to ensure that each character transmitted \r
75  * on the UART is also received on the same UART.  For test purposes the UART\r
76  * FIFO's are not utalised in order to maximise the interrupt overhead.  Also\r
77  * a pseudo random interval is used between the start of each transmission in \r
78  * order that the resultant interrupts are more randomly distributed and \r
79  * therefore more likely to highlight any problems.\r
80  *\r
81  * The flash co-routines control LED's zero to four.  LED five is toggled each\r
82  * time the string is transmitted on the UART.  LED six is toggled each time\r
83  * the string is CORRECTLY received on the UART.  LED seven is latched on \r
84  * should an error be detected in any task or co-routine.\r
85  *\r
86  * In addition the idle task makes repetitive calls to \r
87  * vSetAndCheckRegisters().  This simply loads the general purpose registers \r
88  * with a known value, then checks each register to ensure the held value is \r
89  * still correct.  As a low priority task this checking routine is likely to \r
90  * get repeatedly swapped in and out.  A register being found to contain an \r
91  * incorrect value is therefore indicative of an error in the task switching \r
92  * mechanism.\r
93  *\r
94  */\r
95 \r
96 /* standard include files. */\r
97 #include <stdio.h>\r
98 \r
99 /* Scheduler include files. */\r
100 #include "FreeRTOS.h"\r
101 #include "task.h"\r
102 #include "queue.h"\r
103 #include "croutine.h"\r
104 \r
105 /* Demo application include files. */\r
106 #include "partest.h"\r
107 #include "crflash.h"\r
108 #include "commstest.h"\r
109 \r
110 /* Library include files. */\r
111 #include "DriverLib.h"\r
112 \r
113 /* The time to delay between writing each character to the LCD. */\r
114 #define mainCHAR_WRITE_DELAY            ( 2 / portTICK_RATE_MS )\r
115 \r
116 /* The time to delay between writing each string to the LCD. */\r
117 #define mainSTRING_WRITE_DELAY          ( 400 / portTICK_RATE_MS )\r
118 \r
119 #define mainADC_DELAY                           ( 200 / portTICK_RATE_MS )\r
120 \r
121 /* The number of flash co-routines to create. */\r
122 #define mainNUM_FLASH_CO_ROUTINES       ( 5 )\r
123 \r
124 /* The length of the queue used to send messages to the LCD task. */\r
125 #define mainLCD_QUEUE_LEN                       ( 3 )\r
126 \r
127 /* The priority of the co-routine used to initiate the transmission of the \r
128 string on UART 0. */\r
129 #define mainTX_CO_ROUTINE_PRIORITY      ( 1 )\r
130 #define mainADC_CO_ROUTINE_PRIORITY     ( 2 )\r
131 \r
132 /* Only one of each co-routine is created so its index is not important. */\r
133 #define mainTX_CO_ROUTINE_INDEX         ( 0 )\r
134 #define mainADC_CO_ROUTINE_INDEX        ( 0 )\r
135 \r
136 /* The task priorities. */\r
137 #define mainLCD_TASK_PRIORITY           ( tskIDLE_PRIORITY + 1 )\r
138 #define mainMSG_TASK_PRIORITY           ( mainLCD_TASK_PRIORITY - 1 )\r
139 #define mainCOMMS_RX_TASK_PRIORITY      ( tskIDLE_PRIORITY + 1 )\r
140 \r
141 /* The LCD had two rows. */\r
142 #define mainTOP_ROW             0\r
143 #define mainBOTTOM_ROW  1\r
144 \r
145 /* Dimension for the buffer into which the ADC value string is written. */\r
146 #define mainMAX_ADC_STRING_LEN  20\r
147 \r
148 /* The LED that is lit should an error be detected in any of the tasks or\r
149 co-routines. */\r
150 #define mainFAIL_LED                    ( 7 )\r
151 \r
152 /*-----------------------------------------------------------*/\r
153 \r
154 /*\r
155  * The task that displays text on the LCD.\r
156  */\r
157 static void prvLCDTask( void * pvParameters );\r
158 \r
159 /*\r
160  * The task that sends messages to be displayed on the top row of the LCD.\r
161  */\r
162 static void prvLCDMessageTask( void * pvParameters );\r
163 \r
164 /*\r
165  * The co-routine that reads the ADC and sends messages for display on the\r
166  * bottom row of the LCD.\r
167  */\r
168 static void prvADCCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex );\r
169 \r
170 /*\r
171  * Function to simply set a known value into the general purpose registers\r
172  * then read them back to ensure they remain set correctly.  An incorrect value\r
173  * being indicative of an error in the task switching mechanism.\r
174  */\r
175 extern void vSetAndCheckRegisters( void );\r
176 \r
177 /*\r
178  * Latch the LED that indicates that an error has occurred. \r
179  */\r
180 void vSetErrorLED( void );\r
181 \r
182 /*\r
183  * Thread safe write to the PDC.\r
184  */\r
185 static void prvPDCWrite( portCHAR cAddress, portCHAR cData );\r
186 \r
187 /*\r
188  * Sets up the hardware used by the demo.\r
189  */\r
190 static void prvSetupHardware( void );\r
191 \r
192 \r
193 /*-----------------------------------------------------------*/\r
194 \r
195 /* The structure that is passed on the LCD message queue. */\r
196 typedef struct\r
197 {\r
198         portCHAR **ppcMessageToDisplay; /*<< Points to a char* pointing to the message to display. */\r
199         portBASE_TYPE xRow;                             /*<< The row on which the message should be displayed. */\r
200 } xLCDMessage;\r
201 \r
202 /* Error flag set to pdFAIL if an error is encountered in the tasks/co-routines\r
203 defined within this file. */\r
204 unsigned portBASE_TYPE uxErrorStatus = pdPASS;\r
205 \r
206 /* The queue used to transmit messages to the LCD task. */\r
207 static xQueueHandle xLCDQueue;\r
208 \r
209 /*-----------------------------------------------------------*/\r
210 \r
211 /*\r
212  * Setup the hardware, create the tasks/co-routines, then start the scheduler.\r
213  */\r
214 void main( void )\r
215 {\r
216         /* Create the queue used by tasks wanting to write to the LCD. */\r
217         xLCDQueue = xQueueCreate( mainLCD_QUEUE_LEN, sizeof( xLCDMessage ) );\r
218 \r
219         /* Setup the ports used by the demo and the clock. */\r
220         prvSetupHardware();\r
221 \r
222         /* Create the co-routines that flash the LED's. */\r
223         vStartFlashCoRoutines( mainNUM_FLASH_CO_ROUTINES );\r
224 \r
225         /* Create the co-routine that initiates the transmission of characters\r
226         on the UART and the task that receives them, as described at the top of\r
227         this file. */\r
228         xCoRoutineCreate( vSerialTxCoRoutine, mainTX_CO_ROUTINE_PRIORITY, mainTX_CO_ROUTINE_INDEX );\r
229         xTaskCreate( vCommsRxTask, "CMS", configMINIMAL_STACK_SIZE, NULL, mainCOMMS_RX_TASK_PRIORITY, NULL );\r
230 \r
231         /* Create the task that waits for messages to display on the LCD, plus the\r
232         task and co-routine that send messages for display (as described at the top\r
233         of this file. */\r
234         xTaskCreate( prvLCDTask, "LCD", configMINIMAL_STACK_SIZE, ( void * ) &xLCDQueue, mainLCD_TASK_PRIORITY, NULL );\r
235         xTaskCreate( prvLCDMessageTask, "MSG", configMINIMAL_STACK_SIZE, ( void * ) &xLCDQueue, mainMSG_TASK_PRIORITY, NULL );\r
236         xCoRoutineCreate( prvADCCoRoutine, mainADC_CO_ROUTINE_PRIORITY, mainADC_CO_ROUTINE_INDEX );\r
237 \r
238         /* Start the scheduler running the tasks and co-routines just created. */\r
239         vTaskStartScheduler();\r
240 \r
241         /* Should not get here unless we did not have enough memory to start the\r
242         scheduler. */\r
243         for( ;; );\r
244 }\r
245 /*-----------------------------------------------------------*/\r
246 \r
247 static void prvLCDMessageTask( void * pvParameters )\r
248 {\r
249 /* The strings that are written to the LCD. */\r
250 portCHAR *pcStringsToDisplay[] = {                                                                              \r
251                                                                         "IAR             ",\r
252                                                                         "Stellaris       ",\r
253                                                                         "Demo            ",\r
254                                                                         "www.FreeRTOS.org",\r
255                                                                         ""\r
256                                                                 };\r
257 \r
258 xQueueHandle *pxLCDQueue;       \r
259 xLCDMessage xMessageToSend;\r
260 portBASE_TYPE xIndex = 0;\r
261 \r
262         /* To test the parameter passing mechanism, the queue on which messages are\r
263         posted is passed in as a parameter even though it is available as a file\r
264         scope variable anyway. */\r
265         pxLCDQueue = ( xQueueHandle * ) pvParameters;\r
266 \r
267         for( ;; )\r
268         {\r
269                 /* Wait until it is time to move onto the next string. */\r
270                 vTaskDelay( mainSTRING_WRITE_DELAY );           \r
271                 \r
272                 /* Create the message object to send to the LCD task. */\r
273                 xMessageToSend.ppcMessageToDisplay = &pcStringsToDisplay[ xIndex ];\r
274                 xMessageToSend.xRow = mainTOP_ROW;\r
275                 \r
276                 /* Post the message to be displayed. */\r
277                 if( !xQueueSend( *pxLCDQueue, ( void * ) &xMessageToSend, 0 ) )\r
278                 {\r
279                         uxErrorStatus = pdFAIL;\r
280                 }\r
281                 \r
282                 /* Move onto the next message, wrapping when necessary. */\r
283                 xIndex++;               \r
284                 if( *( pcStringsToDisplay[ xIndex ] ) == 0x00 )\r
285                 {\r
286                         xIndex = 0;\r
287 \r
288                         /* Delay longer before going back to the start of the messages. */\r
289                         vTaskDelay( mainSTRING_WRITE_DELAY * 2 );\r
290                 }\r
291         }\r
292 }\r
293 /*-----------------------------------------------------------*/\r
294 \r
295 void prvLCDTask( void * pvParameters )\r
296 {\r
297 unsigned portBASE_TYPE uxIndex;\r
298 xQueueHandle *pxLCDQueue;\r
299 xLCDMessage xReceivedMessage;\r
300 portCHAR *pcString;\r
301 const unsigned portCHAR ucCFGData[] = { \r
302                                                                                         0x30,   /* Set data bus to 8-bits. */\r
303                                                                                         0x30,\r
304                                                                                         0x30,\r
305                                                                                         0x3C,   /* Number of lines/font. */\r
306                                                                                         0x08,   /* Display off. */\r
307                                                                                         0x01,   /* Display clear. */\r
308                                                                                         0x06,   /* Entry mode [cursor dir][shift]. */\r
309                                                                                         0x0C    /* Display on [display on][curson on][blinking on]. */\r
310                                                                           };  \r
311 \r
312         /* To test the parameter passing mechanism, the queue on which messages are\r
313         received is passed in as a parameter even though it is available as a file\r
314         scope variable anyway. */\r
315         pxLCDQueue = ( xQueueHandle * ) pvParameters;\r
316 \r
317         /* Configure the LCD. */\r
318         uxIndex = 0;\r
319         while( uxIndex < sizeof( ucCFGData ) )\r
320         {\r
321                 prvPDCWrite( PDC_LCD_CSR, ucCFGData[ uxIndex ] );\r
322                 uxIndex++;\r
323                 vTaskDelay( mainCHAR_WRITE_DELAY );\r
324         }\r
325 \r
326         /* Turn the LCD Backlight on. */\r
327         prvPDCWrite( PDC_CSR, 0x01 );\r
328 \r
329         /* Clear display. */\r
330         vTaskDelay( mainCHAR_WRITE_DELAY );\r
331         prvPDCWrite( PDC_LCD_CSR, LCD_CLEAR ); \r
332 \r
333         uxIndex = 0;\r
334         for( ;; )    \r
335         {\r
336                 /* Wait for a message to arrive. */\r
337                 if( xQueueReceive( *pxLCDQueue, &xReceivedMessage, portMAX_DELAY ) )\r
338                 {\r
339                         /* Which row does the received message say to write to? */\r
340                         PDCLCDSetPos( 0, xReceivedMessage.xRow );\r
341 \r
342                         /* Where is the string we are going to display? */\r
343                         pcString = *xReceivedMessage.ppcMessageToDisplay;\r
344                         \r
345                         while( *pcString )\r
346                         {\r
347                                 /* Don't write out the string too quickly as LCD's are usually \r
348                                 pretty slow devices. */\r
349                                 vTaskDelay( mainCHAR_WRITE_DELAY );\r
350                                 prvPDCWrite( PDC_LCD_RAM, *pcString );\r
351                                 pcString++;\r
352                         }               \r
353                 }\r
354         }\r
355 }\r
356 /*-----------------------------------------------------------*/\r
357 \r
358 static void prvADCCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )\r
359 {\r
360 static unsigned portLONG ulADCValue;\r
361 static portCHAR cMessageBuffer[ mainMAX_ADC_STRING_LEN ];\r
362 static portCHAR *pcMessage;\r
363 static xLCDMessage xMessageToSend;\r
364 \r
365         /* Co-routines MUST start with a call to crSTART(). */\r
366         crSTART( xHandle );\r
367         \r
368         for( ;; )\r
369         {\r
370                 /* Start an ADC conversion. */\r
371                 ADCProcessorTrigger( ADC_BASE, 0 );\r
372                 \r
373                 /* Simply delay - when we unblock the result should be available */     \r
374                 crDELAY( xHandle, mainADC_DELAY );\r
375                 \r
376                 /* Get the ADC result. */\r
377                 ADCSequenceDataGet( ADC_BASE, 0, &ulADCValue );\r
378 \r
379                 /* Create a string with the result. */          \r
380                 sprintf( cMessageBuffer, "ADC = %d   ", ulADCValue );\r
381                 pcMessage = cMessageBuffer;\r
382 \r
383                 /* Configure the message we are going to send for display. */\r
384                 xMessageToSend.ppcMessageToDisplay = ( portCHAR** ) &pcMessage;\r
385                 xMessageToSend.xRow = mainBOTTOM_ROW;\r
386                 \r
387                 /* Send the string to the LCD task for display.  We are sending\r
388                 on a task queue so do not have the option to block. */\r
389                 if( !xQueueSend( xLCDQueue, ( void * ) &xMessageToSend, 0 ) )\r
390                 {\r
391                         uxErrorStatus = pdFAIL;\r
392                 }               \r
393         }\r
394         \r
395         /* Co-routines MUST end with a call to crEND(). */\r
396         crEND();\r
397 }\r
398 /*-----------------------------------------------------------*/\r
399 \r
400 static void prvSetupHardware( void )\r
401 {\r
402         /* Setup the PLL. */\r
403         SysCtlClockSet( SYSCTL_SYSDIV_10 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_6MHZ );\r
404         \r
405         /* Initialise the hardware used to talk to the LCD, LED's and UART. */\r
406         PDCInit();\r
407         vParTestInitialise();\r
408         vSerialInit();\r
409 \r
410         /* The ADC is used to read the light sensor. */\r
411         SysCtlPeripheralEnable( SYSCTL_PERIPH_ADC );\r
412     ADCSequenceConfigure( ADC_BASE, 3, ADC_TRIGGER_PROCESSOR, 0);\r
413     ADCSequenceStepConfigure( ADC_BASE, 0, 0, ADC_CTL_CH0 | ADC_CTL_END );\r
414     ADCSequenceEnable( ADC_BASE, 0 );\r
415 \r
416 }\r
417 /*-----------------------------------------------------------*/\r
418 \r
419 static void prvPDCWrite( portCHAR cAddress, portCHAR cData )\r
420 {\r
421         vTaskSuspendAll();\r
422         {\r
423                 PDCWrite( cAddress, cData );\r
424         }\r
425         xTaskResumeAll();\r
426 }\r
427 /*-----------------------------------------------------------*/\r
428 \r
429 void vSetErrorLED( void )\r
430 {\r
431         vParTestSetLED( mainFAIL_LED, pdTRUE );\r
432 }\r
433 /*-----------------------------------------------------------*/\r
434 \r
435 void vApplicationIdleHook( void )\r
436 {\r
437         /* The co-routines are executed in the idle task using the idle task \r
438         hook. */\r
439         for( ;; )\r
440         {\r
441                 /* Schedule the co-routines. */\r
442                 vCoRoutineSchedule();\r
443 \r
444                 /* Run the register check function between each co-routine. */\r
445                 vSetAndCheckRegisters();\r
446                 \r
447                 /* See if the comms task and co-routine has found any errors. */\r
448                 if( uxGetCommsStatus() != pdPASS )\r
449                 {\r
450                         vParTestSetLED( mainFAIL_LED, pdTRUE );\r
451                 }\r
452         }\r
453 }\r
454 /*-----------------------------------------------------------*/\r