diff --git a/.gitignore b/.gitignore index 40b795c..d29451d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .obsidian sdkconfig.esp32-c6-devkitm-1 -.pio/build +.pio +.vscode diff --git a/PLANS.md b/PLANS.md index 6291c86..663b6c0 100644 --- a/PLANS.md +++ b/PLANS.md @@ -114,7 +114,7 @@ If all criteria pass, set this milestone to `DONE`, append its execution record, ## Milestone 001 — Prove build, flashing, and stable basic operation -**Status:** `IN PROGRESS` +**Status:** `DONE` **Depends on:** Milestone 000 ### Objective @@ -153,11 +153,21 @@ Prove that the configuration selected in Milestone 000 works reliably on the phy If all criteria pass, set this milestone to `DONE`, append its execution record, and change Milestone 002 from `BLOCKED` to `READY`. +Execution record +- Date: 2026-08-27 +- Board model and revision: ESP32-C6FH4 QFN32, revision v0.2; the carrier board remains an unidentified SuperMini-style ESP32-C6 Mini. +- Toolchain and library versions: PlatformIO Core 6.1.19; `espressif32` 7.0.1; ESP-IDF 6.0.1; esptool.py 4.11.0; RISC-V toolchain 15.2.0+20251204. +- Result: PASS +- Evidence: `src/main.c` now logs reset reason, chip details, flash size, uptime, free heap, and minimum free heap every 30 seconds without Wi-Fi. `platformio.ini`, `sdkconfig.esp32-c6-devkitm-1`, and `partitions.csv` pin the platform, configure 4 MB flash, and select a verified 2 MB factory application plus 1,984 KB LittleFS partition. Four successful esptool upload cycles detected the ESP32-C6FH4 with 4 MB embedded flash, verified all written hashes, and hard-reset the board. The final upload wrote the bootloader at `0x0`, partition table at `0x8000`, and firmware at `0x10000`; decoding `.pio/build/esp32-c6-devkitm-1/partitions.bin` confirmed the configured NVS, PHY, factory, and LittleFS partitions. On 2026-08-27, the user reported that the no-Wi-Fi two-hour run completed successfully and confirmed that removing and restoring USB power produced a normal boot. +- Measurements: Final clean build: RAM 11,116 / 327,680 bytes (3.4%); firmware 161,288 / 2,097,152 bytes (7.7%). Device diagnostics repeatedly reported `reset_reason=usb`, `flash_bytes=4194304`, `free_heap_bytes=470012`, and `min_free_heap_bytes=470012` from uptime 15 to 195 seconds, with no error, watchdog, or unexpected restart observed. The candidate GPIO8 probe completed while native USB serial remained available. +- Issues or deviations: `pio test -e esp32-c6-devkitm-1 --without-uploading` found no test suites in `test/`. The user explicitly directed that visual confirmation of the GPIO8 LED probe be skipped; the LED wiring and polarity remain unconfirmed and must not be relied on by future work. +- Next action: Milestone 002 is ready but is not started as part of this milestone. + --- ## Milestone 002 — Prove the Wi-Fi, LittleFS, and HTTP vertical slice -**Status:** `BLOCKED` +**Status:** `READY` **Depends on:** Milestone 001 ### Objective diff --git a/partitions.csv b/partitions.csv new file mode 100644 index 0000000..60321a6 --- /dev/null +++ b/partitions.csv @@ -0,0 +1,5 @@ +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x6000, +phy_init, data, phy, 0xf000, 0x1000, +factory, app, factory, 0x10000, 0x200000, +littlefs, data, littlefs,0x210000, 0x1f0000, diff --git a/platformio.ini b/platformio.ini index fa46822..c947a06 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,6 +9,9 @@ ; https://docs.platformio.org/page/projectconf.html [env:esp32-c6-devkitm-1] -platform = espressif32 +platform = espressif32 @ 7.0.1 board = esp32-c6-devkitm-1 framework = espidf +board_build.partitions = partitions.csv +monitor_port = /dev/ttyACM0 +monitor_speed = 115200 diff --git a/src/main.c b/src/main.c index 3b5b685..0d4f8d5 100644 --- a/src/main.c +++ b/src/main.c @@ -1 +1,141 @@ -void app_main() {} \ No newline at end of file +#include +#include +#include + +#include "driver/gpio.h" +#include "esp_chip_info.h" +#include "esp_err.h" +#include "esp_flash.h" +#include "esp_log.h" +#include "esp_system.h" +#include "esp_timer.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +static const char *const kLogTag = "bringup"; +static const gpio_num_t kCandidateLedGpio = GPIO_NUM_8; +static const uint32_t kLedProbeCount = 10; +static const uint32_t kLedProbeIntervalMs = 500; +static const uint32_t kHealthIntervalMs = 30000; +static const uint32_t kStartupAttachmentDelayMs = 10000; + +static const char *reset_reason_name(esp_reset_reason_t reason) { + switch (reason) { + case ESP_RST_UNKNOWN: + return "unknown"; + case ESP_RST_POWERON: + return "power_on"; + case ESP_RST_EXT: + return "external"; + case ESP_RST_SW: + return "software"; + case ESP_RST_PANIC: + return "panic"; + case ESP_RST_INT_WDT: + return "interrupt_watchdog"; + case ESP_RST_TASK_WDT: + return "task_watchdog"; + case ESP_RST_WDT: + return "other_watchdog"; + case ESP_RST_DEEPSLEEP: + return "deep_sleep"; + case ESP_RST_BROWNOUT: + return "brownout"; + case ESP_RST_SDIO: + return "sdio"; + case ESP_RST_USB: + return "usb"; + case ESP_RST_JTAG: + return "jtag"; + case ESP_RST_EFUSE: + return "efuse"; + case ESP_RST_PWR_GLITCH: + return "power_glitch"; + case ESP_RST_CPU_LOCKUP: + return "cpu_lockup"; + } + + return "unrecognized"; +} + +static void log_heap(uint64_t uptime_ms) { + const size_t free_heap_bytes = esp_get_free_heap_size(); + const size_t minimum_free_heap_bytes = esp_get_minimum_free_heap_size(); + uint32_t flash_size_bytes = 0; + const esp_err_t flash_result = esp_flash_get_size(NULL, &flash_size_bytes); + + if (flash_result == ESP_OK) { + ESP_LOGI(kLogTag, + "health uptime_ms=%" PRIu64 " reset_reason=%s flash_bytes=%" PRIu32 + " free_heap_bytes=%u min_free_heap_bytes=%u", + uptime_ms, + reset_reason_name(esp_reset_reason()), + flash_size_bytes, + (unsigned int)free_heap_bytes, + (unsigned int)minimum_free_heap_bytes); + } else { + ESP_LOGE(kLogTag, "health flash_size_failed=%s", esp_err_to_name(flash_result)); + } +} + +static void probe_candidate_led(void) { + ESP_LOGI(kLogTag, + "led_probe gpio=%d transitions=%" PRIu32 " interval_ms=%" PRIu32 "; visually confirm the LED", + (int)kCandidateLedGpio, + kLedProbeCount, + kLedProbeIntervalMs); + + esp_err_t result = gpio_reset_pin(kCandidateLedGpio); + if (result != ESP_OK) { + ESP_LOGW(kLogTag, "led_probe gpio_reset_pin failed: %s", esp_err_to_name(result)); + return; + } + + result = gpio_set_direction(kCandidateLedGpio, GPIO_MODE_OUTPUT); + if (result != ESP_OK) { + ESP_LOGW(kLogTag, "led_probe gpio_set_direction failed: %s", esp_err_to_name(result)); + return; + } + + for (uint32_t transition = 0; transition < kLedProbeCount; ++transition) { + gpio_set_level(kCandidateLedGpio, transition % 2U); + vTaskDelay(pdMS_TO_TICKS(kLedProbeIntervalMs)); + } + + gpio_set_level(kCandidateLedGpio, 0); + ESP_LOGI(kLogTag, "led_probe complete; USB serial remained available during probe"); +} + +static void log_startup(void) { + esp_chip_info_t chip_info = {0}; + uint32_t flash_size_bytes = 0; + const esp_err_t flash_result = esp_flash_get_size(NULL, &flash_size_bytes); + + esp_chip_info(&chip_info); + ESP_LOGI(kLogTag, + "startup reset_reason=%s chip_model=%d chip_revision=%d cores=%d features=0x%08" PRIx32, + reset_reason_name(esp_reset_reason()), + (int)chip_info.model, + chip_info.revision, + chip_info.cores, + chip_info.features); + + if (flash_result == ESP_OK) { + ESP_LOGI(kLogTag, "startup flash_bytes=%" PRIu32, flash_size_bytes); + } else { + ESP_LOGE(kLogTag, "startup flash_size_failed=%s", esp_err_to_name(flash_result)); + } + + log_heap(0); +} + +void app_main(void) { + vTaskDelay(pdMS_TO_TICKS(kStartupAttachmentDelayMs)); + log_startup(); + probe_candidate_led(); + + while (true) { + log_heap((uint64_t)(esp_timer_get_time() / 1000)); + vTaskDelay(pdMS_TO_TICKS(kHealthIntervalMs)); + } +}