px-fwlib 0.10.0
Cross-platform embedded library and documentation for 8/16/32-bit microcontrollers generated with Doxygen 1.9.2
px_wwdg.c
1/* =============================================================================
2 ____ ___ ____ ___ _ _ ___ __ __ ___ __ __ TM
3 | _ \ |_ _| / ___| / _ \ | \ | | / _ \ | \/ | |_ _| \ \/ /
4 | |_) | | | | | | | | | | \| | | | | | | |\/| | | | \ /
5 | __/ | | | |___ | |_| | | |\ | | |_| | | | | | | | / \
6 |_| |___| \____| \___/ |_| \_| \___/ |_| |_| |___| /_/\_\
7
8 Copyright (c) 2021 Pieter Conradie <https://piconomix.com>
9
10 License: MIT
11 https://github.com/piconomix/px-fwlib/blob/master/LICENSE.md
12
13 Title: px_wwdg.h : Watchdog module
14 Author(s): Pieter Conradie
15 Creation Date: 2021-05-08
16
17============================================================================= */
18
19/* _____STANDARD INCLUDES____________________________________________________ */
20
21/* _____PROJECT INCLUDES_____________________________________________________ */
22#include "px_wwdg.h"
23#include "px_stm32cube.h"
24#include "px_log.h"
25
26/* _____LOCAL DEFINITIONS____________________________________________________ */
27PX_LOG_NAME("px_wwdg");
28
29/* _____MACROS_______________________________________________________________ */
30
31/* _____GLOBAL VARIABLES_____________________________________________________ */
32
33/* _____LOCAL VARIABLES______________________________________________________ */
34static uint8_t px_wwdg_counter_reload;
35
36#ifdef PX_WWDG_CFG_EARLY_WARNING_FLAG
37PX_ATTR_SECTION(".noinit") volatile uint32_t px_wwdg_ew_flag;
38#endif
39
40#ifdef PX_WWDG_CFG_EARLY_WARNING_REGS
41PX_ATTR_SECTION(".noinit") volatile uint32_t px_wwdg_r0;
42PX_ATTR_SECTION(".noinit") volatile uint32_t px_wwdg_r1;
43PX_ATTR_SECTION(".noinit") volatile uint32_t px_wwdg_r2;
44PX_ATTR_SECTION(".noinit") volatile uint32_t px_wwdg_r3;
45PX_ATTR_SECTION(".noinit") volatile uint32_t px_wwdg_r12;
46PX_ATTR_SECTION(".noinit") volatile uint32_t px_wwdg_lr;
47PX_ATTR_SECTION(".noinit") volatile uint32_t px_wwdg_pc;
48PX_ATTR_SECTION(".noinit") volatile uint32_t px_wwdg_psr;
49#endif
50
51/* _____LOCAL FUNCTION DECLARATIONS__________________________________________ */
52
53/* _____LOCAL FUNCTIONS______________________________________________________ */
54#ifdef PX_WWDG_CFG_EARLY_WARNING_FLAG
55void WWDG_IRQHandler(void)
56{
57 LL_WWDG_ClearFlag_EWKUP(WWDG);
58 px_wwdg_ew_flag = 0xdeadc0de;
59}
60#endif
61
62#ifdef PX_WWDG_CFG_EARLY_WARNING_REGS
63/*
64 * Origin of register saving code here:
65 * https://stackoverflow.com/questions/38618440/retrieving-return-address-of-an-exception-on-arm-cortex-m0
66 *
67 * Credit: Andrea Biondo
68 */
69PX_ATTR_NORETURN void px_wwdg_save_regs(uint32_t * stack_adr)
70{
71 px_wwdg_r0 = stack_adr[0]; // (sp + 0x00)
72 px_wwdg_r1 = stack_adr[1]; // (sp + 0x04)
73 px_wwdg_r2 = stack_adr[2]; // (sp + 0x08)
74 px_wwdg_r3 = stack_adr[3]; // (sp + 0x0c)
75 px_wwdg_r12 = stack_adr[4]; // (sp + 0x10)
76 px_wwdg_lr = stack_adr[5]; // (sp + 0x14)
77 px_wwdg_pc = stack_adr[6]; // (sp + 0x18)
78 px_wwdg_psr = stack_adr[7]; // (sp + 0x1c)
79
80 // Block forever
81 while(true) {;}
82}
83
84void WWDG_IRQHandler(void) PX_ATTR_NAKED;
85void WWDG_IRQHandler(void)
86{
87#if (__CORTEX_M > 0x03U)
88 // Arm Cortex M3/M4 implementation
89 __asm__ __volatile__
90 (
91 "tst lr, #4 \n\t"
92 "ite eq \n\t"
93 "mrseq r0, msp \n\t"
94 "mrsne r0, psp \n\t"
95 "ldr r1, =px_wwdg_save_regs \n\t"
96 "bx r1 \n\t"
97 );
98#else
99 // Arm Cortex M0/M0+ implementation
100 __asm__ __volatile__
101 (
102 "mrs r0, msp \n\t"
103 "mov r1, lr \n\t"
104 "mov r2, #4 \n\t"
105 "tst r1, r2 \n\t"
106 "beq px_wwdg_save_regs_call \n\t"
107 "mrs r0, psp \n\t"
108 "px_wwdg_save_regs_call: \n\t"
109 "ldr r1, =px_wwdg_save_regs \n\t"
110 "bx r1 \n\t"
111 );
112#endif
113}
114#endif
115
116
117/* _____GLOBAL FUNCTIONS_____________________________________________________ */
118void px_wwdg_init(px_wwdg_prescaler_t prescaler, uint8_t counter, uint8_t window)
119{
120 PX_LOG_ASSERT((window > 0x40) && (window < 0x80));
121 PX_LOG_ASSERT((counter > 0x40) && (counter < 0x80));
122
123 // Enable peripheral clock
124 LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_WWDG);
125 // Set clock (PCLK / 4096) prescaler
126 LL_WWDG_SetPrescaler(WWDG, ((uint32_t)prescaler) << WWDG_CFR_WDGTB_Pos);
127 // Set watchdog counter window
128 if(window != 0)
129 {
130 LL_WWDG_SetWindow(WWDG, window);
131 }
132 // Save counter value and load counter
133 px_wwdg_counter_reload = counter;
134 LL_WWDG_SetCounter(WWDG, counter);
135
136#ifdef PX_WWDG_CFG_EARLY_WARNING_FLAG
137 // Reset early warning flag
138 px_wwdg_ew_flag = 0;
139 // Clear interrupt flag
140 LL_WWDG_ClearFlag_EWKUP(WWDG);
141 // Enable early wake up interrupt
142 NVIC_SetPriority(WWDG_IRQn, 0);
143 NVIC_EnableIRQ(WWDG_IRQn);
144 LL_WWDG_EnableIT_EWKUP(WWDG);
145#endif
146
147#ifdef PX_WWDG_CFG_EARLY_WARNING_REGS
148 // Reset saved register values
149 px_wwdg_r0 = 0;
150 px_wwdg_r1 = 0;
151 px_wwdg_r2 = 0;
152 px_wwdg_r3 = 0;
153 px_wwdg_r12 = 0;
154 px_wwdg_lr = 0;
155 px_wwdg_pc = 0;
156 px_wwdg_psr = 0;
157 // Clear interrupt flag
158 LL_WWDG_ClearFlag_EWKUP(WWDG);
159 // Enable early wake up interrupt
160 NVIC_SetPriority(WWDG_IRQn, 0);
161 NVIC_EnableIRQ(WWDG_IRQn);
162 LL_WWDG_EnableIT_EWKUP(WWDG);
163#endif
164
165#if 0
166 // Freeze watchdog when processor is halted by debugger
167 LL_DBGMCU_APB1_GRP1_FreezePeriph(LL_DBGMCU_APB1_GRP1_WWDG_STOP);
168#endif
169
170 // Enable peripheral
171 LL_WWDG_Enable(WWDG);
172}
173
175{
176 if(!LL_WWDG_IsEnabled(WWDG))
177 {
178 return;
179 }
180 if(px_wwdg_counter_reload <= 0x40)
181 {
182 return;
183 }
184 LL_WWDG_SetCounter(WWDG, px_wwdg_counter_reload);
185}
186
187void px_wwdg_halt(void)
188{
189 LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_WWDG);
190}
191
193{
194 LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_WWDG);
195}
196
198{
199#ifdef PX_WWDG_CFG_EARLY_WARNING_FLAG
200 PX_LOG_TRACE("ew_flag = 0x%08lX\n", px_wwdg_ew_flag);
201#endif
202
203#ifdef PX_WWDG_CFG_EARLY_WARNING_REGS
204 PX_LOG_TRACE("r0 = 0x%08lX\n", px_wwdg_r0);
205 PX_LOG_TRACE("r1 = 0x%08lX\n", px_wwdg_r1);
206 PX_LOG_TRACE("r2 = 0x%08lX\n", px_wwdg_r2);
207 PX_LOG_TRACE("r3 = 0x%08lX\n", px_wwdg_r3);
208 PX_LOG_TRACE("r1 = 0x%08lX\n", px_wwdg_r12);
209 PX_LOG_TRACE("lr = 0x%08lX\n", px_wwdg_lr);
210 PX_LOG_TRACE("pc = 0x%08lX\n", px_wwdg_pc);
211 PX_LOG_TRACE("psr = 0x%08lX\n", px_wwdg_psr);
212#endif
213}
214
#define PX_LOG_TRACE(format,...)
Macro to output a user format string if PX_LOG=1.
Definition: px_log.h:458
#define PX_LOG_NAME(name)
Macro to declare a log name string once for each file to reduce code size.
Definition: px_log.h:349
#define PX_LOG_ASSERT(expression)
Macro that will test an expression, and block indefinitely if false.
Definition: px_log.h:440
px_wwdg_prescaler_t
Window Watchdog clock prescaler (PCLK / 4096 clock source)
Definition: px_wwdg.h:47
void px_wwdg_halt(void)
Halt watchdog by disabling peripheral clock.
Definition: px_wwdg.c:187
void px_wwdg_dbg_report(void)
Report state saved by early warning interrupt in .noinit variables.
Definition: px_wwdg.c:197
void px_wwdg_reload_counter(void)
Reload watchdog counter, a.k.a.
Definition: px_wwdg.c:174
void px_wwdg_init(px_wwdg_prescaler_t prescaler, uint8_t counter, uint8_t window)
Initialise System Window Watchdog.
Definition: px_wwdg.c:118
void px_wwdg_resume(void)
Resume watchdog by enabling peripheral clock.
Definition: px_wwdg.c:192