]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_LM3S102_Rowley/Demo3/main.c
cc9d7f40e37c67d8d4e0d9113f5a8e41ad935e69
[freertos] / FreeRTOS / Demo / CORTEX_LM3S102_Rowley / Demo3 / main.c
1 /*\r
2  * FreeRTOS Kernel V10.3.0\r
3  * Copyright (C) 2020 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 /*\r
30  * This is a mini co-routine demo for the Rowley CrossFire LM3S102 development\r
31  * board.  It makes use of the boards tri-colour LED and analogue input.\r
32  *\r
33  * Four co-routines are created - an 'I2C' co-routine and three 'flash'\r
34  * co-routines.\r
35  *\r
36  * The I2C co-routine triggers an ADC conversion then blocks on a queue to \r
37  * wait for the conversion result - which it receives on the queue directly\r
38  * from the I2C interrupt service routine.  The conversion result is then\r
39  * scalled to a delay period.  The I2C interrupt then wakes each of the \r
40  * flash co-routines before itself delaying for the calculated period and\r
41  * then repeating the whole process.\r
42  *\r
43  * When woken by the I2C co-routine the flash co-routines each block for \r
44  * a given period, illuminate an LED for a fixed period, then go back to\r
45  * sleep to wait for the next cycle.  The uxIndex parameter of the flash\r
46  * co-routines is used to ensure that each flashes a different LED, and that\r
47  * the delay periods are such that the LED's get flashed in sequence.\r
48  */\r
49 \r
50 \r
51 /* Scheduler include files. */\r
52 #include "FreeRTOS.h"\r
53 #include "task.h"\r
54 #include "queue.h"\r
55 #include "croutine.h"\r
56 \r
57 /* Demo application include files. */\r
58 #include "partest.h"\r
59 \r
60 /* Library include files. */\r
61 #include "DriverLib.h"\r
62 \r
63 /* States of the I2C master interface. */\r
64 #define mainI2C_IDLE       0\r
65 #define mainI2C_READ_1     1\r
66 #define mainI2C_READ_2     2\r
67 #define mainI2C_READ_DONE  3\r
68 \r
69 #define mainZERO_LENGTH 0\r
70 \r
71 /* Address of the A2D IC on the CrossFire board. */\r
72 #define mainI2CAddress  0x4D\r
73 \r
74 /* The queue used to send data from the I2C ISR to the co-routine should never\r
75 contain more than one item as the same co-routine is used to trigger the I2C\r
76 activity. */\r
77 #define mainQUEUE_LENGTH 1\r
78 \r
79 /* The CrossFire board contains a tri-colour LED. */\r
80 #define mainNUM_LEDs    3\r
81 \r
82 /* The I2C co-routine has a higher priority than the flash co-routines.  This\r
83 is not really necessary as when the I2C co-routine is active the other \r
84 co-routines are delaying. */\r
85 #define mainI2c_CO_ROUTINE_PRIORITY 1\r
86 \r
87 \r
88 /* The current state of the I2C master. */\r
89 static volatile unsigned portBASE_TYPE uxState = mainI2C_IDLE;\r
90 \r
91 /* The delay period derived from the A2D value. */\r
92 static volatile portBASE_TYPE uxDelay = 250;\r
93 \r
94 /* The queue used to communicate between the I2C interrupt and the I2C \r
95 co-routine. */\r
96 static QueueHandle_t xADCQueue;\r
97 \r
98 /* The queue used to synchronise the flash co-routines. */\r
99 static QueueHandle_t xDelayQueue;\r
100 \r
101 /*\r
102  * Sets up the PLL, I2C and GPIO used by the demo.\r
103  */\r
104 static void prvSetupHardware( void );\r
105 \r
106 /* The co-routines as described at the top of the file. */\r
107 static void vI2CCoRoutine( CoRoutineHandle_t xHandle, unsigned portBASE_TYPE uxIndex );\r
108 static void vFlashCoRoutine( CoRoutineHandle_t xHandle, unsigned portBASE_TYPE uxIndex );\r
109 \r
110 /*-----------------------------------------------------------*/\r
111 \r
112 int main( void )\r
113 {\r
114 unsigned portBASE_TYPE uxCoRoutine;\r
115 \r
116         /* Setup all the hardware used by this demo. */\r
117         prvSetupHardware();\r
118 \r
119         /* Create the queue used to communicate between the ISR and I2C co-routine.\r
120         This can only ever contain one value. */\r
121         xADCQueue = xQueueCreate( mainQUEUE_LENGTH, sizeof( TickType_t ) );\r
122 \r
123         /* Create the queue used to synchronise the flash co-routines.  The queue\r
124         is used to trigger three tasks, but is for synchronisation only and does\r
125         not pass any data.  It therefore has three position each of zero length. */\r
126         xDelayQueue = xQueueCreate( mainNUM_LEDs, mainZERO_LENGTH );\r
127 \r
128         /* Create the co-routine that initiates the i2c. */\r
129         xCoRoutineCreate( vI2CCoRoutine, mainI2c_CO_ROUTINE_PRIORITY, 0 );\r
130 \r
131         /* Create the flash co-routines. */\r
132         for( uxCoRoutine = 0; uxCoRoutine < mainNUM_LEDs; uxCoRoutine++ )\r
133         {\r
134                 xCoRoutineCreate( vFlashCoRoutine, tskIDLE_PRIORITY, uxCoRoutine );        \r
135         }\r
136 \r
137         /* Start the scheduler.  From this point on the co-routines should \r
138         execute. */\r
139         vTaskStartScheduler();\r
140 \r
141         /* Should not get here unless we did not have enough memory to start the\r
142         scheduler. */\r
143         for( ;; );\r
144         return 0;\r
145 }\r
146 /*-----------------------------------------------------------*/\r
147 \r
148 static void prvSetupHardware( void )\r
149 {\r
150         /* Setup the PLL. */\r
151         SysCtlClockSet( SYSCTL_SYSDIV_10 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_6MHZ );\r
152 \r
153         /* Enable the I2C used to read the pot. */\r
154         SysCtlPeripheralEnable( SYSCTL_PERIPH_I2C );\r
155         SysCtlPeripheralEnable( SYSCTL_PERIPH_GPIOB );\r
156         GPIOPinTypeI2C( GPIO_PORTB_BASE, GPIO_PIN_2 | GPIO_PIN_3 );\r
157 \r
158         /* Initialize the I2C master. */\r
159         I2CMasterInit( I2C_MASTER_BASE, pdFALSE );\r
160         \r
161         /* Enable the I2C master interrupt. */\r
162         I2CMasterIntEnable( I2C_MASTER_BASE );\r
163     IntEnable( INT_I2C );\r
164 \r
165         /* Initialise the hardware used to talk to the LED's. */\r
166         vParTestInitialise();\r
167 }\r
168 /*-----------------------------------------------------------*/\r
169 \r
170 static void vI2CCoRoutine( CoRoutineHandle_t xHandle, unsigned portBASE_TYPE uxIndex )\r
171 {\r
172 TickType_t xADCResult;\r
173 static portBASE_TYPE xResult = 0, xMilliSecs, xLED;\r
174 \r
175         crSTART( xHandle );\r
176 \r
177         for( ;; )\r
178         {\r
179                 /* Start the I2C off to read the ADC. */\r
180                 uxState = mainI2C_READ_1;\r
181                 I2CMasterSlaveAddrSet( I2C_MASTER_BASE, mainI2CAddress, pdTRUE );               \r
182                 I2CMasterControl( I2C_MASTER_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START );\r
183 \r
184                 /* Wait to receive the conversion result. */\r
185                 crQUEUE_RECEIVE( xHandle, xADCQueue, &xADCResult, portMAX_DELAY, &xResult );\r
186 \r
187                 /* Scale the result to give a useful range of values for a visual \r
188                 demo. */\r
189                 xADCResult >>= 2;\r
190                 xMilliSecs = xADCResult / portTICK_PERIOD_MS;\r
191 \r
192                 /* The delay is split between the four co-routines so they remain in\r
193                 synch. */\r
194                 uxDelay = xMilliSecs / ( mainNUM_LEDs + 1 );\r
195 \r
196                 /* Trigger each of the flash co-routines. */\r
197                 for( xLED = 0; xLED < mainNUM_LEDs; xLED++ )\r
198                 {\r
199                         crQUEUE_SEND( xHandle, xDelayQueue, &xLED, 0, &xResult );\r
200                 }\r
201 \r
202                 /* Wait for the full delay time then start again.  This delay is long \r
203                 enough to ensure the flash co-routines have done their thing and gone\r
204                 back to sleep. */\r
205                 crDELAY( xHandle, xMilliSecs );\r
206         }\r
207 \r
208         crEND();\r
209 }\r
210 /*-----------------------------------------------------------*/\r
211 \r
212 static void vFlashCoRoutine( CoRoutineHandle_t xHandle, unsigned portBASE_TYPE uxIndex )\r
213 {\r
214 portBASE_TYPE xResult, xNothing;\r
215 \r
216         crSTART( xHandle );\r
217 \r
218         for( ;; )\r
219         {\r
220                 /* Wait for start of next round. */\r
221                 crQUEUE_RECEIVE( xHandle, xDelayQueue, &xNothing, portMAX_DELAY, &xResult );\r
222 \r
223                 /* Wait until it is this co-routines turn to flash. */\r
224                 crDELAY( xHandle, uxDelay * uxIndex );\r
225 \r
226                 /* Turn on the LED for a fixed period. */\r
227                 vParTestSetLED( uxIndex, pdTRUE );\r
228                 crDELAY( xHandle, uxDelay );\r
229                 vParTestSetLED( uxIndex, pdFALSE );\r
230 \r
231                 /* Go back and wait for the next round. */\r
232         }\r
233 \r
234         crEND();\r
235 }\r
236 /*-----------------------------------------------------------*/\r
237 \r
238 void vI2C_ISR(void)\r
239 {\r
240 static TickType_t xReading;\r
241 \r
242         /* Clear the interrupt. */\r
243         I2CMasterIntClear( I2C_MASTER_BASE );\r
244 \r
245         /* Determine what to do based on the current uxState. */\r
246         switch (uxState)\r
247         {\r
248                 case mainI2C_IDLE:              break;\r
249         \r
250                 case mainI2C_READ_1:    /* Read ADC result high byte. */\r
251                                                                 xReading = I2CMasterDataGet( I2C_MASTER_BASE );\r
252                                                                 xReading <<= 8;\r
253                 \r
254                                                                 /* Continue the burst read. */\r
255                                                                 I2CMasterControl( I2C_MASTER_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT );\r
256                                                                 uxState = mainI2C_READ_2;\r
257                                                                 break;\r
258         \r
259                 case mainI2C_READ_2:    /* Read ADC result low byte. */\r
260                                                                 xReading |= I2CMasterDataGet( I2C_MASTER_BASE );                                                                \r
261                         \r
262                                                                 /* Finish the burst read. */\r
263                                                                 I2CMasterControl( I2C_MASTER_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH );\r
264                                                                 uxState = mainI2C_READ_DONE;\r
265                                                                 break;\r
266                         \r
267                 case mainI2C_READ_DONE: /* Complete. */\r
268                                                                 I2CMasterDataGet( I2C_MASTER_BASE );\r
269                                                                 uxState = mainI2C_IDLE;\r
270 \r
271                                                                 /* Send the result to the co-routine. */\r
272                                 crQUEUE_SEND_FROM_ISR( xADCQueue, &xReading, pdFALSE );\r
273                                                                 break;\r
274         }\r
275 }\r
276 /*-----------------------------------------------------------*/\r
277 \r
278 void vApplicationIdleHook( void )\r
279 {\r
280         for( ;; )\r
281         {\r
282                 vCoRoutineSchedule();\r
283         }\r
284 }\r
285 \r