mcu_hi3321_watch/tjd/driver/ppg/ppg_drv_gh3011.c
2025-05-26 20:15:20 +08:00

547 lines
17 KiB
C

/*----------------------------------------------------------------------------
* Copyright (c) Fenda Technologies Co., Ltd. 2021. All rights reserved.
*
* Description: ppg_drv_gh3011.c
*
* Author: shey.tanxiaoyu
*
* Create: 2022-04-20
*--------------------------------------------------------------------------*/
#include "ppg_drv_gh3011.h"
#include "ppg_port.h"
#include "gh3011_example_common.h"
#include "ppg_regs.h"
#define ENABLE_STATIC_PRINT 1
extern uint32_t am_util_stdio_printf(const char *pcFmt, ...);
#define static_print_error(...) am_util_stdio_printf(__VA_ARGS__)//错误打印一般常开
#if ENABLE_STATIC_PRINT
#define static_print_info(...) am_util_stdio_printf(__VA_ARGS__)//一般信息打印宏控制
#else
#define static_print_info(...)
#endif
uint8_t g_ppg_drv_gh3011_err_flag = 0; //调试用, ppg异常中断: 0=未产生异常中断, 1=产生异常中断
typedef struct {
void (*delay_us)(uint16_t);
void (*delay_ms)(uint32_t);
void (*bus_open)(void);
void (*bus_close)(void);
void (*bus_cs_low)(void);
void (*bus_cs_hight)(void);
int32_t (*bus_write)(uint8_t *, uint16_t);
int32_t (*bus_read)(uint8_t *, uint16_t);
void (*exti_enable)(void *);
void (*exti_disable)(void);
void (*reset_pin_init)(void);
void (*reset_pin_deinit)(void);
void (*reset_pin_set)(uint8_t);
void (*power_pin_init)(void);
void (*power_pin_deinit)(void);
void (*power_pin_set)(uint8_t);
uint8_t (*power_pin_get)(void);
void *handle;
} drv_gh3011_handle_t;
typedef struct {
uint8_t deinit_flag; //去初始化标志: 0=已去初始化, 1=未去初始化,防止重复开启或重复关闭,总线报错
uint16_t chip_id;
GH3011_RUN_MODE run_mode;
void (*callback)(void);
} drv_gh3011_param_t;
const drv_gh3011_handle_t g_drv_gh3011_hdl = {
.delay_us = ppg_port_delay_us,
.delay_ms = ppg_port_delay_ms,
.bus_open = ppg_port_bus_open,
.bus_close = ppg_port_bus_close,
.bus_cs_low = ppg_port_bus_cs_low,
.bus_cs_hight = ppg_port_bus_cs_high,
.bus_write = ppg_port_bus_write,
.bus_read = ppg_port_bus_read,
.exti_enable = ppg_port_exti_enable,
.exti_disable = ppg_port_exti_disable,
.reset_pin_init = ppg_port_reset_pin_init,
.reset_pin_deinit = ppg_port_reset_pin_deinit,
.reset_pin_set = ppg_port_reset_pin_set,
.power_pin_init = ppg_port_power_pin_init,
.power_pin_deinit = ppg_port_power_pin_deinit,
.power_pin_set = ppg_port_power_pin_set,
.power_pin_get = ppg_port_power_pin_get,
};
static drv_gh3011_param_t g_drv_param;
static uint8_t drv_gh3011_bus_write(uint8_t device_id, const uint8_t *write_buf, uint16_t write_len)
{
uint8_t ret = GH30X_EXAMPLE_OK_VAL;
uint8_t spi_write_buffer[5] = {0};
uint16_t spi_real_len = 0;
if ((write_len == 3) && (write_buf[0] == 0xDD) && (write_buf[1] == 0xDD)) {
g_drv_gh3011_hdl.bus_cs_low();
g_drv_gh3011_hdl.bus_write((uint8_t *)&write_buf[2], 1);
g_drv_gh3011_hdl.delay_us(20);
g_drv_gh3011_hdl.bus_cs_hight();
g_drv_gh3011_hdl.delay_us(10);
} else {
spi_real_len = write_len - 2;
spi_write_buffer[0] = 0xF0;
spi_write_buffer[1] = write_buf[0];
spi_write_buffer[2] = write_buf[1];
spi_write_buffer[3] = GET_HIGH_BYTE_FROM_WORD(spi_real_len);
spi_write_buffer[4] = GET_LOW_BYTE_FROM_WORD(spi_real_len);
g_drv_gh3011_hdl.bus_cs_low();
g_drv_gh3011_hdl.bus_write(spi_write_buffer, 5);
g_drv_gh3011_hdl.bus_write((uint8_t *)&write_buf[2], spi_real_len);
g_drv_gh3011_hdl.delay_us(20);
g_drv_gh3011_hdl.bus_cs_hight();
g_drv_gh3011_hdl.delay_us(10);
}
return ret;
}
static uint8_t drv_gh3011_bus_read(uint8_t device_id, const uint8_t *write_buf, uint16_t write_len, uint8_t *read_buf, uint16_t read_len)
{
uint8_t ret = GH30X_EXAMPLE_OK_VAL;
uint8_t spi_write_buffer[3] = {0};
if (write_len == 2) {
spi_write_buffer[0] = 0xF0;
spi_write_buffer[1] = write_buf[0];
spi_write_buffer[2] = write_buf[1];
g_drv_gh3011_hdl.bus_cs_low();
g_drv_gh3011_hdl.bus_write(spi_write_buffer, 3);
g_drv_gh3011_hdl.delay_us(20);
g_drv_gh3011_hdl.bus_cs_hight();
g_drv_gh3011_hdl.delay_us(10);
spi_write_buffer[0] = 0xF1;
g_drv_gh3011_hdl.bus_cs_low();
g_drv_gh3011_hdl.bus_write(spi_write_buffer, 1);
g_drv_gh3011_hdl.bus_read(read_buf, read_len);
g_drv_gh3011_hdl.delay_us(20);
g_drv_gh3011_hdl.bus_cs_hight();
g_drv_gh3011_hdl.delay_us(10);
} else {
ret = GH30X_EXAMPLE_ERR_VAL;
}
return ret;
}
static void drv_gh3011_int_handler(void)
{
uint8_t int_status = HBD_GetIntStatus();
switch (int_status) {
case INT_STATUS_CHIP_RESET:
// static_print_info("INT_STATUS_CHIP_RESET\n");
break;
case INT_STATUS_NEW_DATA:
static_print_info("INT_STATUS_NEW_DATA\n");
break;
case INT_STATUS_FIFO_WATERMARK:
// static_print_info("INT_STATUS_FIFO_WATERMARK\n");
g_drv_param.callback();
break;
case INT_STATUS_FIFO_FULL:
static_print_info("INT_STATUS_FIFO_FULL\n");
g_ppg_drv_gh3011_err_flag = INT_STATUS_FIFO_FULL;
break;
case INT_STATUS_WEAR_DETECTED:
static_print_info("INT_STATUS_WEAR_DETECTED\n");
break;
case INT_STATUS_UNWEAR_DETECTED:
static_print_info("INT_STATUS_UNWEAR_DETECTED\n");
g_ppg_drv_gh3011_err_flag = INT_STATUS_UNWEAR_DETECTED;
break;
case INT_STATUS_INVALID:
static_print_info("INT_STATUS_INVALID\n");
g_ppg_drv_gh3011_err_flag = INT_STATUS_INVALID;
break;
default:
break;
}
}
int32_t drv_gh3011_init(void)
{
int8_t ret = 0;
uint32_t err_bitmap = 0;
g_drv_gh3011_hdl.power_pin_init();
g_drv_gh3011_hdl.power_pin_set(0);
g_drv_gh3011_hdl.delay_ms(5);
g_drv_gh3011_hdl.power_pin_set(1);
g_drv_gh3011_hdl.reset_pin_init();
g_drv_gh3011_hdl.reset_pin_set(0);
g_drv_gh3011_hdl.delay_ms(5);
g_drv_gh3011_hdl.reset_pin_set(1);
g_drv_gh3011_hdl.bus_open();
#if (__PLATFORM_DELAY_US_CONFIG__)
HBD_SetDelayUsCallback(g_drv_gh3011_hdl.delay_us);
#endif
#if (__GH30X_IRQ_PLUSE_WIDTH_CONFIG__)
ret = HBD_SetIrqPluseWidth(255);
#endif
ret = HBD_SetI2cRW(HBD_I2C_ID_SEL_1L0L, drv_gh3011_bus_write, drv_gh3011_bus_read);
if (ret != HBD_RET_OK) {
static_print_info("HBD_SetI2cRW failed!!! ret = %d\n", ret);
err_bitmap |= 1 << 0;
}
ret = HBD_CommunicationInterfaceConfirm();
if (ret != HBD_RET_OK) {
static_print_info("HBD_CommunicationInterfaceConfirm failed!!! ret = %d, power = %d\n", ret, g_drv_gh3011_hdl.power_pin_get());
err_bitmap |= 1 << 1;
}
g_drv_param.chip_id = HBD_I2cReadReg(0x0028);
if (g_drv_param.chip_id != GH3011_DEV_ID) {
static_print_info("drv_gh3011_init failed!!! chip_id = 0x%04X, power = %d\n", g_drv_param.chip_id, g_drv_gh3011_hdl.power_pin_get());
err_bitmap |= 1 << 2;
}
ret = HBD_SimpleInit(&gh30x_init_config);
if (ret != HBD_RET_OK) {
static_print_info("HBD_SimpleInit failed!!! ret = %d\n", ret);
err_bitmap |= 1 << 3;
}
if (err_bitmap == 0) {
static_print_info("drv_gh3011_init succeed!!! chip_id = 0x%04X, power = %d, hbd version = %s\n", g_drv_param.chip_id, g_drv_gh3011_hdl.power_pin_get(), HBD_GetHbdVersion());
}
g_drv_param.deinit_flag = 0;
g_drv_param.run_mode = GH3011_RUN_MODE_UNKNOW;
g_drv_gh3011_hdl.bus_close();
g_drv_gh3011_hdl.exti_disable();
g_drv_gh3011_hdl.reset_pin_set(0);
g_drv_gh3011_hdl.power_pin_set(0);
g_drv_gh3011_hdl.reset_pin_deinit();
g_drv_gh3011_hdl.power_pin_deinit();
return 0;
}
int32_t drv_gh3011_get_chip_id(uint16_t *chip_id)
{
int8_t ret = 0;
*chip_id = g_drv_param.chip_id;
return ret;
}
int32_t drv_gh3011_get_run_mode(uint8_t *run_mode)
{
int8_t ret = 0;
*run_mode = g_drv_param.run_mode;
return ret;
}
int32_t drv_gh3011_open(GH3011_RUN_MODE run_mode, void (*p_callback)(void))
{
static_print_info("ppg open\n");
const ST_REGISTER *p_reg_array;
uint8_t reg_array_len;
uint16_t sample_rate;
uint8_t enable_fifo;
uint16_t fifo_threshold;
int8_t ret = 0;
uint32_t err_bitmap = 0;
uint8_t i;
uint8_t retry_max_count = 10;
switch (run_mode) {
case GH3011_RUN_MODE_WEAR:
p_reg_array = hb_adt_confirm_reg_config;
reg_array_len = hb_adt_confirm_reg_config_len;
sample_rate = 5;
enable_fifo = 1;
fifo_threshold = 5;
break;
case GH3011_RUN_MODE_HR:
p_reg_array = getrawdata_reg_config_array;
reg_array_len = getrawdata_reg_config_array_len;
sample_rate = 25;
enable_fifo = 1;
fifo_threshold = 5;
break;
case GH3011_RUN_MODE_HR_ADT:
p_reg_array = hb_reg_config_array;
reg_array_len = hb_reg_config_array_len;
sample_rate = 25;
enable_fifo = 1;
fifo_threshold = 25;
break;
case GH3011_RUN_MODE_SPO2:
p_reg_array = spo2_reg_config_array;
reg_array_len = spo2_reg_config_array_len;
sample_rate = 32;
enable_fifo = 1;
fifo_threshold = 8;
break;
case GH3011_RUN_MODE_SPO2_ADT:
p_reg_array = spo2_reg_config_array;
reg_array_len = spo2_reg_config_array_len;
sample_rate = 32;
enable_fifo = 1;
fifo_threshold = 8;
break;
case GH3011_RUN_MODE_HRV:
p_reg_array = hrv_reg_config_array;
reg_array_len = hrv_reg_config_array_len;
sample_rate = 125;
enable_fifo = 1;
fifo_threshold = 125;
break;
case GH3011_RUN_MODE_HRV_ADT:
p_reg_array = hb_reg_config_array;
reg_array_len = hb_reg_config_array_len;
sample_rate = 125;
enable_fifo = 1;
fifo_threshold = 125;
break;
case GH3011_RUN_MODE_BP_ADT:
p_reg_array = hb_reg_config_array;
reg_array_len = hb_reg_config_array_len;
sample_rate = 128;
enable_fifo = 1;
fifo_threshold = 16;
break;
case GH3011_RUN_MODE_FACT_LED_IR:
p_reg_array = systemtest_led0_reg_config_array;
reg_array_len = systemtest_led0_reg_config_array_len;
sample_rate = 25;
enable_fifo = 1;
fifo_threshold = 25;
break;
case GH3011_RUN_MODE_FACT_LED_GREED:
p_reg_array = systemtest_led2_reg_config_array;
reg_array_len = systemtest_led2_reg_config_array_len;
sample_rate = 25;
enable_fifo = 1;
fifo_threshold = 25;
break;
case GH3011_RUN_MODE_FACT_LED_RED:
p_reg_array = systemtest_led1_reg_config_array;
reg_array_len = systemtest_led1_reg_config_array_len;
sample_rate = 25;
enable_fifo = 1;
fifo_threshold = 25;
break;
default:
static_print_info("gh3011_run_mode err!!!");
return -1;
}
if (g_drv_param.deinit_flag == 0) {
g_drv_param.deinit_flag = 1;
g_drv_gh3011_hdl.power_pin_init();
g_drv_gh3011_hdl.power_pin_set(0);
g_drv_gh3011_hdl.delay_ms(5);
g_drv_gh3011_hdl.power_pin_set(1);
g_drv_gh3011_hdl.reset_pin_init();
g_drv_gh3011_hdl.reset_pin_set(0);
g_drv_gh3011_hdl.delay_ms(5);
g_drv_gh3011_hdl.reset_pin_set(1);
g_drv_gh3011_hdl.bus_open();
}
g_drv_gh3011_hdl.exti_enable(drv_gh3011_int_handler);
g_drv_param.run_mode = run_mode;
g_drv_param.callback = p_callback;
#if (__PLATFORM_DELAY_US_CONFIG__)
HBD_SetDelayUsCallback(g_drv_gh3011_hdl.delay_us);
#endif
#if (__GH30X_IRQ_PLUSE_WIDTH_CONFIG__)
ret = HBD_SetIrqPluseWidth(255);
if (ret != HBD_RET_OK) {
static_print_info("HBD_SetIrqPluseWidth failed!!! ret = %d\n", ret);
err_bitmap |= 1 << 0;
goto DEINIT;
}
#endif
ret = HBD_SetI2cRW(HBD_I2C_ID_SEL_1L0L, drv_gh3011_bus_write, drv_gh3011_bus_read);
if (ret != HBD_RET_OK) {
static_print_info("HBD_SetI2cRW failed!!! ret = %d\n", ret);
err_bitmap |= 1 << 1;
goto DEINIT;
}
ret = HBD_CommunicationInterfaceConfirm();
if (ret != HBD_RET_OK) {
static_print_info("HBD_CommunicationInterfaceConfirm failed!!! ret = %d, power = %d\n", ret, g_drv_gh3011_hdl.power_pin_get());
err_bitmap |= 1 << 2;
goto DEINIT;
}
ret = HBD_ChipReset();
if (ret != HBD_RET_OK) {
static_print_info("HBD_ChipReset failed!!! ret = %d\n", ret);
err_bitmap |= 1 << 3;
goto DEINIT;
}
for (i = 0; i < retry_max_count; i++) {
ret = HBD_SimpleInit(&gh30x_init_config);
if (ret != HBD_RET_OK) {
if (i == retry_max_count - 1) {
static_print_info("HBD_SimpleInit failed!!! exceed retry max count %d\n", i + 1);
err_bitmap |= 1 << 4;
goto DEINIT;
}
static_print_info("HBD_SimpleInit failed!!! ret = %d; retry = %d\n", ret, i + 1);
} else {
break;
}
}
for (i = 0; i < retry_max_count; i++) {
ret = HBD_LoadNewRegConfigArr(p_reg_array, reg_array_len);
if (ret != HBD_RET_OK) {
if (i == retry_max_count - 1) {
static_print_info("HBD_LoadNewRegConfigArr failed!!! exceed retry max count %d\n", i + 1);
err_bitmap |= 1 << 5;
goto DEINIT;
}
static_print_info("HBD_LoadNewRegConfigArr failed!!! ret = %d; retry = %d\n", ret, i + 1);
} else {
break;
}
}
for (i = 0; i < retry_max_count; i++) {
ret = HBD_StartHBDOnly(sample_rate, enable_fifo, fifo_threshold);
if (ret != HBD_RET_OK) {
if (i == retry_max_count - 1) {
static_print_info("HBD_StartHBDOnly failed!!! exceed retry max count %d\n", i + 1);
err_bitmap |= 1 << 6;
goto DEINIT;
}
static_print_info("HBD_StartHBDOnly failed!!! ret = %d; retry = %d\n", ret, i + 1);
} else {
break;
}
}
DEINIT:
if (err_bitmap) {
g_drv_param.deinit_flag = 0;
g_drv_param.run_mode = GH3011_RUN_MODE_UNKNOW;
g_drv_gh3011_hdl.bus_close();
g_drv_gh3011_hdl.exti_disable();
g_drv_gh3011_hdl.reset_pin_set(0);
g_drv_gh3011_hdl.power_pin_set(0);
g_drv_gh3011_hdl.reset_pin_deinit();
g_drv_gh3011_hdl.power_pin_deinit();
}
return 0;
}
void drv_gh3011_close(void)
{
static_print_info("ppg close\n");
if (g_drv_param.deinit_flag == 1) {
g_drv_param.deinit_flag = 0;
g_drv_param.run_mode = GH3011_RUN_MODE_UNKNOW;
g_drv_gh3011_hdl.bus_close();
g_drv_gh3011_hdl.exti_disable();
g_drv_gh3011_hdl.reset_pin_set(0);
g_drv_gh3011_hdl.power_pin_set(0);
g_drv_gh3011_hdl.reset_pin_deinit();
g_drv_gh3011_hdl.power_pin_deinit();
}
}
void drv_gh3011_read(int32_t read_buf[][2], uint16_t *read_len)
{
int8_t ret = HBD_RET_OK;
uint16_t i;
// uint16_t temp_reg;
// uint16_t temp_fifo_len;
// temp_reg = HBD_I2cReadReg(0x0084);
// temp_reg &= 0x07;
// static_print_info("HBD_I2cReadReg(0x0084) = %02X\n", temp_reg);
// temp_fifo_len = HBD_I2cReadReg(0x004A);
// temp_fifo_len = temp_fifo_len;
// static_print_info("HBD_I2cReadReg(0x004A) = %02X\n", temp_fifo_len);
ret = HBD_GetRawdataByFifoInt(256, (GS32 (*)[2])read_buf, read_len);
if (ret != HBD_RET_OK) {
static_print_info("HBD_GetRawdataByFifoInt failed!!! ret = %d\n", ret);
}
HBD_GetRawdataHasDone();
// static_print_info("ppg read len = %d\n", *read_len);
if (*read_len >= 256) {
*read_len = 0;
}
for (i = 0; i < *read_len; i++) {
read_buf[i][0] &= 0x1FFFF;
read_buf[i][1] &= 0x1FFFF;
// static_print_info("[0]%d, [1]%d\n", read_buf[i][0], read_buf[i][1]);
}
}
void drv_gh3011_current_set(uint16_t cur0, uint16_t cur1, uint16_t cur2)
{
uint16_t temp_value;
temp_value = cur0 & 0x00FF;
temp_value |= (cur1 << 8) & 0xFF00;
HBD_I2cWriteReg(0x0118, temp_value);
temp_value = cur2 & 0x00FF;
HBD_I2cWriteReg(0x011A, temp_value);
}
void drv_gh3011_current_get(uint16_t *cur0, uint16_t *cur1, uint16_t *cur2)
{
uint16_t temp_value;
temp_value = HBD_I2cReadReg(0x0122);
*cur0 = temp_value & 0xFF;
*cur1 = (temp_value >> 8) & 0xFF;
temp_value = HBD_I2cReadReg(0x0124);
*cur2 = temp_value & 0xFF;
}