From 954c38ac5a47033762f3ea7d5e1eef86d4265ee8 Mon Sep 17 00:00:00 2001 From: Yilin Sun Date: Thu, 7 Dec 2023 20:48:49 +0800 Subject: [PATCH] Added PAH8001 driver and WIP BMM150 driver. Signed-off-by: Yilin Sun --- CMakeLists.txt | 4 + include/imsensors/magnetic/magnetic_bmm150.h | 52 +++++++ include/imsensors/ppg/ppg_pah8001.h | 26 ++++ src/dht/dht_bme280.c | 14 +- src/magnetic/magnetic_bmm150.c | 144 ++++++++++++++++++ src/ppg/ppg_pah8001.c | 146 +++++++++++++++++++ 6 files changed, 379 insertions(+), 7 deletions(-) create mode 100644 include/imsensors/magnetic/magnetic_bmm150.h create mode 100644 include/imsensors/ppg/ppg_pah8001.h create mode 100644 src/magnetic/magnetic_bmm150.c create mode 100644 src/ppg/ppg_pah8001.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 30b6021..1e93b8b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,8 @@ set(IMSENSORS_SRCS "src/dht/dht_bme280.c" "src/franklin/franklin_as3935.c" "src/imu/imu_lsm6dsl.c" + "src/magnetic/magnetic_bmm150.c" + "src/ppg/ppg_pah8001.c" ) set(IMSENSORS_INCS @@ -18,6 +20,8 @@ set(IMSENSORS_INCS "include/imsensors/dht" "include/imsensors/franklin" "include/imsensors/imu" + "include/imsensors/magnetic" + "include/imsensors/ppg" ) set(IMSENSORS_INTF_INCS diff --git a/include/imsensors/magnetic/magnetic_bmm150.h b/include/imsensors/magnetic/magnetic_bmm150.h new file mode 100644 index 0000000..fea10a5 --- /dev/null +++ b/include/imsensors/magnetic/magnetic_bmm150.h @@ -0,0 +1,52 @@ +#ifndef IMS_BMM150_H +#define IMS_BMM150_H + +#include "imsensors/common/sensors_common.h" + +typedef enum { + IMS_BMM150_ODR_10HZ = 0U, + IMS_BMM150_ODR_2HZ = 1U, + IMS_BMM150_ODR_6HZ = 2U, + IMS_BMM150_ODR_8HZ = 3U, + IMS_BMM150_ODR_15HZ = 4U, + IMS_BMM150_ODR_20HZ = 5U, + IMS_BMM150_ODR_25HZ = 6U, + IMS_BMM150_ODR_30HZ = 7U, +} ims_bmm150_odr_t; + +typedef enum { + IMS_BMM150_PRESET_LOWPOWER, + IMS_BMM150_PRESET_REGULAR, + IMS_BMM150_PRESET_ENHANCED_REGULAR, + IMS_BMM150_PRESET_HIGH_ACCURACY, +} ims_bmm150_preset_t; + +typedef enum { + IMS_BMM150_MODE_SLEEP, + IMS_BMM150_MODE_FORCED, + IMS_BMM150_MODE_NORMAL, +} ims_bmm150_mode_t; + +typedef struct { + +} ims_bmm150_result_t; + +typedef struct { + ims_i2c_xfer_t i2c_xfer; + ims_delay_t delay; +} ims_bmm150_cb_t; + +typedef struct { + uint8_t rep_xy; + uint8_t rep_z; + ims_bmm150_odr_t odr; +} ims_bmm150_config_t; + +typedef struct { + ims_bmm150_cb_t cb; + void *pdev; + uint8_t i2c_addr; + +} ims_bmm150_t; + +#endif \ No newline at end of file diff --git a/include/imsensors/ppg/ppg_pah8001.h b/include/imsensors/ppg/ppg_pah8001.h new file mode 100644 index 0000000..4be3a4d --- /dev/null +++ b/include/imsensors/ppg/ppg_pah8001.h @@ -0,0 +1,26 @@ +#ifndef PPG_PAH8001_H +#define PPG_PAH8001_H + +#include "imsensors/common/sensors_common.h" + +typedef enum { + IMS_PPG_ALG_A, + IMS_PPG_ALG_C, +} ims_pah8001_alg_t; + +typedef struct { + ims_i2c_xfer_t i2c_xfer; + ims_delay_t delay; +} ims_pah8001_cb_t; + +typedef struct { + ims_pah8001_cb_t cb; + void *pdev; +} ims_pah8001_t; + +ims_ret_t ims_pah8001_init(ims_pah8001_t *pah); +ims_ret_t ims_pah8001_power(ims_pah8001_t *pah, const bool on); +ims_ret_t ims_pah8001_touched(ims_pah8001_t *pah, bool *touched); +ims_ret_t ims_pah8001_read_alg_hr(ims_pah8001_t *pah, ims_pah8001_alg_t alg, uint8_t *hr); + +#endif // PPG_PAH8001_H diff --git a/src/dht/dht_bme280.c b/src/dht/dht_bme280.c index 3e6eb00..7a36ae2 100644 --- a/src/dht/dht_bme280.c +++ b/src/dht/dht_bme280.c @@ -99,8 +99,8 @@ static const ims_bme280_config_t ims_bme280_presets[] = { static ims_ret_t ims_bme280_reset(ims_bme280_t *bme); static ims_ret_t ims_bme280_read_trim_data(ims_bme280_t *bme); static ims_ret_t ims_bme280_set_mode(ims_bme280_t *bme, ims_bme280_mode_t mode); -static ims_ret_t ims_bme_get_mode(ims_bme280_t *bme, ims_bme280_mode_t *mode); -static ims_ret_t ims_bme_wait_measure_complete(ims_bme280_t *bme, uint32_t timeout_ms); +static ims_ret_t ims_bme280_get_mode(ims_bme280_t *bme, ims_bme280_mode_t *mode); +static ims_ret_t ims_bme280_wait_measure_complete(ims_bme280_t *bme, uint32_t timeout_ms); static ims_ret_t ims_bme280_read_raw_data(ims_bme280_t *bme, uint32_t *raw_t, uint32_t *raw_p, uint32_t *raw_h); static ims_ret_t ims_bme280_read_register(ims_bme280_t *bme, uint8_t reg, uint8_t *data, uint16_t len); @@ -147,7 +147,7 @@ ims_ret_t ims_bme280_config(ims_bme280_t *bme, ims_bme280_config_t *config) { ims_bme280_mode_t mode; - ret = ims_bme_get_mode(bme, &mode); + ret = ims_bme280_get_mode(bme, &mode); if (ret != IMS_SUCCESS) return ret; if (mode != IMS_BME280_MODE_SLEEP) { @@ -205,7 +205,7 @@ ims_ret_t ims_bme280_read_forced(ims_bme280_t *bme, ims_bme280_result_t *result) ims_bme280_mode_t mode; - ret = ims_bme_get_mode(bme, &mode); + ret = ims_bme280_get_mode(bme, &mode); if (ret != IMS_SUCCESS) return ret; /* @@ -218,7 +218,7 @@ ims_ret_t ims_bme280_read_forced(ims_bme280_t *bme, ims_bme280_result_t *result) if (ret != IMS_SUCCESS) return ret; } - ret = ims_bme_wait_measure_complete(bme, IMS_BME280_FORCED_TIMEOUT_MS); + ret = ims_bme280_wait_measure_complete(bme, IMS_BME280_FORCED_TIMEOUT_MS); if (ret != IMS_SUCCESS) { return ret; } @@ -341,7 +341,7 @@ static ims_ret_t ims_bme280_set_mode(ims_bme280_t *bme, ims_bme280_mode_t mode) return ret; } -static ims_ret_t ims_bme_get_mode(ims_bme280_t *bme, ims_bme280_mode_t *mode) { +static ims_ret_t ims_bme280_get_mode(ims_bme280_t *bme, ims_bme280_mode_t *mode) { ims_ret_t ret; uint8_t ctrl_meas; @@ -354,7 +354,7 @@ static ims_ret_t ims_bme_get_mode(ims_bme280_t *bme, ims_bme280_mode_t *mode) { return IMS_SUCCESS; } -static ims_ret_t ims_bme_wait_measure_complete(ims_bme280_t *bme, uint32_t timeout_ms) { +static ims_ret_t ims_bme280_wait_measure_complete(ims_bme280_t *bme, uint32_t timeout_ms) { ims_ret_t ret; uint8_t loop_count = 0U; diff --git a/src/magnetic/magnetic_bmm150.c b/src/magnetic/magnetic_bmm150.c new file mode 100644 index 0000000..b1f2103 --- /dev/null +++ b/src/magnetic/magnetic_bmm150.c @@ -0,0 +1,144 @@ +#include + +/* Private */ +#include "magnetic_bmm150.h" + +static ims_ret_t ims_bmm150_read_register(ims_bmm150_t *bmm, uint8_t addr, uint8_t *val, uint8_t len) { + ims_i2c_xfer_desc_t desc = { + .tx_data = &addr, + .tx_size = 1U, + .rx_data = val, + .rx_size = len, + }; + + return bmm->cb.i2c_xfer(bmm->pdev, &desc); +} + +static ims_ret_t ims_bmm150_write_register(ims_bmm150_t *bmm, uint8_t addr, uint8_t val) { + uint8_t tx_buf[2] = {addr, val}; + ims_i2c_xfer_desc_t desc = { + .tx_data = tx_buf, + .tx_size = 2U, + .rx_data = NULL, + .rx_size = 0U, + }; + + return bmm->cb.i2c_xfer(bmm->pdev, &desc); +} + +static ims_ret_t ims_bmm150_set_mode(ims_bmm150_t *bmm, ims_bmm150_mode_t mode) { + uint8_t b_mode; + if (ims_bmm150_read_register(bmm, 0x4C, &b_mode, 0x01) != IMS_SUCCESS) { + return IMS_FAIL; + } + switch (mode) { + case IMS_BMM150_MODE_SLEEP: + b_mode |= (0x03U << 1U); + break; + case IMS_BMM150_MODE_NORMAL: + b_mode &= (0x03U << 1U); + break; + case IMS_BMM150_MODE_FORCED: + b_mode &= (0x03U << 1U); + b_mode |= (0x01U << 1U); + break; + default: + break; + } + + if (ims_bmm150_write_register(bmm, 0x4C, b_mode) != IMS_SUCCESS) { + return IMS_FAIL; + } + + return IMS_SUCCESS; +} + +static ims_ret_t ims_bmm150_enable_drdy(ims_bmm150_t *bmm) { + uint8_t reg; + if (ims_bmm150_read_register(bmm, 0x4E, ®, 0x01) != IMS_SUCCESS) { + return IMS_FAIL; + } + + reg |= (1U << 7); + + if (ims_bmm150_write_register(bmm, 0x4E, reg) != IMS_SUCCESS) { + return IMS_FAIL; + } + + return IMS_SUCCESS; +} + +static ims_ret_t ims_bmm150_set_thresholds(ims_bmm150_t *bmm, uint8_t high, uint8_t low) { + if (ims_bmm150_write_register(bmm, 0x4F, low) != IMS_SUCCESS) { + return IMS_FAIL; + } + + if (ims_bmm150_write_register(bmm, 0x50, high) != IMS_SUCCESS) { + return IMS_FAIL; + } + + return IMS_SUCCESS; +} + +static ims_ret_t ims_bmm150_set_repetitions(ims_bmm150_t *bmm, uint8_t xy, uint8_t z) { + if (ims_bmm150_write_register(bmm, 0x51, xy) != IMS_SUCCESS) { + return IMS_FAIL; + } + if (ims_bmm150_write_register(bmm, 0x52, z) != IMS_SUCCESS) { + return IMS_FAIL; + } + + return IMS_SUCCESS; +} + +static ims_ret_t ims_bmm150_reset(ims_bmm150_t *bmm) { + if (ims_bmm150_write_register(bmm, 0x4B, 0x00) != IMS_SUCCESS) { + return IMS_FAIL; + } + + if (ims_bmm150_write_register(bmm, 0x4B, 0x01) != IMS_SUCCESS) { + return IMS_FAIL; + } + + return IMS_SUCCESS; +} + +ims_ret_t ims_bmm150_init(ims_bmm150_t *bmm) { + if (!bmm) return IMS_FAIL; + + if (ims_bmm150_reset(bmm) != IMS_SUCCESS) { + return IMS_FAIL; + } + + return IMS_SUCCESS; +} + +ims_ret_t ims_bmm150_config(ims_bmm150_t *bmm, ims_bmm150_config_t *cfg) { + if (ims_bmm150_set_repetitions(bmm, cfg->rep_xy, cfg->rep_z) != IMS_SUCCESS) { + return IMS_FAIL; + } + + uint8_t b_mode; + + if (ims_bmm150_read_register(bmm, 0x4C, &b_mode, 0x01) != IMS_SUCCESS) { + return IMS_FAIL; + } + + b_mode &= (7U << 3); + b_mode |= (cfg->odr << 3); + + if (ims_bmm150_write_register(bmm, 0x4C, b_mode) != IMS_SUCCESS) { + return IMS_FAIL; + } + + return IMS_SUCCESS; +} + +ims_ret_t ims_bmm150_watch(ims_bmm150_t *bmm) { + /* Enable interrupts and ... */ + if (ims_bmm150_set_thresholds(bmm, 0, 0) != IMS_SUCCESS) { + return IMS_FAIL; + } + + return IMS_SUCCESS; +} \ No newline at end of file diff --git a/src/ppg/ppg_pah8001.c b/src/ppg/ppg_pah8001.c new file mode 100644 index 0000000..b99f021 --- /dev/null +++ b/src/ppg/ppg_pah8001.c @@ -0,0 +1,146 @@ +#include "ppg_pah8001.h" + +#define PAH8001_R_CONFIG ((0U << 8U) | 0x06) +#define PAH8001_R_CONFIG_RESET_Pos 7 +#define PAH8001_R_CONFIG_RESET_Msk (1U << PAH8001_R_CONFIG_RESET_Pos) +#define PAH8001_R_CONFIG_POWERDOWN_Pos 3 +#define PAH8001_R_CONFIG_POWERDOWN_Msk (1U << PAH8001_R_CONFIG_POWERDOWN_Pos) + +#define PAH8001_R_TOUCH_DET ((0U << 8U) | 0x59) +#define PAH8001_R_TOUCH_DET_DETECTED_Pos 7 +#define PAH8001_R_TOUCH_DET_DETECTED_Msk (1U << PAH8001_R_TOUCH_DET_DETECTED_Pos) + +#define PAH8001_R_HR_ALG_A ((1U << 8U) | 0x1A) + +#define PAH8001_R_HR_ALG_C ((1U << 8U) | 0x1C) + +#define PAH8001_ERROR_CHECK(x) \ + if (x != IMS_SUCCESS) return IMS_FAIL + +static ims_ret_t ims_pah8001_register_write(ims_pah8001_t *pah, const uint16_t addr, uint8_t data) { + ims_ret_t ret; + + uint8_t tx_buf[] = {0x7F, (addr >> 8U)}; + + ims_i2c_xfer_desc_t xfer_desc = { + .tx_data = tx_buf, + .tx_size = 2U, + .rx_data = NULL, + .rx_size = 0U, + }; + + /* Switch register bank */ + ret = pah->cb.i2c_xfer(pah->pdev, &xfer_desc); + if (ret != IMS_SUCCESS) { + return ret; + } + + tx_buf[0] = (addr & 0xFFU); + tx_buf[1] = data; + + ret = pah->cb.i2c_xfer(pah->pdev, &xfer_desc); + + return ret; +} + +static ims_ret_t ims_pah8001_register_read(ims_pah8001_t *pah, const uint16_t addr, uint8_t *data) { + ims_ret_t ret; + + uint8_t tx_buf[] = {0x7F, (addr >> 8U)}; + + ims_i2c_xfer_desc_t xfer_desc = { + .tx_data = tx_buf, + .tx_size = 2U, + .rx_data = NULL, + .rx_size = 0U, + }; + + /* Switch register bank */ + ret = pah->cb.i2c_xfer(pah->pdev, &xfer_desc); + if (ret != IMS_SUCCESS) { + return ret; + } + + tx_buf[0] = (addr & 0xFFU); + + xfer_desc.tx_size = 1U; + xfer_desc.rx_data = data; + xfer_desc.rx_size = 1U; + + ret = pah->cb.i2c_xfer(pah->pdev, &xfer_desc); + + return ret; +} + +static ims_ret_t ims_pah8001_reset(ims_pah8001_t *pah) { + uint8_t wdata = PAH8001_R_CONFIG_RESET_Msk | 2U; + PAH8001_ERROR_CHECK(ims_pah8001_register_write(pah, PAH8001_R_CONFIG, wdata)); + + pah->cb.delay(pah->pdev, 5); + + wdata = PAH8001_R_CONFIG_POWERDOWN_Msk | 2U; + PAH8001_ERROR_CHECK(ims_pah8001_register_write(pah, PAH8001_R_CONFIG, wdata)); + + + pah->cb.delay(pah->pdev, 5); + + return IMS_SUCCESS; +} + +ims_ret_t ims_pah8001_init(ims_pah8001_t *pah) { + PAH8001_ERROR_CHECK(ims_pah8001_reset(pah)); + return IMS_SUCCESS; +} + +ims_ret_t ims_pah8001_power(ims_pah8001_t *pah, const bool on) { + ims_ret_t ret; + uint8_t wdata; + + ret = ims_pah8001_register_read(pah, PAH8001_R_CONFIG, &wdata); + if (ret != IMS_SUCCESS) { + return ret; + } + + if (!on) { + wdata |= PAH8001_R_CONFIG_POWERDOWN_Msk; + } else { + wdata &= ~PAH8001_R_CONFIG_POWERDOWN_Msk; + } + + return ims_pah8001_register_write(pah, PAH8001_R_CONFIG, wdata); +} + +ims_ret_t ims_pah8001_touched(ims_pah8001_t *pah, bool *touched) { + ims_ret_t ret; + uint8_t rdata; + + ret = ims_pah8001_register_read(pah, PAH8001_R_TOUCH_DET, &rdata); + if (ret != IMS_SUCCESS) { + return ret; + } + + if (rdata & PAH8001_R_TOUCH_DET_DETECTED_Msk) { + *touched = true; + } else { + *touched = false; + } + + return IMS_SUCCESS; +} + +ims_ret_t ims_pah8001_read_alg_hr(ims_pah8001_t *pah, ims_pah8001_alg_t alg, uint8_t *hr) { + uint16_t rreg; + + switch (alg) { + case IMS_PPG_ALG_A: + rreg = PAH8001_R_HR_ALG_A; + break; + case IMS_PPG_ALG_C: + rreg = PAH8001_R_HR_ALG_C; + break; + default: + return IMS_FAIL; + } + + return ims_pah8001_register_read(pah, rreg, hr); +} \ No newline at end of file