/*---------------------------------------------------------------------------- * 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; }