Align BMA456H driver with Powerpod and document sensor integration.
Clarify hearable variant usage, clean up I2C/GPIO/tap init, and add README coverage for hardware, boot behavior, deadzone paths, and logging. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
e95097085d
commit
a8ae65d9dc
@ -50,13 +50,43 @@ Pins (`powerpod.h`):
|
|||||||
| UART TX | 3 |
|
| UART TX | 3 |
|
||||||
| UART RX | 2 |
|
| UART RX | 2 |
|
||||||
| LED ring | 7 |
|
| LED ring | 7 |
|
||||||
|
| BMA456 INT | 10 |
|
||||||
|
|
||||||
Startup order:
|
Startup order:
|
||||||
|
|
||||||
1. Read DIP + IO expander → `app_config`
|
1. Read DIP + IO expander → `app_config`
|
||||||
2. `esp_now_comm_init(&app_config)` — WiFi + ESP-NOW
|
2. **I2C bus** — IO expander `0x20`; optional **BMA456H** (`init_bma456`, same bus)
|
||||||
3. `led_ring_init()`
|
3. `esp_now_comm_init(&app_config)` — WiFi + ESP-NOW
|
||||||
4. **Master only:** command queue, UART, registered commands (e.g. VERSION)
|
4. `led_ring_init()`
|
||||||
|
5. **Master only:** command queue, UART, registered commands (e.g. VERSION)
|
||||||
|
|
||||||
|
## BMA456 accelerometer (`bosch456.c`)
|
||||||
|
|
||||||
|
Powerpod uses the Bosch **BMA456H** (hearable) variant, not the generic `bma456w` examples in the vendor tree.
|
||||||
|
|
||||||
|
| Item | Value |
|
||||||
|
|------|--------|
|
||||||
|
| Project wrapper | `main/bosch456.c`, `main/bosch456.h` |
|
||||||
|
| Vendor component | `components/bma456` — only `bma4.c` + `bma456h.c` are linked |
|
||||||
|
| I2C | Shared bus with IO expander (SCL/SDA GPIO 5/6), address **0x18**, **100 kHz** |
|
||||||
|
| Interrupt | **GPIO 10**, active high, tap events (single / double / triple) |
|
||||||
|
| Polling | FreeRTOS task `bma456_poll`, **10 Hz** accel read |
|
||||||
|
|
||||||
|
**Boot:** `init_bma456(bus_handle)` runs on **master and slave** after the IO expander. If the sensor is missing or init fails, firmware logs `BMA456 init skipped` and continues (`bma456_is_ready() == false`).
|
||||||
|
|
||||||
|
**Accel logging:** Samples are printed only when any axis changes by more than the **deadzone** (raw LSB) since the last logged sample (default **100**). This is a **software** filter on top of the sensor; it does not change BMA456 hardware thresholds.
|
||||||
|
|
||||||
|
**Configuration paths:**
|
||||||
|
|
||||||
|
| Path | Effect |
|
||||||
|
|------|--------|
|
||||||
|
| UART `ACCEL_DEADZONE` with `client_id = 0` | `bma456_set_accel_deadzone()` on the local node |
|
||||||
|
| ESP-NOW `SET_ACCEL_DEADZONE` | Same on a slave (no-op log path if sensor not installed) |
|
||||||
|
| `make gotool-deadzone-set DEADZONE=… CLIENT=0` | Host shortcut for local deadzone |
|
||||||
|
|
||||||
|
**Logs:** `[BMA456] ACC X=… Y=… Z=…` when deadzone exceeded; `[BMA456] tap: single|double|triple` on interrupt.
|
||||||
|
|
||||||
|
Regenerate nanopb only when changing protos; sensor code has no code generation step.
|
||||||
|
|
||||||
## ESP-NOW discovery
|
## ESP-NOW discovery
|
||||||
|
|
||||||
@ -177,7 +207,7 @@ Encoding: `uart_send_uart_message()` in `uart_proto.c`.
|
|||||||
|
|
||||||
### ACCEL_DEADZONE command
|
### ACCEL_DEADZONE command
|
||||||
|
|
||||||
Filters BMA456 logs: a new accel line is emitted only when any axis changes by more than `deadzone` raw LSB since the last reported sample (default **100**).
|
Sets the **software** deadzone used by `bosch456.c` when logging accel (see [BMA456 accelerometer](#bma456-accelerometer-bosch456c)). Default **100** LSB.
|
||||||
|
|
||||||
**Request:** framed `06` + nanopb `UartMessage` with `accel_deadzone_request`:
|
**Request:** framed `06` + nanopb `UartMessage` with `accel_deadzone_request`:
|
||||||
|
|
||||||
@ -279,6 +309,7 @@ Target: ESP32-S3. Close serial monitor on the UART adapter port before running `
|
|||||||
| `cmd_version.c/h` | VERSION handler |
|
| `cmd_version.c/h` | VERSION handler |
|
||||||
| `cmd_client_info.c/h` | CLIENT_INFO handler |
|
| `cmd_client_info.c/h` | CLIENT_INFO handler |
|
||||||
| `client_registry.c/h` | Registered slave table |
|
| `client_registry.c/h` | Registered slave table |
|
||||||
|
| `bosch456.c/h` | BMA456H I2C driver, accel poll, tap INT, deadzone filter |
|
||||||
| `led_ring.c/h` | LED digit display |
|
| `led_ring.c/h` | LED digit display |
|
||||||
| `proto/uart_messages.proto` | UART protocol schema |
|
| `proto/uart_messages.proto` | UART protocol schema |
|
||||||
| `proto/esp_now_messages.proto` | ESP-NOW protocol schema |
|
| `proto/esp_now_messages.proto` | ESP-NOW protocol schema |
|
||||||
|
|||||||
412
main/bosch456.c
412
main/bosch456.c
@ -1,134 +1,90 @@
|
|||||||
|
/**
|
||||||
|
* BMA456H integration for Powerpod (ESP-IDF I2C master + Bosch SensorAPI).
|
||||||
|
*
|
||||||
|
* Polls accelerometer at 10 Hz; tap events arrive on BMA456_INT_GPIO.
|
||||||
|
* Accel logging is filtered in software (deadzone); see ACCEL_DEADZONE UART command.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "bosch456.h"
|
#include "bosch456.h"
|
||||||
#include "bma4.h"
|
#include "bma4.h"
|
||||||
#include "bma456h.h"
|
|
||||||
#include "bma4_defs.h"
|
#include "bma4_defs.h"
|
||||||
|
#include "bma456h.h"
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
#include "driver/i2c_master.h"
|
#include "driver/i2c_master.h"
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "freertos/idf_additions.h"
|
#include "freertos/idf_additions.h"
|
||||||
#include "hal/gpio_types.h"
|
|
||||||
#include <rom/ets_sys.h>
|
#include <rom/ets_sys.h>
|
||||||
#include <stdint.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
static const char *TAG = "[BMA456]";
|
static const char *TAG = "[BMA456]";
|
||||||
|
|
||||||
static i2c_master_dev_handle_t bma456_dev_handle;
|
#define BMA4_READ_WRITE_LEN UINT8_C(46)
|
||||||
|
#define BMA4_I2C_MAX_WRITE (1u + BMA4_READ_WRITE_LEN)
|
||||||
|
|
||||||
|
#define SENSOR_POLL_MS 100
|
||||||
|
|
||||||
|
static i2c_master_dev_handle_t s_bma456_dev;
|
||||||
static bool s_bma456_ready;
|
static bool s_bma456_ready;
|
||||||
static struct bma4_dev bma456_struct;
|
static struct bma4_dev s_bma456;
|
||||||
static uint32_t s_accel_deadzone = BMA456_DEFAULT_ACCEL_DEADZONE;
|
static uint32_t s_accel_deadzone = BMA456_DEFAULT_ACCEL_DEADZONE;
|
||||||
static int16_t s_last_x;
|
static int16_t s_last_x;
|
||||||
static int16_t s_last_y;
|
static int16_t s_last_y;
|
||||||
static int16_t s_last_z;
|
static int16_t s_last_z;
|
||||||
static bool s_have_last_sample;
|
static bool s_have_last_sample;
|
||||||
|
|
||||||
volatile uint8_t interrupt_status = 0;
|
static volatile bool s_int_pending;
|
||||||
uint8_t int_line;
|
|
||||||
struct bma4_int_pin_config pin_config = {0};
|
|
||||||
uint16_t int_status = 0;
|
|
||||||
|
|
||||||
#define BMA4_READ_WRITE_LEN UINT8_C(46)
|
static esp_err_t check_bma4(const char *api_name, int8_t rslt);
|
||||||
#define BMA456W_INT_PIN 10
|
|
||||||
#define BMA456W_INT_PIN2 9
|
|
||||||
|
|
||||||
static void interrupt_callback(void *) {
|
/* Bosch SensorAPI platform hooks (intf_ptr → i2c_master_dev_handle_t *). */
|
||||||
interrupt_status = 1;
|
|
||||||
// ESP_LOGI("INTERRUPT", "STEP DETECTED");
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
/*! User interface functions */
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* I2C read function map to ESP platform
|
|
||||||
*/
|
|
||||||
BMA4_INTF_RET_TYPE bma4_i2c_read(uint8_t reg_addr, uint8_t *reg_data,
|
BMA4_INTF_RET_TYPE bma4_i2c_read(uint8_t reg_addr, uint8_t *reg_data,
|
||||||
uint32_t len, void *intf_ptr) {
|
uint32_t len, void *intf_ptr) {
|
||||||
if (bma456_dev_handle == NULL) {
|
if (s_bma456_dev == NULL) {
|
||||||
return BMA4_E_COM_FAIL;
|
return BMA4_E_COM_FAIL;
|
||||||
}
|
}
|
||||||
esp_err_t err = i2c_master_transmit_receive(bma456_dev_handle, ®_addr, 1,
|
esp_err_t err = i2c_master_transmit_receive(s_bma456_dev, ®_addr, 1,
|
||||||
reg_data, len, -1);
|
reg_data, len, -1);
|
||||||
return (err == ESP_OK) ? BMA4_OK : BMA4_E_COM_FAIL;
|
return (err == ESP_OK) ? BMA4_OK : BMA4_E_COM_FAIL;
|
||||||
// return BMA4_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* I2C write function map to ESP platform
|
|
||||||
*/
|
|
||||||
BMA4_INTF_RET_TYPE bma4_i2c_write(uint8_t reg_addr, const uint8_t *reg_data,
|
BMA4_INTF_RET_TYPE bma4_i2c_write(uint8_t reg_addr, const uint8_t *reg_data,
|
||||||
uint32_t len, void *intf_ptr) {
|
uint32_t len, void *intf_ptr) {
|
||||||
if (bma456_dev_handle == NULL) {
|
(void)intf_ptr;
|
||||||
|
if (s_bma456_dev == NULL || reg_data == NULL) {
|
||||||
|
return BMA4_E_COM_FAIL;
|
||||||
|
}
|
||||||
|
if (len > BMA4_READ_WRITE_LEN) {
|
||||||
return BMA4_E_COM_FAIL;
|
return BMA4_E_COM_FAIL;
|
||||||
}
|
}
|
||||||
uint8_t *buffer = malloc(len + 1);
|
|
||||||
if (!buffer)
|
|
||||||
return BMA4_E_NULL_PTR;
|
|
||||||
|
|
||||||
|
uint8_t buffer[BMA4_I2C_MAX_WRITE];
|
||||||
buffer[0] = reg_addr;
|
buffer[0] = reg_addr;
|
||||||
|
|
||||||
ESP_LOGI("I2CWrite", "Message Length: %d", len);
|
|
||||||
|
|
||||||
memcpy(&buffer[1], reg_data, len);
|
memcpy(&buffer[1], reg_data, len);
|
||||||
|
|
||||||
esp_err_t err = i2c_master_transmit(bma456_dev_handle, buffer, len + 1, -1);
|
esp_err_t err =
|
||||||
free(buffer);
|
i2c_master_transmit(s_bma456_dev, buffer, (size_t)(len + 1), -1);
|
||||||
|
|
||||||
return (err == ESP_OK) ? BMA4_OK : BMA4_E_COM_FAIL;
|
return (err == ESP_OK) ? BMA4_OK : BMA4_E_COM_FAIL;
|
||||||
// return BMA4_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* Delay function map to ESP platform
|
|
||||||
*/
|
|
||||||
void bma4_delay_us(uint32_t period, void *intf_ptr) {
|
void bma4_delay_us(uint32_t period, void *intf_ptr) {
|
||||||
|
(void)intf_ptr;
|
||||||
uint32_t wait_ms = period / 1000;
|
uint32_t wait_ms = period / 1000;
|
||||||
uint32_t wait_us = period % 1000;
|
uint32_t wait_us = period % 1000;
|
||||||
if (wait_ms) {
|
if (wait_ms > 0) {
|
||||||
vTaskDelay(pdMS_TO_TICKS(wait_ms));
|
vTaskDelay(pdMS_TO_TICKS(wait_ms));
|
||||||
}
|
}
|
||||||
ets_delay_us(wait_us);
|
if (wait_us > 0) {
|
||||||
|
ets_delay_us(wait_us);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Prints the execution status of the APIs.
|
|
||||||
*/
|
|
||||||
void bma4_error_codes_print_result(const char api_name[], int8_t rslt) {
|
void bma4_error_codes_print_result(const char api_name[], int8_t rslt) {
|
||||||
if (rslt == BMA4_OK) {
|
if (rslt == BMA4_OK) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
ESP_LOGW(TAG, "%s failed: %d", api_name, (int)rslt);
|
||||||
ESP_LOGI("BMA4_I2C", "%s\t", api_name);
|
|
||||||
|
|
||||||
switch (rslt) {
|
|
||||||
case BMA4_E_NULL_PTR:
|
|
||||||
ESP_LOGI("BMA4_I2C", "Error [%d] : Null pointer\r\n", rslt);
|
|
||||||
break;
|
|
||||||
case BMA4_E_COM_FAIL:
|
|
||||||
ESP_LOGI("BMA4_I2C", "Error [%d] : Communication failure\r\n", rslt);
|
|
||||||
break;
|
|
||||||
case BMA4_E_CONFIG_STREAM_ERROR:
|
|
||||||
ESP_LOGI("BMA4_I2C", "Error [%d] : Invalid configuration stream\r\n", rslt);
|
|
||||||
break;
|
|
||||||
case BMA4_E_SELF_TEST_FAIL:
|
|
||||||
ESP_LOGI("BMA4_I2C", "Error [%d] : Self test failed\r\n", rslt);
|
|
||||||
break;
|
|
||||||
case BMA4_E_INVALID_SENSOR:
|
|
||||||
ESP_LOGI("BMA4_I2C", "Error [%d] : Device not found\r\n", rslt);
|
|
||||||
break;
|
|
||||||
case BMA4_E_OUT_OF_RANGE:
|
|
||||||
ESP_LOGI("BMA4_I2C", "Error [%d] : Out of Range\r\n", rslt);
|
|
||||||
break;
|
|
||||||
case BMA4_E_AVG_MODE_INVALID_CONF:
|
|
||||||
ESP_LOGI("BMA4_I2C", "Error [%d] : Invalid bandwidth/ODR combination\r\n",
|
|
||||||
rslt);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ESP_LOGI("BMA4_I2C", "Error [%d] : Unknown error code\r\n", rslt);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static esp_err_t check_bma4(const char *api_name, int8_t rslt) {
|
static esp_err_t check_bma4(const char *api_name, int8_t rslt) {
|
||||||
@ -159,17 +115,14 @@ void bma456_set_accel_deadzone(uint32_t deadzone_lsb) {
|
|||||||
s_accel_deadzone = deadzone_lsb;
|
s_accel_deadzone = deadzone_lsb;
|
||||||
s_have_last_sample = false;
|
s_have_last_sample = false;
|
||||||
if (s_bma456_ready) {
|
if (s_bma456_ready) {
|
||||||
ESP_LOGI(TAG, "accel deadzone applied: %lu LSB", (unsigned long)deadzone_lsb);
|
ESP_LOGI(TAG, "accel deadzone %lu LSB", (unsigned long)deadzone_lsb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t bma456_get_accel_deadzone(void) { return s_accel_deadzone; }
|
uint32_t bma456_get_accel_deadzone(void) { return s_accel_deadzone; }
|
||||||
|
|
||||||
void bma456_report_accel_if_changed(int16_t x, int16_t y, int16_t z) {
|
void bma456_report_accel_if_changed(int16_t x, int16_t y, int16_t z) {
|
||||||
if (!s_bma456_ready) {
|
if (!s_bma456_ready || !sample_exceeds_deadzone(x, y, z)) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!sample_exceeds_deadzone(x, y, z)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,165 +135,107 @@ void bma456_report_accel_if_changed(int16_t x, int16_t y, int16_t z) {
|
|||||||
(unsigned long)s_accel_deadzone);
|
(unsigned long)s_accel_deadzone);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void remove_bma456_device(void) {
|
static void IRAM_ATTR bma456_int_isr(void *arg) {
|
||||||
if (bma456_dev_handle != NULL) {
|
(void)arg;
|
||||||
i2c_master_bus_rm_device(bma456_dev_handle);
|
s_int_pending = true;
|
||||||
bma456_dev_handle = NULL;
|
|
||||||
}
|
|
||||||
s_bma456_ready = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void read_sensor_task(void *params) {
|
static void handle_tap_interrupt(void) {
|
||||||
int8_t ret;
|
uint16_t int_status = 0;
|
||||||
struct bma4_accel sens_data = {0};
|
int8_t ret = bma456h_read_int_status(&int_status, &s_bma456);
|
||||||
|
if (ret != BMA4_OK) {
|
||||||
|
bma4_error_codes_print_result("bma456h_read_int_status", ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct bma456h_out_state tap_out = {0};
|
||||||
|
ret = bma456h_output_state(&tap_out, &s_bma456);
|
||||||
|
if (ret != BMA4_OK) {
|
||||||
|
bma4_error_codes_print_result("bma456h_output_state", ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tap_out.single_tap) {
|
||||||
|
ESP_LOGI(TAG, "tap: single");
|
||||||
|
} else if (tap_out.double_tap) {
|
||||||
|
ESP_LOGI(TAG, "tap: double");
|
||||||
|
} else if (tap_out.triple_tap) {
|
||||||
|
ESP_LOGI(TAG, "tap: triple");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void remove_bma456_device(void) {
|
||||||
|
if (s_bma456_ready) {
|
||||||
|
gpio_isr_handler_remove(BMA456_INT_GPIO);
|
||||||
|
}
|
||||||
|
if (s_bma456_dev != NULL) {
|
||||||
|
i2c_master_bus_rm_device(s_bma456_dev);
|
||||||
|
s_bma456_dev = NULL;
|
||||||
|
}
|
||||||
|
s_bma456_ready = false;
|
||||||
|
s_int_pending = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void read_sensor_task(void *param) {
|
||||||
|
(void)param;
|
||||||
|
|
||||||
if (!s_bma456_ready) {
|
if (!s_bma456_ready) {
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct bma4_accel sens_data = {0};
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
ret = bma4_read_accel_xyz(&sens_data, &bma456_struct);
|
int8_t ret = bma4_read_accel_xyz(&sens_data, &s_bma456);
|
||||||
if (ret == BMA4_OK) {
|
if (ret == BMA4_OK) {
|
||||||
bma456_report_accel_if_changed(sens_data.x, sens_data.y, sens_data.z);
|
bma456_report_accel_if_changed(sens_data.x, sens_data.y, sens_data.z);
|
||||||
} else {
|
} else {
|
||||||
bma4_error_codes_print_result("bma4_read_accel_xyz", ret);
|
bma4_error_codes_print_result("bma4_read_accel_xyz", ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interrupt_status) {
|
if (s_int_pending) {
|
||||||
ESP_LOGI("INTERRUPT", "Da war der Interrupt resetting");
|
s_int_pending = false;
|
||||||
interrupt_status = 0;
|
handle_tap_interrupt();
|
||||||
ret = bma456h_read_int_status(&int_status, &bma456_struct);
|
|
||||||
bma4_error_codes_print_result("bma456w_step_counter_output status", ret);
|
|
||||||
|
|
||||||
int8_t rslt;
|
|
||||||
struct bma456h_out_state tap_out = {0};
|
|
||||||
|
|
||||||
rslt = bma456h_output_state(&tap_out, &bma456_struct);
|
|
||||||
|
|
||||||
if (BMA4_OK == rslt) {
|
|
||||||
/* Enters only if the obtained interrupt is single-tap */
|
|
||||||
if (tap_out.single_tap) {
|
|
||||||
ESP_LOGI("INTERRUPT", "Single Tap interrupt occurred\n");
|
|
||||||
}
|
|
||||||
/* Enters only if the obtained interrupt is double-tap */
|
|
||||||
else if (tap_out.double_tap) {
|
|
||||||
ESP_LOGI("INTERRUPT", "Double Tap interrupt occurred\n");
|
|
||||||
}
|
|
||||||
/* Enters only if the obtained interrupt is triple-tap */
|
|
||||||
else if (tap_out.triple_tap) {
|
|
||||||
ESP_LOGI("INTERRUPT", "Triple Tap interrupt occurred\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ESP_LOGI("i2c", "X:%d, Y%d, Z%d", sens_data.x, sens_data.y, sens_data.z);
|
vTaskDelay(pdMS_TO_TICKS(SENSOR_POLL_MS));
|
||||||
vTaskDelay(pdMS_TO_TICKS(100));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t init_bma456(i2c_master_bus_handle_t bus_handle) {
|
static esp_err_t configure_tap_interrupt(void) {
|
||||||
int8_t ret;
|
|
||||||
esp_err_t err;
|
esp_err_t err;
|
||||||
|
int8_t ret;
|
||||||
s_bma456_ready = false;
|
const uint8_t int_line = BMA4_INTR2_MAP;
|
||||||
bma456_dev_handle = NULL;
|
|
||||||
|
|
||||||
if (bus_handle == NULL) {
|
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
|
|
||||||
i2c_device_config_t dev_cfg_bma456 = {
|
|
||||||
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
|
||||||
.device_address = BMA456_ADDRESS,
|
|
||||||
.scl_speed_hz = 100000,
|
|
||||||
};
|
|
||||||
|
|
||||||
err = i2c_master_bus_add_device(bus_handle, &dev_cfg_bma456, &bma456_dev_handle);
|
|
||||||
if (err != ESP_OK) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
bma456_struct.intf = BMA4_I2C_INTF;
|
|
||||||
bma456_struct.bus_read = bma4_i2c_read;
|
|
||||||
bma456_struct.bus_write = bma4_i2c_write;
|
|
||||||
bma456_struct.delay_us = bma4_delay_us;
|
|
||||||
bma456_struct.read_write_len = BMA4_READ_WRITE_LEN;
|
|
||||||
bma456_struct.intf_ptr = &bma456_dev_handle;
|
|
||||||
bma456_struct.chip_id = 0;
|
|
||||||
|
|
||||||
ret = bma456h_init(&bma456_struct);
|
|
||||||
if (check_bma4("bma456h_init", ret) != ESP_OK) {
|
|
||||||
remove_bma456_device();
|
|
||||||
return ESP_ERR_NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "chip id 0x%02x", bma456_struct.chip_id);
|
|
||||||
|
|
||||||
ret = bma4_soft_reset(&bma456_struct);
|
|
||||||
if (check_bma4("bma4_soft_reset", ret) != ESP_OK) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(20));
|
|
||||||
|
|
||||||
ret = bma4_set_advance_power_save(BMA4_DISABLE, &bma456_struct);
|
|
||||||
if (check_bma4("bma4_set_advance_power_save", ret) != ESP_OK) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(10));
|
|
||||||
|
|
||||||
ret = bma456h_write_config_file(&bma456_struct);
|
|
||||||
if (check_bma4("bma456h_write_config_file", ret) != ESP_OK) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct bma4_accel_config accel_config;
|
|
||||||
bma4_get_accel_config(&accel_config, &bma456_struct);
|
|
||||||
accel_config.range = BMA4_ACCEL_RANGE_2G;
|
|
||||||
ret = bma4_set_accel_config(&accel_config, &bma456_struct);
|
|
||||||
if (check_bma4("bma4_set_accel_config", ret) != ESP_OK) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = bma4_set_accel_enable(BMA4_ENABLE, &bma456_struct);
|
|
||||||
if (check_bma4("bma4_set_accel_enable", ret) != ESP_OK) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct bma456h_multitap_settings tap_settings = {0};
|
struct bma456h_multitap_settings tap_settings = {0};
|
||||||
ret = bma456h_tap_get_parameter(&tap_settings, &bma456_struct);
|
ret = bma456h_tap_get_parameter(&tap_settings, &s_bma456);
|
||||||
if (check_bma4("bma456h_tap_get_parameter", ret) != ESP_OK) {
|
if (check_bma4("bma456h_tap_get_parameter", ret) != ESP_OK) {
|
||||||
goto fail;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
tap_settings.tap_sens_thres = 0;
|
tap_settings.tap_sens_thres = 0;
|
||||||
ret = bma456h_tap_set_parameter(&tap_settings, &bma456_struct);
|
ret = bma456h_tap_set_parameter(&tap_settings, &s_bma456);
|
||||||
if (check_bma4("bma456h_tap_set_parameter", ret) != ESP_OK) {
|
if (check_bma4("bma456h_tap_set_parameter", ret) != ESP_OK) {
|
||||||
goto fail;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bma456h_feature_enable(
|
ret = bma456h_feature_enable(
|
||||||
(BMA456H_SINGLE_TAP_EN | BMA456H_DOUBLE_TAP_EN | BMA456H_TRIPLE_TAP_EN),
|
(BMA456H_SINGLE_TAP_EN | BMA456H_DOUBLE_TAP_EN | BMA456H_TRIPLE_TAP_EN),
|
||||||
BMA4_ENABLE, &bma456_struct);
|
BMA4_ENABLE, &s_bma456);
|
||||||
if (check_bma4("bma456h_feature_enable", ret) != ESP_OK) {
|
if (check_bma4("bma456h_feature_enable", ret) != ESP_OK) {
|
||||||
goto fail;
|
return ESP_FAIL;
|
||||||
}
|
|
||||||
|
|
||||||
ret = bma456h_step_counter_set_watermark(1, &bma456_struct);
|
|
||||||
if (check_bma4("bma456h_step_counter_set_watermark", ret) != ESP_OK) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
int_line = BMA4_INTR2_MAP;
|
|
||||||
|
|
||||||
ret = bma4_get_int_pin_config(&pin_config, int_line, &bma456_struct);
|
|
||||||
if (check_bma4("bma4_get_int_pin_config", ret) != ESP_OK) {
|
|
||||||
goto fail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bma456h_map_interrupt(int_line, BMA456H_TAP_OUT_INT, BMA4_ENABLE,
|
ret = bma456h_map_interrupt(int_line, BMA456H_TAP_OUT_INT, BMA4_ENABLE,
|
||||||
&bma456_struct);
|
&s_bma456);
|
||||||
if (check_bma4("bma456h_map_interrupt", ret) != ESP_OK) {
|
if (check_bma4("bma456h_map_interrupt", ret) != ESP_OK) {
|
||||||
goto fail;
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct bma4_int_pin_config pin_config = {0};
|
||||||
|
ret = bma4_get_int_pin_config(&pin_config, int_line, &s_bma456);
|
||||||
|
if (check_bma4("bma4_get_int_pin_config", ret) != ESP_OK) {
|
||||||
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pin_config.edge_ctrl = BMA4_EDGE_TRIGGER;
|
pin_config.edge_ctrl = BMA4_EDGE_TRIGGER;
|
||||||
@ -349,36 +244,113 @@ esp_err_t init_bma456(i2c_master_bus_handle_t bus_handle) {
|
|||||||
pin_config.od = BMA4_PUSH_PULL;
|
pin_config.od = BMA4_PUSH_PULL;
|
||||||
pin_config.input_en = BMA4_INPUT_DISABLE;
|
pin_config.input_en = BMA4_INPUT_DISABLE;
|
||||||
|
|
||||||
ret = bma4_set_int_pin_config(&pin_config, int_line, &bma456_struct);
|
ret = bma4_set_int_pin_config(&pin_config, int_line, &s_bma456);
|
||||||
if (check_bma4("bma4_set_int_pin_config", ret) != ESP_OK) {
|
if (check_bma4("bma4_set_int_pin_config", ret) != ESP_OK) {
|
||||||
goto fail;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
gpio_reset_pin(BMA456W_INT_PIN);
|
gpio_reset_pin(BMA456_INT_GPIO);
|
||||||
gpio_set_direction(BMA456W_INT_PIN, GPIO_MODE_INPUT);
|
gpio_set_direction(BMA456_INT_GPIO, GPIO_MODE_INPUT);
|
||||||
gpio_set_pull_mode(BMA456W_INT_PIN, GPIO_PULLDOWN_ENABLE);
|
gpio_set_pull_mode(BMA456_INT_GPIO, GPIO_PULLDOWN_ONLY);
|
||||||
gpio_set_intr_type(BMA456W_INT_PIN, GPIO_INTR_POSEDGE);
|
gpio_set_intr_type(BMA456_INT_GPIO, GPIO_INTR_POSEDGE);
|
||||||
gpio_intr_enable(BMA456W_INT_PIN);
|
|
||||||
|
|
||||||
err = gpio_install_isr_service(0);
|
err = gpio_install_isr_service(0);
|
||||||
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
|
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
|
||||||
goto fail;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = gpio_isr_handler_add(BMA456W_INT_PIN, interrupt_callback,
|
err = gpio_isr_handler_add(BMA456_INT_GPIO, bma456_int_isr, NULL);
|
||||||
(void *)BMA456W_INT_PIN);
|
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t init_bma456(i2c_master_bus_handle_t bus_handle) {
|
||||||
|
int8_t ret;
|
||||||
|
esp_err_t err;
|
||||||
|
|
||||||
|
s_bma456_ready = false;
|
||||||
|
s_bma456_dev = NULL;
|
||||||
|
s_int_pending = false;
|
||||||
|
|
||||||
|
if (bus_handle == NULL) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_device_config_t dev_cfg = {
|
||||||
|
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
||||||
|
.device_address = BMA456_I2C_ADDR,
|
||||||
|
.scl_speed_hz = 100000,
|
||||||
|
};
|
||||||
|
|
||||||
|
err = i2c_master_bus_add_device(bus_handle, &dev_cfg, &s_bma456_dev);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_bma456.intf = BMA4_I2C_INTF;
|
||||||
|
s_bma456.bus_read = bma4_i2c_read;
|
||||||
|
s_bma456.bus_write = bma4_i2c_write;
|
||||||
|
s_bma456.delay_us = bma4_delay_us;
|
||||||
|
s_bma456.read_write_len = BMA4_READ_WRITE_LEN;
|
||||||
|
s_bma456.intf_ptr = &s_bma456_dev;
|
||||||
|
s_bma456.chip_id = 0;
|
||||||
|
|
||||||
|
ret = bma456h_init(&s_bma456);
|
||||||
|
if (check_bma4("bma456h_init", ret) != ESP_OK) {
|
||||||
|
remove_bma456_device();
|
||||||
|
return ESP_ERR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "chip id 0x%02x", s_bma456.chip_id);
|
||||||
|
|
||||||
|
ret = bma4_soft_reset(&s_bma456);
|
||||||
|
if (check_bma4("bma4_soft_reset", ret) != ESP_OK) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(20));
|
||||||
|
|
||||||
|
ret = bma4_set_advance_power_save(BMA4_DISABLE, &s_bma456);
|
||||||
|
if (check_bma4("bma4_set_advance_power_save", ret) != ESP_OK) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(10));
|
||||||
|
|
||||||
|
ret = bma456h_write_config_file(&s_bma456);
|
||||||
|
if (check_bma4("bma456h_write_config_file", ret) != ESP_OK) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xTaskCreate(read_sensor_task, "READ_SENSOR", 4096, NULL, 1, NULL) !=
|
struct bma4_accel_config accel_config = {0};
|
||||||
|
ret = bma4_get_accel_config(&accel_config, &s_bma456);
|
||||||
|
if (check_bma4("bma4_get_accel_config", ret) != ESP_OK) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
accel_config.range = BMA4_ACCEL_RANGE_2G;
|
||||||
|
ret = bma4_set_accel_config(&accel_config, &s_bma456);
|
||||||
|
if (check_bma4("bma4_set_accel_config", ret) != ESP_OK) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = bma4_set_accel_enable(BMA4_ENABLE, &s_bma456);
|
||||||
|
if (check_bma4("bma4_set_accel_enable", ret) != ESP_OK) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configure_tap_interrupt() != ESP_OK) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xTaskCreate(read_sensor_task, "bma456_poll", 4096, NULL, 1, NULL) !=
|
||||||
pdPASS) {
|
pdPASS) {
|
||||||
gpio_isr_handler_remove(BMA456W_INT_PIN);
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
s_bma456_ready = true;
|
s_bma456_ready = true;
|
||||||
ESP_LOGI(TAG, "initialized");
|
ESP_LOGI(TAG, "ready (I2C 0x%02x, INT GPIO%d, poll %d ms)", BMA456_I2C_ADDR,
|
||||||
|
BMA456_INT_GPIO, SENSOR_POLL_MS);
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
|||||||
@ -1,17 +1,30 @@
|
|||||||
#ifndef BOSCH456_H
|
#ifndef BOSCH456_H
|
||||||
#define BOSCH456_H
|
#define BOSCH456_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Powerpod driver for Bosch BMA456H (hearable variant) on the shared I2C bus.
|
||||||
|
*
|
||||||
|
* Vendor API: components/bma456 (bma4.c + bma456h.c only).
|
||||||
|
* Implementation: bosch456.c
|
||||||
|
*/
|
||||||
|
|
||||||
#include "driver/i2c_types.h"
|
#include "driver/i2c_types.h"
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
|
|
||||||
#define TOUCH_1 9
|
/** 7-bit I2C address (SDO low). */
|
||||||
#define TOUCH_2 8
|
#define BMA456_I2C_ADDR 0x18
|
||||||
|
|
||||||
#define BMA456_ADDRESS 0x18
|
/** Sensor interrupt line → ESP32 GPIO (active high, rising edge). */
|
||||||
|
#define BMA456_INT_GPIO 10
|
||||||
|
|
||||||
|
/** Software filter: log accel only when |axis - last| > deadzone (raw LSB). */
|
||||||
#define BMA456_DEFAULT_ACCEL_DEADZONE 100u
|
#define BMA456_DEFAULT_ACCEL_DEADZONE 100u
|
||||||
|
|
||||||
/** Initialize BMA456 on the shared I2C bus. Returns ESP_OK or logs and skips sensor use. */
|
/**
|
||||||
|
* Probe and configure the sensor on bus_handle (100 kHz device).
|
||||||
|
* On failure the device is removed and ESP_ERR_NOT_FOUND / ESP_FAIL is returned;
|
||||||
|
* firmware continues without a sensor (see bma456_is_ready()).
|
||||||
|
*/
|
||||||
esp_err_t init_bma456(i2c_master_bus_handle_t bus_handle);
|
esp_err_t init_bma456(i2c_master_bus_handle_t bus_handle);
|
||||||
|
|
||||||
bool bma456_is_ready(void);
|
bool bma456_is_ready(void);
|
||||||
@ -19,7 +32,7 @@ bool bma456_is_ready(void);
|
|||||||
void bma456_set_accel_deadzone(uint32_t deadzone_lsb);
|
void bma456_set_accel_deadzone(uint32_t deadzone_lsb);
|
||||||
uint32_t bma456_get_accel_deadzone(void);
|
uint32_t bma456_get_accel_deadzone(void);
|
||||||
|
|
||||||
/** Log accel sample only when any axis changed more than deadzone since last report. */
|
/** Log accel when any axis moved more than deadzone since last reported sample. */
|
||||||
void bma456_report_accel_if_changed(int16_t x, int16_t y, int16_t z);
|
void bma456_report_accel_if_changed(int16_t x, int16_t y, int16_t z);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user