1 /***************************************************************************//**
2 * \file cyhal_wdt.c
3 *
4 * \brief
5 * Provides a high level interface for interacting with the Infineon Watchdog Timer.
6 * This interface abstracts out the chip specific details. If any chip specific
7 * functionality is necessary, or performance is critical the low level functions
8 * can be used directly.
9 *
10 *
11 ********************************************************************************
12 * \copyright
13 * Copyright 2019-2021 Cypress Semiconductor Corporation (an Infineon company) or
14 * an affiliate of Cypress Semiconductor Corporation
15 *
16 * SPDX-License-Identifier: Apache-2.0
17 *
18 * Licensed under the Apache License, Version 2.0 (the "License");
19 * you may not use this file except in compliance with the License.
20 * You may obtain a copy of the License at
21 *
22 * http://www.apache.org/licenses/LICENSE-2.0
23 *
24 * Unless required by applicable law or agreed to in writing, software
25 * distributed under the License is distributed on an "AS IS" BASIS,
26 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27 * See the License for the specific language governing permissions and
28 * limitations under the License.
29 *******************************************************************************/
30
31
32 /**
33 * \addtogroup group_hal_impl_wdt WDT (Watchdog Timer)
34 * \ingroup group_hal_impl
35 * \{
36 *\section subsection_wdt_notes Notes
37 * WDT timeout values for Active and Hibernate modes are different.
38 * In Active mode, the timeout value is used to create a match count that is matched
39 * by the hardware twice, then triggers (ISR) on the third match.
40 * In Hibernate mode, the trigger (reset) happens on the first match. Depending on
41 * the timing of starting the WDT and entering Hibernate mode, this can lead to
42 * WDT reset occurring earlier than it would if the device had not entered Hibernate.
43 *
44 * \} group_hal_wdt
45 */
46
47 #include <stdbool.h>
48 #include "cyhal_wdt.h"
49 #include "cyhal_wdt_impl.h"
50 #include "cy_wdt.h"
51 #include "cy_utils.h"
52
53 #if (CYHAL_DRIVER_AVAILABLE_WDT)
54
55 #if defined(__cplusplus)
56 extern "C" {
57 #endif
58
59 #if defined(SRSS_NUM_WDT_A_BITS)
60 #define _CYHAL_WDT_MATCH_BITS (SRSS_NUM_WDT_A_BITS)
61 #elif defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1C)
62 #if defined (CY_IP_MXS40SRSS) && (CY_IP_MXS40SRSS_VERSION < 2)
63 #define _CYHAL_WDT_MATCH_BITS (16)
64 #else /* CY_IP_MXS40SRSS_VERSION >= 2 */
65 #define _CYHAL_WDT_MATCH_BITS (32)
66 #endif
67 #elif defined(COMPONENT_CAT1B)
68 #define _CYHAL_WDT_MATCH_BITS (16)
69 #elif defined(COMPONENT_CAT2)
70 #define _CYHAL_WDT_MATCH_BITS (16)
71 #else
72 #error Unhandled device type
73 #endif
74
75 #if defined(CY_IP_MXS40SRSS) || defined(CY_IP_MXS40SSRSS)
76 #define _cyhal_wdt_lock() Cy_WDT_Lock()
77 #define _cyhal_wdt_unlock() Cy_WDT_Unlock()
78 #else
79 #define _cyhal_wdt_lock()
80 #define _cyhal_wdt_unlock()
81 #endif
82
83 #if defined(CY_IP_MXS40SRSS) && (CY_IP_MXS40SRSS_VERSION >= 2)
84 // 2^32 * .030518 ms
85 /** Maximum WDT timeout in milliseconds */
86 #define _CYHAL_WDT_MAX_TIMEOUT_MS 131073812
87 #elif defined(CY_IP_MXS22SRSS) && (_CYHAL_WDT_MATCH_BITS == 22)
88 // ILO, PILO, BAK all run at 32768 Hz - Period is ~0.030518 ms
89 // Max WDT Reset Period = 3 * (2^_CYHAL_WDT_MATCH_BITS) * 0.030518 ms
90 #define _CYHAL_WDT_MAX_TIMEOUT_MS 384000
91 // WDT Reset Period (timeout_ms) = .030518 ms * (2 * 2^(_CYHAL_WDT_MATCH_BITS - ignore_bits) + match)
92 // ignore_bits range: 0 -> (_CYHAL_WDT_MATCH_BITS - 4) (Bottom four bits cannot be ignored)
93 #define _CYHAL_WDT_MAX_IGNORE_BITS (_CYHAL_WDT_MATCH_BITS - 4)
94 // match range: 0 -> 2^(_CYHAL_WDT_MATCH_BITS - ignore_bits)
95 static const _cyhal_wdt_ignore_bits_data_t _cyhal_wdt_ignore_data[] = {
96 {256000, 192001}, // 0 bit(s): min period: 256000ms, max period: 384000ms, round up from 192001+ms
97 {128000, 96001}, // 1 bit(s): min period: 128000ms, max period: 192000ms, round up from 96001+ms
98 { 64000, 48001}, // 2 bit(s): min period: 64000ms, max period: 96000ms, round up from 48001+ms
99 { 32000, 24001}, // 3 bit(s): min period: 32000ms, max period: 48000ms, round up from 24001+ms
100 { 16000, 12001}, // 4 bit(s): min period: 16000ms, max period: 24000ms, round up from 12001+ms
101 { 8000, 6001}, // 5 bit(s): min period: 8000ms, max period: 12000ms, round up from 6001+ms
102 { 4000, 3001}, // 6 bit(s): min period: 4000ms, max period: 6000ms, round up from 3001+ms
103 { 2000, 1501}, // 7 bit(s): min period: 2000ms, max period: 3000ms, round up from 1501+ms
104 { 1000, 751}, // 8 bit(s): min period: 1000ms, max period: 1500ms, round up from 751+ms
105 { 500, 376}, // 9 bit(s): min period: 500ms, max period: 750ms, round up from 376+ms
106 { 250, 188}, // 10 bit(s): min period: 250ms, max period: 375ms, round up from 188+ms
107 { 125, 94}, // 11 bit(s): min period: 125ms, max period: 187ms, round up from 94+ms
108 { 63, 47}, // 12 bit(s): min period: 63ms, max period: 93ms, round up from 47+ms
109 { 32, 24}, // 13 bit(s): min period: 32ms, max period: 46ms, round up from 24+ms
110 { 16, 12}, // 14 bit(s): min period: 16ms, max period: 23ms, round up from 12+ms
111 { 8, 6}, // 15 bit(s): min period: 8ms, max period: 11ms, round up from 6+ms
112 { 4, 3}, // 16 bit(s): min period: 4ms, max period: 5ms, round up from 3+ms
113 { 2, 2}, // 17 bit(s): min period: 2ms, max period: 2ms, round up from 2+ms
114 { 1, 1}, // 18 bit(s): min period: 1ms, max period: 1ms, round up from 1+ms
115 };
116 #elif defined(CY_IP_MXS40SRSS)
117 // ILO Frequency = 32768 Hz
118 // ILO Period = 1 / 32768 Hz = .030518 ms
119 // WDT Reset Period (timeout_ms) = .030518 ms * (2 * 2^(16 - ignore_bits) + match)
120 // ignore_bits range: 0 - 12
121 // match range: 0 - 2^(16 - ignore_bits)
122 static const _cyhal_wdt_ignore_bits_data_t _cyhal_wdt_ignore_data[] = {
123 {4000, 3001}, // 0 bit(s): min period: 4000ms, max period: 6000ms, round up from 3001+ms
124 {2000, 1501}, // 1 bit(s): min period: 2000ms, max period: 3000ms, round up from 1501+ms
125 {1000, 751}, // 2 bit(s): min period: 1000ms, max period: 1500ms, round up from 751+ms
126 { 500, 376}, // 3 bit(s): min period: 500ms, max period: 750ms, round up from 376+ms
127 { 250, 188}, // 4 bit(s): min period: 250ms, max period: 375ms, round up from 188+ms
128 { 125, 94}, // 5 bit(s): min period: 125ms, max period: 187ms, round up from 94+ms
129 { 63, 47}, // 6 bit(s): min period: 63ms, max period: 93ms, round up from 47+ms
130 { 32, 24}, // 7 bit(s): min period: 32ms, max period: 46ms, round up from 24+ms
131 { 16, 12}, // 8 bit(s): min period: 16ms, max period: 23ms, round up from 12+ms
132 { 8, 6}, // 9 bit(s): min period: 8ms, max period: 11ms, round up from 6+ms
133 { 4, 3}, // 10 bit(s): min period: 4ms, max period: 5ms, round up from 3+ms
134 { 2, 2}, // 11 bit(s): min period: 2ms, max period: 2ms, round up from 2+ms
135 { 1, 1}, // 12 bit(s): min period: 1ms, max period: 1ms, round up from 1+ms
136 };
137 #elif defined(CY_IP_MXS40SSRSS)
138 // ILO Frequency = 32768 Hz
139 // ILO Period = 1 / 32768 Hz = .030518 ms
140 // WDT Reset Period (timeout_ms) = .030518 ms * (2 * 2^(_CYHAL_WDT_MAX_IGNORE_BITS - ignore_bits) + match)
141 // ignore_bits range: 0 - 18
142 // match range: 0 - 2^(_CYHAL_WDT_MAX_IGNORE_BITS - ignore_bits)
143
144 static const _cyhal_wdt_ignore_bits_data_t _cyhal_wdt_ignore_data[] = {
145 {256000, 192001}, // 0 bit(s): min period: 256000ms, max period: 384000ms, round up from 192001+ms
146 {128000, 96001}, // 1 bit(s): min period: 128000ms, max period: 192000ms, round up from 96001+ms
147 { 64000, 48001}, // 2 bit(s): min period: 64000ms, max period: 96000ms, round up from 48001+ms
148 { 32000, 24001}, // 3 bit(s): min period: 32000ms, max period: 48000ms, round up from 24001+ms
149 { 16000, 12001}, // 4 bit(s): min period: 16000ms, max period: 24000ms, round up from 12001+ms
150 { 8000, 6001}, // 5 bit(s): min period: 8000ms, max period: 12000ms, round up from 6001+ms
151 { 4000, 3001}, // 6 bit(s): min period: 4000ms, max period: 6000ms, round up from 3001+ms
152 { 2000, 1501}, // 7 bit(s): min period: 2000ms, max period: 3000ms, round up from 1501+ms
153 { 1000, 751}, // 8 bit(s): min period: 1000ms, max period: 1500ms, round up from 751+ms
154 { 500, 376}, // 9 bit(s): min period: 500ms, max period: 750ms, round up from 376+ms
155 { 250, 188}, // 10 bit(s): min period: 250ms, max period: 375ms, round up from 188+ms
156 { 125, 94}, // 11 bit(s): min period: 125ms, max period: 187ms, round up from 94+ms
157 { 63, 47}, // 12 bit(s): min period: 63ms, max period: 93ms, round up from 47+ms
158 { 32, 24}, // 13 bit(s): min period: 32ms, max period: 46ms, round up from 24+ms
159 { 16, 12}, // 14 bit(s): min period: 16ms, max period: 23ms, round up from 12+ms
160 { 8, 6}, // 15 bit(s): min period: 8ms, max period: 11ms, round up from 6+ms
161 { 4, 3}, // 16 bit(s): min period: 4ms, max period: 5ms, round up from 3+ms
162 { 2, 2}, // 17 bit(s): min period: 2ms, max period: 2ms, round up from 2+ms
163 { 1, 1}, // 18 bit(s): min period: 1ms, max period: 1ms, round up from 1+ms
164 };
165 #elif defined(COMPONENT_CAT2)
166 // ILO Frequency = 40000 Hz
167 // ILO Period = 1 / 40000 Hz = .025 ms
168 // WDT Reset Period (timeout_ms) = .025 ms * (2 * 2^(16 - ignore_bits) + match)
169 // ignore_bits range: 0 - 16 (only need up to 12)
170 // match range: 0 - 2^(16 - ignore_bits)
171 static const _cyhal_wdt_ignore_bits_data_t _cyhal_wdt_ignore_data[] = {
172 {3277, 2458}, // 0 bit(s): min period: 3277ms, max period: 4915ms, round up from 2458+ms
173 {1639, 1229}, // 1 bit(s): min period: 1639ms, max period: 2457ms, round up from 1229+ms
174 { 820, 615}, // 2 bit(s): min period: 820ms, max period: 1228ms, round up from 615+ms
175 { 410, 308}, // 3 bit(s): min period: 410ms, max period: 614ms, round up from 308+ms
176 { 205, 154}, // 4 bit(s): min period: 205ms, max period: 307ms, round up from 154+ms
177 { 103, 77}, // 5 bit(s): min period: 103ms, max period: 153ms, round up from 77+ms
178 { 52, 39}, // 6 bit(s): min period: 52ms, max period: 76ms, round up from 39+ms
179 { 26, 20}, // 7 bit(s): min period: 26ms, max period: 38ms, round up from 20+ms
180 { 13, 10}, // 8 bit(s): min period: 13ms, max period: 19ms, round up from 10+ms
181 { 7, 5}, // 9 bit(s): min period: 7ms, max period: 9ms, round up from 5+ms
182 { 4, 3}, // 10 bit(s): min period: 4ms, max period: 4ms, round up from 3+ms
183 { 2, 2}, // 11 bit(s): min period: 2ms, max period: 2ms, round up from 2+ms
184 { 1, 1}, // 12 bit(s): min period: 1ms, max period: 1ms, round up from 1+ms
185 };
186 #endif
187
188 static bool _cyhal_wdt_initialized = false;
189 static uint32_t _cyhal_wdt_initial_timeout_ms = 0;
190
191 #if defined (CY_IP_MXS40SRSS) && (CY_IP_MXS40SRSS_VERSION >= 2)
_cyhal_wdt_timeout_to_match(uint16_t timeout_ms)192 __STATIC_INLINE uint32_t _cyhal_wdt_timeout_to_match(uint16_t timeout_ms)
193 {
194 uint32_t timeout = ((uint64_t)timeout_ms * CY_SYSCLK_ILO_FREQ) / 1000;
195 return (uint32_t)(timeout + Cy_WDT_GetCount());
196 }
197 #else /* defined (CY_IP_MXS40SRSS) && (CY_IP_MXS40SRSS_VERSION >= 2) */
198
199 static uint32_t _cyhal_wdt_rounded_timeout_ms = 0;
200 static uint32_t _cyhal_wdt_ignore_bits = 0;
201
202 #define _CYHAL_DETERMINE_MATCH_BITS(bits) ( (WDT_MAX_IGNORE_BITS) - (bits) )
203 #define _CYHAL_GET_COUNT_FROM_MATCH_BITS(bits) (2UL << _CYHAL_DETERMINE_MATCH_BITS(bits) )
204
_cyhal_wdt_timeout_to_match(uint32_t timeout_ms,uint32_t ignore_bits)205 __STATIC_INLINE uint32_t _cyhal_wdt_timeout_to_match(uint32_t timeout_ms, uint32_t ignore_bits)
206 {
207 uint32_t wrap_count_for_ignore_bits = (_CYHAL_GET_COUNT_FROM_MATCH_BITS(ignore_bits) );
208 uint32_t timeout_count = ( (timeout_ms * CY_SYSCLK_ILO_FREQ) / 1000UL);
209 /* handle multiple possible wraps of WDT counter */
210 timeout_count = ( (timeout_count + Cy_WDT_GetCount()) % wrap_count_for_ignore_bits);
211 return timeout_count;
212 }
213
214 // Rounds up *timeout_ms if it's outside of the valid timeout range (_cyhal_wdt_ignore_data)
_cyhal_wdt_timeout_to_ignore_bits(uint32_t * timeout_ms)215 __STATIC_INLINE uint32_t _cyhal_wdt_timeout_to_ignore_bits(uint32_t *timeout_ms)
216 {
217 for (uint32_t i = 0; i <= _CYHAL_WDT_MAX_IGNORE_BITS; i++)
218 {
219 if (*timeout_ms >= _cyhal_wdt_ignore_data[i].round_threshold_ms)
220 {
221 if (*timeout_ms < _cyhal_wdt_ignore_data[i].min_period_ms)
222 {
223 *timeout_ms = _cyhal_wdt_ignore_data[i].min_period_ms;
224 }
225 return i;
226 }
227 }
228 return _CYHAL_WDT_MAX_IGNORE_BITS; // Ideally should never reach this
229 }
230
231 #endif /* defined (CY_IP_MXS40SRSS) && (CY_IP_MXS40SRSS_VERSION >= 2) */
232
cyhal_wdt_init(cyhal_wdt_t * obj,uint32_t timeout_ms)233 cy_rslt_t cyhal_wdt_init(cyhal_wdt_t *obj, uint32_t timeout_ms)
234 {
235 if ((timeout_ms == 0) || (timeout_ms > _CYHAL_WDT_MAX_TIMEOUT_MS))
236 return CY_RSLT_WDT_INVALID_TIMEOUT;
237 if (_cyhal_wdt_initialized)
238 return CY_RSLT_WDT_ALREADY_INITIALIZED;
239
240 cyhal_wdt_stop(obj); // Stop and unlock before doing other work
241
242 Cy_WDT_ClearInterrupt();
243 Cy_WDT_MaskInterrupt();
244
245 _cyhal_wdt_initial_timeout_ms = timeout_ms;
246 #if defined(CY_IP_MXS40SRSS) && (CY_IP_MXS40SRSS_VERSION >= 2)
247 Cy_WDT_SetUpperLimit(_cyhal_wdt_timeout_to_match(_cyhal_wdt_initial_timeout_ms));
248 Cy_WDT_SetUpperAction(CY_WDT_LOW_UPPER_LIMIT_ACTION_RESET);
249 #else
250 _cyhal_wdt_ignore_bits = _cyhal_wdt_timeout_to_ignore_bits(&timeout_ms);
251 _cyhal_wdt_rounded_timeout_ms = timeout_ms;
252 #if defined(SRSS_NUM_WDT_A_BITS) && (SRSS_NUM_WDT_A_BITS == 22)
253 /* Cy_WDT_SetMatchBits configures the bit position above which the bits will be ignored for match,
254 * while _cyhal_wdt_timeout_to_ignore_bits returns number of timer MSB to ignore, so conversion
255 * is needed. */
256 Cy_WDT_SetMatchBits(_CYHAL_DETERMINE_MATCH_BITS(_cyhal_wdt_ignore_bits) );
257 #else
258 Cy_WDT_SetIgnoreBits(_cyhal_wdt_ignore_bits);
259 #endif
260
261 #if defined(COMPONENT_CAT1) && (CY_WDT_DRV_VERSION_MAJOR > 1 ) && (CY_WDT_DRV_VERSION_MINOR > 6 )
262 /* Reset counter every time - large current counts in WDT can cause problems on some boards */
263 Cy_WDT_ResetCounter();
264 /* Twice, as reading back after 1 reset gives same value as before single reset */
265 Cy_WDT_ResetCounter();
266 #endif
267
268 Cy_WDT_SetMatch(_cyhal_wdt_timeout_to_match(_cyhal_wdt_rounded_timeout_ms, _cyhal_wdt_ignore_bits));
269 #endif
270
271 cyhal_wdt_start(obj);
272 _cyhal_wdt_initialized = true;
273
274 return CY_RSLT_SUCCESS;
275 }
276
cyhal_wdt_free(cyhal_wdt_t * obj)277 void cyhal_wdt_free(cyhal_wdt_t *obj)
278 {
279 CY_UNUSED_PARAMETER(obj);
280 cyhal_wdt_stop(obj);
281 _cyhal_wdt_initialized = false;
282 }
283
cyhal_wdt_kick(cyhal_wdt_t * obj)284 void cyhal_wdt_kick(cyhal_wdt_t *obj)
285 {
286 CY_UNUSED_PARAMETER(obj);
287 _cyhal_wdt_unlock();
288 Cy_WDT_ClearWatchdog(); /* Clear to prevent reset from WDT */
289 #if defined(CY_IP_MXS40SRSS) && (CY_IP_MXS40SRSS_VERSION >= 2)
290 Cy_WDT_SetUpperLimit(_cyhal_wdt_timeout_to_match(_cyhal_wdt_initial_timeout_ms));
291 #else
292 Cy_WDT_SetMatch(_cyhal_wdt_timeout_to_match(_cyhal_wdt_rounded_timeout_ms, _cyhal_wdt_ignore_bits));
293 #endif
294 _cyhal_wdt_lock();
295 }
296
cyhal_wdt_start(cyhal_wdt_t * obj)297 void cyhal_wdt_start(cyhal_wdt_t *obj)
298 {
299 CY_UNUSED_PARAMETER(obj);
300 _cyhal_wdt_unlock();
301 Cy_WDT_Enable();
302 _cyhal_wdt_lock();
303 }
304
cyhal_wdt_stop(cyhal_wdt_t * obj)305 void cyhal_wdt_stop(cyhal_wdt_t *obj)
306 {
307 CY_UNUSED_PARAMETER(obj);
308 _cyhal_wdt_unlock();
309 Cy_WDT_Disable();
310 }
311
cyhal_wdt_get_timeout_ms(cyhal_wdt_t * obj)312 uint32_t cyhal_wdt_get_timeout_ms(cyhal_wdt_t *obj)
313 {
314 CY_UNUSED_PARAMETER(obj);
315 return _cyhal_wdt_initial_timeout_ms;
316 }
317
cyhal_wdt_get_max_timeout_ms(void)318 uint32_t cyhal_wdt_get_max_timeout_ms(void)
319 {
320 return _CYHAL_WDT_MAX_TIMEOUT_MS;
321 }
322
cyhal_wdt_is_enabled(cyhal_wdt_t * obj)323 bool cyhal_wdt_is_enabled(cyhal_wdt_t *obj)
324 {
325 CY_UNUSED_PARAMETER(obj);
326 return Cy_WDT_IsEnabled();
327 }
328
329 #if defined(__cplusplus)
330 }
331 #endif
332
333 #endif // CYHAL_DRIVER_AVAILABLE_WDT
334