Add board input driver for button and LiPo ADC logging.
TODO: Hardware pinning in powerpod.h (TASTER_GPIO, V_LIPO_1/2_GPIO) does not match final hardware yet — verify against schematic before production. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
80fb9cf55e
commit
1ad527119d
@ -23,6 +23,7 @@ idf_component_register(
|
||||
"esp_now_comm.c"
|
||||
"esp_now_proto.c"
|
||||
"bosch456.c"
|
||||
"board_input.c"
|
||||
"proto/uart_messages.pb.c"
|
||||
"proto/esp_now_messages.pb.c"
|
||||
"proto/pb_encode.c"
|
||||
@ -40,6 +41,7 @@ idf_component_register(
|
||||
esp_driver_gpio
|
||||
esp_driver_uart
|
||||
esp_driver_i2c
|
||||
esp_adc
|
||||
app_update
|
||||
bma456)
|
||||
|
||||
|
||||
@ -51,6 +51,11 @@ Pins (`powerpod.h`):
|
||||
| UART RX | 2 |
|
||||
| LED ring | 7 |
|
||||
| BMA456 INT | 10 |
|
||||
| Button (Taster) | 12 |
|
||||
| LiPo sense 1 (ADC) | 1 |
|
||||
| LiPo sense 2 (ADC) | 12 (skipped if same as button) |
|
||||
|
||||
> **TODO:** GPIO assignments above are provisional; confirm pinning against the real board before release.
|
||||
|
||||
Startup order:
|
||||
|
||||
@ -58,7 +63,8 @@ Startup order:
|
||||
2. **I2C bus** — IO expander `0x20`; optional **BMA456H** (`init_bma456`, same bus)
|
||||
3. `esp_now_comm_init(&app_config)` — WiFi + ESP-NOW
|
||||
4. `led_ring_init()`
|
||||
5. **Master only:** command queue, UART, registered commands (e.g. VERSION)
|
||||
5. `board_input_init()` — button press logs, LiPo ADC logs every **10 s**
|
||||
6. **Master only:** command queue, UART, registered commands (e.g. VERSION)
|
||||
|
||||
## BMA456 accelerometer (`bosch456.c`)
|
||||
|
||||
@ -310,6 +316,7 @@ Target: ESP32-S3. Close serial monitor on the UART adapter port before running `
|
||||
| `cmd_client_info.c/h` | CLIENT_INFO handler |
|
||||
| `client_registry.c/h` | Registered slave table |
|
||||
| `bosch456.c/h` | BMA456H I2C driver, accel poll, tap INT, deadzone filter |
|
||||
| `board_input.c/h` | Taster GPIO12, LiPo ADC on GPIO1 / GPIO12 |
|
||||
| `led_ring.c/h` | LED digit display |
|
||||
| `proto/uart_messages.proto` | UART protocol schema |
|
||||
| `proto/esp_now_messages.proto` | ESP-NOW protocol schema |
|
||||
|
||||
193
main/board_input.c
Normal file
193
main/board_input.c
Normal file
@ -0,0 +1,193 @@
|
||||
#include "board_input.h"
|
||||
#include "powerpod.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_adc/adc_oneshot.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/idf_additions.h"
|
||||
#include "freertos/queue.h"
|
||||
#include <stdint.h>
|
||||
|
||||
static const char *TAG_BTN = "[BTN]";
|
||||
static const char *TAG_LIPO = "[LIPO]";
|
||||
|
||||
#define LIPO_SAMPLE_INTERVAL_MS 10000
|
||||
#define BUTTON_QUEUE_LEN 4
|
||||
#define BUTTON_DEBOUNCE_MS 80
|
||||
|
||||
static QueueHandle_t s_button_queue;
|
||||
static adc_oneshot_unit_handle_t s_adc;
|
||||
static bool s_lipo1_ok;
|
||||
static bool s_lipo2_ok;
|
||||
static adc_channel_t s_lipo1_ch;
|
||||
static adc_channel_t s_lipo2_ch;
|
||||
|
||||
static esp_err_t adc_init_channel(int gpio, adc_channel_t *out_ch, bool *out_ok) {
|
||||
adc_unit_t unit;
|
||||
esp_err_t err = adc_oneshot_io_to_channel(gpio, &unit, out_ch);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG_LIPO, "GPIO%d not an ADC channel: %s", gpio, esp_err_to_name(err));
|
||||
*out_ok = false;
|
||||
return err;
|
||||
}
|
||||
if (unit != ADC_UNIT_1) {
|
||||
ESP_LOGW(TAG_LIPO, "GPIO%d on ADC unit %d (expected ADC1)", gpio, (int)unit);
|
||||
}
|
||||
adc_oneshot_chan_cfg_t chan_cfg = {
|
||||
.atten = ADC_ATTEN_DB_12,
|
||||
.bitwidth = ADC_BITWIDTH_DEFAULT,
|
||||
};
|
||||
err = adc_oneshot_config_channel(s_adc, *out_ch, &chan_cfg);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG_LIPO, "ADC config GPIO%d failed: %s", gpio, esp_err_to_name(err));
|
||||
*out_ok = false;
|
||||
return err;
|
||||
}
|
||||
*out_ok = true;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void lipo_monitor_task(void *param) {
|
||||
(void)param;
|
||||
|
||||
ESP_LOGI(TAG_LIPO, "monitor task (interval %d ms)", LIPO_SAMPLE_INTERVAL_MS);
|
||||
|
||||
while (1) {
|
||||
int raw1 = -1;
|
||||
int raw2 = -1;
|
||||
int mv1 = -1;
|
||||
int mv2 = -1;
|
||||
|
||||
if (s_lipo1_ok) {
|
||||
raw1 = 0;
|
||||
if (adc_oneshot_read(s_adc, s_lipo1_ch, &raw1) == ESP_OK) {
|
||||
mv1 = (raw1 * 3300) / 4095;
|
||||
}
|
||||
}
|
||||
if (s_lipo2_ok) {
|
||||
raw2 = 0;
|
||||
if (adc_oneshot_read(s_adc, s_lipo2_ch, &raw2) == ESP_OK) {
|
||||
mv2 = (raw2 * 3300) / 4095;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG_LIPO,
|
||||
"LIPO1 GPIO%d raw=%d (~%d mV) LIPO2 GPIO%d raw=%d (~%d mV)",
|
||||
V_LIPO_1_GPIO, raw1, mv1, V_LIPO_2_GPIO, raw2, mv2);
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(LIPO_SAMPLE_INTERVAL_MS));
|
||||
}
|
||||
}
|
||||
|
||||
static void IRAM_ATTR button_isr(void *arg) {
|
||||
(void)arg;
|
||||
uint8_t one = 1;
|
||||
BaseType_t wake = pdFALSE;
|
||||
if (s_button_queue != NULL) {
|
||||
xQueueSendFromISR(s_button_queue, &one, &wake);
|
||||
if (wake) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void button_task(void *param) {
|
||||
(void)param;
|
||||
uint8_t evt;
|
||||
|
||||
while (1) {
|
||||
if (xQueueReceive(s_button_queue, &evt, portMAX_DELAY) != pdTRUE) {
|
||||
continue;
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(BUTTON_DEBOUNCE_MS));
|
||||
if (gpio_get_level(TASTER_GPIO) == 0) {
|
||||
ESP_LOGI(TAG_BTN, "pressed (GPIO%d)", TASTER_GPIO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t init_button(void) {
|
||||
if (V_LIPO_2_GPIO == TASTER_GPIO) {
|
||||
ESP_LOGW(TAG_BTN,
|
||||
"GPIO%d shared with V_LIPO_2 — button only, no ADC on that pin",
|
||||
TASTER_GPIO);
|
||||
}
|
||||
|
||||
s_button_queue = xQueueCreate(BUTTON_QUEUE_LEN, sizeof(uint8_t));
|
||||
if (s_button_queue == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
gpio_config_t cfg = {
|
||||
.pin_bit_mask = 1ULL << TASTER_GPIO,
|
||||
.mode = GPIO_MODE_INPUT,
|
||||
.pull_up_en = GPIO_PULLUP_ENABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_NEGEDGE,
|
||||
};
|
||||
ESP_ERROR_CHECK(gpio_config(&cfg));
|
||||
|
||||
esp_err_t err = gpio_install_isr_service(0);
|
||||
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = gpio_isr_handler_add(TASTER_GPIO, button_isr, NULL);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (xTaskCreate(button_task, "btn", 2048, NULL, 2, NULL) != pdPASS) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG_BTN, "ready GPIO%d (active low)", TASTER_GPIO);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t init_lipo_adc(void) {
|
||||
adc_oneshot_unit_init_cfg_t init_cfg = {
|
||||
.unit_id = ADC_UNIT_1,
|
||||
};
|
||||
esp_err_t err = adc_oneshot_new_unit(&init_cfg, &s_adc);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG_LIPO, "ADC init failed: %s", esp_err_to_name(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
adc_init_channel(V_LIPO_1_GPIO, &s_lipo1_ch, &s_lipo1_ok);
|
||||
|
||||
if (V_LIPO_2_GPIO == TASTER_GPIO) {
|
||||
ESP_LOGW(TAG_LIPO, "LIPO2 on GPIO%d skipped (button uses same pin)",
|
||||
V_LIPO_2_GPIO);
|
||||
s_lipo2_ok = false;
|
||||
} else {
|
||||
adc_init_channel(V_LIPO_2_GPIO, &s_lipo2_ch, &s_lipo2_ok);
|
||||
}
|
||||
|
||||
if (!s_lipo1_ok && !s_lipo2_ok) {
|
||||
adc_oneshot_del_unit(s_adc);
|
||||
s_adc = NULL;
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (xTaskCreate(lipo_monitor_task, "lipo_mon", 3072, NULL, 1, NULL) != pdPASS) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t board_input_init(void) {
|
||||
esp_err_t err = init_button();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG_BTN, "init failed: %s", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
err = init_lipo_adc();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG_LIPO, "init failed: %s", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
12
main/board_input.h
Normal file
12
main/board_input.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef BOARD_INPUT_H
|
||||
#define BOARD_INPUT_H
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
/**
|
||||
* Button (log on press) and LiPo ADC sampling (log every 10 s).
|
||||
* TODO: Pin assignments come from powerpod.h and may not match final hardware yet.
|
||||
*/
|
||||
esp_err_t board_input_init(void);
|
||||
|
||||
#endif
|
||||
@ -15,6 +15,7 @@
|
||||
#include "esp_ota_ops.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/idf_additions.h"
|
||||
#include "board_input.h"
|
||||
#include "bosch456.h"
|
||||
#include "led_ring.h"
|
||||
#include "uart.h"
|
||||
@ -140,6 +141,8 @@ void app_main(void) {
|
||||
|
||||
led_ring_init();
|
||||
|
||||
board_input_init();
|
||||
|
||||
if (app_config.master) {
|
||||
cmd_queue = xQueueCreate(10, sizeof(generic_msg_t));
|
||||
init_cmdHandler(cmd_queue);
|
||||
|
||||
@ -7,4 +7,13 @@
|
||||
#define I2C_PORT 0
|
||||
#define IO_EXPANDER_ADDRESS 0x20
|
||||
|
||||
/* TODO: Hardware pinning not finalized — verify against schematic before production. */
|
||||
/** Front-panel button (active low, internal pull-up). */
|
||||
#define TASTER_GPIO 12
|
||||
|
||||
/** LiPo voltage sense inputs (ADC1-capable GPIOs). */
|
||||
#define V_LIPO_1_GPIO 1
|
||||
/** Shares GPIO with TASTER on current bench wiring; second ADC is skipped in board_input.c. */
|
||||
#define V_LIPO_2_GPIO 12
|
||||
|
||||
#endif
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user