From a04656c7c4a2f84798b45e857c86ae22c95718df Mon Sep 17 00:00:00 2001
From: schneider <schneider@blinkenlichts.net>
Date: Fri, 4 Aug 2023 23:42:56 +0200
Subject: [PATCH] imu: read all sensors at once at 100 Hz

---
 components/flow3r_bsp/flow3r_bsp_imu.c | 57 +++++++---------
 components/flow3r_bsp/flow3r_bsp_imu.h | 33 +++++----
 components/st3m/st3m_imu.c             | 93 +++++++++++++++++++++-----
 components/st3m/st3m_imu.h             |  6 +-
 4 files changed, 123 insertions(+), 66 deletions(-)

diff --git a/components/flow3r_bsp/flow3r_bsp_imu.c b/components/flow3r_bsp/flow3r_bsp_imu.c
index e4439465f0..846ac9bbc2 100644
--- a/components/flow3r_bsp/flow3r_bsp_imu.c
+++ b/components/flow3r_bsp/flow3r_bsp_imu.c
@@ -30,6 +30,8 @@ static int8_t set_bmp_config(
 static float lsb_to_mps(int16_t val, float g_range, uint8_t bit_width);
 static float lsb_to_dps(int16_t val, float dps, uint8_t bit_width);
 
+static struct bmi2_sens_data _bmi_sens_data;
+
 static BMI2_INTF_RETURN_TYPE bmi2_i2c_read(uint8_t reg_addr, uint8_t *reg_data,
                                            uint32_t len, void *intf_ptr) {
     flow3r_bsp_imu_t *imu = (flow3r_bsp_imu_t *)intf_ptr;
@@ -83,11 +85,11 @@ static BMP5_INTF_RET_TYPE bmp5_i2c_read(uint8_t reg_addr, uint8_t *reg_data,
     int8_t rslt;
 
     // The BMI270 is configured to automatically fetch the sensor readings
-    // from the BMP581. We can read them directly from BMI270 memory, avoiding
+    // from the BMP581. We can read them directly from BMI270 state, avoiding
     // extra I2C transactions.
-    if (reg_addr >= BMP5_REG_TEMP_DATA_XLSB &&
-        reg_addr + length <= BMP5_REG_TEMP_DATA_XLSB + 6) {
-        rslt = bmi2_i2c_read(BMI2_AUX_X_LSB_ADDR, reg_data, length, intf_ptr);
+    if (reg_addr == BMP5_REG_TEMP_DATA_XLSB && length <= 6) {
+        memcpy(reg_data, _bmi_sens_data.aux_data, length);
+        rslt = BMI2_OK;
     } else {
         rslt = bmi2_read_aux_man_mode(reg_addr, reg_data, (uint16_t)length,
                                       &imu->bmi);
@@ -221,25 +223,28 @@ esp_err_t flow3r_bsp_imu_init(flow3r_bsp_imu_t *imu) {
     return ESP_OK;
 }
 
-esp_err_t flow3r_bsp_imu_read_acc(flow3r_bsp_imu_t *imu, int *x, int *y,
-                                  int *z) {
+esp_err_t flow3r_bsp_imu_update(flow3r_bsp_imu_t *imu) {
     struct bmi2_sens_data sens_data = {
         0,
     };
-
     int8_t rslt = bmi2_get_sensor_data(&sens_data, &(imu->bmi));
     bmi2_error_codes_print_result(rslt);
 
     if (rslt == BMI2_OK) {
-        if (sens_data.status & BMI2_DRDY_ACC) {
-            *x = sens_data.acc.x;
-            *y = sens_data.acc.y;
-            *z = sens_data.acc.z;
-            return ESP_OK;
-        }
-        return ESP_ERR_NOT_FOUND;
+        _bmi_sens_data = sens_data;
+    }
+    return rslt;
+}
+
+esp_err_t flow3r_bsp_imu_read_acc(flow3r_bsp_imu_t *imu, int *x, int *y,
+                                  int *z) {
+    if (_bmi_sens_data.status & BMI2_DRDY_ACC) {
+        *x = _bmi_sens_data.acc.x;
+        *y = _bmi_sens_data.acc.y;
+        *z = _bmi_sens_data.acc.z;
+        return ESP_OK;
     }
-    return ESP_FAIL;
+    return ESP_ERR_NOT_FOUND;
 }
 
 esp_err_t flow3r_bsp_imu_read_acc_mps(flow3r_bsp_imu_t *imu, float *x, float *y,
@@ -259,23 +264,13 @@ esp_err_t flow3r_bsp_imu_read_acc_mps(flow3r_bsp_imu_t *imu, float *x, float *y,
 
 esp_err_t flow3r_bsp_imu_read_gyro(flow3r_bsp_imu_t *imu, int *x, int *y,
                                    int *z) {
-    struct bmi2_sens_data sens_data = {
-        0,
-    };
-
-    int8_t rslt = bmi2_get_sensor_data(&sens_data, &(imu->bmi));
-    bmi2_error_codes_print_result(rslt);
-
-    if (rslt == BMI2_OK) {
-        if (sens_data.status & BMI2_DRDY_ACC) {
-            *x = sens_data.gyr.x;
-            *y = sens_data.gyr.y;
-            *z = sens_data.gyr.z;
-            return ESP_OK;
-        }
-        return ESP_ERR_NOT_FOUND;
+    if (_bmi_sens_data.status & BMI2_DRDY_GYR) {
+        *x = _bmi_sens_data.gyr.x;
+        *y = _bmi_sens_data.gyr.y;
+        *z = _bmi_sens_data.gyr.z;
+        return ESP_OK;
     }
-    return ESP_FAIL;
+    return ESP_ERR_NOT_FOUND;
 }
 
 esp_err_t flow3r_bsp_imu_read_gyro_dps(flow3r_bsp_imu_t *imu, float *x,
diff --git a/components/flow3r_bsp/flow3r_bsp_imu.h b/components/flow3r_bsp/flow3r_bsp_imu.h
index 93535c6ff6..bdfea3e13c 100644
--- a/components/flow3r_bsp/flow3r_bsp_imu.h
+++ b/components/flow3r_bsp/flow3r_bsp_imu.h
@@ -20,7 +20,7 @@ typedef struct {
     struct bmp5_osr_odr_press_config osr_odr_press_cfg;
 } flow3r_bsp_imu_t;
 
-// Init the IMU to default settings
+// Init the IMU with default settings
 //
 // Configures the IMU to:
 // Accelerometer: 100 Hz sample rate, 2 g range
@@ -28,47 +28,46 @@ typedef struct {
 // Pressure sensor: 50 Hz sample rate
 esp_err_t flow3r_bsp_imu_init(flow3r_bsp_imu_t *imu);
 
-// Query the IMU for an accelerometer reading.
+// Update the IMU readings by reading data from the I2C bus.
 //
 // This directly calls the I2C bus and waits until the bus is available (max 1
-// second). Returns ESP_ERR_NOT_FOUND if there is no new reading available.
+// second).
 // Returns ESP_FAIL if the sensor could not be read (e.g. I2C unavailable).
+esp_err_t flow3r_bsp_imu_update(flow3r_bsp_imu_t *imu);
+
+// Get an accelerometer reading.
+//
+// Returns ESP_ERR_NOT_FOUND if there is no new reading available.
 // Return values are raw data from the BMI270.
 // Use imu->acc_range and imu->bmi.resolution for interpretation.
 esp_err_t flow3r_bsp_imu_read_acc(flow3r_bsp_imu_t *imu, int *x, int *y,
                                   int *z);
 
-// Query the IMU for a converted accelerometer reading.
+// Get aa converted accelerometer reading.
 //
-// This directly calls the I2C bus and waits until the bus is available (max 1
-// second). Returns ESP_ERR_NOT_FOUND if there is no new reading available.
-// Returns ESP_FAIL if the sensor could not be read (e.g. I2C unavailable).
+// Returns ESP_ERR_NOT_FOUND if there is no new reading available.
 // Return values in m/s**2.
 esp_err_t flow3r_bsp_imu_read_acc_mps(flow3r_bsp_imu_t *imu, float *x, float *y,
                                       float *z);
 
-// Query the IMU for a gyroscope reading.
+// Get a gyroscope reading.
 //
-// This directly calls the I2C bus and waits until the bus is available (max 1
-// second). Returns ESP_ERR_NOT_FOUND if there is no new reading available.
-// Returns ESP_FAIL if the sensor could not be read (e.g. I2C unavailable).
+// Returns ESP_ERR_NOT_FOUND if there is no new reading available.
 // Return values are raw data from the BMI270.
 // Use imu->gyro_range and imu->bmi.resolution for interpretation.
 esp_err_t flow3r_bsp_imu_read_gyro(flow3r_bsp_imu_t *imu, int *x, int *y,
                                    int *z);
 
-// Query the IMU for a converted gyroscope reading.
+// Get converted gyroscope reading.
 //
-// This directly calls the I2C bus and waits until the bus is available (max 1
-// second). Returns ESP_ERR_NOT_FOUND if there is no new reading available.
-// Returns ESP_FAIL if the sensor could not be read (e.g. I2C unavailable).
+// Returns ESP_ERR_NOT_FOUND if there is no new reading available.
 // Return values in deg/s.
 esp_err_t flow3r_bsp_imu_read_gyro_dps(flow3r_bsp_imu_t *imu, float *x,
                                        float *y, float *z);
 
-// Query the IMU for a pressure sensor reading.
+// Get a pressure sensor reading.
 //
-// Returns cached data if no new reading is available.
+// Returns ESP_ERR_NOT_FOUND if there is no new reading available.
 // Presssure in Pa, temperature in deg C
 esp_err_t flow3r_bsp_imu_read_pressure(flow3r_bsp_imu_t *imu, float *pressure,
                                        float *temperature);
diff --git a/components/st3m/st3m_imu.c b/components/st3m/st3m_imu.c
index dcf975a3fa..c21ec0f2bb 100644
--- a/components/st3m/st3m_imu.c
+++ b/components/st3m/st3m_imu.c
@@ -2,31 +2,94 @@
 
 #include "flow3r_bsp_imu.h"
 
-#include "flow3r_bsp.h"
-
-#include "esp_system.h"
-#include "esp_task.h"
+static const char *TAG = "st3m-imu";
+#include "esp_err.h"
+#include "esp_log.h"
 
 #include "freertos/FreeRTOS.h"
 #include "freertos/semphr.h"
 #include "freertos/task.h"
 
-#include <math.h>
-#include <stdio.h>
-#include <string.h>
+static void _task(void *data);
+
+static flow3r_bsp_imu_t _imu;
+
+static SemaphoreHandle_t mutex;
+#define LOCK xSemaphoreTake(mutex, portMAX_DELAY)
+#define UNLOCK xSemaphoreGive(mutex)
 
-static flow3r_bsp_imu_t imu;
+static float _acc_x, _acc_y, _acc_z;
+static float _gyro_x, _gyro_y, _gyro_z;
+static float _pressure;
+static float _temperature;
 
-void st3m_imu_init() { flow3r_bsp_imu_init(&imu); }
+void st3m_imu_init() {
+    mutex = xSemaphoreCreateMutex();
+    assert(mutex != NULL);
+
+    esp_err_t ret = flow3r_bsp_imu_init(&_imu);
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "IMU init failed: %s", esp_err_to_name(ret));
+        return;
+    }
+
+    xTaskCreate(&_task, "imu", 4096, NULL, configMAX_PRIORITIES - 2, NULL);
+    ESP_LOGI(TAG, "IMU task started");
+}
 
-esp_err_t st3m_imu_read_acc_mps(float *x, float *y, float *z) {
-    return flow3r_bsp_imu_read_acc_mps(&imu, x, y, z);
+void st3m_imu_read_acc_mps(float *x, float *y, float *z) {
+    LOCK;
+    *x = _acc_x;
+    *y = _acc_y;
+    *z = _acc_z;
+    UNLOCK;
 }
 
-esp_err_t st3m_imu_read_gyro_dps(float *x, float *y, float *z) {
-    return flow3r_bsp_imu_read_gyro_dps(&imu, x, y, z);
+void st3m_imu_read_gyro_dps(float *x, float *y, float *z) {
+    LOCK;
+    *x = _gyro_x;
+    *y = _gyro_y;
+    *z = _gyro_z;
+    UNLOCK;
 }
 
-esp_err_t st3m_imu_read_pressure(float *pressure, float *temperature) {
-    return flow3r_bsp_imu_read_pressure(&imu, pressure, temperature);
+void st3m_imu_read_pressure(float *pressure, float *temperature) {
+    LOCK;
+    *pressure = _pressure;
+    *temperature = _temperature;
+    UNLOCK;
+}
+
+static void _task(void *data) {
+    TickType_t last_wake = xTaskGetTickCount();
+    esp_err_t ret;
+    float a, b, c;
+    while (1) {
+        vTaskDelayUntil(&last_wake, pdMS_TO_TICKS(10));  // 100 Hz
+
+        ret = flow3r_bsp_imu_update(&_imu);
+        if (ret == ESP_OK) {
+            LOCK;
+            ret = flow3r_bsp_imu_read_acc_mps(&_imu, &a, &b, &c);
+            if (ret == ESP_OK) {
+                _acc_x = a;
+                _acc_y = b;
+                _acc_z = c;
+            }
+
+            flow3r_bsp_imu_read_gyro_dps(&_imu, &a, &b, &c);
+            if (ret == ESP_OK) {
+                _gyro_x = a;
+                _gyro_y = b;
+                _gyro_z = c;
+            }
+
+            flow3r_bsp_imu_read_pressure(&_imu, &a, &b);
+            if (ret == ESP_OK) {
+                _pressure = a;
+                _temperature = b;
+            }
+            UNLOCK;
+        }
+    }
 }
diff --git a/components/st3m/st3m_imu.h b/components/st3m/st3m_imu.h
index 8af13fbb6b..9201b4c259 100644
--- a/components/st3m/st3m_imu.h
+++ b/components/st3m/st3m_imu.h
@@ -7,6 +7,6 @@
 
 void st3m_imu_init(void);
 
-esp_err_t st3m_imu_read_acc_mps(float *x, float *y, float *z);
-esp_err_t st3m_imu_read_gyro_dps(float *x, float *y, float *z);
-esp_err_t st3m_imu_read_pressure(float *pressure, float *temperature);
+void st3m_imu_read_acc_mps(float *x, float *y, float *z);
+void st3m_imu_read_gyro_dps(float *x, float *y, float *z);
+void st3m_imu_read_pressure(float *pressure, float *temperature);
-- 
GitLab