Skip to content

Commit 636c1e0

Browse files
mhightower83hasenradball
authored andcommitted
A new approach for erasing WiFi Settings (esp8266#8828)
* A new approach for erasing WiFi Settings Add support for hardware reset function call - simulates EXT_RST via HWDT. Add reset selection to `ESP.eraseConfig()` for calling hardware reset after erasing the WiFi Settings. Update ArduinoOTA to use `ESP.eraseConfig(true)` Externalized `ArduinoOTA.eraseConfigAndReset()` Add OTA examples to illustrate using erase config changes. * style fixed confused example * improve wording * Add new state to retry eraseConfigAndReset * Removed unreachable error test from examples. Removed continuous retry of "eraseConfig" and allow the script to assign an error handling option for "eraseConfig" failure. Update example to use error handling option. * In eboot for function ets_wdt_enable() added missing arguments * Update comments and example * Wording * Rebuilt eboot.elf with current tools from ./get.py * Requested changes. * cleanup comments * Update hardware_reset Avoid using "[[noreturn]]" - not accepted for a .c file function Updated to use __attribute__((noreturn)) to handle both .cpp and .c file functions.
1 parent f3dfea1 commit 636c1e0

File tree

10 files changed

+531
-34
lines changed

10 files changed

+531
-34
lines changed

bootloaders/eboot/eboot.c

+37-6
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,39 @@
1717

1818
#define SWRST do { (*((volatile uint32_t*) 0x60000700)) |= 0x80000000; } while(0);
1919

20-
extern void ets_wdt_enable(void);
21-
extern void ets_wdt_disable(void);
20+
/*
21+
After Power Enable Pin, EXT_RST, or HWDT event, at "main()" in eboot, WDT is
22+
disabled. Key WDT hardware registers are zero.
23+
24+
After "ESP.restart()" and other soft restarts, at "main()" in eboot, WDT is enabled.
25+
26+
References for the under-documented ets_wdt_* API
27+
https://mongoose-os.com/blog/esp8266-watchdog-timer/
28+
http://cholla.mmto.org/esp8266/bootrom/boot.txt
29+
30+
After looking at esp8266-watchdog-timer some more, `ets_wdt_enable(4, 12, 12)`
31+
is good for eboot's needs. From a ".map" the NON-OS SDK does not use the
32+
ets_wdt_* APIs, so our choices are not too critical.
33+
The SDK will set up the WDT as it wants it.
34+
35+
A rationale for keeping the "ets_wdt_enable()" line, if the system is not
36+
stable during a "soft restart," the HWDT would provide a recovery reboot.
37+
*/
38+
extern void ets_wdt_enable(uint32_t mode, uint32_t arg1, uint32_t arg2);
39+
/*
40+
"ets_wdt_disable"
41+
42+
Diables WDT, then feeds the dog.
43+
For current modes other than 1 or 2, returns the current mode.
44+
For current mode 1, calls ets_timer_disarm, then return the current mode.
45+
For current mode 2, calls ets_isr_mask, then return the current mode.
46+
47+
I always see a return value of 0xFFFFFFFF.
48+
49+
The return value would normally be used with ets_wdt_restore; however, that is
50+
not an option since a valid prior call to ets_wdt_enable() may not have been done.
51+
*/
52+
extern uint32_t ets_wdt_disable(void);
2253

2354
int print_version(const uint32_t flash_addr)
2455
{
@@ -241,12 +272,12 @@ int main()
241272

242273
ets_wdt_disable();
243274
res = copy_raw(cmd.args[0], cmd.args[1], cmd.args[2], false);
244-
ets_wdt_enable();
275+
ets_wdt_enable(4, 12, 12); // WDT about 13 secs.
245276

246277
ets_printf("%d\n", res);
247278
#if 0
248-
//devyte: this verify step below (cmp:) only works when the end of copy operation above does not overwrite the
249-
//beginning of the image in the empty area, see #7458. Disabling for now.
279+
//devyte: this verify step below (cmp:) only works when the end of copy operation above does not overwrite the
280+
//beginning of the image in the empty area, see #7458. Disabling for now.
250281
//TODO: replace the below verify with hash type, crc, or similar.
251282
// Verify the copy
252283
ets_printf("cmp:");
@@ -257,7 +288,7 @@ int main()
257288
}
258289

259290
ets_printf("%d\n", res);
260-
#endif
291+
#endif
261292
if (res == 0) {
262293
cmd.action = ACTION_LOAD_APP;
263294
cmd.args[0] = cmd.args[1];

bootloaders/eboot/eboot.elf

112 Bytes
Binary file not shown.

cores/esp8266/Esp.cpp

+13-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "umm_malloc/umm_malloc.h"
3232
#include <pgmspace.h>
3333
#include "reboot_uart_dwnld.h"
34+
#include "hardware_reset.h"
3435

3536
extern "C" {
3637
#include "user_interface.h"
@@ -519,7 +520,7 @@ struct rst_info * EspClass::getResetInfoPtr(void) {
519520
}
520521

521522
bool EspClass::eraseConfig(void) {
522-
const size_t cfgSize = 0x4000;
523+
const size_t cfgSize = 0x4000; // Sectors: RF_CAL + SYSTEMPARAM[3]
523524
size_t cfgAddr = ESP.getFlashChipSize() - cfgSize;
524525

525526
for (size_t offset = 0; offset < cfgSize; offset += SPI_FLASH_SEC_SIZE) {
@@ -531,6 +532,17 @@ bool EspClass::eraseConfig(void) {
531532
return true;
532533
}
533534

535+
bool EspClass::eraseConfigAndReset(void) {
536+
// Before calling, ensure the WiFi state is equivalent to
537+
// "WiFi.mode(WIFI_OFF)." This will reduce the likelihood of the SDK
538+
// performing WiFi data writes to Flash between erasing and resetting.
539+
bool reset = eraseConfig();
540+
if (reset) {
541+
hardware_reset();
542+
}
543+
return reset;
544+
}
545+
534546
uint8_t *EspClass::random(uint8_t *resultArray, const size_t outputSizeBytes)
535547
{
536548
/**

cores/esp8266/Esp.h

+16
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,22 @@ class EspClass {
212212

213213
static bool eraseConfig();
214214

215+
/**
216+
* @brief Erases 4 sectors at the end of flash, 1 - RF_CAL and 3 - SYSTEMPARM.
217+
* These are the same additional sectors that are erase when you select
218+
* Erase Flash: "Sketch + WiFi Settings" from the Arduino IDE Tools menu.
219+
*
220+
* This operation erases the running SDK's flash configuration space.
221+
* As a precaution before calling, first call "WiFi.mode(WIFI_OFF)."
222+
*
223+
* If you need to erase "WiFi Settings" and reboot consider using
224+
* "ArduinoOTA.eraseConfigAndReset()" it handles shutting down WiFi
225+
* before the erase.
226+
* @return bool result of operation. Always False on return.
227+
* Function does not return on success.
228+
*/
229+
static bool eraseConfigAndReset();
230+
215231
static uint8_t *random(uint8_t *resultArray, const size_t outputSizeBytes);
216232
static uint32_t random();
217233

cores/esp8266/hardware_reset.cpp

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
Make the reset look like an EXT_RST reset by:
3+
* Set INTLEVEL to 15 blocking NMI Software WDT interference
4+
* set "restart reason" to REASON_EXT_SYS_RST
5+
* Config Hardware WDT for 1.6ms
6+
* Disable Hardware WDT Level-1 interrupt option
7+
* wait, ...
8+
9+
Inspired by RTOS SDK hardware_restart in panic.c
10+
*/
11+
12+
#include "Arduino.h"
13+
#include <user_interface.h>
14+
#include <ets_sys.h>
15+
#include "hardware_reset.h"
16+
17+
18+
// Extracted from RTOS_SDK eagle_soc.h
19+
/*
20+
* ESPRSSIF MIT License
21+
*
22+
* Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
23+
*
24+
* Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
25+
* it is free of charge, to any person obtaining a copy of this software and associated
26+
* documentation files (the "Software"), to deal in the Software without restriction, including
27+
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
28+
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
29+
* to do so, subject to the following conditions:
30+
*
31+
* The above copyright notice and this permission notice shall be included in all copies or
32+
* substantial portions of the Software.
33+
*
34+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
36+
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
37+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
38+
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
39+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40+
*
41+
*/
42+
#define REG_WRITE(_r, _v) (*(volatile uint32_t *)(_r)) = (_v)
43+
#define REG_READ(_r) (*(volatile uint32_t *)(_r))
44+
45+
//Watchdog reg {{
46+
#define PERIPHS_WDT_BASEADDR 0x60000900
47+
48+
#define WDT_CTL_ADDRESS 0
49+
#define WDT_OP_ADDRESS 0x4
50+
#define WDT_OP_ND_ADDRESS 0x8
51+
#define WDT_RST_ADDRESS 0x14
52+
53+
#define WDT_CTL_RSTLEN_MASK 0x38
54+
#define WDT_CTL_RSPMOD_MASK 0x6
55+
#define WDT_CTL_EN_MASK 0x1
56+
57+
#define WDT_CTL_RSTLEN_LSB 0x3
58+
#define WDT_CTL_RSPMOD_LSB 0x1
59+
#define WDT_CTL_EN_LSB 0
60+
61+
#define WDT_FEED_VALUE 0x73
62+
63+
#define WDT_REG_READ(_reg) REG_READ(PERIPHS_WDT_BASEADDR + _reg)
64+
#define WDT_REG_WRITE(_reg, _val) REG_WRITE(PERIPHS_WDT_BASEADDR + _reg, _val)
65+
#define CLEAR_WDT_REG_MASK(_reg, _mask) WDT_REG_WRITE(_reg, WDT_REG_READ(_reg) & (~_mask))
66+
#define SET_WDT_REG_MASK(_reg, _mask, _val) SET_PERI_REG_BITS((PERIPHS_WDT_BASEADDR + _reg), _mask, _val, 0)
67+
#undef WDT_FEED
68+
#define WDT_FEED() WDT_REG_WRITE(WDT_RST_ADDRESS, WDT_FEED_VALUE)
69+
//}}
70+
71+
// Inspired by RTOS SDK task_wdt.c and hardware_restart in panic.c
72+
73+
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
74+
//
75+
// Licensed under the Apache License, Version 2.0 (the "License");
76+
// you may not use this file except in compliance with the License.
77+
// You may obtain a copy of the License at
78+
//
79+
// http://www.apache.org/licenses/LICENSE-2.0
80+
//
81+
// Unless required by applicable law or agreed to in writing, software
82+
// distributed under the License is distributed on an "AS IS" BASIS,
83+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
84+
// See the License for the specific language governing permissions and
85+
// limitations under the License.
86+
87+
extern "C" {
88+
void hardware_reset(void) {
89+
volatile uint32_t* const rtc_mem = (volatile uint32_t *)0x60001100u;
90+
91+
// Block NMI or Software WDT from disturbing out restart reason
92+
xt_rsil(15);
93+
94+
// An HWDT reason would imply a fault or bug, but this reset was requested.
95+
// Set hint reason to EXT_RST. From empirical evidence, an HWDT looks a lot
96+
// like an EXT_RST. The WDT registers are reset to zero like an EXT_RST;
97+
// however, the PLL initialization is still set. We can still read the Boot
98+
// ROM serial output messages.
99+
// SDK restart reason/hint location
100+
rtc_mem[0] = REASON_EXT_SYS_RST;
101+
102+
// Disable WDT
103+
CLEAR_WDT_REG_MASK(WDT_CTL_ADDRESS, WDT_CTL_EN_MASK);
104+
105+
// Set Reset pulse to maximum
106+
// Select Reset only - no level-1 interrupt
107+
SET_WDT_REG_MASK(WDT_CTL_ADDRESS,
108+
WDT_CTL_RSTLEN_MASK | WDT_CTL_RSPMOD_MASK,
109+
(7 << WDT_CTL_RSTLEN_LSB) | (2 << WDT_CTL_RSPMOD_LSB));
110+
111+
// Set WDT Reset timer to 1.6 ms.
112+
WDT_REG_WRITE(WDT_OP_ADDRESS, 1); // 2^n * 0.8ms, mask 0xf, n = 1 -> (2^1 = 2) * 0.8 * 0.001 = 0.0016
113+
114+
// Enable WDT
115+
SET_WDT_REG_MASK(WDT_CTL_ADDRESS, WDT_CTL_EN_MASK, 1 << WDT_CTL_EN_LSB);
116+
117+
while (true);
118+
}
119+
};

cores/esp8266/hardware_reset.h

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#ifndef HARDWARE_RESET_H
2+
#define HARDWARE_RESET_H
3+
4+
#ifdef __cplusplus
5+
extern "C" {
6+
#endif
7+
8+
void hardware_reset(void) __attribute__((noreturn));
9+
10+
#ifdef __cplusplus
11+
}
12+
#endif
13+
14+
#endif

0 commit comments

Comments
 (0)