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