1 /***********************************************************************************************//**
2 * \file cyabs_freertos_helpers.c
3 *
4 * \brief
5 * Provides implementations for functions required to enable static allocation and
6 * tickless mode in FreeRTOS.
7 *
8 ***************************************************************************************************
9 * \copyright
10 * Copyright 2018-2022 Cypress Semiconductor Corporation (an Infineon company) or
11 * an affiliate of Cypress Semiconductor Corporation
12 *
13 * SPDX-License-Identifier: Apache-2.0
14 *
15 * Licensed under the Apache License, Version 2.0 (the "License");
16 * you may not use this file except in compliance with the License.
17 * You may obtain a copy of the License at
18 *
19 * http://www.apache.org/licenses/LICENSE-2.0
20 *
21 * Unless required by applicable law or agreed to in writing, software
22 * distributed under the License is distributed on an "AS IS" BASIS,
23 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24 * See the License for the specific language governing permissions and
25 * limitations under the License.
26 **************************************************************************************************/
27 #include "FreeRTOS.h"
28 #include "task.h"
29 #include "cyabs_rtos.h"
30 #if defined(CY_USING_HAL)
31 #include "cyhal.h"
32 #include "cyhal_syspm.h"
33 #endif
34
35 // This is included to allow the user to control the idle task behavior via the configurator
36 // System->Power->RTOS->System Idle Power Mode setting.
37 #include "cybsp.h"
38
39 #define pdTICKS_TO_MS(xTicks) ( ( ( TickType_t ) ( xTicks ) * 1000u ) / configTICK_RATE_HZ )
40
41 #if defined(CY_USING_HAL)
42 static cyhal_lptimer_t* _lptimer = NULL;
43
44 //--------------------------------------------------------------------------------------------------
45 // cyabs_rtos_set_lptimer
46 //--------------------------------------------------------------------------------------------------
cyabs_rtos_set_lptimer(cyhal_lptimer_t * timer)47 void cyabs_rtos_set_lptimer(cyhal_lptimer_t* timer)
48 {
49 _lptimer = timer;
50 }
51
52
53 //--------------------------------------------------------------------------------------------------
54 // cyabs_rtos_get_lptimer
55 //--------------------------------------------------------------------------------------------------
cyabs_rtos_get_lptimer(void)56 cyhal_lptimer_t* cyabs_rtos_get_lptimer(void)
57 {
58 return _lptimer;
59 }
60
61
62 #if (configUSE_TICKLESS_IDLE != 0)
63 //--------------------------------------------------------------------------------------------------
64 // cyabs_rtos_get_deepsleep_latency
65 //--------------------------------------------------------------------------------------------------
cyabs_rtos_get_deepsleep_latency(void)66 uint32_t cyabs_rtos_get_deepsleep_latency(void)
67 {
68 uint32_t latency = 0;
69
70 #if defined(CY_CFG_PWR_DEEPSLEEP_LATENCY)
71 latency = CY_CFG_PWR_DEEPSLEEP_LATENCY;
72 #endif //defined(CY_CFG_PWR_DEEPSLEEP_LATENCY)
73
74 #if defined (CYHAL_API_AVAILABLE_SYSPM_GET_DEEPSLEEP_MODE)
75 cyhal_syspm_system_deep_sleep_mode_t deep_sleep_mode = cyhal_syspm_get_deepsleep_mode();
76
77 switch (deep_sleep_mode)
78 {
79 case CYHAL_SYSPM_SYSTEM_DEEPSLEEP:
80 case CYHAL_SYSPM_SYSTEM_DEEPSLEEP_OFF:
81 case CYHAL_SYSPM_SYSTEM_DEEPSLEEP_NONE:
82 #if defined(CY_CFG_PWR_DEEPSLEEP_LATENCY)
83 latency = CY_CFG_PWR_DEEPSLEEP_LATENCY;
84 #endif //defined(CY_CFG_PWR_DEEPSLEEP_LATENCY)
85 break;
86
87 case CYHAL_SYSPM_SYSTEM_DEEPSLEEP_RAM:
88 #if defined(CY_CFG_PWR_DEEPSLEEP_RAM_LATENCY)
89 latency = CY_CFG_PWR_DEEPSLEEP_RAM_LATENCY;
90 #endif //defined(CY_CFG_PWR_DEEPSLEEP_RAM_LATENCY)
91 break;
92
93 default:
94 #if defined(CY_CFG_PWR_DEEPSLEEP_LATENCY)
95 latency = CY_CFG_PWR_DEEPSLEEP_LATENCY;
96 #endif //defined(CY_CFG_PWR_DEEPSLEEP_LATENCY)
97 break;
98 }
99 #endif // if defined (CYHAL_API_AVAILABLE_SYSPM_GET_DEEPSLEEP_MODE)
100 return latency;
101 }
102
103
104 #endif //(configUSE_TICKLESS_IDLE != 0)
105
106 #endif //defined(CY_USING_HAL)
107
108
109 // The following implementations were sourced from https://www.freertos.org/a00110.html
110
111 //--------------------------------------------------------------------------------------------------
112 // vApplicationGetIdleTaskMemory
113 //
114 // configSUPPORT_STATIC_ALLOCATION is set to 1, so the application must provide an implementation of
115 // vApplicationGetIdleTaskMemory() to provide the memory that is used by the Idle task.
116 //--------------------------------------------------------------------------------------------------
vApplicationGetIdleTaskMemory(StaticTask_t ** ppxIdleTaskTCBBuffer,StackType_t ** ppxIdleTaskStackBuffer,uint32_t * pulIdleTaskStackSize)117 __WEAK void vApplicationGetIdleTaskMemory(StaticTask_t** ppxIdleTaskTCBBuffer,
118 StackType_t** ppxIdleTaskStackBuffer,
119 uint32_t* pulIdleTaskStackSize)
120 {
121 // If the buffers to be provided to the Idle task are declared inside this function then they
122 // must be declared static – otherwise they will be allocated on the stack and so not exists
123 // after this function exits.
124 static StaticTask_t xIdleTaskTCB;
125 static StackType_t uxIdleTaskStack[configMINIMAL_STACK_SIZE];
126
127 // Pass out a pointer to the StaticTask_t structure in which the Idle task’s state will be
128 // stored.
129 *ppxIdleTaskTCBBuffer = &xIdleTaskTCB;
130
131 // Pass out the array that will be used as the Idle task’s stack.
132 *ppxIdleTaskStackBuffer = uxIdleTaskStack;
133
134 // Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer. Note that, as the
135 // array is necessarily of type StackType_t, configMINIMAL_STACK_SIZE is specified in words, not
136 // bytes.
137 *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
138 }
139
140
141 /*———————————————————–*/
142
143 //--------------------------------------------------------------------------------------------------
144 // vApplicationGetTimerTaskMemory
145 //
146 // configSUPPORT_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the application must
147 // provide an implementation of vApplicationGetTimerTaskMemory() to provide the memory that is used
148 // by the Timer service task.
149 //--------------------------------------------------------------------------------------------------
vApplicationGetTimerTaskMemory(StaticTask_t ** ppxTimerTaskTCBBuffer,StackType_t ** ppxTimerTaskStackBuffer,uint32_t * pulTimerTaskStackSize)150 __WEAK void vApplicationGetTimerTaskMemory(StaticTask_t** ppxTimerTaskTCBBuffer,
151 StackType_t** ppxTimerTaskStackBuffer,
152 uint32_t* pulTimerTaskStackSize)
153 {
154 // If the buffers to be provided to the Timer task are declared inside this function then they
155 // must be declared static – otherwise they will be allocated on the stack and so not exists
156 // after this function exits.
157 static StaticTask_t xTimerTaskTCB;
158 static StackType_t uxTimerTaskStack[configTIMER_TASK_STACK_DEPTH];
159
160 // Pass out a pointer to the StaticTask_t structure in which the Timer task’s state will be
161 // stored.
162 *ppxTimerTaskTCBBuffer = &xTimerTaskTCB;
163
164 // Pass out the array that will be used as the Timer task’s stack.
165 *ppxTimerTaskStackBuffer = uxTimerTaskStack;
166
167 // Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer. Note that, as the
168 // array is necessarily of type StackType_t, configTIMER_TASK_STACK_DEPTH is specified in words,
169 // not bytes.
170 *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
171 }
172
173
174 #if defined(CY_USING_HAL) && (configUSE_TICKLESS_IDLE != 0)
175 //--------------------------------------------------------------------------------------------------
176 // vApplicationSleep
177 //
178 /** User defined tickless idle sleep function.
179 *
180 * Provides a implementation for portSUPPRESS_TICKS_AND_SLEEP macro that allows
181 * the device to attempt to deep-sleep for the idle time the kernel expects before
182 * the next task is ready. This function disables the system timer and enables low power
183 * timer that can operate in deep-sleep mode to wake the device from deep-sleep after
184 * expected idle time has elapsed.
185 *
186 * @param[in] xExpectedIdleTime Total number of tick periods before
187 * a task is due to be moved into the Ready state.
188 */
189 //--------------------------------------------------------------------------------------------------
vApplicationSleep(TickType_t xExpectedIdleTime)190 __WEAK void vApplicationSleep(TickType_t xExpectedIdleTime)
191 {
192 #if (defined(CY_CFG_PWR_MODE_DEEPSLEEP) && \
193 (CY_CFG_PWR_SYS_IDLE_MODE == CY_CFG_PWR_MODE_DEEPSLEEP)) || \
194 (defined(CY_CFG_PWR_MODE_DEEPSLEEP_RAM) && \
195 (CY_CFG_PWR_SYS_IDLE_MODE == CY_CFG_PWR_MODE_DEEPSLEEP_RAM))
196 #define DEEPSLEEP_ENABLE
197 #endif
198 static cyhal_lptimer_t timer;
199 uint32_t actual_sleep_ms = 0;
200 cy_rslt_t result = CY_RSLT_SUCCESS;
201
202 if (NULL == _lptimer)
203 {
204 result = cyhal_lptimer_init(&timer);
205 if (result == CY_RSLT_SUCCESS)
206 {
207 _lptimer = &timer;
208 }
209 else
210 {
211 CY_ASSERT(false);
212 }
213 }
214
215 if (NULL != _lptimer)
216 {
217 /* Disable interrupts so that nothing can change the status of the RTOS while
218 * we try to go to sleep or deep-sleep.
219 */
220 uint32_t status = cyhal_system_critical_section_enter();
221 eSleepModeStatus sleep_status = eTaskConfirmSleepModeStatus();
222
223 if (sleep_status != eAbortSleep)
224 {
225 // By default, the device will deep-sleep in the idle task unless if the device
226 // configurator overrides the behaviour to sleep in the System->Power->RTOS->System
227 // Idle Power Mode setting.
228 #if defined (CY_CFG_PWR_SYS_IDLE_MODE)
229 uint32_t sleep_ms = pdTICKS_TO_MS(xExpectedIdleTime);
230 #if defined DEEPSLEEP_ENABLE
231 bool deep_sleep = true;
232 // If the system needs to operate in active mode the tickless mode should not be used in
233 // FreeRTOS
234 CY_ASSERT(CY_CFG_PWR_SYS_IDLE_MODE != CY_CFG_PWR_MODE_ACTIVE);
235 deep_sleep =
236 #if defined(CY_CFG_PWR_MODE_DEEPSLEEP_RAM)
237 (CY_CFG_PWR_SYS_IDLE_MODE == CY_CFG_PWR_MODE_DEEPSLEEP_RAM) ||
238 #endif
239 (CY_CFG_PWR_SYS_IDLE_MODE == CY_CFG_PWR_MODE_DEEPSLEEP);
240 if (deep_sleep)
241 {
242 // Adjust the deep-sleep time by the sleep/wake latency if set.
243 #if defined(CY_CFG_PWR_DEEPSLEEP_LATENCY) || \
244 defined(CY_CFG_PWR_DEEPSLEEP_RAM_LATENCY)
245 uint32_t deep_sleep_latency = cyabs_rtos_get_deepsleep_latency();
246 if (sleep_ms > deep_sleep_latency)
247 {
248 result = cyhal_syspm_tickless_deepsleep(_lptimer,
249 (sleep_ms - deep_sleep_latency),
250 &actual_sleep_ms);
251 }
252 else
253 {
254 result = CY_RTOS_TIMEOUT;
255 }
256 #else \
257 // defined(CY_CFG_PWR_DEEPSLEEP_LATENCY) ||
258 // defined(CY_CFG_PWR_DEEPSLEEP_RAM_LATENCY)
259 result = cyhal_syspm_tickless_deepsleep(_lptimer, sleep_ms, &actual_sleep_ms);
260 #endif \
261 // defined(CY_CFG_PWR_DEEPSLEEP_LATENCY) ||
262 // defined(CY_CFG_PWR_DEEPSLEEP_RAM_LATENCY)
263 //maintain compatibility with older HAL versions that didn't define this error
264 #ifdef CYHAL_SYSPM_RSLT_DEEPSLEEP_LOCKED
265 //Deepsleep has been locked, continuing into normal sleep
266 if (result == CYHAL_SYSPM_RSLT_DEEPSLEEP_LOCKED)
267 {
268 deep_sleep = false;
269 }
270 #endif
271 }
272 if (!deep_sleep)
273 {
274 #endif // if defined DEEPSLEEP_ENABLE
275 uint32_t sleep_latency =
276 #if defined (CY_CFG_PWR_SLEEP_LATENCY)
277 CY_CFG_PWR_SLEEP_LATENCY +
278 #endif
279 0;
280 if (sleep_ms > sleep_latency)
281 {
282 result = cyhal_syspm_tickless_sleep(_lptimer, (sleep_ms - sleep_latency),
283 &actual_sleep_ms);
284 }
285 else
286 {
287 result = CY_RTOS_TIMEOUT;
288 }
289 #if defined DEEPSLEEP_ENABLE
290 }
291 #endif
292 #else // if defined (CY_CFG_PWR_SYS_IDLE_MODE)
293 CY_UNUSED_PARAMETER(xExpectedIdleTime);
294 #endif // if defined (CY_CFG_PWR_SYS_IDLE_MODE)
295 if (result == CY_RSLT_SUCCESS)
296 {
297 // If you hit this assert, the latency time (CY_CFG_PWR_DEEPSLEEP_LATENCY) should
298 // be increased. This can be set though the Device Configurator, or by manually
299 // defining the variable in cybsp.h for the TARGET platform.
300 CY_ASSERT(actual_sleep_ms <= pdTICKS_TO_MS(xExpectedIdleTime));
301 vTaskStepTick(convert_ms_to_ticks(actual_sleep_ms));
302 }
303 }
304
305 cyhal_system_critical_section_exit(status);
306 }
307 }
308
309
310 #endif // defined(CY_USING_HAL) && (configUSE_TICKLESS_IDLE != 0)
311