rtc craziness

This commit is contained in:
Thaddeus Hughes
2026-03-11 09:01:32 -05:00
parent e2451fce78
commit f4077e5e26
40 changed files with 45559 additions and 131 deletions

View File

@@ -0,0 +1,18 @@
{
"permissions": {
"allow": [
"Bash(python:*)",
"Bash(idf.py build:*)",
"Read(//c/Users/Thad/.espressif//**)",
"Read(//c/Espressif//**)",
"Bash(find /c/Espressif/frameworks -maxdepth 6 -name \"rtc.h\" -path \"*/soc/*\" 2>/dev/null | head -5)",
"Bash(grep -rl \"rtc_clk_cal\" /c/Espressif/frameworks/esp-idf-v5.3.1/components/ --include=\"*.h\" 2>/dev/null | head -10)",
"Bash(cat C:/data/stockcropper-sw/SC-F001/logtool/rtc_analysis_20260310_144044.txt 2>/dev/null || ls C:/data/stockcropper-sw/SC-F001/logtool/rtc_analysis_20260310_144044*.txt 2>/dev/null)",
"Read(//mnt/c/Users/Thad/**)",
"Bash(grep -r \"esp_bt\" C:/data/stockcropper-sw/SC-F001/build/esp-idf/bt/ --include=\"*.cmake\" -l 2>/dev/null | head -5)",
"Bash(grep -r \"esp_bt.h\" C:/data/stockcropper-sw/SC-F001/build/ --include=\"*.cmake\" 2>/dev/null | head -5)",
"WebFetch(domain:docs.espressif.com)",
"Bash(curl -s \"https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/peripherals/clk_tree.html\" | sed 's/<script[^>]*>.*<\\\\/script>//g; s/<style[^>]*>.*<\\\\/style>//g; s/<[^>]*>//g; s/&amp;/\\\\&/g; s/&lt;/</g; s/&gt;/>/g; s/&nbsp;/ /g; s/&quot;/\"/g; s/&#39;/'\"'\"'/g' | tr -s ' \\\\n' | grep -v '^[[:space:]]*$' 2>&1 | head -2000)"
]
}
}

View File

@@ -23,7 +23,7 @@ The SC-F001 is a **solar-powered automated crop harvesting robot** built on the
| 25 | 433MHz RF receiver (RMT input) | | 25 | 433MHz RF receiver (RMT input) |
| 26 | Solar charger bulk enable (RTC GPIO, holds across deep sleep) | | 26 | Solar charger bulk enable (RTC GPIO, holds across deep sleep) |
| 27 | Safety sensor (active low) | | 27 | Safety sensor (active low) |
| 32/33 | External 32kHz RTC crystal | | 32/33 | External 32.768 kHz RTC crystal (standard watch crystal, 2¹⁵ Hz) |
| 36 (VP) | ADC: drive current sense | | 36 (VP) | ADC: drive current sense |
| 39 (VN) | ADC: battery voltage | | 39 (VN) | ADC: battery voltage |
| 34 | ADC: jack current sense | | 34 | ADC: jack current sense |
@@ -222,6 +222,24 @@ Safety break → immediate `STATE_UNDO_JACK_START`.
--- ---
## RTC & 32.768 kHz Crystal
**Crystal:** Standard 32.768 kHz (32768 Hz = 2¹⁵ Hz) tuning-fork watch crystal on GPIO32/GPIO33. This frequency is universal for RTCs because it divides to exactly 1 Hz with a 15-bit binary counter.
**sdkconfig.defaults settings:**
- `CONFIG_RTC_CLK_SRC_EXT_CRYS=y` — selects the external crystal as the RTC slow clock source instead of the internal ~150 kHz RC oscillator
- `CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT_V2=y` — enables extra drive current during the crystal startup window; required for high-ESR tuning-fork crystals (e.g. CM315D32768DZFT ~70 kΩ ESR)
**Known startup failure mode:** On power-on, the ESP32 bootloader attempts to calibrate the crystal. If it fails to detect oscillation within its calibration window, it logs `W: 32 kHz XTAL not found, switching to internal 150 kHz oscillator` and falls back to the RC oscillator. The RC oscillator has ±5% accuracy, producing up to ~180 s/hr of RTC drift — this completely breaks harvest scheduling.
**Firmware mitigation (`rtc_xtal_init()` in `rtc.c`):** If `rtc_clk_slow_src_get()` does not return `SOC_RTC_SLOW_CLK_SRC_XTAL32K` at startup, the code applies a manual bootstrap: `rtc_clk_32k_bootstrap(20000)` (~600 ms of extra drive current at 32 kHz cycles), waits 500 ms for oscillation to stabilise, then calls `rtc_clk_slow_src_set(SOC_RTC_SLOW_CLK_SRC_XTAL32K)` to switch explicitly. Success or failure is logged via `ESP_LOGI/LOGE`.
**Diagnosing crystal issues:** Run `RTCDEBUG` over UART and check `slow_clk_src`. It reports either `XTAL32K (OK)` or `NOT XTAL32K — check crystal!`. The `logtool/rtc_test.py` script automates this and runs multi-cycle drift tests.
**Time persistence across deep sleep:** `rtc_backup_s` and `rtc_sleep_entry_s` are `RTC_DATA_ATTR` (survive deep sleep). On wakeup, `rtc_restore_time()` adds exactly `DEEP_SLEEP_US / 1e6` seconds to `rtc_sleep_entry_s` to reconstruct the correct time without an NTP sync.
---
## Power Management ## Power Management
- **Battery voltage:** GPIO39, divider → `V = raw × 0.00767 + 0.4` - **Battery voltage:** GPIO39, divider → `V = raw × 0.00767 + 0.4`

BIN
logtool/04MAR2026_1505.bin Normal file

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,4 @@
requests requests
matplotlib matplotlib
tabulate tabulate
pyserial

View File

@@ -0,0 +1,45 @@
Raw serial log : logtool/rtc_raw_20260310_132756.txt
Analysis log : logtool/rtc_analysis_20260310_132756.txt
[1] Opening COM3 at 115200 baud and resetting board...
EN pulsed. Waiting for boot... Boot complete.
[SYNC] Setting device RTC to host time 1773167278 (2026-03-10 18:27:58 UTC)...
OK
[BASE] Baseline RTCDEBUG:
device_time : 1773167278 (2026-03-10 18:27:58 UTC)
host_time : 1773167279 (2026-03-10 18:27:59 UTC)
slow_clk_src : NOT XTAL32K — check crystal!
crystal_ok : True
[sleep] Sending sleep command...
[wait] 135s until wakeup (cycle 1/1, ETA 13:28:02 + 135s) 135s 130s 125s 120s 115s 110s 105s 100s 95s 90s 85s 80s 75s 70s 65s 60s 55s 50s 45s 40s 35s 30s 25s 20s 15s 10s 5s
[wake] Reconnecting to COM3...
Prompt not seen — forcing board reset...
[POST] Post-sleep RTCDEBUG:
device_time : 3 (1970-01-01 00:00:03 UTC)
host_time : 1773167436 (2026-03-10 18:30:36 UTC)
slow_clk_src : NOT XTAL32K — check crystal!
sleep_add : 0s
reset_reason : POWER_ON
Cycle Host time (UTC) Device time (UTC) CycDrift CumDrift Rate s/hr XTAL Notes
----- ------------------- ------------------- -------- -------- ---------- ------ -----
1 2026-03-10 18:30:36 1970-01-01 00:00:03 -1773167432s -1773167432s -40658616275.2 OK
=== RESULT ===
host elapsed : 157s
device elapsed: -1773167275s
drift : -1773167432s
[FAIL] Clock accuracy (-1773167432s (tolerance +/-5s))
[FAIL] reset_reason == DEEP_SLEEP (POWER_ON)
[FAIL] sleep_add == 120s (0s)
[PASS] 32kHz crystal running (NOT XTAL32K — check crystal!)
[FAIL] rtc_set == true (false)
Overall: FAIL

View File

@@ -0,0 +1,49 @@
Raw serial log : logtool/rtc_raw_20260310_133445.txt
Analysis log : logtool/rtc_analysis_20260310_133445.txt
[1] Opening COM3 at 115200 baud and resetting board...
EN pulsed. Waiting for boot prompt... OK
[SYNC] Setting device RTC to 1773167687 (2026-03-10 18:34:47 UTC)...
OK
[BASE] Baseline RTCDEBUG:
device_time : 1773167687 (2026-03-10 18:34:47 UTC)
host_time : 1773167688 (2026-03-10 18:34:48 UTC)
slow_clk_src : NOT XTAL32K — check crystal!
crystal_ok : False
clock_offset : 1773167686s (device_time - uptime)
[sleep] Sending sleep command at 13:34:48.234...
[wait] 130s (cycle 1/1, countdown from 13:34:53) 130s 125s 120s 115s 110s 105s 100s 95s 90s 85s 80s 75s 70s 65s 60s 55s 50s 45s 40s 35s 30s 25s 20s 15s 10s 5s
[wake] Listening for boot prompt (up to 30s)...
No prompt -- closing and reopening port (explicit DTR/RTS control)...
Connected (NOTE: port was reopened -- reset_reason may be POWER_ON)
[POST] Post-sleep RTCDEBUG:
device_time : 0 (N/A UTC)
host_time : 1773167856 (2026-03-10 18:37:36 UTC)
slow_clk_src : ?
sleep_add : 0s
reset_reason : POWER_ON
clock_offset : 0s
Cycle Host time (UTC) Device time (UTC) CycDrift CumDrift Rate s/hr XTAL Notes
----- ------------------- ------------------- --------- --------- ---------- ------- -----
1 2026-03-10 18:37:36 N/A -1773167855s -1773167855s -37996454035.7 OK
=== RESULT ===
host elapsed : 168s
device elapsed : -1773167687s
drift : -1773167855s
[FAIL] Clock accuracy (-1773167855s (tolerance +/-5s))
[FAIL] reset_reason == DEEP_SLEEP (POWER_ON)
[FAIL] sleep_add == 120s (0s)
[PASS] 32kHz crystal running
[FAIL] rtc_set == true (false)
Overall: FAIL

View File

@@ -0,0 +1,43 @@
Raw serial log : logtool/rtc_raw_20260310_134529.txt
Analysis log : logtool/rtc_analysis_20260310_134529.txt
[1] Opening COM3 at 115200 baud and resetting board...
EN pulsed. Waiting for boot prompt... OK
Multi-cycle mode: 30 cycles x 120s = ~60 min
[INIT] Syncing device RTC to 1773168335 (2026-03-10 18:45:35 UTC)...
OK
[INIT] Baseline RTCDEBUG:
device_t0 : 1773168335 (2026-03-10 18:45:35 UTC)
host_t0 : 1773168336 (2026-03-10 18:45:36 UTC)
slow_clk_src : XTAL32K (OK)
crystal_ok : True
clock_offset : 1773168331s (should stay near-constant if clock tracks correctly)
Starting 30 cycles x ~175s = ~87 min
ETA: 13:45 + 87m (finish ~15:13)
Clock will NOT be re-synced -- drift accumulates intentionally.
Cycle Host time (UTC) Device time (UTC) CycDrift CumDrift Rate s/hr XTAL Notes
----- ------------------- ------------------- --------- --------- ---------- ------- -----
[sleep] Sending sleep command at 13:45:36.371...
[wait] 105s countdown (cycle 1/30, from 13:45:41, device wakes ~15s after countdown ends) 105s 100s 95s 90s 85s 80s 75s 70s 65s 60s 55s 50s 45s 40s 35s 30s 25s 20s 15s 10s 5s
[wake] Listening for boot prompt (up to 55s)...
No prompt after wait -- performing controlled board reset (port stays open)...
NOTE: reset_reason will be POWER_ON for this cycle, not DEEP_SLEEP.
1 2026-03-10 18:48:24 1970-01-01 00:00:01 -1773168502s -1773168502s -37996467900.0 OK reason=POWER_ON offset_chg=-1773168331s
[sleep] Sending sleep command at 13:48:24.581...
[wait] 105s countdown (cycle 2/30, from 13:48:29, device wakes ~15s after countdown ends) 105s 100s 95s 90s 85s 80s 75s 70s 65s 60s 55s 50s 45s 40s 35s 30s 25s 20s 15s 10s 5s
[wake] Listening for boot prompt (up to 55s)...
No prompt after wait -- performing controlled board reset (port stays open)...
NOTE: reset_reason will be POWER_ON for this cycle, not DEEP_SLEEP.
WARNING: RTCDEBUG parse failed on cycle 2 -- skipping
[sleep] Sending sleep command at 13:51:14.819...
[wait] 105s countdown (cycle 3/30, from 13:51:19, device wakes ~15s after countdown ends) 105s 100s 95s 90s 85s 80s 75s

View File

@@ -0,0 +1,21 @@
Raw log : logtool/rtc_raw_20260310_135504.txt
Analysis log : logtool/rtc_analysis_20260310_135504.txt
Port : COM3 115200 baud
Ctrl+C to stop.
[13:55:04.538] Resetting board...
[13:55:07.288] Boot complete.
[13:55:07.288] Syncing device RTC to host: 1773168907 (2026-03-10 18:55:07 UTC)...
[13:55:07.615] Sync OK.
# Wall clock (host) Device time (UTC) Diff Source Uptime
-- ------------------- ------------------- ------ -------- ------
Streaming... (device will sleep after 180s inactivity, wake every 120s)
[14:04:29.495] Stopped by user.
No TIME events captured.

View File

@@ -0,0 +1,31 @@
Raw log : logtool/rtc_raw_20260310_144044.txt
Analysis log : logtool/rtc_analysis_20260310_144044.txt
Port : COM3 115200 baud
Ctrl+C to stop.
[14:40:44.532] Resetting board...
[14:40:47.184] Boot complete.
[14:40:47.184] Syncing device RTC to host: 1773171647 (2026-03-10 19:40:47 UTC)...
[14:40:47.514] Sync OK.
# Wall clock (host) Device time (UTC) Diff Source Uptime
-- ------------------- ------------------- ------ -------- ------
Streaming... (device will sleep after 180s inactivity, wake every 120s)
1 2026-03-10 19:41:49 2026-03-10 19:43:44 +115s SLEEP 1s
2 2026-03-10 19:43:07 2026-03-10 19:46:57 +230s SLEEP 1s
3 2026-03-10 19:43:23 2026-03-10 19:49:10 +347s SLEEP 1s
4 2026-03-10 19:44:00 2026-03-10 19:51:41 +461s SLEEP 1s
5 2026-03-10 19:50:42 2026-03-10 20:00:17 +575s SLEEP 1s
6 2026-03-10 19:56:44 2026-03-10 20:06:19 +575s SLEEP 1s
7 2026-03-10 19:58:45 2026-03-10 20:08:19 +574s SLEEP 1s
8 2026-03-10 20:00:47 2026-03-10 20:10:19 +572s SLEEP 1s
9 2026-03-10 20:02:48 2026-03-10 20:12:19 +571s SLEEP 1s
10 2026-03-10 20:08:19 2026-03-10 20:17:50 +571s SLEEP 1s
[15:10:04.323] Stopped by user.
10 event(s) logged to logtool/rtc_analysis_20260310_144044.txt

View File

@@ -0,0 +1,24 @@
Raw log : logtool/rtc_raw_20260310_154958.txt
Analysis log : logtool/rtc_analysis_20260310_154958.txt
Port : COM3 115200 baud
Ctrl+C to stop.
[15:49:58.745] Resetting board...
[15:50:01.425] Boot complete.
[15:50:01.426] Syncing device RTC to host: 1773175801 (2026-03-10 20:50:01 UTC)...
[15:50:01.756] Sync OK.
# Wall clock (host) Device time (UTC) Diff Source Uptime
-- ------------------- ------------------- ------ -------- ------
Streaming... (device will sleep after 180s inactivity, wake every 120s)
1 2026-03-10 20:50:36 2026-03-10 20:50:35 -1s SLEEP 1s
2 2026-03-10 20:50:50 2026-03-10 20:50:49 -1s SLEEP 1s
3 2026-03-10 21:08:36 2026-03-10 21:08:30 -6s SLEEP 1s
[16:10:53.545] Stopped by user.
3 event(s) logged to logtool/rtc_analysis_20260310_154958.txt

View File

@@ -0,0 +1,17 @@
Raw log : logtool/rtc_raw_20260310_161314.txt
Analysis log : logtool/rtc_analysis_20260310_161314.txt
Port : COM3 115200 baud
Ctrl+C to stop.
[16:13:14.819] Resetting board...
[16:13:17.490] Boot complete.
[16:13:17.491] Syncing device RTC to host: 1773177197 (2026-03-10 21:13:17 UTC)...
[16:13:17.779] Sync OK.
# Wall clock (host) Device time (UTC) Diff Source Uptime
-- ------------------- ------------------- ------ -------- ------
Streaming... (device will sleep after 180s inactivity, wake every 120s)

View File

@@ -0,0 +1,21 @@
Raw log : logtool/rtc_raw_20260310_162229.txt
Analysis log : logtool/rtc_analysis_20260310_162229.txt
Port : COM3 115200 baud
Ctrl+C to stop.
[16:22:29.657] Resetting board...
[16:22:32.317] Boot complete.
[16:22:32.318] Syncing device RTC to host: 1773177752 (2026-03-10 21:22:32 UTC)...
[16:22:32.647] Sync OK.
# Wall clock (host) Device time (UTC) Diff Source Uptime
-- ------------------- ------------------- ------ -------- ------
Streaming... (device will sleep after 180s inactivity, wake every 120s)
[16:23:07.577] Stopped by user.
No TIME events captured.

View File

@@ -0,0 +1,5 @@
Raw log : logtool/rtc_raw_20260311_085444.txt
Analysis log : logtool/rtc_analysis_20260311_085444.txt
Port : COM3 115200 baud
Ctrl+C to stop.

View File

@@ -0,0 +1,2 @@
cycle,host_ts,host_utc,device_ts,device_utc,cycle_host_elapsed,cycle_device_elapsed,cycle_drift,cumulative_drift,drift_rate_s_per_hr,clock_offset,clock_offset_delta,sleep_add,reset_reason,slow_clk_src
1,1773168504,2026-03-10 18:48:24,1,1970-01-01 00:00:01,168,-1773168334,-1773168502,-1773168502,-37996467900.00,0,-1773168331,0,POWER_ON,XTAL32K (OK)
1 cycle host_ts host_utc device_ts device_utc cycle_host_elapsed cycle_device_elapsed cycle_drift cumulative_drift drift_rate_s_per_hr clock_offset clock_offset_delta sleep_add reset_reason slow_clk_src
2 1 1773168504 2026-03-10 18:48:24 1 1970-01-01 00:00:01 168 -1773168334 -1773168502 -1773168502 -37996467900.00 0 -1773168331 0 POWER_ON XTAL32K (OK)

358
logtool/rtc_drift_run.txt Normal file
View File

@@ -0,0 +1,358 @@
[1] Opening COM3 at 115200 baud and resetting board...
EN pulsed. Waiting for boot output...
ets Jul 29 2019 12:21:46
rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:7176
load:0x40078000,len:16092
ho 0 tail 12 room 4
load:0x40080400,len:4
load:0x40080404,len:3912
entry 0x40080640
I (31) boot: ESP-IDF v5.3.1-dirty 2nd stage bootloader
I (31) boot: compile time Mar 4 2026 13:08:05
I (31) boot: Multicore bootloader
I (36) boot: chip revision: v3.1
I (40) boot.esp32: SPI Speed : 40MHz
I (44) boot.esp32: SPI Mode : DIO
I (49) boot.esp32: SPI Flash Size : 8MB
I (53) boot: Enabling RNG early entropy source...
I (59) boot: Partition Table:
I (62) boot: ## Label Usage Type ST Offset Length
I (70) boot: 0 nvs WiFi data 01 02 00009000 00004000
I (77) boot: 1 otadata OTA data 01 00 0000d000 00002000
I (84) boot: 2 phy_init RF data 01 01 0000f000 00001000
I (92) boot: 3 ota_0 OTA app 00 10 00010000 00180000
I (99) boot: 4 ota_1 OTA app 00 11 00190000 00180000
I (107) boot: 5 storage Unknown data 01 40 00310000 00020000
I (114) boot: End of partition table
I (119) esp_image: segment 0: paddr=00010020 vaddr=3f400020 size=409d0h (264656) map
I (218) esp_image: segment 1: paddr=000509f8 vaddr=3ff80063 size=00008h ( 8) load
I (218) esp_image: segment 2: paddr=00050a08 vaddr=3ffbdb60 size=0648ch ( 25740) load
I (233) esp_image: segment 3: paddr=00056e9c vaddr=40080000 size=0917ch ( 37244) load
I (248) esp_image: segment 4: paddr=00060020 vaddr=400d0020 size=ffbf0h (1047536) map
I (607) esp_image: segment 5: paddr=0015fc18 vaddr=4008917c size=11f50h ( 73552) load
I (636) esp_image: segment 6: paddr=00171b70 vaddr=400c0000 size=00064h ( 100) load
I (637) esp_image: segment 7: paddr=00171bdc vaddr=50000000 size=0004ch ( 76) load
I (656) boot: Loaded app from partition at offset 0x10000
I (656) boot: Disabling RNG early entropy source...
I (668) cpu_start: Multicore app
W (830) clk: 32 kHz XTAL not found, switching to internal 150 kHz oscillator
I (838) cpu_start: Pro cpu start user code
I (838) cpu_start: cpu freq: 160000000 Hz
I (839) app_init: Application information:
I (843) app_init: Project name: SC-F001
I (848) app_init: App version: e2451fc-dirty
I (853) app_init: Compile time: Mar 5 2026 16:20:24
I (859) app_init: ELF file SHA256: 3aee52b89...
I (865) app_init: ESP-IDF: v5.3.1-dirty
I (870) efuse_init: Min chip rev: v0.0
I (875) efuse_init: Max chip rev: v3.99 
I (880) efuse_init: Chip rev: v3.1
I (885) heap_init: Initializing. RAM available for dynamic allocation:
I (892) heap_init: At 3FFAFF10 len 000000F0 (0 KiB): DRAM
I (898) heap_init: At 3FFB6388 len 00001C78 (7 KiB): DRAM
I (904) heap_init: At 3FFB9A20 len 00004108 (16 KiB): DRAM
I (910) heap_init: At 3FFCDD48 len 000122B8 (72 KiB): DRAM
I (916) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (922) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (929) heap_init: At 4009B0CC len 00004F34 (19 KiB): IRAM
I (937) spi_flash: detected chip: generic
I (940) spi_flash: flash io: dio
W (944) i2c: This driver is an old driver, please migrate your application code to adapt `driver/i2c_master.h`
I (955) coexist: coex firmware version: 4482466
I (960) main_task: Started on CPU0
I (970) main_task: Calling app_main()
W (970) RTC: Slow clock source is 0 — expected XTAL32K (1). Check sdkconfig.
I (970) RTC: Wakeup: normal boot
I (980) MAIN: Firmware: V_e2451fc-dirty (2026-03-05 22:20:22)
I (980) MAIN: Version: e2451fc-dirty
I (990) MAIN: Branch: main
I (990) MAIN: Built: 2026-03-05 22:20:22
I (990) STORAGE: Initializing storage system...
I (1000) STORAGE: Storage partition found: size=131072 bytes
I (1010) STORAGE: Log init: scanning 28 sectors with bisection
I (1030) STORAGE: Log system initialized (bisection). Head: 131072, Tail: 16384
I (1030) STORAGE: Log writer task started
I (1030) STORAGE: Log wr
========================================
UART JSON Interface Ready
========================================
Type 'HELP' for available commands
Type 'GET' to see system status
> I (1050) UART: UART interface started
I (1050) gpio: GPIO[25]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 
I (1060) RF: RF receiver task started on core 0
I (1070) BTDM_INIT: BT controller compile version [b022216]
I (1070) BTDM_INIT: Bluetooth MAC: 94:54:c5:38:c4:3a
I (1080) phy_init: phy_version 4830,54550f7,Jun 20 2024,14:22:08
E (1090) phy_init: esp_phy_load_cal_data_from_nvs: NVS has not been initialized. Call nvs_flash_init before starting WiFi/BT.
W (1100) phy_init: failed to load RF calibration data (0x1101), falling back to full calibration
W (1170) phy_init: saving new calibration data because of checksum failure, mode(2)
E (1410) BT_OSI: config_new: NVS not initialized. Call nvs_flash_init before initializing bluetooth.
W (1410) BT_BTC: btc_config_init unable to load config file; starting unconfigured.

E (1410) BT_OSI: config_save: NVS not initialized. Call nvs_flash_init before initializing bluetooth.
E (1420) BT_OSI: config_save, err_code: 0x2

E (1480) BT_APPL: bta_gattc_co_cache_addr_init, Line = 436, nvs flash open fail, err_code = 1101
E (1500) BT_OSI: config_save: NVS not initialized. Call nvs_flash_init before initializing bluetooth.
E (1500) BT_OSI: config_save, err_code: 0x2

E (1510) BT_OSI: config_save: NVS not initialized. Call nvs_flash_init before initializing bluetooth.
E (1520) BT_OSI: config_save, err_code: 0x2

E (1520) BT_OSI: config_save: NVS not initialized. Call nvs_flash_init before initializing bluetooth.
E (1530) BT_OSI: config_save, err_code: 0x2

E (1540) BT_OSI: config_save: NVS not initialized. Call nvs_flash_init before initializing bluetooth.
E (1550) BT_OSI: config_save, err_code: 0x2

I (1560) BT_HID: Scanning for HID devices (3s)...
I (1560) BT_HID: BLE HID host initialised
I (1560) gpio: GPIO[14]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:3 
I (1570) WEBSERVER: Initializing webserver...
I (1570) gpio: GPIO[27]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:3 
I (1590) WEBSERVER: AP LAUNCHING
I (1610) WEBSERVER: AP LAUNCHING...
I (1610) WEBSERVER: HI THERE
I (1630) wifi:wifi driver task: 3ffe2808, prio:23, stack:6656, core=0
I (1640) wifi:wifi firmware version: ccaebfa
I (1640) wifi:wifi certification version: v7.0
I (1640) wifi:config NVS flash: enabled
I (1640) wifi:config nano formating: disabled
I (1640) wifi:Init data frame dynamic rx buffer num: 32
I (1650) wifi:Init static rx mgmt buffer num: 5
I (1650) wifi:Init management short buffer num: 32
I (1650) wifi:Init dynamic tx buffer num: 32
I (1660) wifi:Init static rx buffer size: 1600
I (1660) wifi:Init static rx buffer num: 10
I (1670) wifi:Init dynamic rx buffer num: 32
I (1680) wifi_init: rx ba win: 6
I (1680) wifi_init: accept mbox: 6
I (1680) wifi_init: tcpip mbox: 32
I (1680) wifi_init: udp mbox: 6
I (1690) wifi_init: tcp mbox: 6
I (1690) wifi_init: tcp tx win: 5760
I (1690) wifi_init: tcp rx win: 5760
I (1700) wifi_init: tcp mss: 1440
I (1710) wifi:mode : softAP (94:54:c5:38:c4:39)
I (1720) wifi:Total power save buffer number: 16
I (1720) wifi:Init max length of beacon: 752/752
I (1720) wifi:Init max length of beacon: 752/752
I (1730) esp_netif_lwip: DHCP server started on interface WIFI_AP_DEF with IP: 192.168.4.1
I (1730) DNS_SERVER: DNS server started on port 53
I (1740) mdns_mem: mDNS task will be created from internal RAM
I (1740) WEBSERVER: SoftAP ready. SSID: sc.local, Channel: 6, Password: password
I (1760) WEBSERVER: Access at: http://sc.local or http://sc.local.local or http://192.168.4.1
I (1760) WEBSERVER: AP LAUNCHED
I (1760) WEBSERVER: STARTING HTTP
I (1770) WEBSERVER: HTTP server started successfully
I (1770) WEBSERVER: Registered URI handler: /
I (1780) WEBSERVER: Registered URI handler: /get
I (1780) WEBSERVER: Registered URI handler: /post
I (1790) WEBSERVER: Registered URI handler: /log
I (1790) WEBSERVER: Registered URI handler: /ota
I (1800) WEBSERVER: Registered URI handler: /*
I (1800) WEBSERVER: Webserver initialization complete
E rmt: hw buffer too small, received symbols truncated
E rmt: hw buffer too small, received symbols truncated
I (2110) wifi:new:<6,1>, old:<6,1>, ap:<6,1>, sta:<255,255>, prof:6, snd_ch_cfg:0x0
I (2110) wifi:station: 84:5c:f3:b4:49:ed join, AID=1, bgn, 40U
E rmt: hw buffer too small, received symbols truncated
I (2170) WEBSERVER: Station connected, AID=1
I (2210) esp_netif_lwip: DHCP server assigned IP to a client, IP is: 192.168.4.2
I (2670) wifi:<ba-add>idx:2 (ifx:1, 84:5c:f3:b4:49:ed), tid:0, ssn:23, winSize:64
E rmt: hw buffer too small, received symbols truncated
>
> W (3320) httpd_txrx: httpd_resp_send_err: 404 Not Found - Nothing matches the given URI
W (3420) httpd_txrx: httpd_resp_send_err: 404 Not Found - Nothing matches the given URI
E rmt: hw buffer too small, received symbols truncated

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,369 @@
[13:34:45.721 RX] ets Jul 29 2019 12:21:46
[13:34:45.721 RX]
[13:34:45.721 RX] rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
[13:34:45.721 RX] configsip: 0, SPIWP:0xee
[13:34:45.721 RX] clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
[13:34:45.721 RX] mode:DIO, clock div:2
[13:34:45.721 RX] load:0x3fff0030,len:7176
[13:34:45.721 RX] load:0x40078000,len:160
[13:34:45.771 RX] 92
[13:34:45.771 RX] ho 0 tail 12 room 4
[13:34:45.771 RX] load:0x40080400,len:4
[13:34:45.771 RX] load:0x40080404,len:3912
[13:34:45.771 RX] entry 0x40080640
[13:34:45.771 RX] I (31) boot: ESP-IDF v5.3.1-dirty 2nd stage bootloader
[13:34:45.771 RX] I (31) boot: compile time Mar 4 2026 13:08:05
[13:34:45.771 RX] I (31) boot: Multicore bootload
[13:34:45.822 RX] er
[13:34:45.822 RX] I (36) boot: chip revision: v3.1
[13:34:45.822 RX] I (40) boot.esp32: SPI Speed : 40MHz
[13:34:45.822 RX] I (44) boot.esp32: SPI Mode : DIO
[13:34:45.822 RX] I (49) boot.esp32: SPI Flash Size : 8MB
[13:34:45.822 RX] I (53) boot: Enabling RNG early entrop
[13:34:45.872 RX] y source...
[13:34:45.872 RX] I (59) boot: Partition Table:
[13:34:45.872 RX] I (62) boot: ## Label Usage Type ST Offset Length
[13:34:45.872 RX] I (70) boot: 0 nvs WiFi data 01 02 00009000 00004000
[13:34:45.872 RX] I (77) boot: 1 otad
[13:34:45.923 RX] ata OTA data 01 00 0000d000 00002000
[13:34:45.923 RX] I (84) boot: 2 phy_init RF data 01 01 0000f000 00001000
[13:34:45.923 RX] I (92) boot: 3 ota_0 OTA app 00 10 00010000 00180000
[13:34:45.923 RX] I (99) boot: 4 ot
[13:34:45.973 RX] a_1 OTA app 00 11 00190000 00180000
[13:34:45.973 RX] I (107) boot: 5 storage Unknown data 01 40 00310000 00020000
[13:34:45.973 RX] I (114) boot: End of partition table
[13:34:45.973 RX] I (119) esp_image: segment 0: paddr=00010020 vaddr=3
[13:34:46.024 RX] f400020 size=409d0h (264656) map
[13:34:46.024 RX] I (218) esp_image: segment 1: paddr=000509f8 vaddr=3ff80063 size=00008h ( 8) load
[13:34:46.024 RX] I (218) esp_image: segment 2: paddr=00050a08 vaddr=3ffbdb60 size=0648ch ( 25740) load
[13:34:46.024 RX] I (233) esp_ima
[13:34:46.286 RX] ge: segment 3: paddr=00056e9c vaddr=40080000 size=0917ch ( 37244) load
[13:34:46.286 RX] I (248) esp_image: segment 4: paddr=00060020 vaddr=400d0020 size=ffbf0h (1047536) map
[13:34:46.286 RX] I (607) esp_image: segment 5: paddr=0015fc18 vaddr=4008
[13:34:46.336 RX] 917c size=11f50h ( 73552) load
[13:34:46.337 RX] I (636) esp_image: segment 6: paddr=00171b70 vaddr=400c0000 size=00064h ( 100) load
[13:34:46.337 RX] I (637) esp_image: segment 7: paddr=00171bdc vaddr=50000000 size=0004ch ( 76) load
[13:34:46.337 RX] I (656) boot: Loa
[13:34:46.517 RX] ded app from partition at offset 0x10000
[13:34:46.517 RX] I (656) boot: Disabling RNG early entropy source...
[13:34:46.517 RX] I (668) cpu_start: Multicore app
[13:34:46.517 RX] W (830) clk: 32 kHz XTAL not found, switching to internal 150 kHz oscillator
[13:34:46.517 RX] I (83
[13:34:46.568 RX] 8) cpu_start: Pro cpu start user code
[13:34:46.568 RX] I (838) cpu_start: cpu freq: 160000000 Hz
[13:34:46.568 RX] I (838) app_init: Application information:
[13:34:46.568 RX] I (843) app_init: Project name: SC-F001
[13:34:46.568 RX] I (848) app_init: App version: e2451
[13:34:46.618 RX] fc-dirty
[13:34:46.618 RX] I (853) app_init: Compile time: Mar 5 2026 16:20:24
[13:34:46.618 RX] I (859) app_init: ELF file SHA256: 3aee52b89...
[13:34:46.618 RX] I (865) app_init: ESP-IDF: v5.3.1-dirty
[13:34:46.618 RX] I (870) efuse_init: Min chip rev: v0.0[
[13:34:46.668 RX] 0m
[13:34:46.668 RX] I (875) efuse_init: Max chip rev: v3.99
[13:34:46.668 RX] I (880) efuse_init: Chip rev: v3.1
[13:34:46.668 RX] I (885) heap_init: Initializing. RAM available for dynamic allocation:
[13:34:46.668 RX] I (892) heap_init: At 3FFAFF10 len 000000F0 (0 KiB
[13:34:46.718 RX] ): DRAM
[13:34:46.718 RX] I (898) heap_init: At 3FFB6388 len 00001C78 (7 KiB): DRAM
[13:34:46.718 RX] I (904) heap_init: At 3FFB9A20 len 00004108 (16 KiB): DRAM
[13:34:46.718 RX] I (910) heap_init: At 3FFCDD48 len 000122B8 (72 KiB): DRAM
[13:34:46.718 RX] I (916) heap_init: At 3F
[13:34:46.769 RX] FE0440 len 00003AE0 (14 KiB): D/IRAM
[13:34:46.769 RX] I (922) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
[13:34:46.769 RX] I (929) heap_init: At 4009B0CC len 00004F34 (19 KiB): IRAM
[13:34:46.769 RX] I (937) spi_flash: detected chip: generic
[13:34:46.769 RX] I (940)
[13:34:46.819 RX] spi_flash: flash io: dio
[13:34:46.819 RX] W (944) i2c: This driver is an old driver, please migrate your application code to adapt `driver/i2c_master.h`
[13:34:46.819 RX] I (955) coexist: coex firmware version: 4482466
[13:34:46.819 RX] I (960) main_task: Started on CPU0[
[13:34:46.869 RX] 0m
[13:34:46.869 RX] I (970) main_task: Calling app_main()
[13:34:46.869 RX] W (970) RTC: Slow clock source is 0 — expected XTAL32K (1). Check sdkconfig.
[13:34:46.869 RX] I (970) RTC: Wakeup: normal boot
[13:34:46.869 RX] I (980) MAIN: Firmware: V_e2451fc-dirty (2026-03-05 22:20:2
[13:34:46.920 RX] 2)
[13:34:46.920 RX] I (980) MAIN: Version: e2451fc-dirty
[13:34:46.920 RX] I (990) MAIN: Branch: main
[13:34:46.920 RX] I (990) MAIN: Built: 2026-03-05 22:20:22
[13:34:46.920 RX] I (990) STORAGE: Initializing storage system...
[13:34:46.920 RX] I (1000) STORAGE: Storage partition foun
[13:34:46.970 RX] d: size=131072 bytes
[13:34:46.970 RX] I (1010) STORAGE: Log init: scanning 28 sectors with bisection
[13:34:46.970 RX] I (1030) STORAGE: Log system initialized (bisection). Head: 131072, Tail: 16384
[13:34:46.970 RX] I (1030) STORAGE: Log writer task started
[13:34:46.970 RX] I
[13:34:47.021 RX] (1030) STORAGE: Log wr
[13:34:47.021 RX]
[13:34:47.021 RX] ========================================
[13:34:47.021 RX] UART JSON Interface Ready
[13:34:47.021 RX] ========================================
[13:34:47.021 RX] Type 'HELP' for available commands
[13:34:47.021 RX] Type 'GET' to see system status
[13:34:47.021 RX]
[13:34:47.021 RX] > I (1050) UART: UART interface started
[13:34:47.072 RX]
[13:34:47.072 RX] I (1050) gpio: GPIO[25]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
[13:34:47.072 RX] I (1060) RF: RF receiver task started on core 0
[13:34:47.072 RX] I (1070) BTDM_INIT: BT controller compile version [b022216]
[13:34:47.072 RX] I (
[13:34:47.123 RX] 1070) BTDM_INIT: Bluetooth MAC: 94:54:c5:38:c4:3a
[13:34:47.123 RX] I (1080) phy_init: phy_version 4830,54550f7,Jun 20 2024,14:22:08
[13:34:47.123 RX] E (1090) phy_init: esp_phy_load_cal_data_from_nvs: NVS has not been initialized. Call nvs_flash_init before starting
[13:34:47.174 RX] WiFi/BT.
[13:34:47.174 RX] W (1100) phy_init: failed to load RF calibration data (0x1101), falling back to full calibration
[13:34:47.174 RX] W (1170) phy_init: saving new calibration data because of checksum failure, mode(2)
[13:34:47.174 RX] E (1410) BT_OSI: config_new: N
[13:34:47.224 RX] VS not initialized. Call nvs_flash_init before initializing bluetooth.
[13:34:47.224 RX] W (1410) BT_BTC: btc_config_init unable to load config file; starting unconfigured.
[13:34:47.224 RX]
[13:34:47.224 RX] E (1420) BT_OSI: config_save: NVS not initialized. Call nvs_flash_init befo
[13:34:47.225 TX] POST: {"time": 1773167687}
[13:34:47.250 RX] alizing bluetooth.
[13:34:47.250 RX] E (1540) BT_OSI: config_save, err_code: 0x2
[13:34:47.250 RX]
[13:34:47.250 RX] E (1540) BT_OSI: config_save: NVS not initialized. Call nvs_flash_init before initializing bluetooth.
[13:34:47.250 RX] E (1550) BT_OSI: config_save, err_code: 0x2
[13:34:47.250 RX]
[13:34:47.250 RX] [
[13:34:47.301 RX] 0;32mI (1560) BT_HID: Scanning for HID devices (3s)...
[13:34:47.301 RX] I (1560) BT_HID: BLE HID host initialised
[13:34:47.301 RX] POST: {"time": 1773167687}
[13:34:47.301 RX]
[13:34:47.301 RX]
[13:34:47.301 RX] I (1570) gpio: GPIO[14]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:3
[13:34:47.301 RX] [0
[13:34:47.351 RX] ;32mI (1570) COMMS: Setting time to 1773167687
[13:34:47.351 RX] I (1580) ALARM: SET FOR 1773168516 (in 829 s)
[13:34:47.351 RX] I (1580) gpio: GPIO[27]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:3
[13:34:47.351 RX] {
[13:34:47.351 RX] "status": "ok",
[13:34:47.351 RX] "params_updated"
[13:34:47.402 RX] : 0,
[13:34:47.402 RX] "params_failed": 0,
[13:34:47.402 RX] "cmd_executed": false
[13:34:47.402 RX] }
[13:34:47.402 RX] I (1590) STORAGE: Wrote; Tail/Head are now 16384/131093
[13:34:47.402 RX]
[13:34:47.402 RX] >
[13:34:47.402 RX]
[13:34:47.402 RX]
[13:34:47.402 RX] > I (1570) WEBSERVER: Initializing webserver...
[13:34:47.402 RX] I (1620) WEBSERVER: AP LAUNCHING
[13:34:47.402 RX] I (1640) WE
[13:34:47.452 RX] BSERVER: AP LAUNCHING...
[13:34:47.452 RX] I (1640) WEBSERVER: HI THERE
[13:34:47.452 RX] I (1660) wifi:wifi driver task: 3ffe2808, prio:23, stack:6656, core=0
[13:34:47.452 RX] I (1670) wifi:wifi firmware version: ccaebfa
[13:34:47.452 RX] I (1670) wifi:wifi certification version: v7.0
[13:34:47.452 RX] I (1670) wifi:config
[13:34:47.502 RX] NVS flash: enabled
[13:34:47.502 RX] I (1670) wifi:config nano formating: disabled
[13:34:47.502 RX] I (1670) wifi:Init data frame dynamic rx buffer num: 32
[13:34:47.502 RX] I (1680) wifi:Init static rx mgmt buffer num: 5
[13:34:47.502 RX] I (1680) wifi:Init management short buffer num: 32
[13:34:47.502 RX] I (1680) wifi:Init dynamic tx
[13:34:47.553 RX] buffer num: 32
[13:34:47.553 RX] I (1690) wifi:Init static rx buffer size: 1600
[13:34:47.553 RX] I (1690) wifi:Init static rx buffer num: 10
[13:34:47.553 RX] I (1700) wifi:Init dynamic rx buffer num: 32
[13:34:47.553 RX] I (1700) wifi_init: rx ba win: 6
[13:34:47.553 RX] I (1700) wifi_init: accept mbox: 6
[13:34:47.553 RX] I
[13:34:47.603 RX] (1710) wifi_init: tcpip mbox: 32
[13:34:47.603 RX] I (1710) wifi_init: udp mbox: 6
[13:34:47.603 RX] I (1720) wifi_init: tcp mbox: 6
[13:34:47.603 RX] I (1720) wifi_init: tcp tx win: 5760
[13:34:47.603 RX] I (1720) wifi_init: tcp rx win: 5760
[13:34:47.603 RX] I (1730) wifi_init: tcp m
[13:34:47.604 TX] RTCDEBUG
[13:34:47.645 RX] RTCDEBUG
[13:34:47.645 RX]
[13:34:47.645 RX]
[13:34:47.645 RX] === RTC DEBUG ===
[13:34:47.645 RX] reset_reason: POWER_ON (1)
[13:34:47.645 RX] wakeup_cause: UNDEFINED (normal boot/reset) (0)
[13:34:47.645 RX] slow_clk_src: NOT XTAL32K — check crystal! (0)
[13:34:47.645 RX]
[13:34:47.645 RX] rtc_set: true
[13:34:47.645 RX] current_time: 1773167687 (2026-03-10 18
[13:34:47.695 RX] :34:47 UTC)
[13:34:47.695 RX] rtc_backup_s: 1773167687 (2026-03-10 18:34:47 UTC)
[13:34:47.695 RX] rtc_sleep_entry_s: 0 (N/A UTC)
[13:34:47.695 RX] next_alarm_s: 1773168516 (2026-03-10 18:48:36 UTC)
[13:34:47.695 RX]
[13:34:47.695 RX] uptime: 1s
[13:34:47.695 RX] clock_offset: 1773167686s (current - uptime; stable =
[13:34:47.959 RX] good)
[13:34:47.959 RX] sleep_add: 0s (added to entry_s on this boot, 0 if no sleep)
[13:34:47.960 RX] =================
[13:34:47.960 RX]
[13:34:47.960 RX]
[13:34:47.960 RX] >

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -0,0 +1,294 @@
[16:13:14.971 RX] ets Jul 29 2019 12:21:46
[16:13:14.971 RX]
[16:13:14.971 RX] rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
[16:13:14.972 RX] configsip: 0, SPIWP:0xee
[16:13:14.972 RX] clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
[16:13:14.972 RX] mode:DIO, clock div:2
[16:13:14.972 RX] load:0x3fff0030,len:7176
[16:13:14.972 RX] load:0x40078000,len:160
[16:13:15.022 RX] 92
[16:13:15.022 RX] ho 0 tail 12 room 4
[16:13:15.022 RX] load:0x40080400,len:4
[16:13:15.022 RX] load:0x40080404,len:3912
[16:13:15.022 RX] entry 0x40080640
[16:13:15.022 RX] I (31) boot: ESP-IDF v5.3.1-dirty 2nd stage bootloader
[16:13:15.022 RX] I (31) boot: compile time Mar 4 2026 13:08:05
[16:13:15.022 RX] I (31) boot: Multicore bootload
[16:13:15.082 RX] er
[16:13:15.082 RX] I (36) boot: chip revision: v3.1
[16:13:15.082 RX] I (40) boot.esp32: SPI Speed : 40MHz
[16:13:15.082 RX] I (44) boot.esp32: SPI Mode : DIO
[16:13:15.082 RX] I (49) boot.esp32: SPI Flash Size : 8MB
[16:13:15.082 RX] I (53) boot: Enabling RNG early entrop
[16:13:15.133 RX] y source...
[16:13:15.133 RX] I (59) boot: Partition Table:
[16:13:15.133 RX] I (62) boot: ## Label Usage Type ST Offset Length
[16:13:15.133 RX] I (70) boot: 0 nvs WiFi data 01 02 00009000 00004000
[16:13:15.133 RX] I (77) boot: 1 otad
[16:13:15.183 RX] ata OTA data 01 00 0000d000 00002000
[16:13:15.183 RX] I (84) boot: 2 phy_init RF data 01 01 0000f000 00001000
[16:13:15.183 RX] I (92) boot: 3 ota_0 OTA app 00 10 00010000 00180000
[16:13:15.183 RX] I (99) boot: 4 ot
[16:13:15.234 RX] a_1 OTA app 00 11 00190000 00180000
[16:13:15.234 RX] I (107) boot: 5 storage Unknown data 01 40 00310000 00020000
[16:13:15.234 RX] I (114) boot: End of partition table
[16:13:15.234 RX] I (119) esp_image: segment 0: paddr=00010020 vaddr=3
[16:13:15.284 RX] f400020 size=40a70h (264816) map
[16:13:15.284 RX] I (218) esp_image: segment 1: paddr=00050a98 vaddr=3ff80063 size=00008h ( 8) load
[16:13:15.284 RX] I (218) esp_image: segment 2: paddr=00050aa8 vaddr=3ffbdb60 size=0648ch ( 25740) load
[16:13:15.284 RX] I (233) esp_ima
[16:13:15.538 RX] ge: segment 3: paddr=00056f3c vaddr=40080000 size=090dch ( 37084) load
[16:13:15.538 RX] I (248) esp_image: segment 4: paddr=00060020 vaddr=400d0020 size=ffc84h (1047684) map
[16:13:15.538 RX] I (607) esp_image: segment 5: paddr=0015fcac vaddr=400890dc size=12200h ( 7
[16:13:15.588 RX] 4240) load
[16:13:15.588 RX] I (637) esp_image: segment 6: paddr=00171eb4 vaddr=400c0000 size=00064h ( 100) load
[16:13:15.588 RX] I (637) esp_image: segment 7: paddr=00171f20 vaddr=50000000 size=0004ch ( 76) load
[16:13:15.588 RX] I (657) boot: Loaded app from partiti
[16:13:15.767 RX] on at offset 0x10000
[16:13:15.768 RX] I (657) boot: Disabling RNG early entropy source...
[16:13:15.768 RX] I (669) cpu_start: Multicore app
[16:13:15.768 RX] W (830) clk: 32 kHz XTAL not found, switching to internal 150 kHz oscillator
[16:13:15.768 RX] I (839) cpu_start: Pro cp
[16:13:15.818 RX] u start user code
[16:13:15.818 RX] I (839) cpu_start: cpu freq: 160000000 Hz
[16:13:15.818 RX] I (839) app_init: Application information:
[16:13:15.818 RX] I (843) app_init: Project name: SC-F001
[16:13:15.818 RX] I (848) app_init: App version: e2451fc-dirty
[16:13:15.818 RX] [0;32
[16:13:15.869 RX] mI (854) app_init: Compile time: Mar 5 2026 16:20:24
[16:13:15.869 RX] I (860) app_init: ELF file SHA256: dafdfaaee...
[16:13:15.869 RX] I (865) app_init: ESP-IDF: v5.3.1-dirty
[16:13:15.869 RX] I (870) efuse_init: Min chip rev: v0.0
[16:13:15.869 RX] I (875) e
[16:13:15.920 RX] fuse_init: Max chip rev: v3.99
[16:13:15.920 RX] I (880) efuse_init: Chip rev: v3.1
[16:13:15.920 RX] I (885) heap_init: Initializing. RAM available for dynamic allocation:
[16:13:15.920 RX] I (892) heap_init: At 3FFAFF10 len 000000F0 (0 KiB): DRAM
[16:13:15.920 RX]
[16:13:15.970 RX] I (898) heap_init: At 3FFB6388 len 00001C78 (7 KiB): DRAM
[16:13:15.970 RX] I (904) heap_init: At 3FFB9A20 len 00004108 (16 KiB): DRAM
[16:13:15.970 RX] I (910) heap_init: At 3FFCDD48 len 000122B8 (72 KiB): DRAM
[16:13:15.970 RX] I (916) heap_init: At 3FFE0440 len 00003AE0
[16:13:16.020 RX] (14 KiB): D/IRAM
[16:13:16.020 RX] I (923) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
[16:13:16.020 RX] I (929) heap_init: At 4009B2DC len 00004D24 (19 KiB): IRAM
[16:13:16.020 RX] I (937) spi_flash: detected chip: generic
[16:13:16.020 RX] I (940) spi_flash: flash io:
[16:13:16.071 RX] dio
[16:13:16.071 RX] W (944) i2c: This driver is an old driver, please migrate your application code to adapt `driver/i2c_master.h`
[16:13:16.071 RX] I (955) coexist: coex firmware version: 4482466
[16:13:16.071 RX] I (961) main_task: Started on CPU0
[16:13:16.071 RX] I (971) m
[16:13:16.328 RX] ain_task: Calling app_main()
[16:13:16.328 RX] W (971) RTC: Crystal not running at boot (src=0), attempting bootstrap...
[16:13:17.056 RX] E (2101) RTC: Crystal not oscillating after bootstrap (cal=0) — staying on RC, timekeeping inaccurate
[16:13:17.057 RX] I (2101) RTC: Wakeup: normal boot
[16:13:17.057 RX] I (2111) MAIN: Firmware: V_e2451fc-dirty (2026-03-05 22:20:22)
[16:13:17.057 RX] I (2111) MAI
[16:13:17.107 RX] N: Version: e2451fc-dirty
[16:13:17.107 RX] I (2121) MAIN: Branch: main
[16:13:17.107 RX] I (2121) MAIN: Built: 2026-03-05 22:20:22
[16:13:17.107 RX] I (2121) STORAGE: Initializing storage system...
[16:13:17.107 RX] I (2131) STORAGE: Storage partition found: size=131072 bytes[0
[16:13:17.157 RX] m
[16:13:17.157 RX] I (2141) STORAGE: Log init: scanning 28 sectors with bisection
[16:13:17.157 RX] I (2161) STORAGE: Log system initialized (bisection). Head: 131072, Tail: 16384
[16:13:17.157 RX] I (2161) STORAGE: Log writer task started
[16:13:17.157 RX] I (2161) STORAGE: Log wri
[16:13:17.208 RX]
[16:13:17.208 RX]
[16:13:17.208 RX] ========================================
[16:13:17.208 RX] UART JSON Interface Ready
[16:13:17.208 RX] ========================================
[16:13:17.208 RX] Type 'HELP' for available commands
[16:13:17.208 RX] Type 'GET' to see system status
[16:13:17.208 RX]
[16:13:17.208 RX] > I (2181) UART: UART interface started
[16:13:17.208 RX] I (2181)
[16:13:17.258 RX] gpio: GPIO[25]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
[16:13:17.258 RX] I (2191) RF: RF receiver task started on core 0
[16:13:17.258 RX] I (2201) BTDM_INIT: BT controller compile version [b022216]
[16:13:17.258 RX] I (2211) BTDM_INIT: Bluet
[16:13:17.309 RX] ooth MAC: 94:54:c5:38:c4:3a
[16:13:17.309 RX] I (2211) phy_init: phy_version 4830,54550f7,Jun 20 2024,14:22:08
[16:13:17.309 RX] E (2221) phy_init: esp_phy_load_cal_data_from_nvs: NVS has not been initialized. Call nvs_flash_init before starting WiFi/BT.
[16:13:17.309 RX] W
[16:13:17.360 RX] (2231) phy_init: failed to load RF calibration data (0x1101), falling back to full calibration
[16:13:17.360 RX] W (2301) phy_init: saving new calibration data because of checksum failure, mode(2)
[16:13:17.360 RX] E rmt: hw buffer too small, received symbols truncated
[16:13:17.360 RX] E r
[16:13:17.490 RX] mt: hw buffer too small, received symbols truncated
[16:13:17.490 RX] E (2541) BT_OSI: config_new: NVS not initialized. Call nvs_flash_init before initializing bluetooth.
[16:13:17.490 RX] W (2541) BT_BTC: btc_config_init unable to load config file; starting unconfigured.
[16:13:17.491 TX] POST: {"time": 1773177197}
[16:13:17.527 RX] NVS not initialized. Call nvs_flash_init before initializing bluetooth.
[16:13:17.527 RX] E (2561) BT_OSI: config_save, err_code: 0x2
[16:13:17.527 RX]
[16:13:17.527 RX] POST: {"time": 1773177197}
[16:13:17.527 RX]
[16:13:17.527 RX]
[16:13:17.527 RX] I (2591) COMMS: Setting time to 1773177197
[16:13:17.527 RX] I (2591) ALARM: SET FOR 1773
[16:13:17.577 RX] 177712 (in 515 s)
[16:13:17.577 RX] I (2591) RTC: TIME unix=1773177197 src=SYNC uptime=1s
[16:13:17.577 RX] I (2591) STORAGE: Wrote; Tail/Head are now 16384/131093
[16:13:17.577 RX] {
[16:13:17.577 RX] "status": "ok",
[16:13:17.577 RX] "params_updated": 0,
[16:13:17.577 RX] "params_failed": 0,
[16:13:17.577 RX] "cmd_executed": false
[16:13:17.577 RX] }
[16:13:17.577 RX]
[16:13:17.577 RX] >
[16:13:17.628 RX]
[16:13:17.628 RX]
[16:13:17.628 RX] > E (2621) BT_APPL: bta_gattc_co_cache_addr_init, Line = 436, nvs flash open fail, err_code = 1101
[16:13:17.628 RX] E (2641) BT_OSI: config_save: NVS not initialized. Call nvs_flash_init before initializing bluetooth.
[16:13:17.628 RX] E (2641) BT_OSI: con
[16:13:17.678 RX] fig_save, err_code: 0x2
[16:13:17.678 RX]
[16:13:17.678 RX] E (2651) BT_OSI: config_save: NVS not initialized. Call nvs_flash_init before initializing bluetooth.
[16:13:17.678 RX] E (2661) BT_OSI: config_save, err_code: 0x2
[16:13:17.678 RX]
[16:13:17.678 RX] E (2661) BT_OSI: config_save: NVS not initiali
[16:13:17.729 RX] zed. Call nvs_flash_init before initializing bluetooth.
[16:13:17.729 RX] E (2671) BT_OSI: config_save, err_code: 0x2
[16:13:17.729 RX]
[16:13:17.729 RX] E (2681) BT_OSI: config_save: NVS not initialized. Call nvs_flash_init before initializing bluetooth.
[16:13:17.729 RX] E (2691) BT_OSI:
[16:13:17.779 RX] config_save, err_code: 0x2
[16:13:17.779 RX]
[16:13:17.779 RX] I (2691) BT_HID: Scanning for HID devices (3s)...
[16:13:17.779 RX] I (2701) BT_HID: BLE HID host initialised

View File

@@ -0,0 +1,276 @@
[16:22:29.810 RX] ets Jul 29 2019 12:21:46
[16:22:29.810 RX]
[16:22:29.810 RX] rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
[16:22:29.810 RX] configsip: 0, SPIWP:0xee
[16:22:29.810 RX] clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
[16:22:29.810 RX] mode:DIO, clock div:2
[16:22:29.810 RX] load:0x3fff0030,len:7176
[16:22:29.810 RX] load:0x40078000,len:160
[16:22:29.860 RX] 92
[16:22:29.860 RX] ho 0 tail 12 room 4
[16:22:29.860 RX] load:0x40080400,len:4
[16:22:29.860 RX] load:0x40080404,len:3912
[16:22:29.860 RX] entry 0x40080640
[16:22:29.860 RX] I (31) boot: ESP-IDF v5.3.1-dirty 2nd stage bootloader
[16:22:29.860 RX] I (31) boot: compile time Mar 4 2026 13:08:05
[16:22:29.860 RX] I (31) boot: Multicore bootload
[16:22:29.921 RX] er
[16:22:29.921 RX] I (36) boot: chip revision: v3.1
[16:22:29.921 RX] I (40) boot.esp32: SPI Speed : 40MHz
[16:22:29.921 RX] I (44) boot.esp32: SPI Mode : DIO
[16:22:29.921 RX] I (49) boot.esp32: SPI Flash Size : 8MB
[16:22:29.921 RX] I (53) boot: Enabling RNG early entrop
[16:22:29.971 RX] y source...
[16:22:29.971 RX] I (59) boot: Partition Table:
[16:22:29.971 RX] I (62) boot: ## Label Usage Type ST Offset Length
[16:22:29.971 RX] I (70) boot: 0 nvs WiFi data 01 02 00009000 00004000
[16:22:29.971 RX] I (77) boot: 1 otad
[16:22:30.022 RX] ata OTA data 01 00 0000d000 00002000
[16:22:30.022 RX] I (84) boot: 2 phy_init RF data 01 01 0000f000 00001000
[16:22:30.022 RX] I (92) boot: 3 ota_0 OTA app 00 10 00010000 00180000
[16:22:30.022 RX] I (99) boot: 4 ot
[16:22:30.073 RX] a_1 OTA app 00 11 00190000 00180000
[16:22:30.073 RX] I (107) boot: 5 storage Unknown data 01 40 00310000 00020000
[16:22:30.073 RX] I (114) boot: End of partition table
[16:22:30.073 RX] I (119) esp_image: segment 0: paddr=00010020 vaddr=3
[16:22:30.123 RX] f400020 size=40a70h (264816) map
[16:22:30.123 RX] I (218) esp_image: segment 1: paddr=00050a98 vaddr=3ff80063 size=00008h ( 8) load
[16:22:30.123 RX] I (218) esp_image: segment 2: paddr=00050aa8 vaddr=3ffbdb60 size=0648ch ( 25740) load
[16:22:30.123 RX] I (233) esp_ima
[16:22:30.376 RX] ge: segment 3: paddr=00056f3c vaddr=40080000 size=090dch ( 37084) load
[16:22:30.376 RX] I (248) esp_image: segment 4: paddr=00060020 vaddr=400d0020 size=ffc84h (1047684) map
[16:22:30.376 RX] I (607) esp_image: segment 5: paddr=0015fcac vaddr=400890dc size=12200h ( 7
[16:22:30.427 RX] 4240) load
[16:22:30.427 RX] I (637) esp_image: segment 6: paddr=00171eb4 vaddr=400c0000 size=00064h ( 100) load
[16:22:30.427 RX] I (637) esp_image: segment 7: paddr=00171f20 vaddr=50000000 size=0004ch ( 76) load
[16:22:30.427 RX] I (657) boot: Loaded app from partiti
[16:22:30.606 RX] on at offset 0x10000
[16:22:30.606 RX] I (657) boot: Disabling RNG early entropy source...
[16:22:30.606 RX] I (669) cpu_start: Multicore app
[16:22:30.606 RX] W (830) clk: 32 kHz XTAL not found, switching to internal 150 kHz oscillator
[16:22:30.606 RX] I (839) cpu_start: Pro cp
[16:22:30.657 RX] u start user code
[16:22:30.657 RX] I (839) cpu_start: cpu freq: 160000000 Hz
[16:22:30.657 RX] I (839) app_init: Application information:
[16:22:30.657 RX] I (843) app_init: Project name: SC-F001
[16:22:30.657 RX] I (848) app_init: App version: e2451fc-dirty
[16:22:30.657 RX] [0;32
[16:22:30.707 RX] mI (854) app_init: Compile time: Mar 5 2026 16:20:24
[16:22:30.707 RX] I (860) app_init: ELF file SHA256: dafdfaaee...
[16:22:30.707 RX] I (865) app_init: ESP-IDF: v5.3.1-dirty
[16:22:30.707 RX] I (870) efuse_init: Min chip rev: v0.0
[16:22:30.707 RX] I (875) e
[16:22:30.758 RX] fuse_init: Max chip rev: v3.99
[16:22:30.758 RX] I (880) efuse_init: Chip rev: v3.1
[16:22:30.758 RX] I (885) heap_init: Initializing. RAM available for dynamic allocation:
[16:22:30.758 RX] I (892) heap_init: At 3FFAFF10 len 000000F0 (0 KiB): DRAM
[16:22:30.758 RX]
[16:22:30.808 RX] I (898) heap_init: At 3FFB6388 len 00001C78 (7 KiB): DRAM
[16:22:30.808 RX] I (904) heap_init: At 3FFB9A20 len 00004108 (16 KiB): DRAM
[16:22:30.808 RX] I (910) heap_init: At 3FFCDD48 len 000122B8 (72 KiB): DRAM
[16:22:30.808 RX] I (916) heap_init: At 3FFE0440 len 00003AE0
[16:22:30.858 RX] (14 KiB): D/IRAM
[16:22:30.858 RX] I (923) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
[16:22:30.858 RX] I (929) heap_init: At 4009B2DC len 00004D24 (19 KiB): IRAM
[16:22:30.858 RX] I (937) spi_flash: detected chip: generic
[16:22:30.858 RX] I (940) spi_flash: flash io:
[16:22:30.910 RX] dio
[16:22:30.910 RX] W (944) i2c: This driver is an old driver, please migrate your application code to adapt `driver/i2c_master.h`
[16:22:30.910 RX] I (955) coexist: coex firmware version: 4482466
[16:22:30.910 RX] I (961) main_task: Started on CPU0
[16:22:30.910 RX] I (971) m
[16:22:31.170 RX] ain_task: Calling app_main()
[16:22:31.170 RX] W (971) RTC: Crystal not running at boot (src=0), attempting bootstrap...
[16:22:31.895 RX] E (2101) RTC: Crystal not oscillating after bootstrap (cal=0) — staying on RC, timekeeping inaccurate
[16:22:31.895 RX] I (2101) RTC: Wakeup: normal boot
[16:22:31.895 RX] I (2111) MAIN: Firmware: V_e2451fc-dirty (2026-03-05 22:20:22)
[16:22:31.895 RX] I (2111) MAI
[16:22:31.946 RX] N: Version: e2451fc-dirty
[16:22:31.946 RX] I (2121) MAIN: Branch: main
[16:22:31.946 RX] I (2121) MAIN: Built: 2026-03-05 22:20:22
[16:22:31.946 RX] I (2121) STORAGE: Initializing storage system...
[16:22:31.946 RX] I (2131) STORAGE: Storage partition found: size=131072 bytes[0
[16:22:31.996 RX] m
[16:22:31.996 RX] I (2141) STORAGE: Log init: scanning 28 sectors with bisection
[16:22:31.996 RX] I (2161) STORAGE: Log system initialized (bisection). Head: 131072, Tail: 16384
[16:22:31.996 RX] I (2161) STORAGE: Log writer task started
[16:22:31.996 RX] I (2161) STORAGE: Log wri
[16:22:32.046 RX]
[16:22:32.046 RX]
[16:22:32.046 RX] ========================================
[16:22:32.046 RX] UART JSON Interface Ready
[16:22:32.046 RX] ========================================
[16:22:32.046 RX] Type 'HELP' for available commands
[16:22:32.046 RX] Type 'GET' to see system status
[16:22:32.046 RX]
[16:22:32.046 RX] > I (2181) UART: UART interface started
[16:22:32.046 RX] I (2181)
[16:22:32.097 RX] gpio: GPIO[25]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
[16:22:32.097 RX] I (2191) RF: RF receiver task started on core 0
[16:22:32.097 RX] I (2201) BTDM_INIT: BT controller compile version [b022216]
[16:22:32.097 RX] I (2211) BTDM_INIT: Bluet
[16:22:32.147 RX] ooth MAC: 94:54:c5:38:c4:3a
[16:22:32.147 RX] I (2211) phy_init: phy_version 4830,54550f7,Jun 20 2024,14:22:08
[16:22:32.147 RX] E (2221) phy_init: esp_phy_load_cal_data_from_nvs: NVS has not been initialized. Call nvs_flash_init before starting WiFi/BT.
[16:22:32.147 RX] W
[16:22:32.317 RX] (2231) phy_init: failed to load RF calibration data (0x1101), falling back to full calibration
[16:22:32.317 RX] E rmt: hw buffer too small, received symbols truncated
[16:22:32.317 RX] W (2301) phy_init: saving new calibration data because of checksum failure, mode(2)
[16:22:32.317 RX] [0
[16:22:32.318 TX] POST: {"time": 1773177752}
[16:22:32.344 RX] nvs_flash_init before initializing bluetooth.
[16:22:32.344 RX] W (2551) BT_BTC: btc_config_init unable to load config file; starting unconfigured.
[16:22:32.344 RX]
[16:22:32.344 RX] E (2551) BT_OSI: config_save: NVS not initialized. Call nvs_flash_init before initializing bluetooth
[16:22:32.394 RX] .
[16:22:32.394 RX] E (2561) BT_OSI: config_save, err_code: 0x2
[16:22:32.394 RX]
[16:22:32.394 RX] E rmt: hw buffer too small, received symbols truncated
[16:22:32.394 RX] POST: {"time": 1773177752}
[16:22:32.394 RX]
[16:22:32.394 RX]
[16:22:32.394 RX] I (2581) COMMS: Setting time to 1773177752
[16:22:32.394 RX] I (2581) ALARM: SET FOR 1773178549 (in 797
[16:22:32.444 RX] s)
[16:22:32.444 RX] I (2581) RTC: TIME unix=1773177752 src=SYNC uptime=1s
[16:22:32.444 RX] I (2581) STORAGE: Wrote; Tail/Head are now 16384/131093
[16:22:32.444 RX] {
[16:22:32.444 RX] "status": "ok",
[16:22:32.444 RX] "params_updated": 0,
[16:22:32.444 RX] "params_failed": 0,
[16:22:32.444 RX] "cmd_executed": false
[16:22:32.444 RX] }
[16:22:32.444 RX]
[16:22:32.444 RX] >
[16:22:32.444 RX]
[16:22:32.444 RX]
[16:22:32.444 RX] > E
[16:22:32.496 RX] (2621) BT_APPL: bta_gattc_co_cache_addr_init, Line = 436, nvs flash open fail, err_code = 1101
[16:22:32.496 RX] E rmt: hw buffer too small, received symbols truncated
[16:22:32.496 RX] E (2641) BT_OSI: config_save: NVS not initialized. Call nvs_flash_init before initializing b
[16:22:32.546 RX] luetooth.
[16:22:32.546 RX] E (2651) BT_OSI: config_save, err_code: 0x2

View File

290
logtool/rtc_test.py Normal file
View File

@@ -0,0 +1,290 @@
#!/usr/bin/env python3
"""
rtc_test.py -- SC-F001 RTC timekeeping monitor
1. Reset board and wait for boot
2. Sync device RTC to host clock
3. Stream UART continuously -- no sleep commands issued
4. Every time the firmware logs a TIME line, record host time vs device time and print diff
5. Ctrl+C to stop
The device will sleep naturally after 180s of inactivity and wake every 120s,
producing a TIME line on each wakeup. This script catches each one.
Firmware emits parseable lines of the form:
I (uptime) RTC: TIME unix=<seconds> src=<SYNC|SLEEP|CRASH> uptime=<seconds>s
Generates two log files automatically:
rtc_raw_TIMESTAMP.txt -- every UART byte in/out, wall-clock timestamped
rtc_analysis_TIMESTAMP.txt -- clean parsed comparison table, no ANSI codes
Usage:
pip install pyserial
python logtool/rtc_test.py COM3
python logtool/rtc_test.py COM3 --verbose # also print raw device output
"""
import serial
import time
import re
import sys
import argparse
from datetime import datetime, timezone
if hasattr(sys.stdout, "reconfigure"):
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
BAUD = 115200
BOOT_TIMEOUT = 35 # seconds to wait for prompt after reset
_ANSI = re.compile(r"\x1b\[[0-9;]*[A-Za-z]")
# Matches: I (123) RTC: TIME unix=1773167687 src=SLEEP uptime=5s
_TIME_RE = re.compile(r"TIME unix=(\d+) src=(\S+) uptime=(\d+)s")
def _strip(s):
return _ANSI.sub("", s)
def _ts():
return datetime.now().strftime("%H:%M:%S.%f")[:-3]
def _utc(unix_s):
return datetime.fromtimestamp(int(unix_s), tz=timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
# ---------------------------------------------------------------------------
# Log handles
# ---------------------------------------------------------------------------
_raw_log = None
_analysis_log = None
def _rawlog(direction, text):
if not _raw_log:
return
for line in text.splitlines(keepends=True):
_raw_log.write(f"[{_ts()} {direction}] {_strip(line)}")
if text and not text.endswith("\n"):
_raw_log.write("\n")
_raw_log.flush()
def aprint(*args, **kwargs):
"""Print to console AND analysis log (ANSI stripped in file)."""
end = kwargs.get("end", "\n")
text = " ".join(str(a) for a in args) + end
sys.stdout.write(text)
sys.stdout.flush()
if _analysis_log:
_analysis_log.write(_strip(text))
_analysis_log.flush()
# ---------------------------------------------------------------------------
# Serial helpers
# ---------------------------------------------------------------------------
def reset_board(ser):
"""Pulse EN via RTS; keep DTR=False so GPIO0 stays HIGH (normal boot)."""
ser.dtr = False
ser.rts = True
time.sleep(0.1)
ser.rts = False
time.sleep(0.05)
def wait_for_boot(ser, timeout=BOOT_TIMEOUT, verbose=False):
"""
Read until the UART prompt (\\n> ) appears anywhere in the buffer.
Nudges the device every 3s in case the prompt is buried under log spam.
"""
buf = ""
deadline = time.time() + timeout
last_nudge = time.time()
prompt_seen_at = None
while time.time() < deadline:
chunk = ser.read(256).decode(errors="replace")
if chunk:
buf += chunk
_rawlog("RX", chunk)
if verbose:
sys.stdout.write(chunk)
sys.stdout.flush()
if prompt_seen_at is None and ("\n> " in buf or "\r\n> " in buf):
prompt_seen_at = time.time()
if prompt_seen_at is not None and time.time() - prompt_seen_at >= 0.20:
return buf
if time.time() - last_nudge > 3.0:
ser.write(b"\r\n")
_rawlog("TX", "\r\n")
last_nudge = time.time()
time.sleep(0.05)
raise TimeoutError(f"Boot prompt not seen within {timeout}s")
def send_cmd(ser, cmd, timeout=10.0, verbose=False):
"""Send a command and wait for the next prompt."""
ser.read_all()
ser.write((cmd + "\r\n").encode())
_rawlog("TX", cmd + "\r\n")
buf = ""
deadline = time.time() + timeout
prompt_seen_at = None
while time.time() < deadline:
chunk = ser.read(256).decode(errors="replace")
if chunk:
buf += chunk
_rawlog("RX", chunk)
if verbose:
sys.stdout.write(chunk)
sys.stdout.flush()
if prompt_seen_at is None and ("\n> " in buf or "\r\n> " in buf):
prompt_seen_at = time.time()
if prompt_seen_at is not None and time.time() - prompt_seen_at >= 0.20:
return buf
time.sleep(0.05)
return buf # return whatever we got even on timeout
# ---------------------------------------------------------------------------
# Comparison table
# ---------------------------------------------------------------------------
_HDR = (
"\n"
" # Wall clock (host) Device time (UTC) Diff Source Uptime\n"
" -- ------------------- ------------------- ------ -------- ------"
)
_ROW = " {n:>2} {ht:<19} {dt:<19} {diff:>+6}s {src:<8} {up}s"
def _table_row(n, host_ts, device_unix, src, uptime_s):
diff = device_unix - host_ts
return _ROW.format(
n = n,
ht = _utc(host_ts),
dt = _utc(device_unix),
diff = diff,
src = src,
up = uptime_s,
)
# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------
def main():
global _raw_log, _analysis_log
parser = argparse.ArgumentParser(description="SC-F001 RTC timekeeping monitor")
parser.add_argument("port", help="Serial port, e.g. COM3 or /dev/ttyUSB0")
parser.add_argument("--boot-timeout", type=float, default=BOOT_TIMEOUT)
parser.add_argument("--verbose", action="store_true",
help="Print raw device output to console (always in raw log)")
args = parser.parse_args()
stamp = datetime.now().strftime("%Y%m%d_%H%M%S")
raw_path = f"logtool/rtc_raw_{stamp}.txt"
analysis_path = f"logtool/rtc_analysis_{stamp}.txt"
_raw_log = open(raw_path, "w", encoding="utf-8", errors="replace")
_analysis_log = open(analysis_path, "w", encoding="utf-8", errors="replace")
aprint(f"Raw log : {raw_path}")
aprint(f"Analysis log : {analysis_path}")
aprint(f"Port : {args.port} {BAUD} baud")
aprint(f"Ctrl+C to stop.\n")
# ---- Open port -------------------------------------------------------- #
ser = serial.Serial(args.port, BAUD, timeout=0.2)
ser.dtr = False
ser.rts = False
time.sleep(0.2)
ser.read_all()
# ---- Reset and wait for boot ------------------------------------------ #
aprint(f"[{_ts()}] Resetting board...")
reset_board(ser)
try:
wait_for_boot(ser, timeout=args.boot_timeout, verbose=args.verbose)
except TimeoutError as e:
aprint(f"ERROR: {e}")
ser.close(); sys.exit(1)
aprint(f"[{_ts()}] Boot complete.\n")
# ---- Sync RTC --------------------------------------------------------- #
host_sync = int(time.time())
aprint(f"[{_ts()}] Syncing device RTC to host: {host_sync} ({_utc(host_sync)} UTC)...")
resp = send_cmd(ser, f'POST: {{"time": {host_sync}}}', verbose=args.verbose)
if "ok" in resp.lower():
aprint(f"[{_ts()}] Sync OK.\n")
else:
aprint(f"[{_ts()}] WARNING: unexpected response: {_strip(resp.strip())}\n")
# ---- Table header ----------------------------------------------------- #
aprint(_HDR)
# ---- Stream loop ------------------------------------------------------ #
event_n = 0
line_buf = ""
aprint()
aprint("Streaming... (device will sleep after 180s inactivity, wake every 120s)")
aprint()
try:
while True:
chunk = ser.read(256).decode(errors="replace")
if not chunk:
continue
_rawlog("RX", chunk)
if args.verbose:
sys.stdout.write(chunk)
sys.stdout.flush()
line_buf += chunk
# Process complete lines
while "\n" in line_buf:
line, line_buf = line_buf.split("\n", 1)
line = line.rstrip("\r")
m = _TIME_RE.search(_strip(line))
if not m:
continue
# Got a TIME event
host_ts = int(time.time())
device_unix = int(m.group(1))
src = m.group(2)
uptime_s = m.group(3)
event_n += 1
row = _table_row(event_n, host_ts, device_unix, src, uptime_s)
aprint(row)
except KeyboardInterrupt:
aprint(f"\n\n[{_ts()}] Stopped by user.")
if event_n == 0:
aprint("No TIME events captured.")
else:
aprint(f"{event_n} event(s) logged to {analysis_path}")
ser.close()
_raw_log.close()
_analysis_log.close()
if __name__ == "__main__":
main()

Binary file not shown.

View File

@@ -60,7 +60,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
#define TAG "BT_HID" #define TAG "BT_HID"
#define BT_HID_SCAN_DURATION_S 5 #define BT_HID_SCAN_DURATION_S 3 /* ceiling only — scan stops early on first HID hit */
#define BT_HID_RECONNECT_MS 2000 #define BT_HID_RECONNECT_MS 2000
#define BT_HID_BOND_TIMEOUT_MS 5000 /* wait for saved device before scanning */ #define BT_HID_BOND_TIMEOUT_MS 5000 /* wait for saved device before scanning */
#define BT_HID_CONNECT_WAIT_MS 5000 /* wait after open() before next loop */ #define BT_HID_CONNECT_WAIT_MS 5000 /* wait after open() before next loop */
@@ -103,8 +103,13 @@ static portMUX_TYPE s_mux = portMUX_INITIALIZER_UNLOCKED;
static SemaphoreHandle_t s_scan_sem = NULL; static SemaphoreHandle_t s_scan_sem = NULL;
/* Set once we have a saved BDA from NVS (direct reconnect path). */ /* Set once we have a saved BDA from NVS (direct reconnect path). */
static bool s_has_saved_bda = false; static bool s_has_saved_bda = false;
static esp_bd_addr_t s_saved_bda = {0}; static esp_bd_addr_t s_saved_bda = {0};
static esp_ble_addr_type_t s_saved_addr_type = BLE_ADDR_TYPE_RANDOM;
/* Address type used for the most recent esp_hidh_dev_open() call.
* Set immediately before open so the OPEN callback can persist it. */
static esp_ble_addr_type_t s_connect_addr_type = BLE_ADDR_TYPE_RANDOM;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Scan-result list (heap-allocated, freed after each scan round) // Scan-result list (heap-allocated, freed after each scan round)
@@ -121,6 +126,8 @@ typedef struct scan_result_s {
static scan_result_t *s_scan_results = NULL; static scan_result_t *s_scan_results = NULL;
static size_t s_num_scan_results = 0; static size_t s_num_scan_results = 0;
static TaskHandle_t s_scan_task_handle = NULL;
static scan_result_t *find_scan_result(const esp_bd_addr_t bda) static scan_result_t *find_scan_result(const esp_bd_addr_t bda)
{ {
scan_result_t *r = s_scan_results; scan_result_t *r = s_scan_results;
@@ -163,23 +170,29 @@ static void free_scan_results(void)
// NVS helpers — store / load the last-connected BDA // NVS helpers — store / load the last-connected BDA
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
static void nvs_save_bda(const esp_bd_addr_t bda) static void nvs_save_bda(const esp_bd_addr_t bda, esp_ble_addr_type_t addr_type)
{ {
nvs_handle_t h; nvs_handle_t h;
if (nvs_open(BT_HID_NVS_NAMESPACE, NVS_READWRITE, &h) != ESP_OK) return; if (nvs_open(BT_HID_NVS_NAMESPACE, NVS_READWRITE, &h) != ESP_OK) return;
nvs_set_blob(h, BT_HID_NVS_BDA_KEY, bda, sizeof(esp_bd_addr_t)); nvs_set_blob(h, BT_HID_NVS_BDA_KEY, bda, sizeof(esp_bd_addr_t));
nvs_set_u8(h, "addr_type", (uint8_t)addr_type);
nvs_commit(h); nvs_commit(h);
nvs_close(h); nvs_close(h);
ESP_LOGI(TAG, "Saved BDA %02x:%02x:%02x:%02x:%02x:%02x to NVS", ESP_LOGI(TAG, "Saved BDA %02x:%02x:%02x:%02x:%02x:%02x (addr_type=%d) to NVS",
bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]); bda[0], bda[1], bda[2], bda[3], bda[4], bda[5], (int)addr_type);
} }
static bool nvs_load_bda(esp_bd_addr_t out_bda) static bool nvs_load_bda(esp_bd_addr_t out_bda, esp_ble_addr_type_t *out_addr_type)
{ {
nvs_handle_t h; nvs_handle_t h;
if (nvs_open(BT_HID_NVS_NAMESPACE, NVS_READONLY, &h) != ESP_OK) return false; if (nvs_open(BT_HID_NVS_NAMESPACE, NVS_READONLY, &h) != ESP_OK) return false;
size_t len = sizeof(esp_bd_addr_t); size_t len = sizeof(esp_bd_addr_t);
bool ok = (nvs_get_blob(h, BT_HID_NVS_BDA_KEY, out_bda, &len) == ESP_OK); bool ok = (nvs_get_blob(h, BT_HID_NVS_BDA_KEY, out_bda, &len) == ESP_OK);
if (ok) {
uint8_t at = (uint8_t)BLE_ADDR_TYPE_RANDOM;
nvs_get_u8(h, "addr_type", &at); /* missing key → stays RANDOM, safe default */
*out_addr_type = (esp_ble_addr_type_t)at;
}
nvs_close(h); nvs_close(h);
return ok; return ok;
} }
@@ -229,7 +242,7 @@ static void hidh_callback(void *handler_args,
memcpy(s_remote.bda, bda, sizeof(esp_bd_addr_t)); memcpy(s_remote.bda, bda, sizeof(esp_bd_addr_t));
taskEXIT_CRITICAL(&s_mux); taskEXIT_CRITICAL(&s_mux);
nvs_save_bda(bda); nvs_save_bda(bda, s_connect_addr_type);
} else { } else {
ESP_LOGE(TAG, "OPEN failed, status=%d", p->open.status); ESP_LOGE(TAG, "OPEN failed, status=%d", p->open.status);
} }
@@ -339,6 +352,9 @@ static void ble_gap_event_handler(esp_gap_ble_cb_event_t event,
param->scan_rst.ble_addr_type, param->scan_rst.ble_addr_type,
name, name,
param->scan_rst.rssi); param->scan_rst.rssi);
/* Stop scanning immediately — we have what we need. */
esp_ble_gap_stop_scanning();
break; break;
} }
@@ -405,7 +421,8 @@ static void bt_hid_scan_task(void *pvParameters)
* BLE_ADDR_TYPE_RANDOM is the most common for consumer remotes; if it * BLE_ADDR_TYPE_RANDOM is the most common for consumer remotes; if it
* fails the outer scan loop will find it correctly. * fails the outer scan loop will find it correctly.
*/ */
esp_hidh_dev_open(s_saved_bda, ESP_HID_TRANSPORT_BLE, BLE_ADDR_TYPE_RANDOM); s_connect_addr_type = s_saved_addr_type;
esp_hidh_dev_open(s_saved_bda, ESP_HID_TRANSPORT_BLE, s_saved_addr_type);
vTaskDelay(pdMS_TO_TICKS(BT_HID_BOND_TIMEOUT_MS)); vTaskDelay(pdMS_TO_TICKS(BT_HID_BOND_TIMEOUT_MS));
/* If the open succeeded the state will be CONNECTED — skip to main loop. */ /* If the open succeeded the state will be CONNECTED — skip to main loop. */
@@ -461,6 +478,7 @@ static void bt_hid_scan_task(void *pvParameters)
best->bda[3], best->bda[4], best->bda[5], best->bda[3], best->bda[4], best->bda[5],
best->name, best->rssi); best->name, best->rssi);
s_connect_addr_type = best->addr_type;
esp_hidh_dev_open(best->bda, ESP_HID_TRANSPORT_BLE, best->addr_type); esp_hidh_dev_open(best->bda, ESP_HID_TRANSPORT_BLE, best->addr_type);
free_scan_results(); free_scan_results();
@@ -536,7 +554,7 @@ esp_err_t bt_hid_init(void)
} }
/* Try to load a previously bonded device address from NVS. */ /* Try to load a previously bonded device address from NVS. */
s_has_saved_bda = nvs_load_bda(s_saved_bda); s_has_saved_bda = nvs_load_bda(s_saved_bda, &s_saved_addr_type);
if (s_has_saved_bda) { if (s_has_saved_bda) {
ESP_LOGI(TAG, "Found saved BDA in NVS — will try direct reconnect first"); ESP_LOGI(TAG, "Found saved BDA in NVS — will try direct reconnect first");
} }
@@ -551,8 +569,24 @@ esp_err_t bt_hid_init(void)
* Priority 4: above webserver (typically 56 on core 0) is fine; below * Priority 4: above webserver (typically 56 on core 0) is fine; below
* the FSM (10) and RF task (5) so control always wins CPU. * the FSM (10) and RF task (5) so control always wins CPU.
*/ */
xTaskCreate(bt_hid_scan_task, "bt_hid_scan", 6 * 1024, NULL, 4, NULL); xTaskCreate(bt_hid_scan_task, "bt_hid_scan", 6 * 1024, NULL, 4, &s_scan_task_handle);
ESP_LOGI(TAG, "BLE HID host initialised"); ESP_LOGI(TAG, "BLE HID host initialised");
return ESP_OK; return ESP_OK;
} }
void bt_hid_stop(void)
{
if (s_scan_task_handle != NULL) {
vTaskSuspend(s_scan_task_handle);
ESP_LOGI(TAG, "BT HID scan task suspended");
}
}
void bt_hid_resume(void)
{
if (s_scan_task_handle != NULL) {
vTaskResume(s_scan_task_handle);
ESP_LOGI(TAG, "BT HID scan task resumed");
}
}

View File

@@ -27,5 +27,7 @@
#define BT_HID_REPEAT_MS 50 #define BT_HID_REPEAT_MS 50
esp_err_t bt_hid_init(void); esp_err_t bt_hid_init(void);
void bt_hid_stop(void); // Suspend BT scan task (soft idle)
void bt_hid_resume(void); // Resume BT scan task (wake from soft idle)
#endif /* BT_HID_H */ #endif /* BT_HID_H */

View File

@@ -70,7 +70,9 @@ static inline void set_timer(uint64_t us) {
static inline bool timer_done() { return fsm_now >= timer_end; } static inline bool timer_done() { return fsm_now >= timer_end; }
void pulse_override(fsm_override_t cmd) { void pulse_override(fsm_override_t cmd) {
if (soft_idle_is_active()) return;
if (current_state == STATE_IDLE) { if (current_state == STATE_IDLE) {
rtc_reset_shutdown_timer();
override_cmd = cmd; override_cmd = cmd;
override_time = fsm_now + get_param_value_t(PARAM_RF_PULSE_LENGTH).u32; override_time = fsm_now + get_param_value_t(PARAM_RF_PULSE_LENGTH).u32;
} }
@@ -84,8 +86,13 @@ int64_t fsm_get_cal_e(){return fsm_cal_e;}
void fsm_request(fsm_cmd_t cmd) void fsm_request(fsm_cmd_t cmd)
{ {
if (fsm_cmd_queue != NULL) // STOP always goes through (safety). All other commands are blocked during soft idle —
xQueueSend(fsm_cmd_queue, &cmd, 0); // Safe from any context // the device must be woken by physical button or alarm before remote/RF movement is allowed.
if (cmd != FSM_CMD_STOP && soft_idle_is_active()) return;
rtc_reset_shutdown_timer(); // any accepted command extends the wake period
if (fsm_cmd_queue != NULL)
xQueueSend(fsm_cmd_queue, &cmd, 0); // safe from any context
} }
int8_t fsm_get_current_progress(int8_t denominator) { int8_t fsm_get_current_progress(int8_t denominator) {

View File

@@ -103,31 +103,29 @@ void drive_leds(led_state_t state) {
} }
} }
RTC_DATA_ATTR bool first_boot = true;
void app_main(void) {esp_task_wdt_add(NULL); void app_main(void) {esp_task_wdt_add(NULL);
//run_all_log_tests(); //run_all_log_tests();
if (rtc_xtal_init() != ESP_OK) ESP_LOGE(TAG, "RTC FAILED");
rtc_restore_time(); // Restore time from RTC backup if we crashed
// Say hello; turn on the lights
esp_sleep_wakeup_cause_t cause = rtc_wakeup_cause();
if (i2c_init() != ESP_OK) ESP_LOGE(TAG, "I2C FAILED");
i2c_set_relays((relay_port_t){.raw=0});
drive_leds(LED_STATE_BOOTING);
ESP_LOGI(TAG, "Firmware: %s", FIRMWARE_STRING); ESP_LOGI(TAG, "Firmware: %s", FIRMWARE_STRING);
ESP_LOGI(TAG, "Version: %s", FIRMWARE_VERSION); ESP_LOGI(TAG, "Version: %s", FIRMWARE_VERSION);
ESP_LOGI(TAG, "Branch: %s", FIRMWARE_BRANCH); ESP_LOGI(TAG, "Branch: %s", FIRMWARE_BRANCH);
ESP_LOGI(TAG, "Built: %s", BUILD_DATE); ESP_LOGI(TAG, "Built: %s", BUILD_DATE);
if (rtc_xtal_init() != ESP_OK) ESP_LOGE(TAG, "RTC FAILED");
rtc_restore_time(); // Recover time from RTC domain if we crashed
// Check for factory reset condition: Cold boot + button held // Say hello; turn on the lights
// This is a cold boot (power-on or hard reset) rtc_wakeup_cause(); // log wakeup cause (informational only)
// Check if button is being held (pin is LOW) if (i2c_init() != ESP_OK) ESP_LOGE(TAG, "I2C FAILED");
if (first_boot && gpio_get_level(GPIO_NUM_13) == 0) { i2c_set_relays((relay_port_t){.raw=0});
drive_leds(LED_STATE_BOOTING);
// Check for factory reset condition: Cold boot (power-on/ext-reset) + button held
esp_reset_reason_t boot_reset_reason = esp_reset_reason();
if ((boot_reset_reason == ESP_RST_POWERON || boot_reset_reason == ESP_RST_EXT)
&& gpio_get_level(GPIO_NUM_13) == 0) {
ESP_LOGW(TAG, "FACTORY RESET TRIGGERED - Button held on cold boot"); ESP_LOGW(TAG, "FACTORY RESET TRIGGERED - Button held on cold boot");
// Flash LED pattern to indicate factory reset // Flash LED pattern to indicate factory reset
@@ -209,26 +207,7 @@ void app_main(void) {esp_task_wdt_add(NULL);
//write_dummy_log_1(); //write_dummy_log_1();
// Check wake reasons /*** FULL BOOT — always, every boot ***/
// If button held, we stay #woke
// If not it must've been the RTC - check alarms
// If there's an alarm or the button was held, do a full boot
// Full boot will handle things from there
// only truly wake up if we saw it on EXT0, or from alarm
/*if (!rtc_is_set()) {
//ESP_LOGI("MAIN", "RTC is not set. Can't sleep til then.");
} else */if (cause == ESP_SLEEP_WAKEUP_EXT0) {
ESP_LOGI("MAIN", "Woke from button press");
} else {
if (!rtc_alarm_tripped() && !first_boot) {
rtc_enter_deep_sleep();
}
}
first_boot = false;
/*** FULL BOOT ***/
if (uart_init() != ESP_OK) ESP_LOGE(TAG, "UART FAILED"); if (uart_init() != ESP_OK) ESP_LOGE(TAG, "UART FAILED");
//if (power_init() != ESP_OK) ESP_LOGE(TAG, "POWER FAILED"); //if (power_init() != ESP_OK) ESP_LOGE(TAG, "POWER FAILED");
if (rf_433_init() != ESP_OK) ESP_LOGE(TAG, "RF FAILED"); if (rf_433_init() != ESP_OK) ESP_LOGE(TAG, "RF FAILED");
@@ -252,8 +231,10 @@ void app_main(void) {esp_task_wdt_add(NULL);
i2c_poll_buttons(); i2c_poll_buttons();
if (i2c_get_button_state(0)) if (i2c_get_button_state(0)) {
rtc_reset_shutdown_timer(); rtc_reset_shutdown_timer();
soft_idle_exit();
}
switch (fsm_get_state()) { switch (fsm_get_state()) {
case STATE_IDLE: case STATE_IDLE:
@@ -285,8 +266,8 @@ void app_main(void) {esp_task_wdt_add(NULL);
i2c_set_led1(state); i2c_set_led1(state);
} }
// when not actively moving we log at a low frequency // when not actively moving we log at a low frequency (every 120s)
if ((esp_timer_get_time() > last_bat_log_time + DEEP_SLEEP_US)) if ((esp_timer_get_time() > last_bat_log_time + 120000000ULL))
send_bat_log(); send_bat_log();
if(i2c_get_button_ms(0) > 2100) if(i2c_get_button_ms(0) > 2100)
@@ -340,13 +321,17 @@ void app_main(void) {esp_task_wdt_add(NULL);
if (rtc_alarm_tripped()) { if (rtc_alarm_tripped()) {
bool was_idle = soft_idle_is_active();
soft_idle_exit();
if (was_idle) {
// Give WiFi softAP time to come up before movement begins
vTaskDelay(pdMS_TO_TICKS(500));
}
fsm_request(FSM_CMD_START); fsm_request(FSM_CMD_START);
rtc_schedule_next_alarm(); rtc_schedule_next_alarm();
} }
solar_run_fsm(); solar_run_fsm();
rtc_save_time(); // Keep RTC backup fresh so crashes don't lose time
rtc_check_shutdown_timer(); rtc_check_shutdown_timer();
esp_task_wdt_reset(); esp_task_wdt_reset();
} }

View File

@@ -8,6 +8,7 @@
*/ */
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h>
#include <time.h> #include <time.h>
#include <sys/time.h> #include <sys/time.h>
@@ -15,58 +16,55 @@
#include "rtc.h" #include "rtc.h"
#include "control_fsm.h" #include "control_fsm.h"
#include "esp_sleep.h" #include "esp_sleep.h"
#include "i2c.h" // for lcd_off() #include "esp_timer.h"
#include "i2c.h"
#include "driver/gpio.h" #include "driver/gpio.h"
#include "rtc_wdt.h" #include "rtc_wdt.h"
#include "esp_sleep.h"
#include "esp_log.h" #include "esp_log.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "i2c.h"
#include "rtc_wdt.h" #include "rtc_wdt.h"
#include "soc/rtc.h"
// External 32kHz crystal enabled via CONFIG_RTC_CLK_SRC_EXT_CRYS in sdkconfig.defaults
#include "driver/rtc_io.h" // For RTC I/O handling (optional but recommended for pin configuration)
#include "soc/rtc.h" // For rtc_clk_slow_src_get()
#include "solar.h" #include "solar.h"
#include "storage.h" #include "storage.h"
#include "webserver.h"
#include "bt_hid.h"
#define PIN_BTN_INTERRUPT GPIO_NUM_13 #define PIN_BTN_INTERRUPT GPIO_NUM_13
// Return microseconds from the RTC hardware timer.
// Used ONLY in rtc_restore_time() for crash-recovery (survives panics/WDT via RTC domain).
// RC oscillator drift (~150 kHz, ±5%) is negligible over a <30s crash restart (~1.5s worst case).
static uint64_t rtc_hw_time_us(void)
{
uint32_t cal = rtc_clk_cal(RTC_CAL_RTC_MUX, 20);
uint64_t ticks = rtc_time_get();
return (ticks * (uint64_t)cal) >> 19;
}
uint64_t last_activity_tick = 0; uint64_t last_activity_tick = 0;
// RTC_DATA_ATTR keeps these in RTC memory; persists across deep sleep AND software resets (panics, WDT) // RTC_DATA_ATTR keeps these in RTC memory; persists across software resets (panics, WDT)
RTC_DATA_ATTR int64_t next_alarm_time_s = -1; RTC_DATA_ATTR int64_t next_alarm_time_s = -1;
RTC_DATA_ATTR bool rtc_set = false; RTC_DATA_ATTR bool rtc_set = false;
RTC_DATA_ATTR int64_t rtc_backup_s = 0; // Crash-safe time snapshot RTC_DATA_ATTR int64_t sync_unix_us = 0; // Unix time in µs at last rtc_set_s() call
RTC_DATA_ATTR uint64_t sync_rtc_us = 0; // rtc_hw_time_us() at last rtc_set_s() call (for crash recovery)
// esp_timer value at last rtc_set_s() call. NOT RTC_DATA_ATTR — resets on every boot;
// rtc_restore_time() reinitialises it from the RTC hardware counter on crash recovery.
static uint64_t sync_esp_us = 0;
static bool in_soft_idle = false;
bool rtc_is_set() { bool rtc_is_set() {
return rtc_set; return rtc_set;
} }
esp_err_t rtc_xtal_init(void) { esp_err_t rtc_xtal_init(void) {
/* ---- Wake sources ---- */ // 32kHz crystal no longer used — time tracking via esp_timer (40MHz APB crystal).
esp_sleep_enable_ext0_wakeup(PIN_BTN_INTERRUPT, 0); // Just configure the button GPIO; no sleep wakeup sources needed.
gpio_set_direction(PIN_BTN_INTERRUPT, GPIO_MODE_INPUT); gpio_set_direction(PIN_BTN_INTERRUPT, GPIO_MODE_INPUT);
gpio_set_pull_mode(PIN_BTN_INTERRUPT, GPIO_PULLUP_ONLY); gpio_set_pull_mode(PIN_BTN_INTERRUPT, GPIO_PULLUP_ONLY);
esp_sleep_enable_ext0_wakeup(PIN_BTN_INTERRUPT, 0);
/* ---- Enable External 32 kHz Oscillator ---- */
// Configure RTC I/O pins for crystal (hold in reset initially if needed)
rtc_gpio_init(GPIO_NUM_32);
rtc_gpio_init(GPIO_NUM_33);
rtc_gpio_set_direction(GPIO_NUM_32, RTC_GPIO_MODE_DISABLED);
rtc_gpio_set_direction(GPIO_NUM_33, RTC_GPIO_MODE_DISABLED);
// 32kHz crystal selected as slow clock source via CONFIG_RTC_CLK_SRC_EXT_CRYS.
// Verify at runtime that the clock source is actually the external crystal.
soc_rtc_slow_clk_src_t slow_src = rtc_clk_slow_src_get();
if (slow_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
ESP_LOGI("RTC", "Slow clock: external 32kHz crystal");
} else {
ESP_LOGW("RTC", "Slow clock source is %d — expected XTAL32K (%d). Check sdkconfig.",
(int)slow_src, (int)SOC_RTC_SLOW_CLK_SRC_XTAL32K);
}
return ESP_OK; return ESP_OK;
} }
@@ -76,54 +74,84 @@ void rtc_reset_shutdown_timer(void)
rtc_wdt_feed(); rtc_wdt_feed();
} }
void rtc_enter_deep_sleep(void) void soft_idle_enter(void)
{ {
//close_current_log(); if (in_soft_idle) return;
fsm_request(FSM_CMD_STOP); in_soft_idle = true;
i2c_stop(); ESP_LOGI("RTC", "Entering soft idle (WiFi/BT off, LEDs off)");
esp_sleep_enable_timer_wakeup(DEEP_SLEEP_US); webserver_stop();
esp_deep_sleep_start(); bt_hid_stop();
i2c_set_led1(0);
}
bool soft_idle_is_active(void) { return in_soft_idle; }
void soft_idle_exit(void)
{
if (!in_soft_idle) return;
in_soft_idle = false;
ESP_LOGI("RTC", "Exiting soft idle");
webserver_restart_wifi();
bt_hid_resume();
rtc_reset_shutdown_timer();
} }
int64_t rtc_get_s(void) int64_t rtc_get_s(void)
{ {
struct timeval tv; if (!rtc_set) return 0;
gettimeofday(&tv, NULL); return (int64_t)(sync_unix_us / 1000000LL)
return (int64_t)tv.tv_sec; + (int64_t)((esp_timer_get_time() - sync_esp_us) / 1000000LL);
} }
void rtc_set_s(int64_t tv_sec) void rtc_set_s(int64_t tv_sec)
{ {
rtc_set = true; sync_unix_us = tv_sec * 1000000LL;
settimeofday(&(struct timeval){.tv_sec = tv_sec, .tv_usec=0}, NULL); sync_rtc_us = rtc_hw_time_us(); // kept for crash recovery in rtc_restore_time()
rtc_backup_s = tv_sec; sync_esp_us = (uint64_t)esp_timer_get_time();
rtc_set = true;
// Keep stdlib (gmtime_r etc.) in sync
settimeofday(&(struct timeval){.tv_sec = tv_sec, .tv_usec = 0}, NULL);
solar_reset_fsm(); solar_reset_fsm();
rtc_schedule_next_alarm(); rtc_schedule_next_alarm();
uint64_t ts_ms = (uint64_t)tv_sec * 1000ULL; uint64_t ts_ms = (uint64_t)tv_sec * 1000ULL;
log_write((uint8_t*)&ts_ms, sizeof(ts_ms), LOG_TYPE_TIME_SET); log_write((uint8_t*)&ts_ms, sizeof(ts_ms), LOG_TYPE_TIME_SET);
// Parseable marker used by logtool/rtc_test.py to compare device vs host time
ESP_LOGI("RTC", "TIME unix=%lld src=SYNC uptime=%llds",
(long long)tv_sec,
(long long)(esp_timer_get_time() / 1000000ULL));
} }
void rtc_save_time(void) void rtc_save_time(void)
{ {
if (rtc_set) // No-op: time is always derivable from sync_unix_us + rtc_hw_time_us() delta,
rtc_backup_s = rtc_get_s(); // both of which survive deep sleep and crashes via RTC_DATA_ATTR / RTC hardware.
} }
void rtc_restore_time(void) void rtc_restore_time(void)
{ {
if (rtc_set && rtc_backup_s > 0) { if (!rtc_set) return;
settimeofday(&(struct timeval){.tv_sec = rtc_backup_s, .tv_usec = 0}, NULL); // Recover time via RTC hardware counter (survives panics/WDT resets via RTC domain).
ESP_LOGI("RTC", "Time restored from crash backup: %lld", (long long)rtc_backup_s); // RC drift during a <30s crash restart is ~1.5s worst case — acceptable.
} int64_t t = (sync_unix_us + (int64_t)(rtc_hw_time_us() - sync_rtc_us)) / 1000000LL;
// Anchor esp_timer tracking to recovered time — APB timer resets on every boot.
sync_unix_us = t * 1000000LL;
sync_esp_us = (uint64_t)esp_timer_get_time();
// Re-sync the stdlib clock (gettimeofday) for gmtime_r() etc.
settimeofday(&(struct timeval){.tv_sec = t, .tv_usec = 0}, NULL);
ESP_LOGI("RTC", "TIME unix=%lld src=CRASH uptime=%llds",
(long long)t,
(long long)(esp_timer_get_time() / 1000000ULL));
} }
int64_t rtc_get_ms(void) int64_t rtc_get_ms(void)
{ {
struct timeval tv; if (!rtc_set) return 0;
gettimeofday(&tv, NULL); return sync_unix_us / 1000LL
return (int64_t)tv.tv_sec * 1000ULL + tv.tv_usec / 1000ULL; + (int64_t)((esp_timer_get_time() - sync_esp_us) / 1000LL);
} }
int64_t rtc_get_s_in_day(void) int64_t rtc_get_s_in_day(void)
@@ -147,10 +175,9 @@ esp_sleep_wakeup_cause_t rtc_wakeup_cause(void)
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
void rtc_check_shutdown_timer(void) void rtc_check_shutdown_timer(void)
{ {
TickType_t elapsed = xTaskGetTickCount() - last_activity_tick; TickType_t elapsed = xTaskGetTickCount() - last_activity_tick;
if (elapsed * portTICK_PERIOD_MS >= POWER_INACTIVITY_TIMEOUT_MS) if (elapsed * portTICK_PERIOD_MS >= POWER_INACTIVITY_TIMEOUT_MS)
rtc_enter_deep_sleep(); soft_idle_enter();
} }
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
@@ -253,3 +280,75 @@ bool rtc_alarm_tripped() {
} }
return rtc_get_s() > next_alarm_time_s; return rtc_get_s() > next_alarm_time_s;
} }
static const char *reset_reason_str(esp_reset_reason_t r) {
switch (r) {
case ESP_RST_POWERON: return "POWER_ON";
case ESP_RST_EXT: return "EXT_PIN";
case ESP_RST_SW: return "SOFTWARE";
case ESP_RST_PANIC: return "PANIC";
case ESP_RST_INT_WDT: return "INT_WDT";
case ESP_RST_TASK_WDT: return "TASK_WDT";
case ESP_RST_WDT: return "OTHER_WDT";
case ESP_RST_DEEPSLEEP: return "DEEP_SLEEP";
case ESP_RST_BROWNOUT: return "BROWNOUT";
case ESP_RST_SDIO: return "SDIO";
default: return "UNKNOWN";
}
}
static const char *wakeup_cause_str(esp_sleep_wakeup_cause_t c) {
switch (c) {
case ESP_SLEEP_WAKEUP_UNDEFINED: return "UNDEFINED (normal boot/reset)";
case ESP_SLEEP_WAKEUP_EXT0: return "EXT0 (button)";
case ESP_SLEEP_WAKEUP_TIMER: return "TIMER";
default: return "OTHER";
}
}
void rtc_print_debug(void)
{
int64_t now_s = rtc_get_s();
int64_t uptime = (int64_t)(esp_timer_get_time() / 1000000ULL);
// Human-readable timestamps
char now_str[32] = "N/A";
char sync_str[32] = "N/A";
char alarm_str[32] = "N/A";
if (rtc_set) {
time_t t;
struct tm tm;
t = (time_t)now_s; gmtime_r(&t, &tm);
strftime(now_str, sizeof(now_str), "%Y-%m-%d %H:%M:%S", &tm);
t = (time_t)(sync_unix_us / 1000000LL); gmtime_r(&t, &tm);
strftime(sync_str, sizeof(sync_str), "%Y-%m-%d %H:%M:%S", &tm);
if (next_alarm_time_s > 0) {
t = (time_t)next_alarm_time_s; gmtime_r(&t, &tm);
strftime(alarm_str, sizeof(alarm_str), "%Y-%m-%d %H:%M:%S", &tm);
}
}
esp_reset_reason_t reset = esp_reset_reason();
esp_sleep_wakeup_cause_t wake = esp_sleep_get_wakeup_cause();
printf("\n=== RTC DEBUG ===\n");
printf(" reset_reason: %s (%d)\n", reset_reason_str(reset), (int)reset);
printf(" wakeup_cause: %s (%d)\n", wakeup_cause_str(wake), (int)wake);
printf(" time_source: esp_timer (40MHz APB crystal, ~20ppm)\n");
printf(" 32kHz_xtal: NOT USED (deep sleep disabled)\n");
printf("\n");
uint64_t esp_us_now = (uint64_t)esp_timer_get_time();
uint64_t elapsed_s = rtc_set ? (esp_us_now - sync_esp_us) / 1000000ULL : 0;
printf(" rtc_set: %s\n", rtc_set ? "true" : "false");
printf(" current_time: %lld (%s UTC)\n", (long long)now_s, now_str);
printf(" sync_time: %lld (%s UTC)\n", (long long)(sync_unix_us / 1000000LL), sync_str);
printf(" elapsed_since_sync:%llus\n", (unsigned long long)elapsed_s);
printf(" next_alarm_s: %lld (%s UTC)\n", (long long)next_alarm_time_s, alarm_str);
printf("\n");
printf(" uptime: %llds\n", (long long)uptime);
printf(" esp_timer_us: %llu\n", (unsigned long long)esp_us_now);
printf(" soft_idle: %s\n", in_soft_idle ? "YES" : "no");
printf("=================\n\n");
}

View File

@@ -20,7 +20,6 @@
#define POWER_INACTIVITY_TIMEOUT_MS 180000 #define POWER_INACTIVITY_TIMEOUT_MS 180000
#define DEEP_SLEEP_US 120000000ULL /* 120 seconds in deep sleep */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* Public API */ /* Public API */
@@ -33,7 +32,9 @@ bool rtc_is_set();
void rtc_check_shutdown_timer(); void rtc_check_shutdown_timer();
void rtc_reset_shutdown_timer(); // reset shutoff timer void rtc_reset_shutdown_timer(); // reset shutoff timer
void rtc_enter_deep_sleep(); void soft_idle_enter(void);
void soft_idle_exit(void);
bool soft_idle_is_active(void);
esp_sleep_wakeup_cause_t rtc_wakeup_cause(); esp_sleep_wakeup_cause_t rtc_wakeup_cause();
/*void adjust_rtc_hour(char *key, int8_t dir); /*void adjust_rtc_hour(char *key, int8_t dir);
@@ -43,13 +44,15 @@ int64_t rtc_get_s (void);
int64_t rtc_get_ms(void); int64_t rtc_get_ms(void);
void rtc_set_s(int64_t); void rtc_set_s(int64_t);
void rtc_save_time(void); // Snapshot current time to RTC memory (call periodically) void rtc_save_time(void); // No-op: time is always live via rtc_get_s()
void rtc_restore_time(void); // Restore time from RTC backup after a crash reboot void rtc_restore_time(void); // Re-syncs stdlib clock on boot; emits TIME log marker
void rtc_schedule_next_alarm(void); void rtc_schedule_next_alarm(void);
int64_t rtc_get_next_alarm_s(); int64_t rtc_get_next_alarm_s();
bool rtc_alarm_tripped(); bool rtc_alarm_tripped();
void rtc_print_debug(void); // Dump full RTC state to stdout (UART)
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
#endif /* MAIN_RTC_H_ */ #endif /* MAIN_RTC_H_ */

View File

@@ -98,10 +98,10 @@ static void cmd_post(char *json_data) {
} }
if (should_sleep) { if (should_sleep) {
printf("\nEntering deep sleep in 2 seconds...\n"); printf("\nEntering soft idle in 2 seconds...\n");
fflush(stdout); fflush(stdout);
vTaskDelay(pdMS_TO_TICKS(2000)); vTaskDelay(pdMS_TO_TICKS(2000));
rtc_enter_deep_sleep(); soft_idle_enter();
} }
} }
@@ -111,6 +111,7 @@ static void cmd_help(void) {
printf("\nCommands:\n"); printf("\nCommands:\n");
printf(" GET - Get complete system status (JSON)\n"); printf(" GET - Get complete system status (JSON)\n");
printf(" POST: {json} - Send command or update parameters (JSON)\n"); printf(" POST: {json} - Send command or update parameters (JSON)\n");
printf(" RTCDEBUG - Dump RTC timekeeping state (time, backup, sleep entry, clock source)\n");
printf(" HELP - Show this help\n"); printf(" HELP - Show this help\n");
printf("\nPOST JSON Format:\n"); printf("\nPOST JSON Format:\n");
printf("{\n"); printf("{\n");
@@ -186,6 +187,9 @@ static void process_command(char *cmd) {
else if (strcmp(command, "HELP") == 0) { else if (strcmp(command, "HELP") == 0) {
cmd_help(); cmd_help();
} }
else if (strcmp(command, "RTCDEBUG") == 0) {
rtc_print_debug();
}
else { else {
printf("ERROR: Unknown command '%s'\n", command); printf("ERROR: Unknown command '%s'\n", command);
printf("Type 'HELP' for available commands\n"); printf("Type 'HELP' for available commands\n");

File diff suppressed because one or more lines are too long

View File

@@ -4,7 +4,7 @@
#include <Arduino.h> #include <Arduino.h>
const unsigned char PROGMEM html_content_gz[] = { const unsigned char PROGMEM html_content_gz[] = {
0x1f, 0x8b, 0x08, 0x00, 0x4f, 0x8d, 0xa8, 0x69, 0x02, 0xff, 0xed, 0x3d, 0x69, 0x77, 0xdb, 0x46, 0x1f, 0x8b, 0x08, 0x00, 0x6c, 0xcb, 0xb0, 0x69, 0x02, 0xff, 0xed, 0x3d, 0x69, 0x77, 0xdb, 0x46,
0x92, 0x9f, 0x27, 0xbf, 0xa2, 0xa5, 0x38, 0x0a, 0x60, 0x83, 0x20, 0x29, 0xc9, 0x49, 0x86, 0x14, 0x92, 0x9f, 0x27, 0xbf, 0xa2, 0xa5, 0x38, 0x0a, 0x60, 0x83, 0x20, 0x29, 0xc9, 0x49, 0x86, 0x14,
0xa8, 0x91, 0x25, 0x7a, 0xe2, 0xd8, 0x3a, 0x9e, 0x0e, 0x27, 0xb3, 0x1a, 0x3d, 0x01, 0x24, 0x9a, 0xa8, 0x91, 0x25, 0x7a, 0xe2, 0xd8, 0x3a, 0x9e, 0x0e, 0x27, 0xb3, 0x1a, 0x3d, 0x01, 0x24, 0x9a,
0x22, 0x22, 0x10, 0x60, 0x00, 0x50, 0xb2, 0x06, 0xe2, 0x7f, 0xdf, 0xaa, 0x3e, 0x80, 0xc6, 0x41, 0x22, 0x22, 0x10, 0x60, 0x00, 0x50, 0xb2, 0x06, 0xe2, 0x7f, 0xdf, 0xaa, 0x3e, 0x80, 0xc6, 0x41,

View File

@@ -529,10 +529,10 @@ static esp_err_t post_handler(httpd_req_t *req) {
} }
if (should_sleep) { if (should_sleep) {
ESP_LOGI(TAG, "Sleeping in 2 seconds..."); ESP_LOGI(TAG, "Entering soft idle in 2 seconds...");
vTaskDelay(pdMS_TO_TICKS(2000)); vTaskDelay(pdMS_TO_TICKS(2000));
rtc_enter_deep_sleep(); soft_idle_enter();
return ESP_OK; // Never reached return ESP_OK;
} }
err = httpd_resp_set_hdr(req, "Connection", "close"); err = httpd_resp_set_hdr(req, "Connection", "close");
@@ -794,6 +794,7 @@ httpd_uri_t uris[] = {{
**********************************************************/ **********************************************************/
bool server_running = false; bool server_running = false;
static bool s_wifi_running = false;
static esp_err_t start_http_server(void) { static esp_err_t start_http_server(void) {
if (server_running) return ESP_OK; if (server_running) return ESP_OK;
@@ -999,6 +1000,7 @@ static esp_err_t launch_soft_ap(void) {
ESP_LOGE(TAG, "Failed to start WiFi: %s", esp_err_to_name(err)); ESP_LOGE(TAG, "Failed to start WiFi: %s", esp_err_to_name(err));
return err; return err;
} }
s_wifi_running = true;
// Start DNS server with your specific hostname // Start DNS server with your specific hostname
err = simple_dns_server_start("192.168.4.1"); err = simple_dns_server_start("192.168.4.1");
@@ -1040,11 +1042,23 @@ static esp_err_t launch_soft_ap(void) {
return ESP_OK; return ESP_OK;
} }
esp_err_t webserver_stop(void) {
stop_http_server();
if (s_wifi_running) {
esp_wifi_stop();
s_wifi_running = false;
}
return ESP_OK;
}
esp_err_t webserver_restart_wifi(void) { esp_err_t webserver_restart_wifi(void) {
ESP_LOGI(TAG, "Restarting WiFi AP with updated params..."); ESP_LOGI(TAG, "Restarting WiFi AP with updated params...");
stop_http_server(); stop_http_server();
esp_wifi_stop(); if (s_wifi_running) {
esp_wifi_stop();
s_wifi_running = false;
}
wifi_config_t wifi_config = { wifi_config_t wifi_config = {
.ap = { .ap = {
@@ -1068,6 +1082,7 @@ esp_err_t webserver_restart_wifi(void) {
esp_wifi_set_config(WIFI_IF_AP, &wifi_config); esp_wifi_set_config(WIFI_IF_AP, &wifi_config);
esp_wifi_start(); esp_wifi_start();
s_wifi_running = true;
start_http_server(); start_http_server();
ESP_LOGI(TAG, "WiFi AP restarted. New SSID: %s, Channel: %d", ESP_LOGI(TAG, "WiFi AP restarted. New SSID: %s, Channel: %d",

View File

@@ -2,3 +2,4 @@
esp_err_t webserver_init(void); esp_err_t webserver_init(void);
esp_err_t webserver_restart_wifi(void); // Reconfigure and restart AP with current params esp_err_t webserver_restart_wifi(void); // Reconfigure and restart AP with current params
esp_err_t webserver_stop(void); // Stop HTTP server and WiFi (for soft idle)

View File

@@ -1079,11 +1079,11 @@ CONFIG_ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS=y
CONFIG_RTC_CLK_SRC_EXT_CRYS=y CONFIG_RTC_CLK_SRC_EXT_CRYS=y
# CONFIG_RTC_CLK_SRC_EXT_OSC is not set # CONFIG_RTC_CLK_SRC_EXT_OSC is not set
# CONFIG_RTC_CLK_SRC_INT_8MD256 is not set # CONFIG_RTC_CLK_SRC_INT_8MD256 is not set
CONFIG_RTC_EXT_CRYST_ADDIT_CURRENT_NONE=y # CONFIG_RTC_EXT_CRYST_ADDIT_CURRENT_NONE is not set
# CONFIG_RTC_EXT_CRYST_ADDIT_CURRENT is not set # CONFIG_RTC_EXT_CRYST_ADDIT_CURRENT is not set
# CONFIG_RTC_EXT_CRYST_ADDIT_CURRENT_V2 is not set CONFIG_RTC_EXT_CRYST_ADDIT_CURRENT_V2=y
CONFIG_RTC_CLK_CAL_CYCLES=1024 CONFIG_RTC_CLK_CAL_CYCLES=1024
CONFIG_RTC_XTAL_CAL_RETRY=1 CONFIG_RTC_XTAL_CAL_RETRY=3
# end of RTC Clock Config # end of RTC Clock Config
# #
@@ -1205,7 +1205,7 @@ CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y
# CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set # CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set
CONFIG_ESP_SYSTEM_PANIC_REBOOT_DELAY_SECONDS=0 CONFIG_ESP_SYSTEM_PANIC_REBOOT_DELAY_SECONDS=0
CONFIG_ESP_SYSTEM_RTC_EXT_XTAL=y CONFIG_ESP_SYSTEM_RTC_EXT_XTAL=y
CONFIG_ESP_SYSTEM_RTC_EXT_XTAL_BOOTSTRAP_CYCLES=5 CONFIG_ESP_SYSTEM_RTC_EXT_XTAL_BOOTSTRAP_CYCLES=500
# #
# Memory protection # Memory protection
@@ -2422,12 +2422,12 @@ CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL=y
# CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_OSC is not set # CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_OSC is not set
# CONFIG_ESP32_RTC_CLK_SRC_INT_8MD256 is not set # CONFIG_ESP32_RTC_CLK_SRC_INT_8MD256 is not set
# CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_8MD256 is not set # CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_8MD256 is not set
CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT_NONE=y # CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT_NONE is not set
# CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT is not set # CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT is not set
# CONFIG_ESP32_RTC_EXTERNAL_CRYSTAL_ADDITIONAL_CURRENT is not set # CONFIG_ESP32_RTC_EXTERNAL_CRYSTAL_ADDITIONAL_CURRENT is not set
# CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT_V2 is not set CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT_V2=y
CONFIG_ESP32_RTC_CLK_CAL_CYCLES=1024 CONFIG_ESP32_RTC_CLK_CAL_CYCLES=1024
CONFIG_ESP32_RTC_XTAL_CAL_RETRY=1 CONFIG_ESP32_RTC_XTAL_CAL_RETRY=3
# CONFIG_ESP32_XTAL_FREQ_26 is not set # CONFIG_ESP32_XTAL_FREQ_26 is not set
CONFIG_ESP32_XTAL_FREQ_40=y CONFIG_ESP32_XTAL_FREQ_40=y
# CONFIG_ESP32_XTAL_FREQ_AUTO is not set # CONFIG_ESP32_XTAL_FREQ_AUTO is not set
@@ -2449,7 +2449,7 @@ CONFIG_TRACEMEM_RESERVE_DRAM=0x0
CONFIG_ESP32_PANIC_PRINT_REBOOT=y CONFIG_ESP32_PANIC_PRINT_REBOOT=y
# CONFIG_ESP32_PANIC_SILENT_REBOOT is not set # CONFIG_ESP32_PANIC_SILENT_REBOOT is not set
# CONFIG_ESP32_PANIC_GDBSTUB is not set # CONFIG_ESP32_PANIC_GDBSTUB is not set
CONFIG_ESP32_RTC_XTAL_BOOTSTRAP_CYCLES=5 CONFIG_ESP32_RTC_XTAL_BOOTSTRAP_CYCLES=500
CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32
CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304 CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304
CONFIG_MAIN_TASK_STACK_SIZE=3584 CONFIG_MAIN_TASK_STACK_SIZE=3584

View File

@@ -5,3 +5,18 @@
# Use external 32kHz crystal for the RTC slow clock (GPIO32/33 on the PCB). # Use external 32kHz crystal for the RTC slow clock (GPIO32/33 on the PCB).
# This gives accurate timekeeping across deep sleep instead of the +/-5% internal RC. # This gives accurate timekeeping across deep sleep instead of the +/-5% internal RC.
CONFIG_RTC_CLK_SRC_EXT_CRYS=y CONFIG_RTC_CLK_SRC_EXT_CRYS=y
# Enable additional drive current for the external 32kHz crystal.
# Required for high-ESR tuning-fork crystals (e.g. CM315D32768DZFT ~70kΩ ESR, CL=12.5pF).
# Without this the ESP32 oscillator can't drive the crystal reliably.
# V2 injects extra current only during the oscillation startup window.
CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT_V2=y
# Increase bootstrap cycles for high-ESR crystal.
# Default of 5 is insufficient; 500 gives the oscillator enough time to build amplitude.
CONFIG_ESP_SYSTEM_RTC_EXT_XTAL_BOOTSTRAP_CYCLES=500
CONFIG_ESP32_RTC_XTAL_BOOTSTRAP_CYCLES=500
# Allow more calibration retries before falling back to RC oscillator.
CONFIG_RTC_XTAL_CAL_RETRY=3
CONFIG_ESP32_RTC_XTAL_CAL_RETRY=3