|
27 | 27 |
|
28 | 28 | #include "mongoose.h"
|
29 | 29 |
|
| 30 | +#include "mgos_core_dump.h" |
30 | 31 | #include "mgos_hal.h"
|
31 | 32 | #include "mgos_mongoose.h"
|
32 | 33 | #include "mgos_sys_config.h"
|
33 | 34 | #include "mgos_timers.h"
|
34 | 35 | #include "mgos_utils.h"
|
35 | 36 |
|
| 37 | +#include "stm32_system.h" |
36 | 38 | #include "stm32_uart.h"
|
37 | 39 |
|
38 | 40 | void mgos_dev_system_restart(void) {
|
@@ -105,43 +107,72 @@ uint32_t HAL_GetTick(void) {
|
105 | 107 | return xTaskGetTickCount() * portTICK_PERIOD_MS;
|
106 | 108 | }
|
107 | 109 |
|
108 |
| -#define IWDG_1_SECOND 128 |
109 |
| -IWDG_HandleTypeDef hiwdg = { |
110 |
| - .Instance = IWDG, |
| 110 | +WWDG_HandleTypeDef hwwdg = { |
| 111 | + .Instance = WWDG, |
111 | 112 | .Init =
|
112 | 113 | {
|
113 |
| - .Prescaler = IWDG_PRESCALER_256, |
114 |
| - .Reload = 5 * IWDG_1_SECOND, |
115 |
| -#ifdef IWDG_WINDOW_DISABLE |
116 |
| - .Window = IWDG_WINDOW_DISABLE, |
117 |
| -#endif |
| 114 | + .Prescaler = WWDG_PRESCALER_8, |
| 115 | + .Window = 0x7f, |
| 116 | + .Counter = 0x7f, |
| 117 | + .EWIMode = WWDG_EWI_ENABLE, |
118 | 118 | },
|
119 | 119 | };
|
120 | 120 |
|
| 121 | +#define WWDT_MAGIC_OFF 0xf001 |
| 122 | + |
| 123 | +static int s_wwdt_ttl = 0; |
| 124 | +static int s_wwdt_reload = 50; |
| 125 | + |
| 126 | +IRAM static void stm32_wwdg_int_handler(void) { |
| 127 | + if (s_wwdt_ttl != WWDT_MAGIC_OFF) { |
| 128 | + s_wwdt_ttl--; |
| 129 | + if ((s_wwdt_ttl & 0xffff0000) == 0) { |
| 130 | + HAL_WWDG_Refresh(&hwwdg); |
| 131 | + } else { |
| 132 | + // TTL expired or has been smashed, explode. |
| 133 | + // Refresh one last time to get the message out. |
| 134 | + HAL_WWDG_Refresh(&hwwdg); |
| 135 | + mgos_cd_printf("!! WDT\n"); |
| 136 | + // TODO(rojer): Trigger core dump. |
| 137 | + // Do not refresh anymore, WDT will reset the device soon. |
| 138 | + while (1) { |
| 139 | + } |
| 140 | + } |
| 141 | + } else { |
| 142 | + HAL_WWDG_Refresh(&hwwdg); |
| 143 | + } |
| 144 | + __HAL_WWDG_CLEAR_FLAG(&hwwdg, WWDG_FLAG_EWIF); |
| 145 | +} |
| 146 | + |
121 | 147 | void mgos_wdt_enable(void) {
|
122 |
| - HAL_IWDG_Init(&hiwdg); |
| 148 | + __HAL_RCC_WWDG_CLK_ENABLE(); |
| 149 | + stm32_set_int_handler(WWDG_IRQn, stm32_wwdg_int_handler); |
| 150 | + HAL_NVIC_SetPriority(WWDG_IRQn, 0, 0); // Highest possible prio. |
| 151 | + HAL_NVIC_EnableIRQ(WWDG_IRQn); |
| 152 | + HAL_WWDG_Init(&hwwdg); |
123 | 153 | }
|
124 | 154 |
|
125 | 155 | void mgos_wdt_feed(void) {
|
126 |
| - HAL_IWDG_Refresh(&hiwdg); |
| 156 | + s_wwdt_ttl = s_wwdt_reload; |
| 157 | + HAL_WWDG_Refresh(&hwwdg); |
| 158 | + /* |
| 159 | + * For backward compatibility with older bootloaders we have to feed IWDG. |
| 160 | + * We only do it if we detect the calue BL sets (10 seconds). |
| 161 | + */ |
| 162 | + if (IWDG->RLR == 10 * 128) { |
| 163 | + IWDG->KR = IWDG_KEY_RELOAD; |
| 164 | + } |
127 | 165 | }
|
128 | 166 |
|
129 | 167 | void mgos_wdt_set_timeout(int secs) {
|
130 |
| - uint32_t new_reload = (secs * IWDG_1_SECOND); |
131 |
| - if (!IS_IWDG_RELOAD(new_reload)) { |
132 |
| - LOG(LL_ERROR, ("Invalid WDT reload value %lu", new_reload)); |
133 |
| - return; |
134 |
| - } |
135 |
| - hiwdg.Init.Reload = new_reload; |
136 |
| - HAL_IWDG_Init(&hiwdg); |
| 168 | + uint32_t f_wwdt = HAL_RCC_GetPCLK1Freq(); // Valid for F2, F4, F7 and L4. |
| 169 | + uint32_t ints_per_sec = f_wwdt / 4096 / 8 / (0x7f - 0x41); |
| 170 | + s_wwdt_reload = ints_per_sec * secs; |
| 171 | + mgos_wdt_feed(); |
137 | 172 | }
|
138 | 173 |
|
139 | 174 | void mgos_wdt_disable(void) {
|
140 |
| - static bool printed = false; |
141 |
| - if (!printed) { |
142 |
| - printed = true; |
143 |
| - LOG(LL_ERROR, ("Once enabled, WDT cannot be disabled!")); |
144 |
| - } |
| 175 | + s_wwdt_ttl = WWDT_MAGIC_OFF; |
145 | 176 | }
|
146 | 177 |
|
147 | 178 | uint32_t mgos_get_cpu_freq(void) {
|
|
0 commit comments