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 #include <stdbool.h>
32 #include "cyhal_wdt.h"
33 #include "cyhal_wdt_impl.h"
34 #include "cy_wdt.h"
35 #include "cy_utils.h"
36
37 #if (CYHAL_DRIVER_AVAILABLE_WDT)
38
39 #if defined(__cplusplus)
40 extern "C" {
41 #endif
42
43 #if defined(SRSS_NUM_WDT_A_BITS)
44 #define _CYHAL_WDT_MATCH_BITS (SRSS_NUM_WDT_A_BITS)
45 #elif defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B)
46 #define _CYHAL_WDT_MATCH_BITS (16)
47 #elif defined(COMPONENT_CAT1C)
48 #define _CYHAL_WDT_MATCH_BITS (32)
49 #elif defined(COMPONENT_CAT2)
50 #define _CYHAL_WDT_MATCH_BITS (16)
51 #else
52 #error Unhandled device type
53 #endif
54
55 #if defined(CY_IP_MXS40SRSS) || defined(CY_IP_MXS40SSRSS)
56 #define _cyhal_wdt_lock() Cy_WDT_Lock()
57 #define _cyhal_wdt_unlock() Cy_WDT_Unlock()
58 #else
59 #define _cyhal_wdt_lock()
60 #define _cyhal_wdt_unlock()
61 #endif
62
63 #if defined(CY_IP_MXS40SRSS) && (CY_IP_MXS40SRSS_VERSION >= 3)
64 // 2^32 * .030518 ms
65 /** Maximum WDT timeout in milliseconds */
66 #define _CYHAL_WDT_MAX_TIMEOUT_MS 131073812
67 #elif defined(CY_IP_MXS22SRSS) && (_CYHAL_WDT_MATCH_BITS == 22)
68 // ILO, PILO, BAK all run at 32768 Hz - Period is ~0.030518 ms
69 // Max WDT Reset Period = 3 * (2^_CYHAL_WDT_MATCH_BITS) * 0.030518 ms
70 #define _CYHAL_WDT_MAX_TIMEOUT_MS 384000
71 // WDT Reset Period (timeout_ms) = .030518 ms * (2 * 2^(_CYHAL_WDT_MATCH_BITS - ignore_bits) + match)
72 // ignore_bits range: 0 -> (_CYHAL_WDT_MATCH_BITS - 4) (Bottom four bits cannot be ignored)
73 #define _CYHAL_WDT_MAX_IGNORE_BITS (_CYHAL_WDT_MATCH_BITS - 4)
74 // match range: 0 -> 2^(_CYHAL_WDT_MATCH_BITS - ignore_bits)
75 static const _cyhal_wdt_ignore_bits_data_t _cyhal_wdt_ignore_data[] = {
76 {256000, 192001}, // 0 bit(s): min period: 256000ms, max period: 384000ms, round up from 192001+ms
77 {128000, 96001}, // 1 bit(s): min period: 128000ms, max period: 192000ms, round up from 96001+ms
78 { 64000, 48001}, // 2 bit(s): min period: 64000ms, max period: 96000ms, round up from 48001+ms
79 { 32000, 24001}, // 3 bit(s): min period: 32000ms, max period: 48000ms, round up from 24001+ms
80 { 16000, 12001}, // 4 bit(s): min period: 16000ms, max period: 24000ms, round up from 12001+ms
81 { 8000, 6001}, // 5 bit(s): min period: 8000ms, max period: 12000ms, round up from 6001+ms
82 { 4000, 3001}, // 6 bit(s): min period: 4000ms, max period: 6000ms, round up from 3001+ms
83 { 2000, 1501}, // 7 bit(s): min period: 2000ms, max period: 3000ms, round up from 1501+ms
84 { 1000, 751}, // 8 bit(s): min period: 1000ms, max period: 1500ms, round up from 751+ms
85 { 500, 376}, // 9 bit(s): min period: 500ms, max period: 750ms, round up from 376+ms
86 { 250, 188}, // 10 bit(s): min period: 250ms, max period: 375ms, round up from 188+ms
87 { 125, 94}, // 11 bit(s): min period: 125ms, max period: 187ms, round up from 94+ms
88 { 63, 47}, // 12 bit(s): min period: 63ms, max period: 93ms, round up from 47+ms
89 { 32, 24}, // 13 bit(s): min period: 32ms, max period: 46ms, round up from 24+ms
90 { 16, 12}, // 14 bit(s): min period: 16ms, max period: 23ms, round up from 12+ms
91 { 8, 6}, // 15 bit(s): min period: 8ms, max period: 11ms, round up from 6+ms
92 { 4, 3}, // 16 bit(s): min period: 4ms, max period: 5ms, round up from 3+ms
93 { 2, 2}, // 17 bit(s): min period: 2ms, max period: 2ms, round up from 2+ms
94 { 1, 1}, // 18 bit(s): min period: 1ms, max period: 1ms, round up from 1+ms
95 };
96 #elif defined(CY_IP_MXS40SRSS) || defined(CY_IP_MXS40SSRSS)
97 // ILO Frequency = 32768 Hz
98 // ILO Period = 1 / 32768 Hz = .030518 ms
99 // WDT Reset Period (timeout_ms) = .030518 ms * (2 * 2^(16 - ignore_bits) + match)
100 // ignore_bits range: 0 - 12
101 // match range: 0 - 2^(16 - ignore_bits)
102 static const _cyhal_wdt_ignore_bits_data_t _cyhal_wdt_ignore_data[] = {
103 {4000, 3001}, // 0 bit(s): min period: 4000ms, max period: 6000ms, round up from 3001+ms
104 {2000, 1501}, // 1 bit(s): min period: 2000ms, max period: 3000ms, round up from 1501+ms
105 {1000, 751}, // 2 bit(s): min period: 1000ms, max period: 1500ms, round up from 751+ms
106 { 500, 376}, // 3 bit(s): min period: 500ms, max period: 750ms, round up from 376+ms
107 { 250, 188}, // 4 bit(s): min period: 250ms, max period: 375ms, round up from 188+ms
108 { 125, 94}, // 5 bit(s): min period: 125ms, max period: 187ms, round up from 94+ms
109 { 63, 47}, // 6 bit(s): min period: 63ms, max period: 93ms, round up from 47+ms
110 { 32, 24}, // 7 bit(s): min period: 32ms, max period: 46ms, round up from 24+ms
111 { 16, 12}, // 8 bit(s): min period: 16ms, max period: 23ms, round up from 12+ms
112 { 8, 6}, // 9 bit(s): min period: 8ms, max period: 11ms, round up from 6+ms
113 { 4, 3}, // 10 bit(s): min period: 4ms, max period: 5ms, round up from 3+ms
114 { 2, 2}, // 11 bit(s): min period: 2ms, max period: 2ms, round up from 2+ms
115 { 1, 1}, // 12 bit(s): min period: 1ms, max period: 1ms, round up from 1+ms
116 };
117 #elif defined(COMPONENT_CAT2)
118 // ILO Frequency = 40000 Hz
119 // ILO Period = 1 / 40000 Hz = .025 ms
120 // WDT Reset Period (timeout_ms) = .025 ms * (2 * 2^(16 - ignore_bits) + match)
121 // ignore_bits range: 0 - 16 (only need up to 12)
122 // match range: 0 - 2^(16 - ignore_bits)
123 static const _cyhal_wdt_ignore_bits_data_t _cyhal_wdt_ignore_data[] = {
124 {3277, 2458}, // 0 bit(s): min period: 3277ms, max period: 4915ms, round up from 2458+ms
125 {1639, 1229}, // 1 bit(s): min period: 1639ms, max period: 2457ms, round up from 1229+ms
126 { 820, 615}, // 2 bit(s): min period: 820ms, max period: 1228ms, round up from 615+ms
127 { 410, 308}, // 3 bit(s): min period: 410ms, max period: 614ms, round up from 308+ms
128 { 205, 154}, // 4 bit(s): min period: 205ms, max period: 307ms, round up from 154+ms
129 { 103, 77}, // 5 bit(s): min period: 103ms, max period: 153ms, round up from 77+ms
130 { 52, 39}, // 6 bit(s): min period: 52ms, max period: 76ms, round up from 39+ms
131 { 26, 20}, // 7 bit(s): min period: 26ms, max period: 38ms, round up from 20+ms
132 { 13, 10}, // 8 bit(s): min period: 13ms, max period: 19ms, round up from 10+ms
133 { 7, 5}, // 9 bit(s): min period: 7ms, max period: 9ms, round up from 5+ms
134 { 4, 3}, // 10 bit(s): min period: 4ms, max period: 4ms, round up from 3+ms
135 { 2, 2}, // 11 bit(s): min period: 2ms, max period: 2ms, round up from 2+ms
136 { 1, 1}, // 12 bit(s): min period: 1ms, max period: 1ms, round up from 1+ms
137 };
138 #endif
139
140 static bool _cyhal_wdt_initialized = false;
141 static uint16_t _cyhal_wdt_initial_timeout_ms = 0;
142
143 #if defined (CY_IP_MXS40SRSS) && (CY_IP_MXS40SRSS_VERSION >= 3)
_cyhal_wdt_timeout_to_match(uint16_t timeout_ms)144 __STATIC_INLINE uint32_t _cyhal_wdt_timeout_to_match(uint16_t timeout_ms)
145 {
146 uint32_t timeout = ((uint64_t)timeout_ms * CY_SYSCLK_ILO_FREQ) / 1000;
147 return (uint32_t)(timeout + Cy_WDT_GetCount());
148 }
149 #else
150
151 static uint16_t _cyhal_wdt_rounded_timeout_ms = 0;
152 static uint32_t _cyhal_wdt_ignore_bits = 0;
153
_cyhal_wdt_timeout_to_match(uint16_t timeout_ms,uint16_t ignore_bits)154 __STATIC_INLINE uint16_t _cyhal_wdt_timeout_to_match(uint16_t timeout_ms, uint16_t ignore_bits)
155 {
156 uint32_t timeout = ((uint32_t)timeout_ms * CY_SYSCLK_ILO_FREQ) / 1000;
157 return (uint16_t)(timeout - (1UL << ((_CYHAL_WDT_MATCH_BITS + 1) - ignore_bits)) + Cy_WDT_GetCount());
158 }
159
160 // 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)161 __STATIC_INLINE uint32_t _cyhal_wdt_timeout_to_ignore_bits(uint32_t *timeout_ms)
162 {
163 for (uint32_t i = 0; i <= _CYHAL_WDT_MAX_IGNORE_BITS; i++)
164 {
165 if (*timeout_ms >= _cyhal_wdt_ignore_data[i].round_threshold_ms)
166 {
167 if (*timeout_ms < _cyhal_wdt_ignore_data[i].min_period_ms)
168 {
169 *timeout_ms = _cyhal_wdt_ignore_data[i].min_period_ms;
170 }
171 return i;
172 }
173 }
174 return _CYHAL_WDT_MAX_IGNORE_BITS; // Ideally should never reach this
175 }
176 #endif
177
cyhal_wdt_init(cyhal_wdt_t * obj,uint32_t timeout_ms)178 cy_rslt_t cyhal_wdt_init(cyhal_wdt_t *obj, uint32_t timeout_ms)
179 {
180 if ((timeout_ms == 0) || (timeout_ms > _CYHAL_WDT_MAX_TIMEOUT_MS))
181 return CY_RSLT_WDT_INVALID_TIMEOUT;
182 if (_cyhal_wdt_initialized)
183 return CY_RSLT_WDT_ALREADY_INITIALIZED;
184
185 cyhal_wdt_stop(obj); // Stop and unlock before doing other work
186 Cy_WDT_ClearInterrupt();
187 Cy_WDT_MaskInterrupt();
188
189 _cyhal_wdt_initial_timeout_ms = timeout_ms;
190 #if defined(CY_IP_MXS40SRSS) && (CY_IP_MXS40SRSS_VERSION >= 3)
191 Cy_WDT_SetUpperLimit(_cyhal_wdt_timeout_to_match(_cyhal_wdt_initial_timeout_ms));
192 Cy_WDT_SetUpperAction(CY_WDT_LOW_UPPER_LIMIT_ACTION_RESET);
193 #else
194 _cyhal_wdt_ignore_bits = _cyhal_wdt_timeout_to_ignore_bits(&timeout_ms);
195 _cyhal_wdt_rounded_timeout_ms = timeout_ms;
196 Cy_WDT_SetIgnoreBits(_cyhal_wdt_ignore_bits);
197 Cy_WDT_SetMatch(_cyhal_wdt_timeout_to_match(_cyhal_wdt_rounded_timeout_ms, _cyhal_wdt_ignore_bits));
198 #endif
199 cyhal_wdt_start(obj);
200 _cyhal_wdt_initialized = true;
201
202 return CY_RSLT_SUCCESS;
203 }
204
cyhal_wdt_free(cyhal_wdt_t * obj)205 void cyhal_wdt_free(cyhal_wdt_t *obj)
206 {
207 CY_UNUSED_PARAMETER(obj);
208 cyhal_wdt_stop(obj);
209 _cyhal_wdt_initialized = false;
210 }
211
cyhal_wdt_kick(cyhal_wdt_t * obj)212 void cyhal_wdt_kick(cyhal_wdt_t *obj)
213 {
214 CY_UNUSED_PARAMETER(obj);
215 _cyhal_wdt_unlock();
216 Cy_WDT_ClearWatchdog(); /* Clear to prevent reset from WDT */
217 #if defined(CY_IP_MXS40SRSS) && (CY_IP_MXS40SRSS_VERSION >= 3)
218 Cy_WDT_SetUpperLimit(_cyhal_wdt_timeout_to_match(_cyhal_wdt_initial_timeout_ms));
219 #else
220 Cy_WDT_SetMatch(_cyhal_wdt_timeout_to_match(_cyhal_wdt_rounded_timeout_ms, _cyhal_wdt_ignore_bits));
221 #endif
222 _cyhal_wdt_lock();
223 }
224
cyhal_wdt_start(cyhal_wdt_t * obj)225 void cyhal_wdt_start(cyhal_wdt_t *obj)
226 {
227 CY_UNUSED_PARAMETER(obj);
228 _cyhal_wdt_unlock();
229 Cy_WDT_Enable();
230 _cyhal_wdt_lock();
231 }
232
cyhal_wdt_stop(cyhal_wdt_t * obj)233 void cyhal_wdt_stop(cyhal_wdt_t *obj)
234 {
235 CY_UNUSED_PARAMETER(obj);
236 _cyhal_wdt_unlock();
237 Cy_WDT_Disable();
238 }
239
cyhal_wdt_get_timeout_ms(cyhal_wdt_t * obj)240 uint32_t cyhal_wdt_get_timeout_ms(cyhal_wdt_t *obj)
241 {
242 CY_UNUSED_PARAMETER(obj);
243 return _cyhal_wdt_initial_timeout_ms;
244 }
245
cyhal_wdt_get_max_timeout_ms(void)246 uint32_t cyhal_wdt_get_max_timeout_ms(void)
247 {
248 return _CYHAL_WDT_MAX_TIMEOUT_MS;
249 }
250
cyhal_wdt_is_enabled(cyhal_wdt_t * obj)251 bool cyhal_wdt_is_enabled(cyhal_wdt_t *obj)
252 {
253 CY_UNUSED_PARAMETER(obj);
254 return Cy_WDT_IsEnabled();
255 }
256
257 #if defined(__cplusplus)
258 }
259 #endif
260
261 #endif // CYHAL_DRIVER_AVAILABLE_WDT
262