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