Skip to content

Commit e6d757a

Browse files
committedMar 18, 2020
STM32: Use WWDT to implement mos watchdog
IWDT cannot be disabled and interferes with sleep (wakes up the system from standby). So we use WWDT, which is stopped when going into standby. However, WWDT is more tircky to use - it runs off PCLK with divider that is not big enough to handle reasonable timeouts just by itself: with 80 MHz PCLK maximum possible interval is 25 ms. So we have to use and count interrupts ourselves.
1 parent 0a540a8 commit e6d757a

File tree

6 files changed

+113
-41
lines changed

6 files changed

+113
-41
lines changed
 

‎.clang-format

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ AllowShortFunctionsOnASingleLine: false
33
SpaceAfterCStyleCast: true
44
PointerBindsToType: false
55
DerivePointerBinding: false
6+
IncludeBlocks: Preserve

‎platforms/stm32/Makefile.build

+1-1
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ MGOS_SRCS += $(notdir $(MGOS_CONFIG_C)) $(notdir $(MGOS_RO_VARS_C)) \
158158
mgos_dlsym.c mgos_file_utils.c mgos_system.c mgos_utils.c \
159159
arm_exc_top.S arm_exc.c arm_nsleep100.c \
160160
stm32_entry.c stm32_gpio.c \
161-
stm32_hal.c stm32_hw_timers.c \
161+
stm32_hal.c stm32_ints.c stm32_hw_timers.c \
162162
stm32_libc.c \
163163
stm32_main.c stm32_uart.c \
164164
error_codes.cpp status.cpp

‎platforms/stm32/include/stm32_system.h

+2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ void stm32_set_int_handler(int irqn, void (*handler)(void));
3030

3131
extern uint32_t SystemCoreClockMHZ;
3232

33+
void stm32_setup_int_vectors(void);
34+
3335
#ifdef __cplusplus
3436
}
3537
#endif

‎platforms/stm32/src/stm32_hal.c

+53-22
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@
2727

2828
#include "mongoose.h"
2929

30+
#include "mgos_core_dump.h"
3031
#include "mgos_hal.h"
3132
#include "mgos_mongoose.h"
3233
#include "mgos_sys_config.h"
3334
#include "mgos_timers.h"
3435
#include "mgos_utils.h"
3536

37+
#include "stm32_system.h"
3638
#include "stm32_uart.h"
3739

3840
void mgos_dev_system_restart(void) {
@@ -105,43 +107,72 @@ uint32_t HAL_GetTick(void) {
105107
return xTaskGetTickCount() * portTICK_PERIOD_MS;
106108
}
107109

108-
#define IWDG_1_SECOND 128
109-
IWDG_HandleTypeDef hiwdg = {
110-
.Instance = IWDG,
110+
WWDG_HandleTypeDef hwwdg = {
111+
.Instance = WWDG,
111112
.Init =
112113
{
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,
118118
},
119119
};
120120

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+
121147
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);
123153
}
124154

125155
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+
}
127165
}
128166

129167
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();
137172
}
138173

139174
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;
145176
}
146177

147178
uint32_t mgos_get_cpu_freq(void) {

‎platforms/stm32/src/stm32_ints.c

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright (c) 2014-2018 Cesanta Software Limited
3+
* All rights reserved
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the ""License"");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an ""AS IS"" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#include <string.h>
19+
20+
#include "common/platform.h"
21+
22+
#include "stm32_sdk_hal.h"
23+
#include "stm32_system.h"
24+
25+
void (*stm32_int_vectors[256])(void)
26+
__attribute__((section(".ram_int_vectors")));
27+
extern const void *stm32_flash_int_vectors[2];
28+
29+
extern void arm_exc_handler_top(void);
30+
31+
void stm32_set_int_handler(int irqn, void (*handler)(void)) {
32+
stm32_int_vectors[irqn + 16] = handler;
33+
}
34+
35+
void stm32_setup_int_vectors(void) {
36+
/* Move int vectors to RAM. */
37+
for (int i = 0; i < (int) ARRAY_SIZE(stm32_int_vectors); i++) {
38+
stm32_int_vectors[i] = arm_exc_handler_top;
39+
}
40+
memcpy(stm32_int_vectors, stm32_flash_int_vectors,
41+
sizeof(stm32_flash_int_vectors));
42+
SCB->VTOR = (uint32_t) &stm32_int_vectors[0];
43+
}

‎platforms/stm32/src/stm32_main.c

+13-18
Original file line numberDiff line numberDiff line change
@@ -101,17 +101,6 @@ void SystemCoreClockUpdate(void) {
101101
}
102102

103103
#ifndef MGOS_BOOT_BUILD
104-
void (*stm32_int_vectors[256])(void)
105-
__attribute__((section(".ram_int_vectors")));
106-
extern const void *stm32_flash_int_vectors[2];
107-
108-
extern void arm_exc_handler_top(void);
109-
extern void __libc_init_array(void);
110-
111-
void stm32_set_int_handler(int irqn, void (*handler)(void)) {
112-
stm32_int_vectors[irqn + 16] = handler;
113-
}
114-
115104
static void stm32_dump_sram(void) {
116105
mgos_cd_write_section("SRAM", (void *) STM32_SRAM_BASE_ADDR, STM32_SRAM_SIZE);
117106
}
@@ -123,20 +112,26 @@ static void stm32_dump_sram2(void) {
123112
}
124113
#endif
125114

115+
extern void __libc_init_array(void);
116+
126117
int main(void) {
127-
/* Move int vectors to RAM. */
128-
for (int i = 0; i < (int) ARRAY_SIZE(stm32_int_vectors); i++) {
129-
stm32_int_vectors[i] = arm_exc_handler_top;
118+
stm32_setup_int_vectors();
119+
if ((WWDG->CR & WWDG_CR_WDGA) != 0) {
120+
// WWDG was started by boot loader and is already ticking,
121+
// we have to reconfigure the int handler *now*.
122+
mgos_wdt_enable();
123+
mgos_wdt_set_timeout(10 /* seconds */);
130124
}
131-
memcpy(stm32_int_vectors, stm32_flash_int_vectors,
132-
sizeof(stm32_flash_int_vectors));
133-
SCB->VTOR = (uint32_t) &stm32_int_vectors[0];
134-
135125
stm32_system_init();
136126
__libc_init_array();
137127
stm32_clock_config();
138128
SystemCoreClockUpdate();
139129

130+
if ((WWDG->CR & WWDG_CR_WDGA) != 0) {
131+
// APB clock has most likely changed, recalculate the WDT timings.
132+
mgos_wdt_set_timeout(10 /* seconds */);
133+
}
134+
140135
mgos_cd_register_section_writer(arm_exc_dump_regs);
141136
mgos_cd_register_section_writer(stm32_dump_sram);
142137
#if STM32_SRAM2_SIZE > 0

0 commit comments

Comments
 (0)
Please sign in to comment.