diff --git a/components/board_wroom/idf_component.yml b/components/board_wroom/idf_component.yml index 80ddb51..c093387 100644 --- a/components/board_wroom/idf_component.yml +++ b/components/board_wroom/idf_component.yml @@ -1,2 +1 @@ -dependencies: - espressif/arduino-esp32: "~3.2.1" +dependencies: {} diff --git a/components/hal_audio/CMakeLists.txt b/components/hal_audio/CMakeLists.txt index c0ecc3a..a421f3e 100644 --- a/components/hal_audio/CMakeLists.txt +++ b/components/hal_audio/CMakeLists.txt @@ -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) diff --git a/components/hal_audio/wroom/hal_audio.cpp b/components/hal_audio/wroom/hal_audio.c similarity index 93% rename from components/hal_audio/wroom/hal_audio.cpp rename to components/hal_audio/wroom/hal_audio.c index 14b80f8..ca4757c 100644 --- a/components/hal_audio/wroom/hal_audio.cpp +++ b/components/hal_audio/wroom/hal_audio.c @@ -1,4 +1,5 @@ #include +#include #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); } diff --git a/components/hal_display/CMakeLists.txt b/components/hal_display/CMakeLists.txt index e95bd70..6aeb734 100644 --- a/components/hal_display/CMakeLists.txt +++ b/components/hal_display/CMakeLists.txt @@ -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) diff --git a/components/hal_display/hal_display_lcd2004.c b/components/hal_display/hal_display_lcd2004.c new file mode 100644 index 0000000..25cdd8b --- /dev/null +++ b/components/hal_display/hal_display_lcd2004.c @@ -0,0 +1,190 @@ +#include "hal_display.h" + +#include + +#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; +} diff --git a/components/hal_display/hal_display_lcd2004.cpp b/components/hal_display/hal_display_lcd2004.cpp deleted file mode 100644 index 10e1012..0000000 --- a/components/hal_display/hal_display_lcd2004.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include "hal_display.h" - -#include -#include -#include - -#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(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; -} diff --git a/components/hal_input/CMakeLists.txt b/components/hal_input/CMakeLists.txt index bac6335..16c0b5b 100644 --- a/components/hal_input/CMakeLists.txt +++ b/components/hal_input/CMakeLists.txt @@ -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) diff --git a/components/hal_input/hal_input_keypad.c b/components/hal_input/hal_input_keypad.c new file mode 100644 index 0000000..c648091 --- /dev/null +++ b/components/hal_input/hal_input_keypad.c @@ -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; +} diff --git a/components/hal_input/hal_input_keypad.cpp b/components/hal_input/hal_input_keypad.cpp deleted file mode 100644 index 15fdbcb..0000000 --- a/components/hal_input/hal_input_keypad.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "hal_input.h" - -#include -#include - -#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; -} diff --git a/components/hal_motor/CMakeLists.txt b/components/hal_motor/CMakeLists.txt index eebe24e..4c17532 100644 --- a/components/hal_motor/CMakeLists.txt +++ b/components/hal_motor/CMakeLists.txt @@ -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() diff --git a/components/hal_motor/wroom/hal_motor.c b/components/hal_motor/wroom/hal_motor.c new file mode 100644 index 0000000..c6a6121 --- /dev/null +++ b/components/hal_motor/wroom/hal_motor.c @@ -0,0 +1,267 @@ +#include +#include +#include + +#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; +} diff --git a/components/hal_motor/wroom/hal_motor.cpp b/components/hal_motor/wroom/hal_motor.cpp deleted file mode 100644 index 179264f..0000000 --- a/components/hal_motor/wroom/hal_motor.cpp +++ /dev/null @@ -1,153 +0,0 @@ -#include -#include -#include - -#include "esp_err.h" -#include "esp_log.h" -#include "driver/gpio.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" - -#include -#include - -#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; -} diff --git a/components/hal_temp/CMakeLists.txt b/components/hal_temp/CMakeLists.txt index 75c973b..e9f3dfa 100644 --- a/components/hal_temp/CMakeLists.txt +++ b/components/hal_temp/CMakeLists.txt @@ -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() diff --git a/components/hal_temp/idf_component.yml b/components/hal_temp/idf_component.yml new file mode 100644 index 0000000..1875747 --- /dev/null +++ b/components/hal_temp/idf_component.yml @@ -0,0 +1,2 @@ +dependencies: + espressif/onewire_bus: "^1.1.0" diff --git a/components/hal_temp/wroom/hal_temp.c b/components/hal_temp/wroom/hal_temp.c new file mode 100644 index 0000000..f57baf9 --- /dev/null +++ b/components/hal_temp/wroom/hal_temp.c @@ -0,0 +1,128 @@ +#include +#include +#include + +#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; +} diff --git a/components/hal_temp/wroom/hal_temp.cpp b/components/hal_temp/wroom/hal_temp.cpp deleted file mode 100644 index 1716fd7..0000000 --- a/components/hal_temp/wroom/hal_temp.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include - -#include "esp_err.h" -#include "esp_log.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" - -#include -#include -#include - -#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; -} diff --git a/docs/megaplans/REFACTOR-MEGAPLAN.md b/docs/megaplans/REFACTOR-MEGAPLAN.md index 4a25f40..297b480 100644 --- a/docs/megaplans/REFACTOR-MEGAPLAN.md +++ b/docs/megaplans/REFACTOR-MEGAPLAN.md @@ -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 ``` diff --git a/docs/megaplans/refactor/P08-idf-debt.md b/docs/megaplans/refactor/P08-idf-debt.md index ba40a0a..d92bf1f 100644 --- a/docs/megaplans/refactor/P08-idf-debt.md +++ b/docs/megaplans/refactor/P08-idf-debt.md @@ -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 |#include "` empty in `main/` `components/` -- [ ] Stop still EN-off first -- [ ] STATUS→DONE +- [x] `rg -n "Arduino.h|AccelStepper|LiquidCrystal|DallasTemperature|#include |#include "` 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. diff --git a/main/main.c b/main/main.c index c050fa1..c8e7e43 100644 --- a/main/main.c +++ b/main/main.c @@ -19,10 +19,6 @@ #include "freertos/task.h" #include "freertos/queue.h" -#ifdef AUTOFILM_BOARD_WROOM -#include -#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 = {