@@ -86,24 +86,101 @@ void mbed_sdk_init(void)
8686 /* Lock protected registers */
8787 SYS_LockReg ();
8888
89- /* Get around h/w limit with WDT reset from PD */
90- if (SYS_IS_WDT_RST ()) {
89+ #if MBED_CONF_TARGET_WDT_RESET_WORKAROUND
90+ /* Work around H/W limit with WDT reset from PD
91+ *
92+ * To reproduce WDT reset from PD, run like:
93+ * Watchdog &watchdog = Watchdog::get_instance();
94+ * watchdog.start(2500);
95+ * while (1) {
96+ * SYS_UnlockReg();
97+ * CLK_PowerDown();
98+ * }
99+ *
100+ * To reproduce WDT wake-up from PD and then WDT reset, run:
101+ * Watchdog &watchdog = Watchdog::get_instance();
102+ * watchdog.start(2500);
103+ * SYS_UnlockReg();
104+ * CLK_PowerDown();
105+ * while (1);
106+ *
107+ * NOTE: The H/W limit is met on WDT reset from PD, not WDT wake-up
108+ * from PD and then WDT reset.
109+ *
110+ * NOTE: Per test, WDT reset from PD won't raise SYS_RSTSTS.WDTRF flag,
111+ * and WDT wake-up from PD will. So don't rely on SYS_IS_WDT_RST() to
112+ * determine to use or not the workaround.
113+ *
114+ * NOTE: To avoid the workaround duplicate run by bootloader (e.g. MCUBoot)
115+ * and application and then crash when bootloader is enabled, the workaround
116+ * is applied only when any H/W reset flag (SYS.RSTSTS) raised.
117+ *
118+ * NOTE: The workaround will change SYS.RSTSTS and DEVICE_RESET_REASON won't
119+ * work as expected. Don't enable MBED_CONF_TARGET_WDT_RESET_WORKAROUND and
120+ * DEVICE_RESET_REASON at the same time.
121+ *
122+ * NOTE: Per test, DPD wake-up reset will clean RTC spare registers,
123+ * so use SPD wake-up reset instead to get around the limit.
124+ *
125+ * NOTE: Per test, SPD wake-up reset doesn't release I/O hold status
126+ * (CLK->IOPDCTL) automatically. Must do it manually.
127+ */
128+
129+ #if DEVICE_RESET_REASON
130+ #warning "MBED_CONF_TARGET_WDT_RESET_WORKAROUND will change SYS.RSTSTS \
131+ and DEVICE_RESET_REASON won't work as expected. Don't enable \
132+ MBED_CONF_TARGET_WDT_RESET_WORKAROUND and DEVICE_RESET_REASON \
133+ at the same time."
134+ #endif
135+
136+ #define ALL_RESET_FLAGS \
137+ (SYS_RSTSTS_PORF_Msk | \
138+ SYS_RSTSTS_PINRF_Msk | \
139+ SYS_RSTSTS_WDTRF_Msk | \
140+ SYS_RSTSTS_LVRF_Msk | \
141+ SYS_RSTSTS_BODRF_Msk | \
142+ SYS_RSTSTS_SYSRF_Msk | \
143+ SYS_RSTSTS_CPURF_Msk | \
144+ SYS_RSTSTS_CPULKRF_Msk)
145+
146+ /* Apply the workaround only when any H/W reset flag is raised. For
147+ * bootloader enabled application, the workaround must apply either
148+ * by bootloader or by application, but not both.
149+ */
150+ if (SYS -> RSTSTS & ALL_RESET_FLAGS ) {
91151 /* Re-unlock protected clock setting */
92152 SYS_UnlockReg ();
93153
94- /* Set up DPD power down mode */
95- CLK -> PMUSTS |= CLK_PMUSTS_CLRWK_Msk ;
96- CLK -> PMUSTS |= CLK_PMUSTS_TMRWK_Msk ;
97- CLK_SetPowerDownMode (CLK_PMUCTL_PDMSEL_DPD );
154+ /* Without this, bootloader enabled application will trap in
155+ * loop of wake-up timer wake-up reset armed here by bootloader
156+ * and application alternately, if both integrate this piece
157+ * of code.
158+ */
159+ SYS_CLEAR_RST_SOURCE (ALL_RESET_FLAGS );
160+
161+ /* Release I/O hold status */
162+ CLK -> IOPDCTL = 1 ;
163+
164+ if (!(CLK -> PMUSTS & CLK_PMUSTS_TMRWK_Msk )) {
165+ /* Set up DPD/SPD power down mode */
166+ CLK_SetPowerDownMode (CLK_PMUCTL_PDMSEL_SPD0 );
98167
99- CLK_SET_WKTMR_INTERVAL (CLK_PMUCTL_WKTMRIS_256 );
100- CLK_ENABLE_WKTMR ();
168+ /* Enable wake-up timer */
169+ CLK_SET_WKTMR_INTERVAL (CLK_PMUCTL_WKTMRIS_256 );
170+ CLK_ENABLE_WKTMR ();
101171
102- CLK_PowerDown ();
172+ CLK_PowerDown ();
173+
174+ MBED_UNREACHABLE ;
175+ }
176+
177+ /* Clean previous wake-up flag */
178+ CLK -> PMUSTS |= (CLK_PMUSTS_CLRWK_Msk | CLK_PMUSTS_TMRWK_Msk );
103179
104180 /* Lock protected registers */
105181 SYS_LockReg ();
106182 }
183+ #endif
107184}
108185
109186// Override mbed_mac_address of mbed_interface.c to provide ethernet devices with a semi-unique MAC address
0 commit comments