]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_STM32L152_Discovery_IAR/main_low_power.c
Prepare for V9.0.0 release:
[freertos] / FreeRTOS / Demo / CORTEX_STM32L152_Discovery_IAR / main_low_power.c
1 /*\r
2     FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.\r
3     All rights reserved\r
4 \r
5     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
6 \r
7     This file is part of the FreeRTOS distribution.\r
8 \r
9     FreeRTOS is free software; you can redistribute it and/or modify it under\r
10     the terms of the GNU General Public License (version 2) as published by the\r
11     Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.\r
12 \r
13     ***************************************************************************\r
14     >>!   NOTE: The modification to the GPL is included to allow you to     !<<\r
15     >>!   distribute a combined work that includes FreeRTOS without being   !<<\r
16     >>!   obliged to provide the source code for proprietary components     !<<\r
17     >>!   outside of the FreeRTOS kernel.                                   !<<\r
18     ***************************************************************************\r
19 \r
20     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY\r
21     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
22     FOR A PARTICULAR PURPOSE.  Full license text is available on the following\r
23     link: http://www.freertos.org/a00114.html\r
24 \r
25     ***************************************************************************\r
26      *                                                                       *\r
27      *    FreeRTOS provides completely free yet professionally developed,    *\r
28      *    robust, strictly quality controlled, supported, and cross          *\r
29      *    platform software that is more than just the market leader, it     *\r
30      *    is the industry's de facto standard.                               *\r
31      *                                                                       *\r
32      *    Help yourself get started quickly while simultaneously helping     *\r
33      *    to support the FreeRTOS project by purchasing a FreeRTOS           *\r
34      *    tutorial book, reference manual, or both:                          *\r
35      *    http://www.FreeRTOS.org/Documentation                              *\r
36      *                                                                       *\r
37     ***************************************************************************\r
38 \r
39     http://www.FreeRTOS.org/FAQHelp.html - Having a problem?  Start by reading\r
40     the FAQ page "My application does not run, what could be wrong?".  Have you\r
41     defined configASSERT()?\r
42 \r
43     http://www.FreeRTOS.org/support - In return for receiving this top quality\r
44     embedded software for free we request you assist our global community by\r
45     participating in the support forum.\r
46 \r
47     http://www.FreeRTOS.org/training - Investing in training allows your team to\r
48     be as productive as possible as early as possible.  Now you can receive\r
49     FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers\r
50     Ltd, and the world's leading authority on the world's leading RTOS.\r
51 \r
52     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
53     including FreeRTOS+Trace - an indispensable productivity tool, a DOS\r
54     compatible FAT file system, and our tiny thread aware UDP/IP stack.\r
55 \r
56     http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.\r
57     Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.\r
58 \r
59     http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High\r
60     Integrity Systems ltd. to sell under the OpenRTOS brand.  Low cost OpenRTOS\r
61     licenses offer ticketed support, indemnification and commercial middleware.\r
62 \r
63     http://www.SafeRTOS.com - High Integrity Systems also provide a safety\r
64     engineered and independently SIL3 certified version for use in safety and\r
65     mission critical applications that require provable dependability.\r
66 \r
67     1 tab == 4 spaces!\r
68 */\r
69 \r
70 /* ****************************************************************************\r
71  * When configCREATE_LOW_POWER_DEMO is set to 1 in FreeRTOSConfig.h main() will\r
72  * call main_low_power(), which is defined in this file.  main_low_power()\r
73  * demonstrates FreeRTOS tick suppression being used to allow the MCU to be\r
74  * placed into the Sleep, Low Power Sleep and Stop low power modes.  When\r
75  * configCREATE_LOW_POWER_DEMO is set to 0 main will instead call main_full(),\r
76  * which is a more comprehensive RTOS demonstration.\r
77  * ****************************************************************************\r
78  *\r
79  * This application demonstrates the FreeRTOS tickless idle mode (tick\r
80  * suppression) being used to allow the STM32L to enter various low power modes\r
81  * during extended idle periods.  See\r
82  * http://www.freertos.org/low-power-tickless-rtos.html for information on\r
83  * tickless operation.\r
84  *\r
85  * Deeper low power modes have longer wake up periods that lighter low power\r
86  * modes, and power is also used simply entering and especially exiting the low\r
87  * power modes.  How the low power modes are used therefore requires careful\r
88  * consideration to ensure power consumption is truly minimised and that the\r
89  * embedded device meets its real time requirements.  This demo is configured to\r
90  * select between four different modes depending on the anticipated idle period.\r
91  * Note the time thresholds used to decide which low power mode to enter are\r
92  * purely for convenience of demonstration and are not intended to represent\r
93  * optimal values for any particular application.\r
94  *\r
95  * The STM32L specific part of the tickless operation is implemented in\r
96  * STM32L_low_power_tick_management.c.\r
97  *\r
98  * The demo is configured to execute on the STM32L Discovery board.\r
99  *\r
100  * Functionality:\r
101  *\r
102  *  + Two tasks are created, an Rx task and a Tx task.  A queue is created to\r
103  *        pass a message from the Tx task to the Rx task.\r
104  *\r
105  *  + The Rx task blocks on a queue to wait for data, blipping an LED each time\r
106  *    data is received (turning it on and then off again) before returning to\r
107  *    block on the queue once more.\r
108  *\r
109  *  + The Tx task repeatedly blocks on an attempt to obtain a semaphore, and\r
110  *        unblocks if either the semaphore is received or its block time expires.\r
111  *        After leaving the blocked state the Tx task uses the queue to send a\r
112  *        value to the Rx task, which in turn causes the Rx task to exit the\r
113  *        Blocked state and blip the LED.  The rate at which the LED is seen to blip\r
114  *        is therefore dependent on the block time.\r
115  *\r
116  *  + The Tx task's block time is changed by the interrupt service routine that\r
117  *        executes when the USER button is pressed.  The low power mode entered\r
118  *        depends on the block time (as described in the Observed Behaviour section\r
119  *        below).  Four block times are used: short, medium, long and infinite.\r
120  *\r
121  * Observed behaviour:\r
122  *\r
123  * 1) The block time used by the Tx task is initialised to its 'short' value,\r
124  * so when the Tx task blocks on the semaphore it times-out quickly, resulting\r
125  * in the LED toggling rapidly.  The timeout period is less than the value of\r
126  * configEXPECTED_IDLE_TIME_BEFORE_SLEEP (set in FreeRTOSConfig.h), so the\r
127  * initial state does not suppress the tick interrupt or enter a low power mode.\r
128  *\r
129  * 2) When the button is pressed the block time used by the Tx task is increased\r
130  * to its 'medium' value.  The longer block time results in a slowing of the\r
131  * rate at which the LED toggles.  The time the Tx task spends in the blocked\r
132  * state is now greater than configEXPECTED_IDLE_TIME_BEFORE_SLEEP, so the tick\r
133  * is suppressed.  The MCU is placed into the 'Sleep' low power state while the\r
134  * tick is suppressed.\r
135  *\r
136  * 3) When the button is pressed again the block time used by the Tx task is\r
137  * increased to its 'long' value, so the rate at which the LED is observed to\r
138  * blip gets even slow.  When the 'long' block time is used the MCU is placed\r
139  * into its 'Low Power Sleep' low power state.\r
140  *\r
141  * 4) The next time the button is pressed the block time used by the Tx task is\r
142  * set to infinite, so the Tx task does not time out when it attempts to obtain\r
143  * the semaphore, and therefore the LED stops blipping completely.  Both tasks\r
144  * are now blocked indefinitely and the MCU is placed into its 'Stop' low power\r
145  * state.\r
146  *\r
147  * 5) Pressing the button one final time results in the semaphore being 'given'\r
148  * to unblock the Tx task, the CPU clocks being returned to their pre-stop\r
149  * state, and the block time being reset to its 'short' time.  The system is\r
150  * then back to its initial condition with the LED blipping rapidly.\r
151  *\r
152  */\r
153 \r
154 /* Kernel includes. */\r
155 #include "FreeRTOS.h"\r
156 #include "task.h"\r
157 #include "queue.h"\r
158 #include "semphr.h"\r
159 \r
160 /* ST library functions. */\r
161 #include "stm32l1xx.h"\r
162 #include "discover_board.h"\r
163 #include "stm32l_discovery_lcd.h"\r
164 \r
165 /* Priorities at which the Rx and Tx tasks are created. */\r
166 #define configQUEUE_RECEIVE_TASK_PRIORITY       ( tskIDLE_PRIORITY + 1 )\r
167 #define configQUEUE_SEND_TASK_PRIORITY          ( tskIDLE_PRIORITY + 2 )\r
168 \r
169 /* The number of items the queue can hold.  This is 1 as the Rx task will\r
170 remove items as they are added so the Tx task should always find the queue\r
171 empty. */\r
172 #define mainQUEUE_LENGTH                                        ( 1 )\r
173 \r
174 /* A block time of zero simply means "don't block". */\r
175 #define mainDONT_BLOCK                                          ( 0 )\r
176 \r
177 /* The value that is sent from the Tx task to the Rx task on the queue. */\r
178 #define mainQUEUED_VALUE                                        ( 100UL )\r
179 \r
180 /* The length of time the LED will remain on for. */\r
181 #define mainLED_TOGGLE_DELAY                            ( 10 / portTICK_PERIOD_MS )\r
182 \r
183 /*-----------------------------------------------------------*/\r
184 \r
185 /*\r
186  * The Rx and Tx tasks as described at the top of this file.\r
187  */\r
188 static void prvQueueReceiveTask( void *pvParameters );\r
189 static void prvQueueSendTask( void *pvParameters );\r
190 \r
191 /*-----------------------------------------------------------*/\r
192 \r
193 /* The queue used to pass data from the Tx task to the Rx task. */\r
194 static QueueHandle_t xQueue = NULL;\r
195 \r
196 /*-----------------------------------------------------------*/\r
197 \r
198 /* Holds the block time used by the Tx task. */\r
199 TickType_t xSendBlockTime = ( 100UL / portTICK_PERIOD_MS );\r
200 \r
201 /* The lower an upper limits of the block time.  An infinite block time is used\r
202 if xSendBlockTime is incremented past xMaxBlockTime. */\r
203 static const TickType_t xMaxBlockTime = ( 500L / portTICK_PERIOD_MS ), xMinBlockTime = ( 100L / portTICK_PERIOD_MS );\r
204 \r
205 /* The semaphore on which the Tx task blocks. */\r
206 static SemaphoreHandle_t xTxSemaphore = NULL;\r
207 \r
208 /*-----------------------------------------------------------*/\r
209 \r
210 /* See the comments at the top of the file. */\r
211 void main_low_power( void )\r
212 {\r
213         /* Create the semaphore as described at the top of this file. */\r
214         xTxSemaphore = xSemaphoreCreateBinary();\r
215         configASSERT( xTxSemaphore );\r
216 \r
217         /* Create the queue as described at the top of this file. */\r
218         xQueue = xQueueCreate( mainQUEUE_LENGTH, sizeof( unsigned long ) );\r
219         configASSERT( xQueue );\r
220 \r
221         /* Start the two tasks as described at the top of this file. */\r
222         xTaskCreate( prvQueueReceiveTask, "Rx", configMINIMAL_STACK_SIZE, NULL, configQUEUE_RECEIVE_TASK_PRIORITY, NULL );\r
223         xTaskCreate( prvQueueSendTask, "TX", configMINIMAL_STACK_SIZE, NULL, configQUEUE_SEND_TASK_PRIORITY, NULL );\r
224 \r
225         /* Start the scheduler running running. */\r
226         vTaskStartScheduler();\r
227 \r
228         /* If all is well the next line of code will not be reached as the\r
229         scheduler will be running.  If the next line is reached then it is likely\r
230         there was insufficient FreeRTOS heap available for the idle task and/or\r
231         timer task to be created.  See http://www.freertos.org/a00111.html. */\r
232         for( ;; );\r
233 }\r
234 /*-----------------------------------------------------------*/\r
235 \r
236 static void prvQueueSendTask( void *pvParameters )\r
237 {\r
238 const unsigned long ulValueToSend = mainQUEUED_VALUE;\r
239 \r
240         /* Remove compiler warning about unused parameter. */\r
241         ( void ) pvParameters;\r
242 \r
243         for( ;; )\r
244         {\r
245                 /* Enter the Blocked state to wait for the semaphore.  The task will\r
246                 leave the Blocked state if either the semaphore is received or\r
247                 xSendBlockTime ticks pass without the semaphore being received. */\r
248                 xSemaphoreTake( xTxSemaphore, xSendBlockTime );\r
249 \r
250                 /* Send to the queue - causing the Tx task to flash its LED. */\r
251                 xQueueSend( xQueue, &ulValueToSend, mainDONT_BLOCK );\r
252         }\r
253 }\r
254 /*-----------------------------------------------------------*/\r
255 \r
256 static void prvQueueReceiveTask( void *pvParameters )\r
257 {\r
258 unsigned long ulReceivedValue;\r
259 \r
260         /* Remove compiler warning about unused parameter. */\r
261         ( void ) pvParameters;\r
262 \r
263         for( ;; )\r
264         {\r
265                 /* Wait until something arrives in the queue. */\r
266                 xQueueReceive( xQueue, &ulReceivedValue, portMAX_DELAY );\r
267 \r
268                 /*  To get here something must have arrived, but is it the expected\r
269                 value?  If it is, turn the LED on for a short while. */\r
270                 if( ulReceivedValue == mainQUEUED_VALUE )\r
271                 {\r
272                         /* LED on... */\r
273                         GPIO_HIGH( LD_GPIO_PORT, LD_GREEN_GPIO_PIN );\r
274 \r
275                         /* ... short delay ... */\r
276                         vTaskDelay( mainLED_TOGGLE_DELAY );\r
277 \r
278                         /* ... LED off again. */\r
279                         GPIO_LOW( LD_GPIO_PORT, LD_GREEN_GPIO_PIN );\r
280                 }\r
281         }\r
282 }\r
283 /*-----------------------------------------------------------*/\r
284 \r
285 /* Handles interrupts generated by pressing the USER button. */\r
286 void EXTI0_IRQHandler(void)\r
287 {\r
288 static const TickType_t xIncrement = 200UL / portTICK_PERIOD_MS;\r
289 \r
290         /* If xSendBlockTime is already portMAX_DELAY then the Tx task was blocked\r
291         indefinitely, and this interrupt is bringing the MCU out of STOP low power\r
292         mode. */\r
293         if( xSendBlockTime == portMAX_DELAY )\r
294         {\r
295                 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;\r
296 \r
297                 /* Unblock the Tx task. */\r
298                 xSemaphoreGiveFromISR( xTxSemaphore, &xHigherPriorityTaskWoken );\r
299 \r
300                 /* Start over with the 'short' block time as described at the top of\r
301                 this file. */\r
302                 xSendBlockTime = xMinBlockTime;\r
303 \r
304                 /* Request a yield if calling xSemaphoreGiveFromISR() caused a task to\r
305                 leave the Blocked state (which it will have done) and the task that left\r
306                 the Blocked state has a priority higher than the currently running task\r
307                 (which it will have). */\r
308                 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
309         }\r
310         else\r
311         {\r
312                 /* Increase the block time used by the Tx task, as described at the top\r
313                 of this file. */\r
314                 xSendBlockTime += xIncrement;\r
315 \r
316                 /* If the block time has gone over the configured maximum then set it to\r
317                 an infinite block time to allow the MCU to go into its STOP low power\r
318                 mode. */\r
319                 if( xSendBlockTime > xMaxBlockTime )\r
320                 {\r
321                         xSendBlockTime = portMAX_DELAY;\r
322                 }\r
323         }\r
324 \r
325         EXTI_ClearITPendingBit( EXTI_Line0 );\r
326 }\r
327 /*-----------------------------------------------------------*/\r
328 \r
329 /* The configPOST_STOP_PROCESSING() macro is called when the MCU leaves its\r
330 STOP low power mode.  The macro is set in FreeRTOSConfig.h to call\r
331 vMainPostStopProcessing(). */\r
332 void vMainPostStopProcessing( void )\r
333 {\r
334 extern void SetSysClock( void );\r
335 \r
336         /* The STOP low power mode has been exited.  Reconfigure the system clocks\r
337         ready for normally running again. */\r
338         SetSysClock();\r
339 }\r
340 /*-----------------------------------------------------------*/\r