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