9 Commits
Author SHA1 Message Date
gronod d70df219f8 Mark I04 status DONE
ci / test (pull_request) Successful in 1m16s
ci / firmware (jc4827w543, sdkconfig.s3, esp32s3) (pull_request) Successful in 4m4s
ci / firmware (wroom, sdkconfig.wroom, esp32) (pull_request) Successful in 4m5s
ci / test (push) Successful in 1m13s
ci / firmware (wroom, sdkconfig.wroom, esp32) (push) Successful in 4m15s
ci / firmware (jc4827w543, sdkconfig.s3, esp32s3) (push) Successful in 4m19s
2026-09-16 22:28:17 +01:00
gronod 7e854e10f0 Add I2S speaker audio for S3
ci / test (push) Successful in 1m14s
ci / firmware (wroom, sdkconfig.wroom, esp32) (push) Successful in 4m26s
ci / firmware (jc4827w543, sdkconfig.s3, esp32s3) (push) Successful in 4m28s
2026-09-16 22:20:53 +01:00
gronod b6c385e09c Mark I03 status DONE
ci / test (pull_request) Successful in 1m14s
ci / test (push) Successful in 1m17s
ci / firmware (wroom, sdkconfig.wroom, esp32) (pull_request) Successful in 3m48s
ci / firmware (jc4827w543, sdkconfig.s3, esp32s3) (pull_request) Successful in 3m57s
ci / firmware (wroom, sdkconfig.wroom, esp32) (push) Successful in 4m4s
ci / firmware (jc4827w543, sdkconfig.s3, esp32s3) (push) Successful in 4m8s
2026-09-16 21:58:26 +01:00
gronod a9f76ea058 Share RMT motor HAL across both boards
ci / test (push) Successful in 1m18s
ci / firmware (wroom, sdkconfig.wroom, esp32) (push) Successful in 4m30s
ci / firmware (jc4827w543, sdkconfig.s3, esp32s3) (push) Successful in 4m39s
2026-09-16 21:51:32 +01:00
gronod c40c714028 Mark I02 status DONE
ci / test (pull_request) Successful in 1m13s
ci / firmware (wroom, sdkconfig.wroom, esp32) (pull_request) Successful in 4m39s
ci / firmware (jc4827w543, sdkconfig.s3, esp32s3) (pull_request) Successful in 4m41s
ci / test (push) Successful in 1m8s
ci / firmware (wroom, sdkconfig.wroom, esp32) (push) Successful in 4m9s
ci / firmware (jc4827w543, sdkconfig.s3, esp32s3) (push) Successful in 4m15s
2026-09-16 21:31:03 +01:00
gronod f87ab0c65f Fix temp_task starvation bug on non-WROOM
ci / test (push) Successful in 1m9s
ci / firmware (wroom, sdkconfig.wroom, esp32) (push) Successful in 4m9s
ci / firmware (jc4827w543, sdkconfig.s3, esp32s3) (push) Successful in 4m10s
2026-09-16 21:21:12 +01:00
gronod b4230b2a0e Share onewire temp HAL across both boards 2026-09-16 21:20:18 +01:00
gronod 04e1ed0f16 Merge pull request 'I01 board pin allocations & accessors' (#12) from feature/integration-I01 into develop
ci / test (push) Successful in 1m14s
ci / firmware (wroom, sdkconfig.wroom, esp32) (push) Successful in 4m46s
ci / firmware (jc4827w543, sdkconfig.s3, esp32s3) (push) Successful in 4m48s
Merge I01 board pin allocations & accessors into develop
2026-09-16 21:15:46 +01:00
gronod a33b4b0c74 Mark I01 status DONE
ci / test (push) Successful in 1m4s
ci / firmware (jc4827w543, sdkconfig.s3, esp32s3) (push) Successful in 3m56s
ci / firmware (wroom, sdkconfig.wroom, esp32) (push) Successful in 3m57s
ci / test (pull_request) Successful in 1m22s
ci / firmware (wroom, sdkconfig.wroom, esp32) (pull_request) Successful in 4m42s
ci / firmware (jc4827w543, sdkconfig.s3, esp32s3) (pull_request) Successful in 4m47s
2026-09-16 21:05:57 +01:00
15 changed files with 410 additions and 33 deletions
+3
View File
@@ -4,6 +4,9 @@ set(priv_req driver)
if(IDF_TARGET STREQUAL "esp32") if(IDF_TARGET STREQUAL "esp32")
list(APPEND srcs wroom/hal_audio.c) list(APPEND srcs wroom/hal_audio.c)
list(APPEND priv_req board_wroom) list(APPEND priv_req board_wroom)
elseif(IDF_TARGET STREQUAL "esp32s3")
list(APPEND srcs s3/hal_audio.c)
list(APPEND priv_req board_jc4827w543)
else() else()
list(APPEND srcs stub/hal_audio.c) list(APPEND srcs stub/hal_audio.c)
endif() endif()
+212
View File
@@ -0,0 +1,212 @@
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "esp_err.h"
#include "esp_log.h"
#include "driver/i2s_std.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "board.h"
#define SPK_SAMPLE_RATE 48000
#define TONE_HZ 2000
#define TONE_PERIOD_SMP (SPK_SAMPLE_RATE / TONE_HZ) /* 24 samples */
#define CHUNK_MS 10
#define CHUNK_FRAMES (SPK_SAMPLE_RATE / 1000 * CHUNK_MS) /* 480, multiple of period */
#define TONE_AMPLITUDE 12000
#define DMA_DESC_NUM 4
#define DMA_FRAME_NUM 240
static const char *TAG = "audio";
enum {
AUDIO_SHORT = 1,
AUDIO_ALARM,
AUDIO_CANCEL,
};
static QueueHandle_t s_q;
static TaskHandle_t s_task;
static i2s_chan_handle_t s_tx;
static bool s_chan_on;
static bool s_inited;
static int16_t s_tone[CHUNK_FRAMES * 2];
static int16_t s_silence[CHUNK_FRAMES * 2];
static void chan_on(void)
{
if (!s_chan_on && s_tx != NULL) {
i2s_channel_enable(s_tx);
s_chan_on = true;
}
}
static void chan_off(void)
{
if (s_chan_on && s_tx != NULL) {
size_t w = 0;
i2s_channel_write(s_tx, s_silence, sizeof(s_silence), &w, 50);
i2s_channel_disable(s_tx);
s_chan_on = false;
}
}
static bool drain_cancel(void)
{
int msg;
while (xQueueReceive(s_q, &msg, 0) == pdTRUE) {
if (msg == AUDIO_CANCEL) {
return true;
}
}
return false;
}
/* Write buf for ~ms wall time. DMA pacing makes each 10 ms write block
* in this task only; the UI path never touches I2S. */
static bool play_buf_ms(const int16_t *buf, size_t len, uint32_t ms)
{
TickType_t t0 = xTaskGetTickCount();
while ((xTaskGetTickCount() - t0) < pdMS_TO_TICKS(ms)) {
if (drain_cancel()) {
return false;
}
size_t w = 0;
if (i2s_channel_write(s_tx, buf, len, &w, portMAX_DELAY) != ESP_OK) {
return false;
}
}
return true;
}
static void play_short(void)
{
chan_on();
play_buf_ms(s_tone, sizeof(s_tone), 100);
chan_off();
}
static void play_alarm(void)
{
chan_on();
for (int i = 0; i < 10; i++) {
if (!play_buf_ms(s_tone, sizeof(s_tone), 500)) {
break;
}
if (!play_buf_ms(s_silence, sizeof(s_silence), 250)) {
break;
}
}
chan_off();
}
static void audio_task(void *arg)
{
(void)arg;
int msg;
for (;;) {
if (xQueueReceive(s_q, &msg, portMAX_DELAY) != pdTRUE) {
continue;
}
if (msg == AUDIO_SHORT) {
play_short();
} else if (msg == AUDIO_ALARM) {
play_alarm();
} else if (msg == AUDIO_CANCEL) {
chan_off();
}
}
}
static void post(int msg)
{
if (s_q == NULL) {
return;
}
xQueueSend(s_q, &msg, 0);
}
void autofilm_audio_task(void *arg)
{
audio_task(arg);
}
void hal_audio_init(void)
{
if (s_inited) {
return;
}
gpio_num_t bclk = board_pin_spk_bclk();
gpio_num_t lrclk = board_pin_spk_lrclk();
gpio_num_t din = board_pin_spk_din();
if (bclk == GPIO_NUM_NC || lrclk == GPIO_NUM_NC || din == GPIO_NUM_NC) {
ESP_LOGW(TAG, "no speaker pins on this board");
s_inited = true;
return;
}
for (int i = 0; i < CHUNK_FRAMES; i++) {
int16_t v = ((i % TONE_PERIOD_SMP) < (TONE_PERIOD_SMP / 2))
? TONE_AMPLITUDE : -TONE_AMPLITUDE;
s_tone[i * 2] = v;
s_tone[i * 2 + 1] = v;
}
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
chan_cfg.dma_desc_num = DMA_DESC_NUM;
chan_cfg.dma_frame_num = DMA_FRAME_NUM;
if (i2s_new_channel(&chan_cfg, &s_tx, NULL) != ESP_OK) {
ESP_LOGE(TAG, "i2s_new_channel failed");
s_inited = true;
return;
}
i2s_std_config_t std_cfg = {
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SPK_SAMPLE_RATE),
.slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT,
I2S_SLOT_MODE_STEREO),
.gpio_cfg = {
.mclk = I2S_GPIO_UNUSED,
.bclk = bclk,
.ws = lrclk,
.dout = din,
.din = I2S_GPIO_UNUSED,
.invert_flags = {
.mclk_inv = false,
.bclk_inv = false,
.ws_inv = false,
},
},
};
if (i2s_channel_init_std_mode(s_tx, &std_cfg) != ESP_OK) {
ESP_LOGE(TAG, "i2s_channel_init_std_mode failed");
i2s_del_channel(s_tx);
s_tx = NULL;
s_inited = true;
return;
}
s_q = xQueueCreate(8, sizeof(int));
if (s_task == NULL) {
xTaskCreate(audio_task, "audio", 3072, NULL, 2, &s_task);
}
s_inited = true;
ESP_LOGI(TAG, "init i2s bclk=%d ws=%d dout=%d", bclk, lrclk, din);
}
void hal_audio_beep_short(void)
{
post(AUDIO_SHORT);
}
void hal_audio_alarm_complete(void)
{
post(AUDIO_ALARM);
}
void hal_audio_alarm_cancel(void)
{
post(AUDIO_CANCEL);
}
+4 -1
View File
@@ -3,8 +3,11 @@ set(priv_inc)
set(priv_req driver) set(priv_req driver)
if(IDF_TARGET STREQUAL "esp32") if(IDF_TARGET STREQUAL "esp32")
list(APPEND srcs wroom/hal_motor.c) list(APPEND srcs hal_motor.c)
list(APPEND priv_req board_wroom) list(APPEND priv_req board_wroom)
elseif(IDF_TARGET STREQUAL "esp32s3")
list(APPEND srcs hal_motor.c)
list(APPEND priv_req board_jc4827w543)
else() else()
list(APPEND srcs stub/hal_motor.c) list(APPEND srcs stub/hal_motor.c)
endif() endif()
@@ -10,9 +10,9 @@
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#define PIN_STEP 12 #include "board.h"
#define PIN_DIR 14 #include "hal_motor.h"
#define PIN_EN 27
#define STEPS_PER_REV 4800 #define STEPS_PER_REV 4800
#define DEFAULT_RPM 60 #define DEFAULT_RPM 60
#define ACCEL 9600 #define ACCEL 9600
@@ -23,6 +23,10 @@
static const char *TAG = "motor"; static const char *TAG = "motor";
static gpio_num_t s_pin_en = GPIO_NUM_NC;
static gpio_num_t s_pin_dir = GPIO_NUM_NC;
static gpio_num_t s_pin_step = GPIO_NUM_NC;
static int s_en_disable_level = 1;
static TaskHandle_t s_task; static TaskHandle_t s_task;
static atomic_uint s_stop_req; static atomic_uint s_stop_req;
static float s_cw; static float s_cw;
@@ -35,13 +39,17 @@ static rmt_encoder_handle_t s_enc;
static void en_disable(void) static void en_disable(void)
{ {
gpio_set_level((gpio_num_t)PIN_EN, 1); if (s_pin_en != GPIO_NUM_NC) {
gpio_set_level(s_pin_en, s_en_disable_level);
}
s_enabled = false; s_enabled = false;
} }
static void en_enable(void) static void en_enable(void)
{ {
gpio_set_level((gpio_num_t)PIN_EN, 0); if (s_pin_en != GPIO_NUM_NC) {
gpio_set_level(s_pin_en, !s_en_disable_level);
}
s_enabled = true; s_enabled = true;
} }
@@ -111,7 +119,7 @@ static bool run_move(long steps)
if (steps < 0) { if (steps < 0) {
steps = -steps; steps = -steps;
} }
gpio_set_level((gpio_num_t)PIN_DIR, dir); gpio_set_level(s_pin_dir, dir);
uint32_t cruise = (s_rpm * STEPS_PER_REV) / 60; uint32_t cruise = (s_rpm * STEPS_PER_REV) / 60;
if (cruise == 0) { if (cruise == 0) {
@@ -189,22 +197,31 @@ void hal_motor_init(void)
if (s_inited) { if (s_inited) {
return; return;
} }
s_pin_en = board_pin_motor_en();
s_pin_dir = board_pin_motor_dir();
s_pin_step = board_pin_motor_step();
s_en_disable_level = board_motor_en_disable_level();
if (s_pin_en == GPIO_NUM_NC || s_pin_dir == GPIO_NUM_NC || s_pin_step == GPIO_NUM_NC) {
ESP_LOGW(TAG, "no motor pins on this board");
s_inited = true;
return;
}
gpio_config_t io = { gpio_config_t io = {
.pin_bit_mask = (1ULL << PIN_EN) | (1ULL << PIN_DIR), .pin_bit_mask = (1ULL << s_pin_en) | (1ULL << s_pin_dir),
.mode = GPIO_MODE_OUTPUT, .mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE, .pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE, .intr_type = GPIO_INTR_DISABLE,
}; };
gpio_config(&io); gpio_config(&io);
gpio_set_level((gpio_num_t)PIN_EN, 1); gpio_set_level(s_pin_en, s_en_disable_level);
gpio_set_level((gpio_num_t)PIN_DIR, 0); gpio_set_level(s_pin_dir, 0);
s_enabled = false; s_enabled = false;
atomic_store(&s_stop_req, 0); atomic_store(&s_stop_req, 0);
rmt_tx_channel_config_t txcfg = { rmt_tx_channel_config_t txcfg = {
.clk_src = RMT_CLK_SRC_DEFAULT, .clk_src = RMT_CLK_SRC_DEFAULT,
.gpio_num = PIN_STEP, .gpio_num = s_pin_step,
.mem_block_symbols = 64, .mem_block_symbols = 64,
.resolution_hz = RMT_RES_HZ, .resolution_hz = RMT_RES_HZ,
.trans_queue_depth = 4, .trans_queue_depth = 4,
@@ -219,7 +236,8 @@ void hal_motor_init(void)
configMAX_PRIORITIES - 2, &s_task, 0); configMAX_PRIORITIES - 2, &s_task, 0);
} }
s_inited = true; s_inited = true;
ESP_LOGI(TAG, "init EN=HIGH RMT step=%d dir=%d", PIN_STEP, PIN_DIR); ESP_LOGI(TAG, "init en=%d step=%d dir=%d dis_lvl=%d",
s_pin_en, s_pin_step, s_pin_dir, s_en_disable_level);
} }
void hal_motor_enable(bool on) void hal_motor_enable(bool on)
@@ -234,8 +252,7 @@ void hal_motor_enable(bool on)
void hal_motor_request_stop(void) void hal_motor_request_stop(void)
{ {
atomic_store(&s_stop_req, 1); atomic_store(&s_stop_req, 1);
gpio_set_level((gpio_num_t)PIN_EN, 1); en_disable();
s_enabled = false;
rmt_abort(); rmt_abort();
if (s_task != NULL) { if (s_task != NULL) {
xTaskNotifyGive(s_task); xTaskNotifyGive(s_task);
+4 -1
View File
@@ -3,8 +3,11 @@ set(priv_inc)
set(priv_req driver) set(priv_req driver)
if(IDF_TARGET STREQUAL "esp32") if(IDF_TARGET STREQUAL "esp32")
list(APPEND srcs wroom/hal_temp.c) list(APPEND srcs hal_temp.c)
list(APPEND priv_req board_wroom onewire_bus) list(APPEND priv_req board_wroom onewire_bus)
elseif(IDF_TARGET STREQUAL "esp32s3")
list(APPEND srcs hal_temp.c)
list(APPEND priv_req board_jc4827w543 onewire_bus)
else() else()
list(APPEND srcs stub/hal_temp.c) list(APPEND srcs stub/hal_temp.c)
endif() endif()
@@ -8,8 +8,9 @@
#include "freertos/task.h" #include "freertos/task.h"
#include "onewire_bus.h" #include "onewire_bus.h"
#include "board.h"
#include "hal_temp.h"
#define PIN_DS 13
#define TEMP_OFFSET 0.4f #define TEMP_OFFSET 0.4f
#define CMD_SKIP_ROM 0xCC #define CMD_SKIP_ROM 0xCC
#define CMD_CONVERT_T 0x44 #define CMD_CONVERT_T 0x44
@@ -40,7 +41,7 @@ static bool scratch_valid(const uint8_t *sp)
return crc == sp[8]; return crc == sp[8];
} }
void autofilm_temp_tick(void) void hal_temp_tick(void)
{ {
if (s_bus == NULL) { if (s_bus == NULL) {
s_last_ok = false; s_last_ok = false;
@@ -84,21 +85,19 @@ void autofilm_temp_tick(void)
s_last_ok = true; s_last_ok = true;
} }
void autofilm_temp_task(void *arg)
{
(void)arg;
for (;;) {
autofilm_temp_tick();
}
}
void hal_temp_init(void) void hal_temp_init(void)
{ {
if (s_inited) { if (s_inited) {
return; return;
} }
gpio_num_t pin = board_pin_temp();
if (pin == GPIO_NUM_NC) {
ESP_LOGW(TAG, "no temp pin on this board");
s_inited = true;
return;
}
onewire_bus_config_t bus_config = { onewire_bus_config_t bus_config = {
.bus_gpio_num = PIN_DS, .bus_gpio_num = pin,
.flags = { .flags = {
.en_pull_up = true, .en_pull_up = true,
}, },
@@ -108,12 +107,12 @@ void hal_temp_init(void)
}; };
if (onewire_new_bus_rmt(&bus_config, &rmt_config, &s_bus) != ESP_OK) { if (onewire_new_bus_rmt(&bus_config, &rmt_config, &s_bus) != ESP_OK) {
s_bus = NULL; s_bus = NULL;
ESP_LOGE(TAG, "onewire_bus install failed pin=%d", PIN_DS); ESP_LOGE(TAG, "onewire_bus install failed pin=%d", pin);
} }
s_last_ok = false; s_last_ok = false;
s_last_c = 0.0f; s_last_c = 0.0f;
s_inited = true; s_inited = true;
ESP_LOGI(TAG, "init onewire_bus pin=%d offset=%.1f", PIN_DS, (double)TEMP_OFFSET); ESP_LOGI(TAG, "init onewire_bus pin=%d offset=%.1f", pin, (double)TEMP_OFFSET);
} }
esp_err_t hal_temp_read_c(float *out) esp_err_t hal_temp_read_c(float *out)
+1
View File
@@ -7,4 +7,5 @@
#endif #endif
void hal_temp_init(void); void hal_temp_init(void);
void hal_temp_tick(void); /* blocking conversion poll; blocks >=750 ms */
esp_err_t hal_temp_read_c(float *out); /* ESP_FAIL → disconnected */ esp_err_t hal_temp_read_c(float *out); /* ESP_FAIL → disconnected */
+8
View File
@@ -1,9 +1,17 @@
#include "hal_temp.h" #include "hal_temp.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
void hal_temp_init(void) void hal_temp_init(void)
{ {
} }
void hal_temp_tick(void)
{
vTaskDelay(pdMS_TO_TICKS(750));
}
esp_err_t hal_temp_read_c(float *out) esp_err_t hal_temp_read_c(float *out)
{ {
(void)out; (void)out;
+41
View File
@@ -0,0 +1,41 @@
# INTEGRATION MEGAPLAN — AutoFilm-ESP32 S3 Hardware Integration
Audience: coding agent. One phase = one session. Do not start the next phase in the same session.
## Summary
This megaplan drives the hardware integration for the ESP32-S3 (JC4827W543) board, activating the stepper motor, DS18B20 temperature sensor, and I2S speaker using conflict-free, header-available GPIOs. To ensure success, these changes have been broken down from a single monolithic phase into a sequence of safe, isolated phases.
## Protocol (every session)
1. Ensure you are on the appropriate integration branch off `develop`.
2. Read only: `AGENTS.md`, this file (status table), **the assigned phase file**. Open other docs only if the phase `READ:` list says so.
3. Execute `IN` only. Honour `OUT` and `FORBIDDEN`.
4. Run `VERIFY` exactly. Do not push if any verify item fails.
5. Commits: messages listed in the phase. Imperative. No secret tokens.
6. Push to origin. PR target is `develop`, not `main`.
7. Set phase `STATUS:` to `DONE` in the phase file **and** this table. One-line `Notes` if you diverged (API name only — do not silently change behaviour).
If blocked: stop, commit nothing broken, write `BLOCKED:` at top of the phase file with the exact error.
## Frozen constraints (never reinterpret)
- The motor EN/STEP/DIR, DS18B20, and I2S audio pins for the JC4827W543 are strictly defined in this plan and the pin audit doc.
- **Constraints that eliminate S3 pins:**
- QSPI display: 45, 47, 21, 48, 40, 39 + BL 1 — consumed
- GT911: SDA 8, SCL 4, INT 3, RST 38 — consumed
- Speaker I2S: 2 (LRCLK), 41 (DIN), 42 (BCLK) — consumed by onboard amp
- TF slot: 10–13; USB: 19/20; UART0: 43/44; BOOT+LCD_TE: 0
- Octal PSRAM: 33–37 off-limits
- GPIO46 is INPUT-ONLY on ESP32-S3 — excluded from outputs entirely
- UI never blocks on hardware operations (motor, OneWire, I2S).
- Watchdog stays **on**. No `vTaskDelete` of long-lived workers.
## Status
| ID | File | Session goal | STATUS |
| --- | --- | --- | --- |
| I01 | `integration/I01-board-configs.md` | Board pin allocations & accessors | DONE |
| I02 | `integration/I02-temp-fix.md` | Temp HAL shared & starvation fix | DONE |
| I03 | `integration/I03-motor-hal.md` | Motor HAL shared across boards | DONE |
| I04 | `integration/I04-audio-i2s.md` | I2S audio implementation for S3 | DONE |
@@ -0,0 +1,23 @@
STATUS: DONE
DEPENDS: none
**READ:** `docs/megaplans/INTEGRATION-MEGAPLAN.md`, `docs/JC4827W543_PIN_AUDIT_VERIFIED.md`, `components/board_jc4827w543/board.c`, `components/board_wroom/board.c`
**IN:**
1. `board_jc4827w543`: add `board_pin_motor_step()` → 16, `board_pin_motor_dir()` → 15, `board_pin_temp()` → 17, `board_pin_spk_bclk()`, `board_pin_spk_lrclk()`, `board_pin_spk_din()` → 42, 2, 41; change `board_pin_motor_en()` → 7 (keep disable level 1 = active-LOW EN).
2. `board_wroom`: add matching `board_pin_motor_step()` → 12, `board_pin_motor_dir()` → 14, `board_pin_temp()` → 13 so HAL impls can be shared.
3. Update `docs/CURRENT_STATE.md` pin table note and `JC4827W543_PIN_AUDIT_VERIFIED.md` header section with the corrected labels if not already updated (P2: IO46/9/14/5, P3: IO6/7/15/16, P4: GND/3V3/17/18).
**OUT:** HAL implementations, business logic, NVS profiles.
**FORBIDDEN:** GPIO46 for any output; stealing TF, QSPI, GT911, USB, or UART0 pins.
**VERIFY:** `idf.py build` succeeds for both `esp32` and `esp32s3` targets.
**COMMITS:**
1. `Lock S3 header pins and introduce shared board pin accessors`
2. `Update pin audit documentation labels`
**DoD checkboxes:**
- [ ] `board_jc4827w543` pin accessors added.
- [ ] `board_wroom` pin accessors added.
- [ ] Build succeeds on both targets.
@@ -0,0 +1,23 @@
STATUS: DONE
DEPENDS: I01
Notes: Poll API named `hal_temp_tick` (declared in hal_temp.h). `idf.py build` for both targets verified via CI run 38616 (no local IDF). S3 flash watchdog check not run — no device attached to this machine.
**READ:** `docs/megaplans/INTEGRATION-MEGAPLAN.md`, `main/main.c`, `components/hal_temp/*`
**IN:**
1. `hal_temp`: Generalize `hal_temp.c` to use `board_pin_temp()` instead of hardcoded macros. Compile for both targets via CMake (`IDF_TARGET esp32|esp32s3` → shared source, `PRIV_REQUIRES board_wroom|board_jc4827w543`).
2. `main.c` **bug fix**: `temp_task` currently calls `autofilm_temp_tick()` only `#ifdef AUTOFILM_BOARD_WROOM` and has **no `vTaskDelay`** — on S3 it spins at priority 2 and starves the idle task (task-WDT risk). Move the tick loop into a `hal_temp`-level poll (e.g. `hal_temp_tick()` weak per-board) or add `vTaskDelay(pdMS_TO_TICKS(750))` on the non-WROOM path so the task always blocks.
**OUT:** Motor logic, audio logic.
**FORBIDDEN:** Removing the watchdog, deleting the temp task.
**VERIFY:** `idf.py build` succeeds for both `esp32` and `esp32s3`. Flash to S3 and verify no task watchdog panics occur in the console.
**COMMITS:**
1. `Share onewire temp HAL across both boards`
2. `Fix temp_task starvation bug on non-WROOM`
**DoD checkboxes:**
- [x] `hal_temp` generalized to use board accessors.
- [x] `temp_task` starvation bug fixed.
- [x] Build succeeds on both targets.
@@ -0,0 +1,21 @@
STATUS: DONE
DEPENDS: I01
**READ:** `docs/megaplans/INTEGRATION-MEGAPLAN.md`, `components/hal_motor/*`
**IN:**
1. `hal_motor`: Generalize `wroom/hal_motor.c` (already pure-IDF RMT) to read pins from `board.h`; compile for both targets via CMake (`IDF_TARGET esp32|esp32s3` → shared source, `PRIV_REQUIRES board_wroom|board_jc4827w543`).
2. Preserve: EN HIGH at init + on stop, `stop_req` sampled inside step loop, immortal task, `hal_motor_request_stop` ISR-safe.
**OUT:** Temp logic, audio logic.
**FORBIDDEN:** Blocking UI on motor operations.
**VERIFY:** `idf.py build` succeeds for both targets. Run host ctests if any apply to motor logic.
**COMMITS:**
1. `Share RMT motor HAL across both boards`
**DoD checkboxes:**
- [ ] `hal_motor` generalized to use board accessors.
- [ ] EN HIGH initialization preserved.
- [ ] Build succeeds on both targets.
@@ -0,0 +1,23 @@
STATUS: DONE
DEPENDS: I01
Notes: `idf.py build` for both targets verified via CI run 38684 (no local IDF).
**READ:** `docs/megaplans/INTEGRATION-MEGAPLAN.md`, `components/hal_audio/*`
**IN:**
1. `hal_audio` S3: Implement new `s3/hal_audio.c` using `i2s_std` TX on pins 41/42/2 (via `board_pin_spk_*`) to the NS4168 amp.
2. Generate 2 kHz square-wave bursts into a small DMA buffer.
3. Ensure identical queue protocol (SHORT / 10×ALARM 500ms-on/250ms-off / CANCEL) and non-blocking semantics as the WROOM LEDC version.
**OUT:** Motor logic, Temp logic.
**FORBIDDEN:** Blocking the UI on I2S writes.
**VERIFY:** `idf.py build` succeeds for both targets.
**COMMITS:**
1. `Add I2S speaker audio for S3`
**DoD checkboxes:**
- [x] `hal_audio` I2S implementation added for S3.
- [x] Queue protocol and non-blocking semantics maintained.
- [x] Build succeeds.
+1 -5
View File
@@ -28,8 +28,6 @@ static const char *TAG = "app";
#if defined(AUTOFILM_BOARD_WROOM) || defined(AUTOFILM_BOARD_S3) #if defined(AUTOFILM_BOARD_WROOM) || defined(AUTOFILM_BOARD_S3)
static QueueHandle_t s_cmdq; static QueueHandle_t s_cmdq;
extern void autofilm_temp_tick(void);
static void map_and_post_key(char key) static void map_and_post_key(char key)
{ {
ui_cmd_t cmd; ui_cmd_t cmd;
@@ -168,9 +166,7 @@ static void temp_task(void *arg)
(void)arg; (void)arg;
esp_task_wdt_add(NULL); esp_task_wdt_add(NULL);
for (;;) { for (;;) {
#ifdef AUTOFILM_BOARD_WROOM hal_temp_tick();
autofilm_temp_tick();
#endif
float c = 0.0f; float c = 0.0f;
bool ok = (hal_temp_read_c(&c) == ESP_OK); bool ok = (hal_temp_read_c(&c) == ESP_OK);
app_machine_on_temp(ok ? c : 0.0f, ok); app_machine_on_temp(ok ? c : 0.0f, ok);
+4
View File
@@ -10,6 +10,10 @@ void hal_temp_init(void)
stub_temp_c = 20.0f; stub_temp_c = 20.0f;
} }
void hal_temp_tick(void)
{
}
esp_err_t hal_temp_read_c(float *out) esp_err_t hal_temp_read_c(float *out)
{ {
if (stub_temp_fail) { if (stub_temp_fail) {