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