P08 Arduino debt burn-down #10

Merged
gronod merged 6 commits from refactor/esp-idf-modular-ui into develop 2026-09-16 15:39:56 +01:00
19 changed files with 711 additions and 423 deletions
+1 -2
View File
@@ -1,2 +1 @@
dependencies:
espressif/arduino-esp32: "~3.2.1"
dependencies: {}
+1 -1
View File
@@ -2,7 +2,7 @@ set(srcs)
set(priv_req driver)
if(IDF_TARGET STREQUAL "esp32")
list(APPEND srcs wroom/hal_audio.cpp)
list(APPEND srcs wroom/hal_audio.c)
list(APPEND priv_req board_wroom)
else()
list(APPEND srcs stub/hal_audio.c)
@@ -1,4 +1,5 @@
#include <stdint.h>
#include <stdbool.h>
#include "esp_log.h"
#include "driver/ledc.h"
@@ -109,12 +110,12 @@ static void post(int msg)
xQueueSend(s_q, &msg, 0);
}
extern "C" void autofilm_audio_task(void *arg)
void autofilm_audio_task(void *arg)
{
audio_task(arg);
}
extern "C" void hal_audio_init(void)
void hal_audio_init(void)
{
if (s_inited) {
return;
@@ -146,17 +147,17 @@ extern "C" void hal_audio_init(void)
ESP_LOGI(TAG, "init beep pin=%d LEDC", PIN_BEEP);
}
extern "C" void hal_audio_beep_short(void)
void hal_audio_beep_short(void)
{
post(AUDIO_SHORT);
}
extern "C" void hal_audio_alarm_complete(void)
void hal_audio_alarm_complete(void)
{
post(AUDIO_ALARM);
}
extern "C" void hal_audio_alarm_cancel(void)
void hal_audio_alarm_cancel(void)
{
post(AUDIO_CANCEL);
}
+2 -8
View File
@@ -3,14 +3,8 @@ set(priv_inc)
set(priv_req driver)
if(IDF_TARGET STREQUAL "esp32")
list(APPEND srcs
hal_display_lcd2004.cpp
${CMAKE_CURRENT_LIST_DIR}/../third_party/LiquidCrystal_I2C/LiquidCrystal_I2C.cpp
)
list(APPEND priv_inc
${CMAKE_CURRENT_LIST_DIR}/../third_party/LiquidCrystal_I2C/include
)
list(APPEND priv_req board_wroom espressif__arduino-esp32)
list(APPEND srcs hal_display_lcd2004.c)
list(APPEND priv_req board_wroom)
elseif(IDF_TARGET STREQUAL "esp32s3")
list(APPEND srcs hal_display_nv3041a.c)
list(APPEND priv_req board_jc4827w543 esp_lcd)
@@ -0,0 +1,190 @@
#include "hal_display.h"
#include <string.h>
#include "driver/i2c_master.h"
#include "esp_rom_sys.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#define LCD_ADDR 0x27
#define LCD_COLS 20
#define LCD_ROWS 4
#define PIN_SDA 21
#define PIN_SCL 22
#define LCD_RS 0x01
#define LCD_EN 0x04
#define LCD_BL 0x08
static const char *TAG = "display";
static i2c_master_bus_handle_t s_bus;
static i2c_master_dev_handle_t s_dev;
static bool s_inited;
static const uint8_t s_thermo[8] = {
0b00100,
0b01100,
0b00100,
0b01100,
0b00100,
0b01110,
0b01110,
0b01110,
};
static const uint8_t s_row_off[4] = {0x00, 0x40, 0x14, 0x54};
static void i2c_write(uint8_t b)
{
if (s_dev == NULL) {
return;
}
i2c_master_transmit(s_dev, &b, 1, 50);
}
static void pulse(uint8_t data)
{
i2c_write((uint8_t)(data | LCD_EN | LCD_BL));
esp_rom_delay_us(1);
i2c_write((uint8_t)((data & (uint8_t)~LCD_EN) | LCD_BL));
esp_rom_delay_us(50);
}
static void write4(uint8_t nibble, uint8_t rs)
{
uint8_t data = (uint8_t)((nibble & 0xF0) | rs | LCD_BL);
i2c_write(data);
pulse(data);
}
static void send(uint8_t value, uint8_t rs)
{
write4(value, rs);
write4((uint8_t)(value << 4), rs);
}
static void cmd(uint8_t c)
{
send(c, 0);
if (c == 0x01 || c == 0x02) {
vTaskDelay(pdMS_TO_TICKS(2));
}
}
static void data_byte(uint8_t d)
{
send(d, LCD_RS);
}
static void set_ddram(uint8_t addr)
{
cmd((uint8_t)(0x80 | addr));
}
void hal_display_init(void)
{
if (s_inited) {
return;
}
i2c_master_bus_config_t bus_cfg = {
.i2c_port = I2C_NUM_0,
.sda_io_num = PIN_SDA,
.scl_io_num = PIN_SCL,
.clk_source = I2C_CLK_SRC_DEFAULT,
.glitch_ignore_cnt = 7,
.flags = {
.enable_internal_pullup = true,
},
};
if (i2c_new_master_bus(&bus_cfg, &s_bus) != ESP_OK) {
ESP_LOGE(TAG, "i2c bus failed");
return;
}
i2c_device_config_t dev_cfg = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = LCD_ADDR,
.scl_speed_hz = 100000,
};
if (i2c_master_bus_add_device(s_bus, &dev_cfg, &s_dev) != ESP_OK) {
ESP_LOGE(TAG, "i2c device failed");
return;
}
vTaskDelay(pdMS_TO_TICKS(50));
write4(0x30, 0);
vTaskDelay(pdMS_TO_TICKS(5));
write4(0x30, 0);
esp_rom_delay_us(150);
write4(0x30, 0);
write4(0x20, 0);
cmd(0x28); /* 4-bit, 2 line */
cmd(0x08);
cmd(0x01);
cmd(0x06);
cmd(0x0C);
cmd(0x40); /* CGRAM 0 */
for (int i = 0; i < 8; i++) {
data_byte(s_thermo[i]);
}
cmd(0x01);
s_inited = true;
ESP_LOGI(TAG, "init LCD 20x4 addr=0x27 sda=21 scl=22 IDF I2C");
}
void hal_display_clear(void)
{
if (!s_inited) {
return;
}
cmd(0x01);
}
void hal_display_text(int col, int row, const char *s)
{
if (!s_inited || s == NULL) {
return;
}
if (row < 0 || row >= LCD_ROWS) {
return;
}
if (col < 0) {
col = 0;
}
if (col >= LCD_COLS) {
return;
}
set_ddram((uint8_t)(s_row_off[row] + col));
int room = LCD_COLS - col;
int n = 0;
while (s[n] != '\0' && n < room) {
data_byte((uint8_t)s[n]);
n++;
}
}
void hal_display_glyph_thermo(int col, int row)
{
if (!s_inited) {
return;
}
if (row < 0 || row >= LCD_ROWS || col < 0 || col >= LCD_COLS) {
return;
}
set_ddram((uint8_t)(s_row_off[row] + col));
data_byte(0);
}
void hal_display_flush(void)
{
}
void hal_display_softkey(int slot, int slots, const char *label)
{
(void)slot;
(void)slots;
(void)label;
}
@@ -1,98 +0,0 @@
#include "hal_display.h"
#include <Arduino.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "esp_log.h"
#define LCD_ADDR 0x27
#define LCD_COLS 20
#define LCD_ROWS 4
static const char *TAG = "display";
static LiquidCrystal_I2C s_lcd(LCD_ADDR, LCD_COLS, LCD_ROWS);
static bool s_inited;
static const uint8_t s_thermo[8] = {
0b00100,
0b01100,
0b00100,
0b01100,
0b00100,
0b01110,
0b01110,
0b01110,
};
extern "C" void hal_display_init(void)
{
if (s_inited) {
return;
}
Wire.begin(21, 22);
s_lcd.init();
s_lcd.backlight();
s_lcd.createChar(0, const_cast<uint8_t *>(s_thermo));
s_lcd.clear();
s_inited = true;
ESP_LOGI(TAG, "init LCD 20x4 addr=0x27 sda=21 scl=22");
}
extern "C" void hal_display_clear(void)
{
if (!s_inited) {
return;
}
s_lcd.clear();
}
extern "C" void hal_display_text(int col, int row, const char *s)
{
if (!s_inited || s == NULL) {
return;
}
if (row < 0 || row >= LCD_ROWS) {
return;
}
if (col < 0) {
col = 0;
}
if (col >= LCD_COLS) {
return;
}
s_lcd.setCursor((uint8_t)col, (uint8_t)row);
int room = LCD_COLS - col;
char buf[21];
int n = 0;
while (s[n] != '\0' && n < room) {
buf[n] = s[n];
n++;
}
buf[n] = '\0';
s_lcd.print(buf);
}
extern "C" void hal_display_glyph_thermo(int col, int row)
{
if (!s_inited) {
return;
}
if (row < 0 || row >= LCD_ROWS || col < 0 || col >= LCD_COLS) {
return;
}
s_lcd.setCursor((uint8_t)col, (uint8_t)row);
s_lcd.write((uint8_t)0);
}
extern "C" void hal_display_flush(void)
{
}
extern "C" void hal_display_softkey(int slot, int slots, const char *label)
{
(void)slot;
(void)slots;
(void)label;
}
+2 -9
View File
@@ -3,15 +3,8 @@ set(priv_inc)
set(priv_req driver)
if(IDF_TARGET STREQUAL "esp32")
list(APPEND srcs
hal_input_keypad.cpp
${CMAKE_CURRENT_LIST_DIR}/../third_party/Keypad/Keypad.cpp
${CMAKE_CURRENT_LIST_DIR}/../third_party/Keypad/Key.cpp
)
list(APPEND priv_inc
${CMAKE_CURRENT_LIST_DIR}/../third_party/Keypad/include
)
list(APPEND priv_req board_wroom espressif__arduino-esp32)
list(APPEND srcs hal_input_keypad.c)
list(APPEND priv_req board_wroom)
elseif(IDF_TARGET STREQUAL "esp32s3")
list(APPEND srcs hal_input_gt911.c)
list(APPEND priv_req board_jc4827w543)
+99
View File
@@ -0,0 +1,99 @@
#include "hal_input.h"
#include "driver/gpio.h"
#include "esp_log.h"
static const char *TAG = "input";
#define ROWS 5
#define COLS 4
static const gpio_num_t s_row_pins[ROWS] = {19, 18, 5, 17, 16};
static const gpio_num_t s_col_pins[COLS] = {15, 2, 0, 4};
static const char s_keys[ROWS][COLS] = {
{'F', 'E', '#', '*'},
{'1', '2', '3', 'U'},
{'4', '5', '6', 'D'},
{'7', '8', '9', 'X'},
{'L', '0', 'R', 'E'}};
static bool s_inited;
static char s_held;
static void cols_idle_high(void)
{
for (int c = 0; c < COLS; c++) {
gpio_set_level(s_col_pins[c], 1);
}
}
static char scan_once(void)
{
for (int c = 0; c < COLS; c++) {
cols_idle_high();
gpio_set_level(s_col_pins[c], 0);
for (int r = 0; r < ROWS; r++) {
if (gpio_get_level(s_row_pins[r]) == 0) {
cols_idle_high();
return s_keys[r][c];
}
}
}
cols_idle_high();
return 0;
}
void hal_input_init(void)
{
if (s_inited) {
return;
}
for (int r = 0; r < ROWS; r++) {
gpio_config_t io = {
.pin_bit_mask = 1ULL << s_row_pins[r],
.mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_ENABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
gpio_config(&io);
}
for (int c = 0; c < COLS; c++) {
gpio_config_t io = {
.pin_bit_mask = 1ULL << s_col_pins[c],
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
gpio_config(&io);
gpio_set_level(s_col_pins[c], 1);
}
s_held = 0;
s_inited = true;
ESP_LOGI(TAG, "init 5x4 GPIO keypad map byte-identical to src/config.cpp");
}
bool hal_input_pop_key(ui_raw_key_t *out)
{
char k = scan_once();
if (k == 0) {
s_held = 0;
return false;
}
if (k == s_held) {
return false;
}
s_held = k;
if (out != NULL) {
out->key = k;
}
return true;
}
bool hal_input_pop_touch(ui_raw_touch_t *out)
{
(void)out;
return false;
}
-50
View File
@@ -1,50 +0,0 @@
#include "hal_input.h"
#include <Arduino.h>
#include <Keypad.h>
#include "esp_log.h"
static const char *TAG = "input";
static const byte ROWS = 5;
static const byte COLS = 4;
static byte s_rowPins[ROWS] = {19, 18, 5, 17, 16};
static byte s_colPins[COLS] = {15, 2, 0, 4};
static char s_keys[ROWS][COLS] = {
{'F', 'E', '#', '*'},
{'1', '2', '3', 'U'},
{'4', '5', '6', 'D'},
{'7', '8', '9', 'X'},
{'L', '0', 'R', 'E'}};
static Keypad s_keypad = Keypad(makeKeymap(s_keys), s_rowPins, s_colPins, ROWS, COLS);
static bool s_inited;
extern "C" void hal_input_init(void)
{
if (s_inited) {
return;
}
s_inited = true;
ESP_LOGI(TAG, "init 5x4 keypad map byte-identical to src/config.cpp");
}
extern "C" bool hal_input_pop_key(ui_raw_key_t *out)
{
char k = s_keypad.getKey();
if (k == NO_KEY) {
return false;
}
if (out != NULL) {
out->key = k;
}
return true;
}
extern "C" bool hal_input_pop_touch(ui_raw_touch_t *out)
{
(void)out;
return false;
}
+2 -8
View File
@@ -3,14 +3,8 @@ set(priv_inc)
set(priv_req driver)
if(IDF_TARGET STREQUAL "esp32")
list(APPEND srcs
wroom/hal_motor.cpp
${CMAKE_CURRENT_LIST_DIR}/../third_party/AccelStepper/AccelStepper.cpp
)
list(APPEND priv_inc
${CMAKE_CURRENT_LIST_DIR}/../third_party/AccelStepper/include
)
list(APPEND priv_req board_wroom espressif__arduino-esp32)
list(APPEND srcs wroom/hal_motor.c)
list(APPEND priv_req board_wroom)
else()
list(APPEND srcs stub/hal_motor.c)
endif()
+267
View File
@@ -0,0 +1,267 @@
#include <stdint.h>
#include <stdbool.h>
#include <stdatomic.h>
#include "esp_err.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "driver/rmt_tx.h"
#include "driver/rmt_encoder.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#define PIN_STEP 12
#define PIN_DIR 14
#define PIN_EN 27
#define STEPS_PER_REV 4800
#define DEFAULT_RPM 60
#define ACCEL 9600
#define RMT_RES_HZ 1000000
#define CRUISE_HZ ((DEFAULT_RPM * STEPS_PER_REV) / 60) /* 4800 */
#define RAMP_STAGES 8
#define BATCH 32
static const char *TAG = "motor";
static TaskHandle_t s_task;
static atomic_uint s_stop_req;
static float s_cw;
static float s_ccw;
static uint32_t s_rpm = DEFAULT_RPM;
static bool s_enabled;
static bool s_inited;
static rmt_channel_handle_t s_chan;
static rmt_encoder_handle_t s_enc;
static void en_disable(void)
{
gpio_set_level((gpio_num_t)PIN_EN, 1);
s_enabled = false;
}
static void en_enable(void)
{
gpio_set_level((gpio_num_t)PIN_EN, 0);
s_enabled = true;
}
static void rmt_abort(void)
{
if (s_chan != NULL) {
rmt_disable(s_chan);
rmt_enable(s_chan);
}
}
static uint32_t period_us_for_hz(uint32_t hz)
{
if (hz < 100) {
hz = 100;
}
return RMT_RES_HZ / hz;
}
static bool emit_steps(uint32_t n, uint32_t hz)
{
if (n == 0) {
return true;
}
uint32_t period = period_us_for_hz(hz);
uint32_t half = period / 2;
if (half == 0) {
half = 1;
}
rmt_symbol_word_t sym = {
.duration0 = (uint16_t)half,
.level0 = 1,
.duration1 = (uint16_t)(period - half),
.level1 = 0,
};
while (n > 0) {
if (atomic_load(&s_stop_req) != 0) {
rmt_abort();
return false;
}
uint32_t chunk = n > BATCH ? BATCH : n;
rmt_symbol_word_t burst[BATCH];
for (uint32_t i = 0; i < chunk; i++) {
burst[i] = sym;
}
rmt_transmit_config_t tcfg = {
.loop_count = 0,
};
if (rmt_transmit(s_chan, s_enc, burst, chunk * sizeof(rmt_symbol_word_t), &tcfg) != ESP_OK) {
return false;
}
if (rmt_tx_wait_all_done(s_chan, 2000) != ESP_OK) {
rmt_abort();
return false;
}
n -= chunk;
}
return atomic_load(&s_stop_req) == 0;
}
static bool run_move(long steps)
{
if (steps == 0) {
return true;
}
int dir = (steps > 0) ? 1 : 0;
if (steps < 0) {
steps = -steps;
}
gpio_set_level((gpio_num_t)PIN_DIR, dir);
uint32_t cruise = (s_rpm * STEPS_PER_REV) / 60;
if (cruise == 0) {
cruise = CRUISE_HZ;
}
/* Short accel table: ACCEL ≈9600 steps/s^2 into cruise. */
uint32_t remaining = (uint32_t)steps;
uint32_t ramp = remaining / 8;
if (ramp > 200) {
ramp = 200;
}
if (ramp < RAMP_STAGES) {
ramp = (remaining < RAMP_STAGES) ? remaining : RAMP_STAGES;
}
uint32_t start_hz = cruise / 4;
if (start_hz < 200) {
start_hz = 200;
}
for (int i = 0; i < RAMP_STAGES && remaining > 0; i++) {
uint32_t n = ramp / RAMP_STAGES;
if (n == 0) {
n = 1;
}
if (n > remaining) {
n = remaining;
}
uint32_t hz = start_hz + ((cruise - start_hz) * (uint32_t)(i + 1)) / RAMP_STAGES;
if (!emit_steps(n, hz)) {
return false;
}
remaining -= n;
}
if (remaining > 0) {
if (!emit_steps(remaining, cruise)) {
return false;
}
}
return true;
}
static void motor_task(void *arg)
{
(void)arg;
for (;;) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
if (atomic_load(&s_stop_req) != 0) {
rmt_abort();
en_disable();
continue;
}
en_enable();
while (atomic_load(&s_stop_req) == 0) {
if (!run_move((long)((float)STEPS_PER_REV * s_cw))) {
break;
}
if (atomic_load(&s_stop_req) != 0) {
break;
}
if (!run_move((long)(-((float)STEPS_PER_REV * s_ccw)))) {
break;
}
}
rmt_abort();
en_disable();
}
}
void autofilm_motor_task(void *arg)
{
motor_task(arg);
}
void hal_motor_init(void)
{
if (s_inited) {
return;
}
gpio_config_t io = {
.pin_bit_mask = (1ULL << PIN_EN) | (1ULL << PIN_DIR),
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
gpio_config(&io);
gpio_set_level((gpio_num_t)PIN_EN, 1);
gpio_set_level((gpio_num_t)PIN_DIR, 0);
s_enabled = false;
atomic_store(&s_stop_req, 0);
rmt_tx_channel_config_t txcfg = {
.clk_src = RMT_CLK_SRC_DEFAULT,
.gpio_num = PIN_STEP,
.mem_block_symbols = 64,
.resolution_hz = RMT_RES_HZ,
.trans_queue_depth = 4,
};
rmt_new_tx_channel(&txcfg, &s_chan);
rmt_copy_encoder_config_t enc_cfg = {};
rmt_new_copy_encoder(&enc_cfg, &s_enc);
rmt_enable(s_chan);
if (s_task == NULL) {
xTaskCreatePinnedToCore(motor_task, "motor", 4096, NULL,
configMAX_PRIORITIES - 2, &s_task, 0);
}
s_inited = true;
ESP_LOGI(TAG, "init EN=HIGH RMT step=%d dir=%d", PIN_STEP, PIN_DIR);
}
void hal_motor_enable(bool on)
{
if (on) {
en_enable();
} else {
en_disable();
}
}
void hal_motor_request_stop(void)
{
atomic_store(&s_stop_req, 1);
gpio_set_level((gpio_num_t)PIN_EN, 1);
s_enabled = false;
rmt_abort();
if (s_task != NULL) {
xTaskNotifyGive(s_task);
}
}
esp_err_t hal_motor_agitate_start(float cw_revs, float ccw_revs, uint32_t rpm)
{
s_cw = cw_revs;
s_ccw = ccw_revs;
s_rpm = (rpm == 0) ? DEFAULT_RPM : rpm;
atomic_store(&s_stop_req, 0);
if (s_task != NULL) {
xTaskNotifyGive(s_task);
}
return ESP_OK;
}
void hal_motor_agitate_stop(void)
{
atomic_store(&s_stop_req, 1);
rmt_abort();
en_disable();
}
bool hal_motor_is_enabled(void)
{
return s_enabled;
}
-153
View File
@@ -1,153 +0,0 @@
#include <stdint.h>
#include <stdbool.h>
#include <stdatomic.h>
#include "esp_err.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <Arduino.h>
#include <AccelStepper.h>
#define PIN_STEP 12
#define PIN_DIR 14
#define PIN_EN 27
#define STEPS_PER_REV 4800
#define DEFAULT_RPM 60
#define ACCEL 9600
static const char *TAG = "motor";
static AccelStepper s_stepper(AccelStepper::DRIVER, PIN_STEP, PIN_DIR);
static TaskHandle_t s_task;
static atomic_uint s_stop_req;
static float s_cw;
static float s_ccw;
static uint32_t s_rpm = DEFAULT_RPM;
static bool s_enabled;
static bool s_inited;
static void en_disable(void)
{
gpio_set_level((gpio_num_t)PIN_EN, 1);
s_enabled = false;
}
static void en_enable(void)
{
gpio_set_level((gpio_num_t)PIN_EN, 0);
s_enabled = true;
}
static void run_move(long steps)
{
s_stepper.setCurrentPosition(0);
s_stepper.moveTo(steps);
while (s_stepper.distanceToGo() != 0) {
if (atomic_load(&s_stop_req) != 0) {
break;
}
s_stepper.run();
}
}
static void motor_task(void *arg)
{
(void)arg;
for (;;) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
if (atomic_load(&s_stop_req) != 0) {
en_disable();
continue;
}
float speed = ((float)s_rpm * (float)STEPS_PER_REV) / 60.0f;
s_stepper.setMaxSpeed(speed);
s_stepper.setAcceleration((float)ACCEL);
en_enable();
while (atomic_load(&s_stop_req) == 0) {
run_move((long)((float)STEPS_PER_REV * s_cw));
if (atomic_load(&s_stop_req) != 0) {
break;
}
run_move((long)(-((float)STEPS_PER_REV * s_ccw)));
}
en_disable();
}
}
extern "C" void autofilm_motor_task(void *arg)
{
motor_task(arg);
}
extern "C" void hal_motor_init(void)
{
if (s_inited) {
return;
}
gpio_config_t io = {
.pin_bit_mask = (1ULL << PIN_EN) | (1ULL << PIN_STEP) | (1ULL << PIN_DIR),
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
gpio_config(&io);
gpio_set_level((gpio_num_t)PIN_EN, 1);
gpio_set_level((gpio_num_t)PIN_STEP, 0);
gpio_set_level((gpio_num_t)PIN_DIR, 0);
s_enabled = false;
atomic_store(&s_stop_req, 0);
s_stepper.setMaxSpeed(((float)DEFAULT_RPM * (float)STEPS_PER_REV) / 60.0f);
s_stepper.setAcceleration((float)ACCEL);
if (s_task == NULL) {
xTaskCreatePinnedToCore(motor_task, "motor", 4096, NULL,
configMAX_PRIORITIES - 2, &s_task, 0);
}
s_inited = true;
ESP_LOGI(TAG, "init EN=HIGH step=%d dir=%d", PIN_STEP, PIN_DIR);
}
extern "C" void hal_motor_enable(bool on)
{
if (on) {
en_enable();
} else {
en_disable();
}
}
extern "C" void hal_motor_request_stop(void)
{
atomic_store(&s_stop_req, 1);
gpio_set_level((gpio_num_t)PIN_EN, 1);
s_enabled = false;
if (s_task != NULL) {
xTaskNotifyGive(s_task);
}
}
extern "C" esp_err_t hal_motor_agitate_start(float cw_revs, float ccw_revs, uint32_t rpm)
{
s_cw = cw_revs;
s_ccw = ccw_revs;
s_rpm = (rpm == 0) ? DEFAULT_RPM : rpm;
atomic_store(&s_stop_req, 0);
if (s_task != NULL) {
xTaskNotifyGive(s_task);
}
return ESP_OK;
}
extern "C" void hal_motor_agitate_stop(void)
{
atomic_store(&s_stop_req, 1);
en_disable();
}
extern "C" bool hal_motor_is_enabled(void)
{
return s_enabled;
}
+2 -10
View File
@@ -3,16 +3,8 @@ set(priv_inc)
set(priv_req driver)
if(IDF_TARGET STREQUAL "esp32")
list(APPEND srcs
wroom/hal_temp.cpp
${CMAKE_CURRENT_LIST_DIR}/../third_party/OneWire/OneWire.cpp
${CMAKE_CURRENT_LIST_DIR}/../third_party/DallasTemperature/DallasTemperature.cpp
)
list(APPEND priv_inc
${CMAKE_CURRENT_LIST_DIR}/../third_party/OneWire/include
${CMAKE_CURRENT_LIST_DIR}/../third_party/DallasTemperature/include
)
list(APPEND priv_req board_wroom espressif__arduino-esp32)
list(APPEND srcs wroom/hal_temp.c)
list(APPEND priv_req board_wroom onewire_bus)
else()
list(APPEND srcs stub/hal_temp.c)
endif()
+2
View File
@@ -0,0 +1,2 @@
dependencies:
espressif/onewire_bus: "^1.1.0"
+128
View File
@@ -0,0 +1,128 @@
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "esp_err.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "onewire_bus.h"
#define PIN_DS 13
#define TEMP_OFFSET 0.4f
#define CMD_SKIP_ROM 0xCC
#define CMD_CONVERT_T 0x44
#define CMD_READ_SCRATCH 0xBE
static const char *TAG = "temp";
static onewire_bus_handle_t s_bus;
static bool s_inited;
static float s_last_c;
static bool s_last_ok;
static bool scratch_valid(const uint8_t *sp)
{
/* DS18B20 CRC8 over first 8 bytes, poly 0x8C reflected. */
uint8_t crc = 0;
for (int i = 0; i < 8; i++) {
uint8_t in = sp[i];
for (int b = 0; b < 8; b++) {
uint8_t mix = (crc ^ in) & 0x01;
crc >>= 1;
if (mix) {
crc ^= 0x8C;
}
in >>= 1;
}
}
return crc == sp[8];
}
void autofilm_temp_tick(void)
{
if (s_bus == NULL) {
s_last_ok = false;
vTaskDelay(pdMS_TO_TICKS(750));
return;
}
if (onewire_bus_reset(s_bus) != ESP_OK) {
s_last_ok = false;
vTaskDelay(pdMS_TO_TICKS(750));
return;
}
uint8_t conv[2] = {CMD_SKIP_ROM, CMD_CONVERT_T};
if (onewire_bus_write_bytes(s_bus, conv, 2) != ESP_OK) {
s_last_ok = false;
vTaskDelay(pdMS_TO_TICKS(750));
return;
}
vTaskDelay(pdMS_TO_TICKS(750));
if (onewire_bus_reset(s_bus) != ESP_OK) {
s_last_ok = false;
return;
}
uint8_t rd[2] = {CMD_SKIP_ROM, CMD_READ_SCRATCH};
if (onewire_bus_write_bytes(s_bus, rd, 2) != ESP_OK) {
s_last_ok = false;
return;
}
uint8_t sp[9];
memset(sp, 0, sizeof(sp));
if (onewire_bus_read_bytes(s_bus, sp, sizeof(sp)) != ESP_OK) {
s_last_ok = false;
return;
}
if (!scratch_valid(sp)) {
s_last_ok = false;
return;
}
int16_t raw = (int16_t)((uint16_t)sp[0] | ((uint16_t)sp[1] << 8));
float t = ((float)raw) / 16.0f + TEMP_OFFSET;
s_last_c = t;
s_last_ok = true;
}
void autofilm_temp_task(void *arg)
{
(void)arg;
for (;;) {
autofilm_temp_tick();
}
}
void hal_temp_init(void)
{
if (s_inited) {
return;
}
onewire_bus_config_t bus_config = {
.bus_gpio_num = PIN_DS,
.flags = {
.en_pull_up = true,
},
};
onewire_bus_rmt_config_t rmt_config = {
.max_rx_bytes = 10,
};
if (onewire_new_bus_rmt(&bus_config, &rmt_config, &s_bus) != ESP_OK) {
s_bus = NULL;
ESP_LOGE(TAG, "onewire_bus install failed pin=%d", PIN_DS);
}
s_last_ok = false;
s_last_c = 0.0f;
s_inited = true;
ESP_LOGI(TAG, "init onewire_bus pin=%d offset=%.1f", PIN_DS, (double)TEMP_OFFSET);
}
esp_err_t hal_temp_read_c(float *out)
{
if (!s_last_ok) {
return ESP_FAIL;
}
if (out != NULL) {
*out = s_last_c;
}
return ESP_OK;
}
-66
View File
@@ -1,66 +0,0 @@
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <Arduino.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define PIN_DS 13
#define TEMP_OFFSET 0.4f
static const char *TAG = "temp";
static OneWire s_wire(PIN_DS);
static DallasTemperature s_sensors(&s_wire);
static bool s_inited;
static float s_last_c;
static bool s_last_ok;
extern "C" void autofilm_temp_tick(void)
{
s_sensors.requestTemperatures();
vTaskDelay(pdMS_TO_TICKS(750));
float t = s_sensors.getTempCByIndex(0);
bool ok = (t != DEVICE_DISCONNECTED_C);
if (ok) {
t += TEMP_OFFSET;
}
s_last_c = ok ? t : 0.0f;
s_last_ok = ok;
}
extern "C" void autofilm_temp_task(void *arg)
{
(void)arg;
for (;;) {
autofilm_temp_tick();
}
}
extern "C" void hal_temp_init(void)
{
if (s_inited) {
return;
}
s_sensors.begin();
s_last_ok = false;
s_last_c = 0.0f;
s_inited = true;
ESP_LOGI(TAG, "init OneWire pin=%d offset=%.1f", PIN_DS, (double)TEMP_OFFSET);
}
extern "C" esp_err_t hal_temp_read_c(float *out)
{
if (!s_last_ok) {
return ESP_FAIL;
}
if (out != NULL) {
*out = s_last_c;
}
return ESP_OK;
}
+3 -1
View File
@@ -40,7 +40,7 @@ If blocked: stop, commit nothing broken, write `BLOCKED:` at top of the phase fi
| P05 | `refactor/P05-hal-wroom-motion.md` | WROOM motor/temp/audio HAL | DONE |
| P06 | `refactor/P06-ui-wroom-cutover.md` | 2004 UI + keypad + Stop/Resume cutover | DONE |
| P07 | `refactor/P07-board-s3-ui.md` | JC4827W543 display+GT911+STOP | DONE |
| P08 | `refactor/P08-idf-debt.md` | Replace Arduino drivers (RMT etc.) | TODO |
| P08 | `refactor/P08-idf-debt.md` | Replace Arduino drivers (RMT etc.) | DONE |
P04 Notes: merge_bin uses `${{ gitea.sha }}` (not `github.sha`); runner unverified (no Actions run).
@@ -50,6 +50,8 @@ P06 Notes: WROOM input_task dual-path stop (hal_motor_request_stop then CMD_STOP
P07 Notes: custom NV3041A QSPI + GT911; shared app_ui text grid + colour softkeys; EN=NC. idf.py not run here (no IDF_PATH). host ctest green. Hw unflashed.
P08 Notes: LEDC audio; RMT STEP + GPIO DIR/EN; onewire_bus DS18B20 +0.4; GPIO keypad; IDF I2C 2004. Arduino-as-component removed. third_party trees unlinked. host ctest green. idf.py not run here (no IDF_PATH). hw unflashed.
## Dependency
```
+6 -4
View File
@@ -1,6 +1,6 @@
# P08 — Arduino debt burn-down
STATUS: TODO
STATUS: DONE
DEPENDS: P06 (behaviour parity). P07 optional.
READ: this file, `components/hal_motor/**`, HAL headers from P03
OUT: recipe edits; UI redesign; LVGL-by-default
@@ -35,6 +35,8 @@ Per numbered item above, e.g. `Replace AccelStepper with RMT step pulse HAL`.
## DoD
- [ ] `rg -n "Arduino.h|AccelStepper|LiquidCrystal|DallasTemperature|#include <Keypad.h>|#include <OneWire.h>"` empty in `main/` `components/`
- [ ] Stop still EN-off first
- [ ] STATUS→DONE
- [x] `rg -n "Arduino.h|AccelStepper|LiquidCrystal|DallasTemperature|#include <Keypad.h>|#include <OneWire.h>"` empty in `main/` and live `components/hal_*` / `main` (vendor copies remain unlinked under `components/third_party/`)
- [x] Stop still EN-off first (`hal_motor_request_stop` EN HIGH then RMT abort)
- [x] STATUS→DONE
Notes: audio was already LEDC; converted to C. Motor RMT copy-encoder batches + short accel table. Temp `espressif/onewire_bus` + skip-ROM scratchpad, +0.4 °C. Keypad GPIO scan, same 5x4 map. LCD PCF8574 nibble HD44780 on I2C0. Dropped `espressif/arduino-esp32` and `initArduino()`. Host ctest green. Local `idf.py` not run (no IDF_PATH). Hw unflashed.
-8
View File
@@ -19,10 +19,6 @@
#include "freertos/task.h"
#include "freertos/queue.h"
#ifdef AUTOFILM_BOARD_WROOM
#include <Arduino.h>
#endif
#ifndef AUTOFILM_GIT_DESC
#define AUTOFILM_GIT_DESC "dev"
#endif
@@ -187,10 +183,6 @@ void app_main(void)
{
ESP_LOGI(TAG, "board=%s desc=%s", board_name(), AUTOFILM_GIT_DESC);
#ifdef AUTOFILM_BOARD_WROOM
initArduino();
#endif
gpio_num_t en_pin = board_pin_motor_en();
if (en_pin != GPIO_NUM_NC) {
gpio_config_t io = {