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