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