From 0e8e8fc6982af0f62f205b7c4751e21d9c4b54bf Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E5=BD=AD=E7=A3=8A?= <1624952103@qq.com> Date: Sat, 18 Jan 2025 08:26:21 +0000 Subject: [PATCH] Merge #1624 into sdk602patch1126 from refs/changes/1624/head MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit w9添加GNSS相关宏定义 * refs/changes/1624/head: (2 commits squashed) - w9添加GNSS相关宏定义 - 添加w9血压心率驱动,增加u8GPS蓝牙产测 Signed-off-by: aliyun6865282430 <1624952103@qq.com> Reviewed-by: snickersun@163.com Merged-by: snickersun@163.com CR-link: https://codeup.aliyun.com/64191456b9581d62e8f81ac0/FD230/change/1624 --- .../brandy/brandy_standard/service_init.c | 8 + .../brandy/brandy_standard/thread_pri_init.c | 19 +- .../config/target_config/brandy/config.py | 12 +- .../boards/brandy_evb/board_config/board_w9.h | 13 +- .../clocks/drivers/acore/clocks_config_priv.c | 4 + .../UI/producttest/src/testhrsenson.cpp | 36 +- code/sdk/zhihui/drivers/CMakeLists.txt | 3 +- code/sdk/zhihui/drivers/bp/CMakeLists.txt | 47 + code/sdk/zhihui/drivers/bp/bn02/bn02.c | 110 ++ code/sdk/zhihui/drivers/bp/bn02/bn02.h | 32 + .../sdk/zhihui/drivers/bp/service/bp_at_cmd.c | 106 ++ .../sdk/zhihui/drivers/bp/service/bp_at_cmd.h | 40 + .../zhihui/drivers/bp/service/bp_service.c | 132 ++ .../zhihui/drivers/bp/service/bp_service.h | 43 + code/sdk/zhihui/drivers/charge/CMakeLists.txt | 1 + .../drivers/charge/service/charge_at_cmd.h | 6 +- code/sdk/zhihui/drivers/ppg/CMakeLists.txt | 5 +- .../zhihui/drivers/ppg/gh3x2x/CMakeLists.txt | 57 + .../drivers/ppg/gh3x2x/inc/gh3x2x_afe_adt.h | 72 + .../drivers/ppg/gh3x2x/inc/gh3x2x_afe_agc.h | 264 +++ .../drivers/ppg/gh3x2x/inc/gh3x2x_afe_demo.h | 68 + .../drivers/ppg/gh3x2x/inc/gh3x2x_afe_drv.h | 447 +++++ .../drivers/ppg/gh3x2x/inc/gh3x2x_afe_ecg.h | 110 ++ .../drivers/ppg/gh3x2x/inc/gh3x2x_afe_user.h | 57 + .../ppg/gh3x2x/inc/gh3x2x_afe_version.h | 45 + .../drivers/ppg/gh3x2x/inc/gh3x2x_hal.h | 34 + .../drivers/ppg/gh3x2x/src/gh3x2x_afe_adt.c | 156 ++ .../drivers/ppg/gh3x2x/src/gh3x2x_afe_agc.c | 1131 ++++++++++++ .../drivers/ppg/gh3x2x/src/gh3x2x_afe_demo.c | 94 + .../drivers/ppg/gh3x2x/src/gh3x2x_afe_drv.c | 1544 +++++++++++++++++ .../ppg/gh3x2x/src/gh3x2x_afe_lead_off.c | 748 ++++++++ .../drivers/ppg/gh3x2x/src/gh3x2x_afe_user.c | 484 ++++++ .../drivers/ppg/gh3x2x/src/gh3x2x_hal.c | 114 ++ .../drivers/ppg/service/ppg_service.cpp | 11 + .../drivers/slip/cat1Service/cat1_ctl.cpp | 4 +- .../battery/service/battery_driver.cpp | 8 +- .../factorytest_protocol.c | 116 +- .../factorytest_protocol.h | 3 + code/sdk/zhihui/services/gnss/inc/NMEA0183.h | 2 + code/sdk/zhihui/services/gnss/src/NMEA0183.c | 219 +++ code/sdk/zhihui/utils/custom_utils.c | 6 + code/sdk/zhihui/utils/custom_utils_at_cmd.c | 2 +- 42 files changed, 6376 insertions(+), 37 deletions(-) create mode 100644 code/sdk/zhihui/drivers/bp/CMakeLists.txt create mode 100644 code/sdk/zhihui/drivers/bp/bn02/bn02.c create mode 100644 code/sdk/zhihui/drivers/bp/bn02/bn02.h create mode 100644 code/sdk/zhihui/drivers/bp/service/bp_at_cmd.c create mode 100644 code/sdk/zhihui/drivers/bp/service/bp_at_cmd.h create mode 100644 code/sdk/zhihui/drivers/bp/service/bp_service.c create mode 100644 code/sdk/zhihui/drivers/bp/service/bp_service.h create mode 100644 code/sdk/zhihui/drivers/ppg/gh3x2x/CMakeLists.txt create mode 100644 code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_adt.h create mode 100644 code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_agc.h create mode 100644 code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_demo.h create mode 100644 code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_drv.h create mode 100644 code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_ecg.h create mode 100644 code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_user.h create mode 100644 code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_version.h create mode 100644 code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_hal.h create mode 100644 code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_adt.c create mode 100644 code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_agc.c create mode 100644 code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_demo.c create mode 100644 code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_drv.c create mode 100644 code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_lead_off.c create mode 100644 code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_user.c create mode 100644 code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_hal.c diff --git a/code/sdk/application/brandy/brandy_standard/service_init.c b/code/sdk/application/brandy/brandy_standard/service_init.c index dd608c90c..0a7399e4d 100644 --- a/code/sdk/application/brandy/brandy_standard/service_init.c +++ b/code/sdk/application/brandy/brandy_standard/service_init.c @@ -95,6 +95,9 @@ #ifdef SUPPORT_AT_GYRO #include "gyro_at_cmd.h" #endif +#ifdef SUPPORT_AT_BP +#include "bp_at_cmd.h" +#endif static void register_at_service(void) { #ifdef SUPPORT_AT_GRAPHIC @@ -218,6 +221,11 @@ static void register_at_service(void) at_cmd_table_t *gyro_table = get_gyro_cmd_table(&gyro_cmd_count); at_cmd_add_moudle(gyro_table, gyro_cmd_count); #endif +#ifdef SUPPORT_AT_BP + uint32_t bp_cmd_count; + at_cmd_table_t *bp_table = get_bp_cmd_table(&bp_cmd_count); + at_cmd_add_moudle(bp_table, bp_cmd_count); +#endif } #ifdef CONFIG_OTA_UPDATE_SUPPORT diff --git a/code/sdk/application/brandy/brandy_standard/thread_pri_init.c b/code/sdk/application/brandy/brandy_standard/thread_pri_init.c index 5304530e9..c672e658c 100644 --- a/code/sdk/application/brandy/brandy_standard/thread_pri_init.c +++ b/code/sdk/application/brandy/brandy_standard/thread_pri_init.c @@ -123,6 +123,10 @@ #include "lqbp_service.h" #endif +#ifdef ENABLE_BN02 +#include "bp_service.h" +#endif + #define EMMC_BASE_ADDR 0x52062000 #define TASK_PRIORITY_APP (osPriority_t)(17) #define TICK_TEN_MS (10U) @@ -500,15 +504,8 @@ uapi_pm_remove_sleep_veto(PM_ID_DEBUG); #endif #ifdef ENABLE_CUSTOM_I2C - -#ifdef ENABLE_HP4507 -#ifdef BOARD_L22 -#define HP4570_I2C_BUS I2C_BUS_0 -#elif defined BOARD_U8 -#define HP4570_I2C_BUS I2C_BUS_3 -#endif - custom_i2c_init(HP4570_I2C_BUS); -#endif + custom_i2c_init(I2C_BUS_3); + custom_i2c_init(I2C_BUS_0); custom_i2c_init(I2C_BUS_2); #ifdef MAG_MMC5603 @@ -527,6 +524,10 @@ uapi_pm_remove_sleep_veto(PM_ID_DEBUG); uapi_lqbp_service_init(); #endif +#ifdef ENABLE_BN02 + uapi_bp_service_init(); +#endif + #endif /*启动蓝牙ble服务,cywee有重置 mac地址的操作,会需要把 蓝牙服务开启放在cywee服务之后*/ diff --git a/code/sdk/build/config/target_config/brandy/config.py b/code/sdk/build/config/target_config/brandy/config.py index bafc22cf3..512d8027e 100644 --- a/code/sdk/build/config/target_config/brandy/config.py +++ b/code/sdk/build/config/target_config/brandy/config.py @@ -547,7 +547,7 @@ target = { 'FT_SINGLE_UART', # 'WEARABLE_LOG_DEBUG', 'SUPPORT_RC_CALIBRATION', - 'PPG_HX3695', + #'PPG_HX3695', 'VIB_USE_PWM', 'CONFIG_PWM_SUPPORT', # 'ACC_LIS2DOC', @@ -571,13 +571,16 @@ target = { 'SUPPORT_HID_SERVICE', 'SUPPORT_BAIDU_MAP', 'CFG_FLASH_SIZE=8', - 'SUPPORT_BLE_SERVICE', + 'SUPPORT_BLE_SERVICE', # 'FD230', #"MEM_CHECK", #'ENABLE_WEBSOCKET', 'SINGLE_USER_PARTITION', 'BOARD_W9', 'SUPPORT_GNSS', + 'DISABLE_UART_LOG', + 'CONFIG_GNSS_UART_WITH_FLOWCTRL', + 'DOWNLOAD_GNSS_SWITCH', 'SUPPORT_AUTO_OTA_SERVER', 'CONFIG_DFX_SUPPORT_DIAG_UP_MACHINE=1', 'TPTYPE_CST86XX', @@ -586,6 +589,7 @@ target = { 'NANDFLASH_F35UQA', #'BLE_INSTRUCT', 'FACTORYTEST_SERVICE', + 'PPG_GH3X2X', ], 'ram_component': [ #'baidumapsdk', @@ -617,7 +621,9 @@ target = { "factorytest_service", "hid_service", "producttest", - "cywee" + "cywee", + "ppg_sensor_gh3x2x", + "bp_sensor", ], 'image_analysis': False, 'fs_image_path':'evb', diff --git a/code/sdk/drivers/boards/brandy_evb/board_config/board_w9.h b/code/sdk/drivers/boards/brandy_evb/board_config/board_w9.h index 73b7d58e7..b15d665b9 100644 --- a/code/sdk/drivers/boards/brandy_evb/board_config/board_w9.h +++ b/code/sdk/drivers/boards/brandy_evb/board_config/board_w9.h @@ -11,6 +11,10 @@ #include "gpio_porting.h" #include "platform_types.h" +#ifdef ENABLE_BN02 +extern void bp_int_callback(pin_t pin, uintptr_t param); +#endif + /** * @addtogroup connectivity_config_boards * @{ @@ -98,8 +102,8 @@ const hal_pio_config_t g_pio_function_config[PIN_MAX_NUMBER] = { { HAL_PIO_FUNC_SPI1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_DOWN, HAL_PIO_IE_ENBALE }, // S_MGPIO9 SPI1 CS0 { HAL_PIO_FUNC_SPI1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_DOWN, HAL_PIO_IE_DISABLE }, // S_MGPIO10 SPI1 CS1 NC - { HAL_PIO_FUNC_I2C0_M1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_ENBALE }, // S_MGPIO11 i2c0 SCL NC - { HAL_PIO_FUNC_I2C0_M1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_ENBALE }, // S_MGPIO12 I2C0 SDA + { HAL_PIO_FUNC_I2C0_M1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_UP, HAL_PIO_IE_ENBALE }, // S_MGPIO11 i2c0 SCL NC + { HAL_PIO_FUNC_I2C0_M1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_UP, HAL_PIO_IE_ENBALE }, // S_MGPIO12 I2C0 SDA { HAL_PIO_FUNC_I2C1_M1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_ENBALE }, // S_MGPIO13 I2C1 SCL touch i2c { HAL_PIO_FUNC_I2C1_M1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_ENBALE }, // S_MGPIO14 I2C1 SDA #ifdef BOARD_W9 @@ -204,7 +208,7 @@ const hal_pio_config_t g_pio_function_config[PIN_MAX_NUMBER] = { // #else { HAL_PIO_FUNC_GPIO, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_DOWN, HAL_PIO_IE_DISABLE }, // S_AGPIO_R2 VIBR_PWM 马达控制脚 兼容预留马达驱动复位脚 // #endif - { HAL_PIO_FUNC_GPIO, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_DOWN, HAL_PIO_IE_DISABLE }, // S_AGPIO_R3 NC + { HAL_PIO_FUNC_GPIO, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_UP, HAL_PIO_IE_ENBALE }, // S_AGPIO_R3 NC { HAL_PIO_FUNC_GPIO, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_UP, HAL_PIO_IE_DISABLE }, // S_AGPIO_R4 tp reset { HAL_PIO_FUNC_GPIO, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_ENBALE }, // S_AGPIO_R5 touch int { HAL_PIO_FUNC_GPIO, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_ENBALE }, // S_AGPIO_R6 PRG_INT 心率中断 @@ -317,6 +321,9 @@ const hal_gpio_config_t g_gpio_function_config[PIN_MAX_NUMBER] = { /**S_AGPIO_L32 GPO gps reset*/ // { S_AGPIO_L32, HAL_GPIO_DIRECTION_OUTPUT, HAL_GPIO_LEVEL_LOW, 0, NULL }, #endif +#ifdef ENABLE_BN02 + { S_AGPIO_R3, HAL_GPIO_DIRECTION_INPUT, NULL, GPIO_INTERRUPT_FALLING_EDGE, bp_int_callback }, +#endif }; /** * @} diff --git a/code/sdk/drivers/chips/brandy/clocks/drivers/acore/clocks_config_priv.c b/code/sdk/drivers/chips/brandy/clocks/drivers/acore/clocks_config_priv.c index 025bdb90e..9ea77612c 100644 --- a/code/sdk/drivers/chips/brandy/clocks/drivers/acore/clocks_config_priv.c +++ b/code/sdk/drivers/chips/brandy/clocks/drivers/acore/clocks_config_priv.c @@ -369,7 +369,11 @@ static const system_mcu_perip_clk_t g_system_mcu_perp_clk_set_config[] = { {HAL_CLOCKS_APP_SPI2_MS_CLK, TURN_OFF}, // spi2 clock {HAL_CLOCKS_APP_UART_H0_CLK, TURN_ON}, // uart h0 clock {HAL_CLOCKS_APP_UART_H1_CLK, TURN_ON}, // uart h1 clock +#ifdef ENABLE_BN02 + {HAL_CLOCKS_APP_I2C0_CLK, TURN_ON}, // i2c0 clock +#else {HAL_CLOCKS_APP_I2C0_CLK, TURN_OFF}, // i2c0 clock +#endif {HAL_CLOCKS_APP_I2C1_CLK, TURN_ON}, // i2c1 clock {HAL_CLOCKS_APP_I2C2_CLK, TURN_ON}, // i2c2 clock {HAL_CLOCKS_APP_I2C3_CLK, TURN_ON}, // i2c3 clock diff --git a/code/sdk/zhihui/UI/producttest/src/testhrsenson.cpp b/code/sdk/zhihui/UI/producttest/src/testhrsenson.cpp index ac738ad25..6bde9cdf1 100644 --- a/code/sdk/zhihui/UI/producttest/src/testhrsenson.cpp +++ b/code/sdk/zhihui/UI/producttest/src/testhrsenson.cpp @@ -19,6 +19,9 @@ extern "C" #endif #include "pm_veto.h" #include "pm.h" +#ifdef PPG_VC9202 + #include "vc9202_user.h" +#endif #ifdef __cplusplus #if __cplusplus } @@ -97,7 +100,7 @@ namespace OHOS static bool button_falg=true; void testhrsenson1View:: setgrayvalue(int g,int r,int ir) { - +#ifdef PPG_HX3695 if(label_hrsenson_value_vison!=NULL) { @@ -110,23 +113,38 @@ namespace OHOS send_ppg_cmd_msg(md); button_falg=true; } - +#endif } void testhrsenson1View:: setlightvalue(int g,int r,int ir) { - + char buf[124]={0}; + if(label_hrsenson_value_vison!=nullptr) { - char buf[124]={0}; +#ifdef PPG_HX3695 sprintf(buf,"leaklight:\ngreen:%d\nred:%d\nir:%d",g,r,ir); WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "%s",buf); label_hrsenson_value_vison->SetText(buf); RootView::GetInstance()->Invalidate(); int8_t md = PPG_SERVICE_CMD_TYPE_STOP_PPG_TEST; send_ppg_cmd_msg(md); - button_falg=true; - } - + button_falg=true; +#elif defined PPG_VC9202 + //漏光测试 + // send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_DO_LEAKLIGHT_TEST); + LOS_Msleep(500); + uint32_t led_cur = 0; + uint32_t apre_val = 0; + uint32_t aps_val = 9; + vc9202_get_leaklight_data(&led_cur,&apre_val,&aps_val); + send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_STOP_PPG_TEST); + sprintf(buf,"leaklight:\ngreen:%d\nred:%d\nir:%d",led_cur,apre_val,aps_val); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "%s",buf); + label_hrsenson_value_vison->SetText(buf); + RootView::GetInstance()->Invalidate(); + button_falg=true; +#endif + } } UILabelButtonExt *testhrsenson1View::SetTheButton_ext(ButtonConfig_ext_t &buttonconfig) @@ -179,7 +197,11 @@ namespace OHOS int8_t md = PPG_SERVICE_CMD_TYPE_DO_LEAKLIGHT_TEST; send_ppg_cmd_msg(md); button_falg=false; +#ifdef PPG_VC9202 + testhrsenson1View::setlightvalue(0,0,0); +#endif } + } UILabel *testhrsenson1View::InitLabel(LabelConfig &labelConfig) diff --git a/code/sdk/zhihui/drivers/CMakeLists.txt b/code/sdk/zhihui/drivers/CMakeLists.txt index 5ce5f283c..d1d65e112 100644 --- a/code/sdk/zhihui/drivers/CMakeLists.txt +++ b/code/sdk/zhihui/drivers/CMakeLists.txt @@ -6,8 +6,6 @@ add_subdirectory_if_exist(acc) add_subdirectory_if_exist(mag) add_subdirectory_if_exist(ppg) -add_subdirectory_if_exist(ppg/vc9202) -add_subdirectory_if_exist(ppg/vc921x) add_subdirectory_if_exist(vibrator) add_subdirectory_if_exist(slip) add_subdirectory_if_exist(slip/cat1Service) @@ -20,3 +18,4 @@ add_subdirectory_if_exist(barometer) add_subdirectory_if_exist(charge) add_subdirectory_if_exist(charge/hp4570) add_subdirectory_if_exist(gyro) +add_subdirectory_if_exist(bp) diff --git a/code/sdk/zhihui/drivers/bp/CMakeLists.txt b/code/sdk/zhihui/drivers/bp/CMakeLists.txt new file mode 100644 index 000000000..16351bc4f --- /dev/null +++ b/code/sdk/zhihui/drivers/bp/CMakeLists.txt @@ -0,0 +1,47 @@ +#=============================================================================== +# @brief cmake file +# Copyright (c) @CompanyNameMagicTag 2022-2023. All rights reserved. +#=============================================================================== +set(COMPONENT_NAME "bp_sensor") + +set(SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/bn02/bn02.c + ${CMAKE_CURRENT_SOURCE_DIR}/service/bp_at_cmd.c + ${CMAKE_CURRENT_SOURCE_DIR}/service/bp_service.c +) + +set(PUBLIC_HEADER + ${CMAKE_CURRENT_SOURCE_DIR}/bn02/ + ${CMAKE_CURRENT_SOURCE_DIR}/service/ + +) + +set(PRIVATE_HEADER +) + +set(PRIVATE_DEFINES + TARGET_NAME="${TARGET_COMMAND}" + BUILD_TIME="${BUILD_TIME}" +) + +set(PUBLIC_DEFINES +SUPPORT_AT_BP +ENABLE_BN02 +) + +# use this when you want to add ccflags like -include xxx +set(COMPONENT_PUBLIC_CCFLAGS +) + +set(COMPONENT_CCFLAGS +) + +set(WHOLE_LINK + true +) + +set(MAIN_COMPONENT + false +) + +build_component() diff --git a/code/sdk/zhihui/drivers/bp/bn02/bn02.c b/code/sdk/zhihui/drivers/bp/bn02/bn02.c new file mode 100644 index 000000000..4330510e5 --- /dev/null +++ b/code/sdk/zhihui/drivers/bp/bn02/bn02.c @@ -0,0 +1,110 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2025-01-16 12:35:15 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2025-01-17 14:35:00 + * @FilePath: /sdk615/code/sdk/zhihui/drivers/bp/bn02/bn02.c + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +#include "stdint.h" +#include "bn02.h" +#include "custom_utils.h" +#include "pinctrl_porting.h" +#include "hal_gpio.h" +#include "i2c.h" + +#define BN02_I2C_ADDR 0x05 +#define BN02_I2C_BUS I2C_BUS_0 +#define I2C_ADDR_BN02_W 0x0a +#define I2C_ADDR_BN02_R 0x0b +#define P_EN S_AGPIO_L24 +#define P_INT S_AGPIO_R3 + +#define POWER_EN S_AGPIO_R0 + +bool Bn02_write_reg(uint8_t data) +{ + i2c_data_t i2c_data; + i2c_data.send_buf = &data; + i2c_data.send_len = sizeof(data); + i2c_data.receive_buf = NULL; + i2c_data.receive_len = 0; + // custom_i2c_write_reg(BN02_I2C_ADDR, 0x00, 1, &data, 1, BN02_I2C_BUS); + errcode_t ret = uapi_i2c_master_write(BN02_I2C_BUS, BN02_I2C_ADDR, &i2c_data); + if (ret != ERRCODE_SUCC) + printf("i2c Write data write fail! ret=0x%x\n", ret); + + return 1; +} + +bool Bn02_reads(uint8_t *data,int len) +{ + i2c_data_t i2c_data; + i2c_data.send_buf = NULL; + i2c_data.send_len = 0; + i2c_data.receive_buf = data; + i2c_data.receive_len = len; + // custom_i2c_write_reg(BN02_I2C_ADDR, 0x00, 1, &data, 1, BN02_I2C_BUS); + errcode_t ret = uapi_i2c_master_read(BN02_I2C_BUS, BN02_I2C_ADDR, &i2c_data); + if (ret != ERRCODE_SUCC) + printf("i2c read data fail! ret=0x%x\n", ret); + + return 1; +} + +static void delay_ms(int cnt) +{ + LOS_Mdelay(cnt); +} + +void Bn02_Power_Ctrl(int onoff) +{ + if(onoff == 1) + { + uapi_pin_set_mode(POWER_EN, (pin_mode_t)HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(POWER_EN, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(POWER_EN, GPIO_LEVEL_HIGH); + LOS_Mdelay(1); + uapi_pin_set_mode(P_EN, (pin_mode_t)HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(P_EN, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(P_EN, GPIO_LEVEL_HIGH); + // delay_ms(20); + LOS_Mdelay(50); + } + else + { + uapi_pin_set_mode(P_EN, (pin_mode_t)HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(P_EN, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(P_EN, GPIO_LEVEL_LOW); + + uapi_pin_set_mode(POWER_EN, (pin_mode_t)HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(POWER_EN, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(POWER_EN, GPIO_LEVEL_LOW); + } +} + +void bn02_int_handle(void) +{ + uint8_t bn02_buf[48] = {0}; + int i; + memset(bn02_buf,0,sizeof(bn02_buf)); + Bn02_reads(bn02_buf,48); + for(i = 0;i<48;i++) + { + printf("[%d]= 0x%x\n",i,bn02_buf[i]); + } +} + +void bn02_start(void) +{ + Bn02_Power_Ctrl(1); + Bn02_write_reg(BN02_START_CMD); +} + +void bn02_stop(void) +{ + Bn02_write_reg(BN02_STOP_CMD); + Bn02_Power_Ctrl(0); +} + + diff --git a/code/sdk/zhihui/drivers/bp/bn02/bn02.h b/code/sdk/zhihui/drivers/bp/bn02/bn02.h new file mode 100644 index 000000000..c4216a982 --- /dev/null +++ b/code/sdk/zhihui/drivers/bp/bn02/bn02.h @@ -0,0 +1,32 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2025-01-16 12:35:15 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2025-01-16 14:55:48 + * @FilePath: /sdk615/code/sdk/zhihui/drivers/bp/bn02/bn02.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +#ifndef _BN02_H_ +#define _BN02_H_ + +enum +{ + + BN02_INT_HANDLE, + BN02_INIT_ENABLE, + BN02_START, + BN02_POWER_DISABLE, + BN02_STOP, +}; + +#define BN02_START_CMD 0x04 +#define BN02_STOP_CMD 0x08 + +void bn02_int_handle(void); + +void bn02_start(void); + +void bn02_stop(void); + +#endif // _HRS3300_H_ + diff --git a/code/sdk/zhihui/drivers/bp/service/bp_at_cmd.c b/code/sdk/zhihui/drivers/bp/service/bp_at_cmd.c new file mode 100644 index 000000000..f9771b400 --- /dev/null +++ b/code/sdk/zhihui/drivers/bp/service/bp_at_cmd.c @@ -0,0 +1,106 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2024-12-23 15:11:01 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2025-01-16 18:02:23 + * @FilePath: /sdk615/code/sdk/zhihui/drivers/bp/HP4570/service/bp_at_cmd.c + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +#include "at_cmd_api.h" +#include "pm_control.h" +#include "debug_print.h" +#include "bp_service.h" +#include "custom_utils.h" + +#define ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0])) +#define BP_MAX_ARGC 8 +#define BP_MAX_ARGV_LEN 64 + +#define BP_SUCCESS 0 +#define BP_FAILED (-1) + +static int ConvertCmdToParam(uint8_t *para, uint32_t paraLen, + uint8_t argv[BP_MAX_ARGC][BP_MAX_ARGV_LEN], uint32_t* argc) +{ + uint32_t pos = 0; + *argc = 0; + + for (uint32_t i = 0; i < paraLen; i++) { + if ((para[i] == ' ' || para[i] == '\n') && pos != 0) { + argv[*argc][pos] = '\0'; + *argc += 1; + pos = 0; + if (*argc >= BP_MAX_ARGC) { + return BP_FAILED; + } + } else { + argv[*argc][pos] = para[i]; + pos++; + if (pos >= BP_MAX_ARGV_LEN) { + return BP_FAILED; + } + } + } + if (pos != 0) { + *argc += 1; + } + + return BP_SUCCESS; +} + +static uint8_t g_bp_test_started = 0; +static uint32_t bn02_test(uint8_t *para, uint32_t paraLen, char *strCommonCmd) +{ + UNUSED(strCommonCmd); + uint8_t argv[BP_MAX_ARGC][BP_MAX_ARGV_LEN] = { 0 }; + uint32_t argc = 0; + + int ret = ConvertCmdToParam(para, paraLen, argv, &argc); + if (ret != BP_SUCCESS) { + PRINT("BPTEST ATCMD Convert Command Failed\n"); + return ERRCODE_FAIL; + } + + if (argc != 1) { + PRINT("BPTEST ATCMD Set Parameter Failed argc %d\n",argc); + return ERRCODE_FAIL; + } + uint8_t start = (uint8_t)atoi((char*)argv[0]); + if (start == 1) + { + // if (g_bp_test_started == 1) + // { + // PRINT("SKIP bptest start, already start\r\n"); + // return 0; + // } + do_bp_service_check_msg(BP_SERVICE_CMD_START_CHECK); + g_bp_test_started = 1; + }else if (start == 2){ + // if (g_bp_test_started == 0) + // { + // PRINT("SKIP bptest stop, already stopped\r\n"); + // return 0; + // } + do_bp_service_check_msg(BP_SERVICE_CMD_STOP_CHECK); + g_bp_test_started = 0 ; + }else if (start == 3){ + // if (g_bp_test_started == 0) + // { + // PRINT("SKIP bptest stop, already stopped\r\n"); + // return 0; + // } + do_bp_service_check_msg(BP_SERVICE_CMD_TIMER_CHECK); + g_bp_test_started = 0 ; + }else{ + } + return ERRCODE_SUCC; +} +static const at_cmd_table_t g_bp_cmd[] = { + { (char *)"AT^BN02TEST", bn02_test, (char *)"1" }, +}; + +at_cmd_table_t *get_bp_cmd_table(uint32_t *cmd_count) +{ + *cmd_count = ARRAY_COUNT(g_bp_cmd); + return (at_cmd_table_t *)g_bp_cmd; +} diff --git a/code/sdk/zhihui/drivers/bp/service/bp_at_cmd.h b/code/sdk/zhihui/drivers/bp/service/bp_at_cmd.h new file mode 100644 index 000000000..3409d1d3f --- /dev/null +++ b/code/sdk/zhihui/drivers/bp/service/bp_at_cmd.h @@ -0,0 +1,40 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2024-12-18 10:23:22 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2025-01-16 15:07:33 + * @FilePath: /sdk615/code/sdk/drivers/peripheral/rotary_encoder/hx3509/hx3509_at_cmd.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +/** + * Copyright (c) @CompanyNameMagicTag 2022-2022. All rights reserved. \n + * + * Description: Provides at cmd register func \n + * Author: @CompanyNameTag \n + * History: \n + * 2022-07-20, Create file. \n + */ +#ifndef BP_AT_PROCESS_H +#define BP_AT_PROCESS_H + +#include +#include +#include "errcode.h" +#include "soc_osal.h" +#include "at_cmd_api.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +at_cmd_table_t *get_bp_cmd_table(uint32_t *cmd_count); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif diff --git a/code/sdk/zhihui/drivers/bp/service/bp_service.c b/code/sdk/zhihui/drivers/bp/service/bp_service.c new file mode 100644 index 000000000..d319d6a92 --- /dev/null +++ b/code/sdk/zhihui/drivers/bp/service/bp_service.c @@ -0,0 +1,132 @@ +#include "pinctrl.h" +#include "debug_print.h" +#include "rtc.h" +#include "timer.h" +#include "systick.h" + +#include "tcxo.h" + +#include "cmsis_os2.h" +#include "input_app.h" +#include "bp_service.h" +#include "custom_utils.h" +#include "bn02.h" +// #include "custom_runtime.h" +/*** + * 其他cmd在Header里定义,对外开放 +*/ + +#define BP_CHECK_MS 40 + +osTimerId_t g_bp_service_timer = NULL; + +static bool g_bp_sensor_exist = false; + +static bool g_bat_timer_is_running = false; + +static unsigned long g_app_queue= 0xFFFFFFFF; + +static bool bp_service_running_stat = false; + +void do_bp_service_check_msg(int cmd); + +static void bp_service_check_timer_callback(void* data) +{ + do_bp_service_check_msg(BP_SERVICE_CMD_TIMER_CHECK); +} + +void do_bp_service_check_msg(int cmd) +{ + int ret; + if (g_bp_sensor_exist == false) + return ; + common_notify_mail_t mail = {0}; + mail.comm.app = cmd; + ret = osal_msg_queue_write_copy(g_app_queue, (void *)&mail, + sizeof(common_notify_mail_t), 0); + if (ret != OSAL_SUCCESS) { + PRINT("Error bp Check MSG 0x%02X send failed! err=0x%x! \r\n",cmd, ret); + } + +} + +static void bp_service_check_task(void const *arg) +{ + unused(arg); + int32_t ret; + common_notify_mail_t mail; + uint32_t msgsize = (uint32_t)sizeof(common_notify_mail_t); + while (1) { + ret = osal_msg_queue_read_copy(g_app_queue, (void *)&mail, &msgsize, + OSAL_MSGQ_WAIT_FOREVER); + if (ret != OSAL_SUCCESS) { + continue; + } + if (mail.comm.app == BP_SERVICE_CMD_TIMER_CHECK) { + PRINT("bn02_int_handle \n"); + bn02_int_handle(); + }else if (mail.comm.app == BP_SERVICE_CMD_START_CHECK){ + PRINT("bn02_start \n"); + bn02_start(); + if(g_bp_service_timer) + osTimerStart(g_bp_service_timer,150); + }else if (mail.comm.app == BP_SERVICE_CMD_STOP_CHECK){ + PRINT("bn02_stop \n"); + bn02_stop(); + if(g_bp_service_timer) + osTimerStop(g_bp_service_timer); + } + } +} +void create_bp_queue(void) +{ + + if (osal_msg_queue_create("bp_service_queue", APP_BOARD_MSG_COUNT, &g_app_queue, + 0, sizeof(common_notify_mail_t)) != ERRCODE_SUCC) { + PRINT("[bp][service] app create mail fail\n"); + } +} + +#define BP_BOARD_TASK_SIZE 0x1000 +errcode_t uapi_bp_service_init(void) +{ + PRINT("uapi_bp_service_init !\r\n"); + + g_bp_sensor_exist = true; + + app_task_definition_t taskcfg={0}; + taskcfg.create_queue_handle = create_bp_queue; + taskcfg.attr.name="bp_service"; + taskcfg.attr.priority = osPriorityBelowNormal4; + taskcfg.attr.stack_size = BP_BOARD_TASK_SIZE; + taskcfg.func = bp_service_check_task; + taskcfg.use_mem = USE_EXTEND_MEM; + + errcode_t ret=uapi_create_osThread_custom(&taskcfg); + if(ret != ERRCODE_SUCC) + { + PRINT("create bp_service failed %d!\r\n",ret); + return ERRCODE_FAIL; + } + + // g_bp_service_timer = osTimerNew((osTimerFunc_t)bp_service_check_timer_callback, osTimerPeriodic, NULL, NULL); + + return ERRCODE_SUCC; +} + +void bp_int_callback(pin_t pin, uintptr_t param) +{ + PRINT("bp_int_callback %d 0x%X\n",pin,param); + uapi_gpio_clear_interrupt(pin); + do_bp_service_check_msg(BP_SERVICE_CMD_TIMER_CHECK); +} + +// void bp_service_service_resume(void) +// { +// MMC_LOG("bp_service_service resume!\r\n"); +// bp_service_check_timer_callback(0); +// } +// void bp_service_service_suspend(void) +// { +// MMC_LOG("bp_service_service suspend!\r\n"); +// } \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/bp/service/bp_service.h b/code/sdk/zhihui/drivers/bp/service/bp_service.h new file mode 100644 index 000000000..ba02c9a9d --- /dev/null +++ b/code/sdk/zhihui/drivers/bp/service/bp_service.h @@ -0,0 +1,43 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2024-12-23 15:11:01 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2025-01-16 17:39:43 + * @FilePath: /sdk615/code/sdk/zhihui/drivers/charge/HP4570/service/charge_service.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +/** + * Copyright (c) @CompanyNameMagicTag 2022-2022. All rights reserved. \n + * + * Description: Test adc header \n + * Author: @CompanyNameTag \n + * History: \n + * 2022-08-16, Create file. \n + */ + +#ifndef BP_SERVICE_H__ +#define BP_SERVICE_H__ + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#include "stdint.h" +#include "errcode.h" + +#define BP_SERVICE_CMD_START_CHECK 0x12 +#define BP_SERVICE_CMD_STOP_CHECK 0x13 +#define BP_SERVICE_CMD_TIMER_CHECK 0x11 + +errcode_t uapi_bp_service_init(void); +void bp_int_callback(pin_t pin, uintptr_t param); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/charge/CMakeLists.txt b/code/sdk/zhihui/drivers/charge/CMakeLists.txt index b100dae71..97149a107 100644 --- a/code/sdk/zhihui/drivers/charge/CMakeLists.txt +++ b/code/sdk/zhihui/drivers/charge/CMakeLists.txt @@ -26,6 +26,7 @@ set(PRIVATE_DEFINES set(PUBLIC_DEFINES SUPPORT_AT_CHARGE +ENABLE_HP4507 ) # use this when you want to add ccflags like -include xxx diff --git a/code/sdk/zhihui/drivers/charge/service/charge_at_cmd.h b/code/sdk/zhihui/drivers/charge/service/charge_at_cmd.h index e54f7befc..0e55c5584 100644 --- a/code/sdk/zhihui/drivers/charge/service/charge_at_cmd.h +++ b/code/sdk/zhihui/drivers/charge/service/charge_at_cmd.h @@ -2,7 +2,7 @@ * @Author: penglei 1624952103@qq.com * @Date: 2024-12-18 10:23:22 * @LastEditors: penglei 1624952103@qq.com - * @LastEditTime: 2024-12-24 17:58:19 + * @LastEditTime: 2025-01-16 15:07:23 * @FilePath: /sdk615/code/sdk/drivers/peripheral/rotary_encoder/hx3509/hx3509_at_cmd.h * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ @@ -14,8 +14,8 @@ * History: \n * 2022-07-20, Create file. \n */ -#ifndef HX3509_AT_PROCESS_H -#define HX3509_AT_PROCESS_H +#ifndef CHARGE_AT_PROCESS_H +#define CHARGE_AT_PROCESS_H #include #include diff --git a/code/sdk/zhihui/drivers/ppg/CMakeLists.txt b/code/sdk/zhihui/drivers/ppg/CMakeLists.txt index 958ca1f20..88975a2a8 100644 --- a/code/sdk/zhihui/drivers/ppg/CMakeLists.txt +++ b/code/sdk/zhihui/drivers/ppg/CMakeLists.txt @@ -1,3 +1,6 @@ add_subdirectory_if_exist(service) add_subdirectory_if_exist(hx3695) -add_subdirectory_if_exist(ppgBleService) \ No newline at end of file +add_subdirectory_if_exist(ppgBleService) +add_subdirectory_if_exist(vc9202) +add_subdirectory_if_exist(vc921x) +add_subdirectory_if_exist(gh3x2x) \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/CMakeLists.txt b/code/sdk/zhihui/drivers/ppg/gh3x2x/CMakeLists.txt new file mode 100644 index 000000000..1cea5b759 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/gh3x2x/CMakeLists.txt @@ -0,0 +1,57 @@ +#=============================================================================== +# @brief cmake file +# Copyright (c) @CompanyNameMagicTag 2022-2023. All rights reserved. +#=============================================================================== +set(COMPONENT_NAME "ppg_sensor_gh3x2x") + +if("PPG_GH3X2X" IN_LIST DEFINES) + +set(PUBLIC_HEADER + ${CMAKE_CURRENT_SOURCE_DIR}/inc +) + +set(SOURCES ${SOURCES} + ${CMAKE_CURRENT_SOURCE_DIR}/src/gh3x2x_afe_adt.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/gh3x2x_afe_agc.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/gh3x2x_afe_demo.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/gh3x2x_afe_drv.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/gh3x2x_afe_lead_off.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/gh3x2x_afe_user.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/gh3x2x_hal.c +) + +else() +set(SOURCES ${SOURCES} +) +set(PUBLIC_HEADER + ${CMAKE_CURRENT_SOURCE_DIR} +) +endif() + + +set(PRIVATE_HEADER +) + +set(PRIVATE_DEFINES +) + +set(PUBLIC_DEFINES +) + +# use this when you want to add ccflags like -include xxx +set(COMPONENT_PUBLIC_CCFLAGS +) + +set(COMPONENT_CCFLAGS +) + +set(WHOLE_LINK + true +) + +set(MAIN_COMPONENT + false +) + +build_component() + diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_adt.h b/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_adt.h new file mode 100644 index 000000000..d165a76d7 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_adt.h @@ -0,0 +1,72 @@ +#ifndef _GH3X2X_AFE_ADT_H_ +#define _GH3X2X_AFE_ADT_H_ +#include "gh3x2x_afe_drv.h" + + +#define __HARD_ADT_WAER_ON_THRD__ 8600000 +#define __HARD_ADT_WAER_OFF_THRD__ 8538608 +#define __HARD_ADT_WAER_ON_DIFF_THRD__ 100000 + + + +typedef enum +{ + WEAR_DETECT_WEAR_ON = 0, /**< detect wear on */ + WEAR_DETECT_WEAR_OFF, /**< detect wear off */ +} EMWearDetectType; + +typedef enum +{ + WEAR_STATUS_WEAR_ON = 0, /**< detect wear on */ + WEAR_STATUS_WEAR_OFF, /**< detect wear off */ +} EMWearStatus; + + + + + + + + +GS8 GH3x2xAdtAlgoInit(void); +GS8 GH3x2xAdtAlgoDeinit(void); +void GH3x2xAdtAlgoExe(GU32* punRawdata,EMWearStatus* pemWearStatus); + + + + +#endif + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_agc.h b/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_agc.h new file mode 100644 index 000000000..ae3bd7b93 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_agc.h @@ -0,0 +1,264 @@ +#ifndef _GH3X2X_AFE_AGC_H_ +#define _GH3X2X_AFE_AGC_H_ +#include "gh3x2x_afe_drv.h" +#include + + +#define __SUPPORT_SOFT_AGC_CONFIG__ 1 +#define GH3X2X_NEW_AGC_SLOT_NUM_LIMIT (8) +#define GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT (32-8) + +#define GH3X2X_LED_AGC_DISABLE (0) +#define GH3X2X_LED_AGC_ENABLE (1) + + +/// led agc adc num max +#define GH3X2X_AGC_ADC_NUM_MAX (4u) + +/// led agc gain limit number +#define GH3X2X_AGC_LIMIT_NUM_MAX (4u) + +/// raw data base line value +#define GH3X2X_DATA_BASE_LINE (8388608) //2^23 + +/// sys sample rate, 32kHz +#define GH3X2X_SYS_SAMPLE_RATE (32000) + +/* slot register ctrl index */ +#define GH3X2X_SLOT_REG_CTRL_0 (0) /**< slot x ctrl 0 reg */ +#define GH3X2X_SLOT_REG_CTRL_1 (1) /**< slot x ctrl 1 reg */ +#define GH3X2X_SLOT_REG_CTRL_2 (2) /**< slot x ctrl 2 reg */ +#define GH3X2X_SLOT_REG_CTRL_3 (3) /**< slot x ctrl 3 reg */ +#define GH3X2X_SLOT_REG_CTRL_4 (4) /**< slot x ctrl 4 reg */ +#define GH3X2X_SLOT_REG_CTRL_5 (5) /**< slot x ctrl 5 reg */ +#define GH3X2X_SLOT_REG_CTRL_6 (6) /**< slot x ctrl 6 reg */ +#define GH3X2X_SLOT_REG_CTRL_7 (7) /**< slot x ctrl 7 reg */ +#define GH3X2X_SLOT_REG_CTRL_8 (8) /**< slot x ctrl 8 reg */ +#define GH3X2X_SLOT_REG_CTRL_9 (9) /**< slot x ctrl 9 reg */ +#define GH3X2X_SLOT_REG_CTRL_10 (10) /**< slot x ctrl 10 reg */ +#define GH3X2X_SLOT_REG_CTRL_11 (11) /**< slot x ctrl 11 reg */ +#define GH3X2X_SLOT_REG_CTRL_12 (12) /**< slot x ctrl 12 reg */ +#define GH3X2X_SLOT_REG_CTRL_13 (13) /**< slot x ctrl 13 reg */ + +#define GH3X2X_BG_LEVEL_BIT_MASK (0x0030) +#define GH3X2X_ADC_BG_CANCEL_32_UA (0x0) +#define GH3X2X_ADC_BG_CANCEL_64_UA (0x1) +#define GH3X2X_ADC_BG_CANCEL_128_UA (0x2) +#define GH3X2X_ADC_BG_CANCEL_256_UA (0x3) + +/// amb slot select +#define GH3X2X_AGC_AMB_SLOT_DISABLE (0x0) +#define GH3X2X_AGC_AMB_SLOT_USER_DEFINED (0x1) +#define GH3X2X_AGC_AMB_SLOT_FOLLOW_CFG (0x2) + +/// get bits data +#define GH3X2X_GET_REG_BITS_U16(reg_data, lsb, msb) (((reg_data) & ((0xFFFF << (lsb)) & \ + (0xFFFF >> (15 - (msb))))) >> (lsb)) + +/// set bits data +#define GH3X2X_SET_REG_BITS_U16(reg, lsb, msb, value) ((reg) = (((reg) & ((0xFFFF << (lsb)) ^ \ + (0xFFFF >> (15 - (msb))))) | ((value) << (lsb)))) + +/// get adc gain +#define GH3X2X_GET_ADC_GAIN(reg_data, adc_no) GH3X2X_GET_REG_BITS_U16((reg_data), ((adc_no) * 4), \ + ((adc_no) * 4 + 3)) + +/// set adc gain +#define GH3X2X_SET_ADC_GAIN(reg_data, adc_no, gain) GH3X2X_SET_REG_BITS_U16((reg_data), ((adc_no) * 4), \ + ((adc_no) * 4 + 3), (gain)) + +/// get bg cancel i_dacfs +#define GH3X2X_GET_BGC_I_DACFS(reg_data, adc_no) GH3X2X_GET_REG_BITS_U16((reg_data), ((adc_no) << 1), \ + ((adc_no) * 2 + 1)) + +/// set bg cancel i_dacfs +#define GH3X2X_SET_BGC_I_DACFS(reg_data, adc_no, i_dacfs) GH3X2X_SET_REG_BITS_U16((reg_data), ((adc_no) * 2), \ + ((adc_no) * 2 + 1), (i_dacfs)) + +#define ABS(x) ((x) > 0 ? (x) : -(x)) + +/// transfer int to float +#define GH3X2X_TRANS_INT_TO_FLOAT (1.0f) + +/// agc calc seconds (250ms) +#define GH3X2X_AGC_CALC_SECONDS (0.25f) + +/// agc bgc donw cnt, 5s +#define GH3X2X_AGC_BGC_DOWN_CNT (20) + +/// slot tia gain val min +#define GH3X2X_AGC_GAIN_MIN_VAL (0) + +/// slot tia gain val max, 5s, equal (GH3X2X_SLOT_TIA_GAIN_VAL_MAX - 1) +#define GH3X2X_AGC_GAIN_MAX_VAL (12) + +/// Less than thr, include rawdata < thr +#define GH3X2X_AGC_EXCD_FLAG_LESS (0x01) + +/// greater than thr, include rawdatamix > thr | rawdata > thr +#define GH3X2X_AGC_EXCD_FLAG_GREATER (0x06) + +/// AGC failure reason +#define GH3X2X_AGC_FAILURE_REASON_1 (0x1) +#define GH3X2X_AGC_FAILURE_REASON_2 (0x2) +#define GH3X2X_AGC_FAILURE_REASON_4 (0x4) +#define GH3X2X_AGC_FAILURE_REASON_5 (0x5) +#define GH3X2X_AGC_FAILURE_REASON_6 (0x6) + +#define GH3X2X_AGC_CHECK_EN_BITS(x) (((x) & (0x03 << 8)) != 0) /**< check enable bits of ctrl3 */ +#define GH3X2X_AGC_GET_SRC_BITS(x) (((x) >> 6) & 0x03) /**< get agc src bits of ctrl3 */ +#define GH3X2X_AGC_CHECK_BG_2X2_BITS(x) (((x) & (0x03 << 4)) == 0x03) /**< check 2x2 bg lvl bits of ctrl3 */ +#define GH3X2X_AGC_SET_SRC_BITS(x, n) (((x) & 0xFF3Fu) | ((n) << 6u)) /**< set agc src bits of ctrl3 */ + +#define GH3X2X_AGC_GET_DONE_FAIL_BIT(x, i) (((x) >> (i)) & 0x01) /**< get tune done/fail bit of flag */ +#define GH3X2X_AGC_REG_BIT(x, i) (((x) >> (i)) & 0x01) /**< get reg bit value */ +#define GH3X2X_AGC_GET_RESULT_BITS(x, i) (((x) >> (i)) & 0x07) /**< get result bits of flag */ +#define GH3X2X_AGC_RESULT_BITS_SIZE (3u) /**< one result 3 bits size of flag */ + +#define GH3X2X_FRAME_FLAG_NUM 8 +#define GH3X2X_AGC_MAIN_SLOT_NUM 8 + +/** + * @brief soft lead result + */ +typedef struct +{ + GU8 uchAmbSampleEn : 2; /**< AMB sampling enable */ + GU8 uchAmbSlot : 3; /**< slot of amb sampling */ + GU8 uchRes : 3; /**< reserved */ +} STAmbSlotCtrl; + + /** + * @brief gain limit + */ +typedef struct +{ + GU8 uchGainLimitBg32uA : 4; /**< gain limit bg current */ + GU8 uchGainLimitBg64uA : 4; + GU8 uchGainLimitBg128uA : 4; + GU8 uchGainLimitBg256uA : 4; +} STSoftAgcGainLimit; + + /** + * @brief soft agc parameter + */ +typedef struct +{ + GU8 uchSlotxSoftAgcAdjEn; /**< soft agc enable */ + GU8 uchSlotxSoftBgAdjEn; /**< soft bg cancel adjust enable */ + STAmbSlotCtrl stAmbSlotCtrl; /**< amb slot ctrl */ + GU8 uchRes0; /**< reserved */ + GU8 uchSpo2RedSlotCfgEn; + GU8 uchSpo2IrSlotCfgEn; + STSoftAgcGainLimit stSoftAgcGainLimit; /**< soft gain limit */ + GU32 unAgcTrigThd_H; /**< trig threshold(high) of soft agc */ + GU32 unAgcTrigThd_L; /**< trig threshold(low) of soft agc */ + GU32 unAgcRestrainThd_H; /**< restrain threshold(high) of soft agc */ + GU32 unAgcRestrainThd_L; /**< restrain threshold(low) of soft agc */ +} STSoftAgcCfg; + + + +typedef struct +{ + GU8 uchEnable; + GU8 uchSpo2ChnlIndex; //0: is not spo2 channel N(N > 0): is spo2 channl + GU8 uchSlotAdc; + GU8 uchCurrentTiaGain; + GU8 uchCurrentDrv; + GU8 uchTiaGainUpLimit; + GU8 uchHaveBakRegFlag; + GU8 uchBakRegAgcEn; + GU8 uchBakRegAgcSrc; + GU8 uchBakRegLedCurrentMin; + GU8 uchBakRegLedCurrentMax; + GU8 uchBakTiaGain; +} STGh3x2xNewAgcMainChnlInfo; + +typedef struct +{ + GU16 Sat_CheckCnt[GH3X2X_AGC_MAIN_SLOT_NUM]; /* num of data checked*/ + GU16 Sat_cnt[GH3X2X_AGC_MAIN_SLOT_NUM]; /* sat num of each channel*/ + GU8 Sat_flag; /* sat flag one bit each channel*/ +} STGh3x2xNewAgcMainChnlSat; + +typedef struct +{ + GU32 unMaxRawdata; + GU32 unMinRawdata; + GU32 unSumAdjust; // cacluate drv current and gain + GU32 unSumTrige; // judge whether AGC + GU32 unRawdataMean; + GU32 unLastRawdataMean; + GU16 usSampleRate; + GU16 usAnalysisCnt; // numble of nalysis data + GU8 uchHaveAgcAtLastReadPrd; //0: no agc action at last fifo read period 1: have agc action at last fifo read preiod + GU8 uchDropFlag; +} STGh3x2xNewAgcMainChnlMeanInfo; + +typedef struct +{ + GU8 uchIniteFirst; // inite first time 0:yes 1:not + GU8 uchSeconsCnt; // +} STGh3x2xNewAgcMainChnlIdaelAdjInfo; + +typedef struct +{ + GU32 unLastRawdata; + GU32 unLastLastRawdata; + GU32 unRawdataSum; + GU16 usAnalysisCnt; + GU16 usMoreThanUpLimitPointCnt; + GU16 usMoreThanUpLimitPointCntForBiggerGain; + GU16 usTrigeUpLimitForBiggerGain; // rawdate/256 + GU8 uchEn; + GU8 uchSlotAdcNo; + GU8 uchCurrentGain; +}STGh3x2xNewAgcSubChnlRxInfo; + + +void GH3X2X_LedAgcReset(void); +void GH3X2X_LedAgcPramWrite(GU16 usRegAddr, GU16 usRegData); +void GH3X2X_LedAgcInit(STGh3x2xAgcInfo *STGh3x2xAgcInfo); +void GH3X2X_LedAgc_Close(void); +void GH3X2X_LedAgc_Open(void); +void Gh3x2xNewAgcSubChnlModuleReset(void); +GU8 GH3x2xNewAgcSetNewSubChnl(GU8 uchSlotNo, GU8 uchRxEn, STGh3x2xAgcInfo *STGh3x2xAgcInfo); +void GH3X2X_LedAgcProcess(GU8* puchReadFifoBuffer, GU16 usFifoLen, STGh3x2xAgcInfo *STGh3x2xAgcInfo); +void GH3X2X_LedAgcInit(STGh3x2xAgcInfo *STGh3x2xAgcInfo); +void GH3X2X_LedAgcPramConfig(STSoftAgcCfg* stSoftAgcCfg); +#endif + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_demo.h b/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_demo.h new file mode 100644 index 000000000..e1d45e907 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_demo.h @@ -0,0 +1,68 @@ +#ifndef __GH3X2X_AFE_DEMO_H__ +#define __GH3X2X_AFE_DEMO_H__ +#include "gh3x2x_afe_drv.h" + +/** + * @brief channel map for function id + */ +#define GH3X2X_FUNC_OFFSET_ADT (0) /**<0 ADT FUNC_OFFSET */ +#define GH3X2X_FUNC_OFFSET_HR (1) /**<1 HR FUNC_OFFSET */ +#define GH3X2X_FUNC_OFFSET_HRV (2) /**<2 HRV FUNC_OFFSET */ +#define GH3X2X_FUNC_OFFSET_HSM (3) /**<3 HSM FUNC_OFFSET */ +#define GH3X2X_FUNC_OFFSET_FPBP (4) /**<4 BPD FUNC_OFFSET */ +#define GH3X2X_FUNC_OFFSET_PWA (5) /**<5 PFA FUNC_OFFSET */ +#define GH3X2X_FUNC_OFFSET_SPO2 (6) /**<6 SPO2 FUNC_OFFSET */ +#define GH3X2X_FUNC_OFFSET_ECG (7) /**<7 ECG FUNC_OFFSET */ +#define GH3X2X_FUNC_OFFSET_PWTT (8) /**<8 PWTT FUNC_OFFSET */ +#define GH3X2X_FUNC_OFFSET_SOFT_ADT_GREEN (9) /**<9 SOFT ADT GREEN FUNC_OFFSET */ +#define GH3X2X_FUNC_OFFSET_BT (10) /**<10 BT FUNC_OFFSET */ +#define GH3X2X_FUNC_OFFSET_RESP (11) /**<11 RESP FUNC_OFFSET */ +#define GH3X2X_FUNC_OFFSET_AF (12) /**<12 AF ADT FUNC_OFFSET */ +#define GH3X2X_FUNC_OFFSET_TEST1 (13) /**<13 TEST1 FUNC_OFFSET */ +#define GH3X2X_FUNC_OFFSET_TEST2 (14) /**<14 TEST2 ADT FUNC_OFFSET */ +#define GH3X2X_FUNC_OFFSET_SOFT_ADT_IR (15) /**<15 SOFT ADT IR FUNC_OFFSET */ +#define GH3X2X_FUNC_OFFSET_RS0 (16) /**<16 */ +#define GH3X2X_FUNC_OFFSET_RS1 (17) /**<17 */ +#define GH3X2X_FUNC_OFFSET_RS2 (18) /**<18 */ +#define GH3X2X_FUNC_OFFSET_LEAD_DET (19) /**<19 */ +#define GH3X2X_FUNC_OFFSET_MAX (20) + +/* Function mode. */ +#define GH3X2X_NO_FUNCTION (0) /**<0x00000000 NO function */ +#define GH3X2X_FUNCTION_ADT ((0x1) << (GH3X2X_FUNC_OFFSET_ADT)) /**<0x00000001 ADT function */ +#define GH3X2X_FUNCTION_HR ((0x1) << (GH3X2X_FUNC_OFFSET_HR)) /**<0x00000002 HR function */ +#define GH3X2X_FUNCTION_HRV ((0x1) << (GH3X2X_FUNC_OFFSET_HRV)) /**<0x00000004 HRV function */ +#define GH3X2X_FUNCTION_HSM ((0x1) << (GH3X2X_FUNC_OFFSET_HSM)) /**<0x00000008 HSM function */ +#define GH3X2X_FUNCTION_FPBP ((0x1) << (GH3X2X_FUNC_OFFSET_FPBP)) /**<0x00000010 FPBP function */ +#define GH3X2X_FUNCTION_PWA ((0x1) << (GH3X2X_FUNC_OFFSET_PWA)) /**<0x00000020 PWA function */ +#define GH3X2X_FUNCTION_SPO2 ((0x1) << (GH3X2X_FUNC_OFFSET_SPO2)) /**<0x00000040 SPO2 function */ +#define GH3X2X_FUNCTION_ECG ((0x1) << (GH3X2X_FUNC_OFFSET_ECG)) /**<0x00000080 ECG function */ +#define GH3X2X_FUNCTION_PWTT ((0x1) << (GH3X2X_FUNC_OFFSET_PWTT)) /**<0x00000100 PWTT function */ +#define GH3X2X_FUNCTION_SOFT_ADT_GREEN ((0x1) << (GH3X2X_FUNC_OFFSET_SOFT_ADT_GREEN)) /**<0x00000200 SOFT ADT GREEN function */ +#define GH3X2X_FUNCTION_BT ((0x1) << (GH3X2X_FUNC_OFFSET_BT)) /**<0x00000400 BT function */ +#define GH3X2X_FUNCTION_RESP ((0x1) << (GH3X2X_FUNC_OFFSET_RESP)) /**<0x00000800 RESP function */ +#define GH3X2X_FUNCTION_AF ((0x1) << (GH3X2X_FUNC_OFFSET_AF)) /**<0x00001000 AF function */ +#define GH3X2X_FUNCTION_TEST1 ((0x1) << (GH3X2X_FUNC_OFFSET_TEST1)) /**<0x00002000 TEST1 function */ +#define GH3X2X_FUNCTION_TEST2 ((0x1) << (GH3X2X_FUNC_OFFSET_TEST2)) /**<0x00004000 TEST2 function */ +#define GH3X2X_FUNCTION_SOFT_ADT_IR ((0x1) << (GH3X2X_FUNC_OFFSET_SOFT_ADT_IR)) /**<0x00008000 SOFT ADT IR function */ +#define GH3X2X_FUNCTION_RS0 ((0x1) << (GH3X2X_FUNC_OFFSET_RS0)) +#define GH3X2X_FUNCTION_RS1 ((0x1) << (GH3X2X_FUNC_OFFSET_RS1)) +#define GH3X2X_FUNCTION_RS2 ((0x1) << (GH3X2X_FUNC_OFFSET_RS2)) +#define GH3X2X_FUNCTION_LEAD_DET ((0x1) << (GH3X2X_FUNC_OFFSET_LEAD_DET)) + +#define GH3X2X_ADT_FUNC_ENABLE (1) +#define GH3X2X_ECG_FUNC_ENABLE (1) + +#define GH3X2X_ECG_SLOT_NUM (0) +#define GH3X2X_ADT_SLOT_NUM (1) + +#define GH3X2X_ADT_ADC_NUM (0) + +#define GH3X2X_ECG_DOWN_FS (250) //ecg fs:800, 320, 256 +#define GH3X2X_ECG_FS (320) //down sample ecg fs: 500 OR 250 +#define GH3X2X_PPG_DOWN_FS (250) //down sample ppg fs: + +void GH3X2X_DemoLedAgcPramConfig(void); + +#endif + diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_drv.h b/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_drv.h new file mode 100644 index 000000000..16875905d --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_drv.h @@ -0,0 +1,447 @@ +/** + * @copyright (c) 2003 - 2022, Goodix Co., Ltd. All rights reserved. + * + * @file gh3x2x_afe_drv.h + * + * @brief gh3x2x afe driver functions + * + * @version v3.2.4.6 + * + * @author Gooidx Iot Team + * + */ +#ifndef __GH3X2X_AFE_DRV_H__ +#define __GH3X2X_AFE_DRV_H__ + +#include "gh3x2x_afe_user.h" +#include "gh3x2x_afe_version.h" + +#ifndef GH3X2X_AFE_UNUSED_VAR +#define GH3X2X_AFE_UNUSED_VAR(X) ((void)(X)) +#endif // GH3X2X_AFE_UNUSED_VAR + + +#if defined ( __GNUC__ ) && !defined (__CC_ARM) /* GNU Compiler */ + #ifndef __weak + #define __weak __attribute__((weak)) + #endif /* __weak */ + #ifndef __packed + #define __packed __attribute__((__packed__)) + #endif /* __packed */ +#endif /* __GNUC__ */ + + + + + + +/* type redefine */ +typedef unsigned char GU8; /**< 8bit unsigned integer type */ +typedef signed char GS8; /**< 8bit signed integer type */ +typedef unsigned short GU16; /**< 16bit unsigned integer type */ +typedef signed short GS16; /**< 16bit signed integer type */ +typedef int GS32; /**< 32bit signed integer type */ +typedef unsigned int GU32; /**< 32bit unsigned integer type */ +typedef float GF32; /**< float type */ +typedef double GD64; /**< double type */ +typedef char GCHAR; /**< char type */ +typedef unsigned char GBOOL; +typedef long long GS64; /**< 64bit signed integer type */ + + + + +#define GH3020_ID (0x00) +#define GH3026_ID (0x01) + +#define GH3X2X_MP_DISABLE (0) +#define GH3X2X_MP_ENABLE (1) + +/********************* communication interface type******************************/ +#define GH3X2X_AFE_COM_INTERFACE_SPI 0 +#define GH3X2X_AFE_COM_INTERFACE_I2C 1 + + +/********************* spi type ************************************************/ +#define GH3X2X_AFE_SPI_SOFTWARE_CS 0 +#define GH3X2X_AFE_SPI_HARDWEAR_CS 1 + + +/********************* chip process type ***************************************/ +#define GH3X2X_AFE_PRO_BY_INT 0 +#define GH3X2X_AFE_PRO_BY_POLLING 1 + +/********************* chip reset type ***************************************/ +#define GH3X2X_AFE_RESET_HARDWARE 0 +#define GH3X2X_AFE_RESET_SOFTWARE 1 + + + +#define GH3X2X_AFE_SPI_CS_CTRL_LOW 0 +#define GH3X2X_AFE_SPI_CS_CTRL_HIGH 1 + + + + +#define GH3X2X_AFE_CMD_SLEEP 0xC4 +#define GH3X2X_AFE_CMD_WAKEUP 0xC3 +#define GH3X2X_AFE_CMD_RESET 0xC2 +#define GH3X2X_AFE_SPI_CMD_WRITE (0xF0) +#define GH3X2X_AFE_SPI_CMD_READ (0xF1) + + + +#define GH3X2X_AFE_RET_OK (0) /**< there is no error */ +#define GH3X2X_AFE_RET_GENERIC_ERROR (-1) /**< a generic error happens */ + +// special reg addr +#define GH3X2X_AFE_FIFO_REG_ADDR (0xAAAA) /**< fifo reg addr */ +#define GH3X2X_AFE_I2C_CMD_ADDR (0xDDDD) /**< i2c cmd reg addr */ + + +#define GH3X2X_AFE_SPI_END_DELAY_X_US (3) +#define GH3X2X_AFE_SPI_WAIT_DELAY_X_US (4) + +#define GH3X2X_AFE_WAKE_UP_CMD_DELAY_X_US (500) +#define GH3X2X_AFE_HARD_RESET_DELAY_X_US (100) + +/// null val +#define GH3X2X_PTR_NULL ((void *) 0) + + + +#define GH3X2X_AFE_CHANGE_BYTE_U16(x) ((((u16)(((u8*)(&x))[0]))<<8) + ((u16)(((u8 *)(&x))[1]))) +/// get high byte from word +#define GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(sValue) ((GU8)(((sValue) >> 8) & 0xFFU)) +/// get low byte from word +#define GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(sValue) ((GU8)((sValue) & 0xFFU)) +#define GH3X2X_AFE_MAKEUP_WORD(uchHighByte, uchLowByte) ((GU16)(((((GU16)(uchHighByte)) << 8)& 0xFF00) |\ + (((GU16)(uchLowByte))& 0x00FF))) + +/// makeup dword from bytes +#define GH3X2X_AFE_MAKEUP_DWORD(uchByte3, uchByte2, uchByte1, uchByte0) (((((GU32)(uchByte3)) << 24) & 0xFF000000U)|\ + ((((GU32)(uchByte2)) << 16) & 0x00FF0000U) |\ + ((((GU32)(uchByte1)) << 8) & 0x0000FF00U) |\ + (((GU32)(uchByte0)) & 0x000000FFU)) + + +/// rawdata clear all flag +#define GH3X2X_RAWDATA_CLEAR_ALL_FLAG(x) ((x) & 0x00FFFFFF) + + +/// macro of val get bits +#define GH3X2X_AFE_VAL_GET_BIT(x, b) ((x) &= (b)) + + + +#define GH3X2X_AFE_EVENT_BIT(x) ((GU16)1 << x) + + + +#define GH3X2X_AFE_REG_IS_VALID(x) ((x) <= 0x0780) +/// macro of val clear bits +#define GH3X2X_VAL_CLEAR_BIT(x, b) ((x) &= (~(b))) +/// macro of val set bits +#define GH3X2X_VAL_SET_BIT(x, b) ((x) |= (b)) + + +#define GH3X2X_PIN_STATUS_CS_0_MISO_0 (0) +#define GH3X2X_PIN_STATUS_CS_1_MISO_0 (1) +#define GH3X2X_PIN_STATUS_CS_0_MISO_1 (2) +#define GH3X2X_PIN_STATUS_CS_1_MISO_1 (3) + + +/// get byte3 from dword +#define GH3X2X_AFE_GET_BYTE3_FROM_DWORD(unValue) ((GU8)(((unValue) >> 24) & 0x000000FFU)) +/// get byte2 from dword +#define GH3X2X_AFE_GET_BYTE2_FROM_DWORD(unValue) ((GU8)(((unValue) >> 16) & 0x000000FFU)) +/// get byte1 from dword +#define GH3X2X_AFE_GET_BYTE1_FROM_DWORD(unValue) ((GU8)(((unValue) >> 8) & 0x000000FFU)) +/// get byte0 from dword +#define GH3X2X_AFE_GET_BYTE0_FROM_DWORD(unValue) ((GU8)((unValue) & 0x000000FFU)) + +/// macro of val set bits +#define GH3X2X_VAL_SET_BIT(x, b) ((x) |= (b)) + +/// macro of clear bits +#define GH3X2X_CLEAR_BIT(x, b) ((x) & (~(b))) + +/// macro of val clear bits +#define GH3X2X_VAL_CLEAR_BIT(x, b) ((x) &= (~(b))) + +/// macro of val get bits +#define GH3X2X_VAL_GET_BIT(x, b) ((x) &= (b)) + + +#define GH3X2X_AFE_I2C_DEVICE_BASE (0x28) +#define GH3X2X_AFE_I2C_DEVICE_ADDR (GH3X2X_AFE_I2C_DEVICE_BASE | (GH3X2X_AFE_I2C_DEVICE_CTRL_PIN_STATUS << 1)) + + +#define GH3X2X_AFE_FIFO_RAWDATA_SIZE (4) +#define GH3X2X_AFE_SLOT_ADC_NUM_BITS (0xF8) +#define GH3X2X_AFE_CHANNEL_MAP_GET(x) ((x) & GH3X2X_AFE_SLOT_ADC_NUM_BITS) + +/// number of channel map id +#define CHANNEL_MAP_ID_NUM (32) +/// number of channel map id +#define CHANNEL_SLOT_NUM (8) + + +/** + * @brief register struct + */ +typedef struct +{ + GU16 usRegAddr; /**< register address */ + GU16 usRegData; /**< register val */ +} STGH3X2X_AFEReg; + +typedef struct +{ + GU8 uchAddrOffset; + GU8 uchMsb; + GU8 uchLsb; +} STGh3x2xAgcReg; + +typedef struct +{ + /// save gain + GU8 uchTiaGainRecord[CHANNEL_MAP_ID_NUM]; + GU8 uchTiaGainAfterSoftAgc[CHANNEL_MAP_ID_NUM]; + /// save current of drv0 and drv1 + GU16 uchDrvCurrentAfterSoftAgc[CHANNEL_SLOT_NUM]; + GU16 uchDrvCurrentRecord[CHANNEL_SLOT_NUM]; +} STGh3x2xAgcInfo; + +extern void GH3X2X_AFE_SpiSendCmd(GU8 uchCmd); +extern void GH3X2X_AFE_SpiWriteReg(GU16 usRegAddr, GU16 usRegValue); +extern GU16 GH3X2X_AFE_SpiReadReg(GU16 usRegAddr); +extern void GH3X2X_AFE_SpiReadRegs(GU16 usRegAddr, GU16 *pusRegValueBuffer, GU8 uchLen); + +extern void GH3X2X_AFE_SpiWriteRegHardwareCs(GU16 usRegAddr, GU16 usRegValue); +extern void GH3X2X_AFE_SpiReadRegsHardwareCs(GU16 usRegAddr, GU16 *pusRegValueBuffer, GU8 uchLen); +extern GU16 GH3X2X_AFE_SpiReadRegHardwareCs(GU16 usRegAddr); +extern void GH3X2X_AFE_I2cWriteReg(GU16 usRegAddr, GU16 usRegValue); +extern GU16 GH3X2X_AFE_I2cReadReg(GU16 usRegAddr); +extern void GH3X2X_I2cReadRegs(GU16 usRegAddr, GU16 *pusRegValueArr, GU8 uchLen); +extern void GH3X2X_AFE_Reset(void); +extern void GH3X2X_AFE_SpiSendCmdHardwareCs(GU8 uchCmd); +extern void GH3X2X_AFE_I2cSendCmd(GU8 uchCmd); + + +/**************** cmd/read/write funciton define **************************/ +#if(GH3X2X_AFE_COM_INTERFACE_TYPE == GH3X2X_AFE_COM_INTERFACE_SPI) +#if(GH3X2X_AFE_SPI_TYPE == GH3X2X_AFE_SPI_SOFTWARE_CS) +#define GH3X2X_AFE_SEND_CMD(cmd) GH3X2X_AFE_SpiSendCmd(cmd) +#define GH3X2X_AFE_WRITE_REG(usRegAddr, usRegValue) GH3X2X_AFE_SpiWriteReg(usRegAddr, usRegValue) +#define GH3X2X_AFE_READ_REG(usRegAddr) GH3X2X_AFE_SpiReadReg(usRegAddr) +#define GH3X2X_AFE_READ_FIFO(buf, len) GH3X2X_AFE_SpiReadFifo(buf, len) +#define GH3X2X_AFE_READ_REGS(usRegAddr,pusRegValueBuffer,uchLen) GH3X2X_AFE_SpiReadRegs(usRegAddr,pusRegValueBuffer,uchLen) +#else +#define GH3X2X_AFE_SEND_CMD(cmd) GH3X2X_AFE_SpiSendCmdHardwareCs(cmd) +#define GH3X2X_AFE_WRITE_REG(usRegAddr, usRegValue) GH3X2X_AFE_SpiWriteRegHardwareCs(usRegAddr, usRegValue) +#define GH3X2X_AFE_READ_REG(usRegAddr) GH3X2X_AFE_SpiReadRegHardwareCs(usRegAddr) +#define GH3X2X_AFE_READ_FIFO(buf, len) GH3X2X_AFE_SpiReadFifoHardwareCs(buf, len) +#define GH3X2X_AFE_READ_REGS(usRegAddr,pusRegValueBuffer,uchLen) GH3X2X_AFE_SpiReadRegsHardwareCs(usRegAddr,pusRegValueBuffer,uchLen) + +#endif +#else +#define GH3X2X_AFE_SEND_CMD(cmd) GH3X2X_AFE_I2cSendCmd(cmd) +#define GH3X2X_AFE_WRITE_REG(usRegAddr, usRegValue) GH3X2X_AFE_I2cWriteReg(usRegAddr, usRegValue) +#define GH3X2X_AFE_READ_REG(usRegAddr) GH3X2X_AFE_I2cReadReg(usRegAddr) +#define GH3X2X_AFE_READ_FIFO(buf, len) GH3X2X_AFE_I2cReadFifo(buf, len) +#define GH3X2X_AFE_READ_REGS(usRegAddr,pusRegValueBuffer,uchLen) GH3X2X_I2cReadRegs(usRegAddr,pusRegValueBuffer,uchLen) + +#endif + + +/***************************** GH3X2X event *************************************************/ + +#define GH3X2X_AFE_EVENT_COM_READY (0) +#define GH3X2X_AFE_EVENT_LEAD_ON (1) +#define GH3X2X_AFE_EVENT_LEAD_OFF (2) +#define GH3X2X_AFE_EVENT_FAST_RECOVER_DONE (3) +#define GH3X2X_AFE_EVENT_ADC_DONE (4) +#define GH3X2X_AFE_EVENT_FIFO_FULL (5) +#define GH3X2X_AFE_EVENT_FIFO_OV (6) +#define GH3X2X_AFE_EVENT_FIFO_UN (7) +#define GH3X2X_AFE_EVENT_LED_TUNE_FAIL (8) +#define GH3X2X_AFE_EVENT_LED_TUNE_DONE (9) +#define GH3X2X_AFE_EVENT_WEAR_ON (10) +#define GH3X2X_AFE_EVENT_WEAR_OFF (11) +#define GH3X2X_AFE_EVENT_SLOT_TIME_OUT (12) +#define GH3X2X_AFE_EVENT_SAMPLE_RATE_ERROR (13) +#define GH3X2X_AFE_EVENT_ERSET (14) + + + + + + +/***************************** GH3X2X registers *********************************************/ + + +#define GH3X2X_AFE_REG_INT_EVENT_ADDR 0x0508 +#define GH3X2X_AFE_REG_FIFO_USE_ADDR 0x050A +#define GH3X2X_AFE_REG_CHIP_READY_CODE_REG_ADDR 0x0036 +#define GH3X2X_AFE_REG_SLOT_TMR0_REG_ADDR 0x01EC +#define GH3X2X_AFE_REG_INT_EVENT_EN_ADDR 0x0502 + +#define GH3X2X_AFE_REG_SLOT_EN_ADDR 0x0108 + + +#define GH3X2X_AFE_REG_START_ADDR 0x0000 +#define GH3X2X_AFE_REG_START_MSB 0 +#define GH3X2X_AFE_REG_START_LSB 0 + + +/**************************** GH3X2X ppg control reg index ***********************************************/ +#define GH3X2X_AFE_PPG_CTRL_REG_AGC_EN 0 +#define GH3X2X_AFE_PPG_CTRL_REG_LED_CURRENT_UP_LIMIT 1 +#define GH3X2X_AFE_PPG_CTRL_REG_LED_CURRENT_DOWN_LIMIT 2 +#define GH3X2X_AFE_PPG_CTRL_REG_LED_CURRENT_DRV0 3 +#define GH3X2X_AFE_PPG_CTRL_REG_LED_CURRENT_DRV1 4 +#define GH3X2X_AFE_PPG_CTRL_REG_TIA_GAIN_RX0 5 +#define GH3X2X_AFE_PPG_CTRL_REG_TIA_GAIN_RX1 6 +#define GH3X2X_AFE_PPG_CTRL_REG_TIA_GAIN_RX2 7 +#define GH3X2X_AFE_PPG_CTRL_REG_TIA_GAIN_RX3 8 +#define GH3X2X_AFE_PPG_CTRL_REG_AGC_SRC 9 +#define GH3X2X_AFE_PPG_CTRL_REG_BG_CANCEL_RX0 10 +#define GH3X2X_AFE_PPG_CTRL_REG_BG_CANCEL_RX1 11 +#define GH3X2X_AFE_PPG_CTRL_REG_BG_CANCEL_RX2 12 +#define GH3X2X_AFE_PPG_CTRL_REG_BG_CANCEL_RX3 13 +#define GH3X2X_AFE_PPG_CTRL_REG_SR_MULIPLIPER 14 +#define GH3X2X_AFE_PPG_CTRL_ECG_PPG_RX_EN 15 + +#define GH3X2X_DRV0_FULL_SCAL_CURRENT_LSB (4) +#define GH3X2X_DRV0_FULL_SCAL_CURRENT_MSB (5) + +#define GH3X2X_DRV1_FULL_SCAL_CURRENT_LSB (0) +#define GH3X2X_DRV1_FULL_SCAL_CURRENT_MSB (1) + +#define GH3X2X_WHO_AM_I_LSB (5) +#define GH3X2X_WHO_AM_I_MSB (7) + +#define GH3X2X_EFUSE_MODE_LSB (0) +#define GH3X2X_EFUSE_MODE_MSB (1) + +#define GH3X2X_EFUSE_CHOOSE_LSB (2) +#define GH3X2X_EFUSE_CHOOSE_MSB (3) + +#define GH3X2X_EFUSE_START_LSB (4) +#define GH3X2X_EFUSE_START_MSB (4) + +#define GH3X2X_EFUSE_CLK_EN_LSB (5) +#define GH3X2X_EFUSE_CLK_EN_MSB (5) + + + + +#define GH3X2X_LED_DRV_AD_REG_REG_ADDR (0x0692) +#define GH3X2X_WHO_AM_I_REG_ADDR (0x0724) + + +// efuse_ctrl block, start addr: 0x0700 +#define GH3X2X_EFUSE_CTRL_CMD_REG_ADDR (0x0700) +#define GH3X2X_EFUSE_CTRL_PASSWORD_REG_ADDR (0x0702) +#define GH3X2X_EFUSE_CTRL_TIMING_CFG_0_REG_ADDR (0x0704) +#define GH3X2X_EFUSE_CTRL_TIMING_CFG_1_REG_ADDR (0x0706) +#define GH3X2X_EFUSE_CTRL_WDATA_0_REG_ADDR (0x0708) +#define GH3X2X_EFUSE_CTRL_WDATA_1_REG_ADDR (0x070A) +#define GH3X2X_EFUSE_CTRL_WDATA_2_REG_ADDR (0x070C) +#define GH3X2X_EFUSE_CTRL_WDATA_3_REG_ADDR (0x070E) +#define GH3X2X_EFUSE_CTRL_RDATA_0_REG_ADDR (0x0710) +#define GH3X2X_EFUSE_CTRL_RDATA_1_REG_ADDR (0x0712) +#define GH3X2X_EFUSE_CTRL_RDATA_2_REG_ADDR (0x0714) +#define GH3X2X_EFUSE_CTRL_RDATA_3_REG_ADDR (0x0716) +#define GH3X2X_EFUSE_CTRL_STATUS_REG_ADDR (0x0718) +#define GH3X2X_EFUSE_CTRL_REG_MODE_REG_ADDR (0x071A) + + +extern GU8 g_uchGh3x2xAfeIntCallBackIsCalled; + + +extern void GH3X2X_AFE_SetNeedWakeUpGh3x2xFlag(GU8 uchFlag); +extern void hal_gh3x2x_afe_DelayUs(GU16 usUsec); +extern void hal_gh3x2x_afe_DelayMs(GU16 usMsec); + +extern void hal_gh3x2x_afe_i2c_init(void); +extern GU8 hal_gh3x2x_afe_i2c_write(GU8 device_id, const GU8 write_buffer[], GU16 length); +extern GU8 hal_gh3x2x_afe_i2c_read(GU8 device_id, const GU8 write_buffer[], GU16 write_length, GU8 read_buffer[], GU16 read_length); + +extern void hal_gh3x2x_afe_spi_init(void); +extern GU8 hal_gh3x2x_afe_spi_write(GU8 write_buffer[], GU16 length); +extern GU8 hal_gh3x2x_afe_spi_read(GU8 read_buffer[], GU16 length); +extern GU8 hal_gh3x2x_afe_spi_write_F1_and_read(GU8 read_buffer[], GU16 length); +extern void hal_gh3x2x_afe_spi_cs_ctrl(GU8 cs_pin_level); + +extern void hal_gh3x2x_afe_reset_pin_init(void); +extern void hal_gh3x2x_afe_reset_pin_ctrl(GU8 pin_level); + +extern void hal_gh3x2x_afe_int_init(void); +extern void hal_gh3x2x_afe_int_handler_call_back(void); + +extern void GH3X2X_AFE_Log(GCHAR *log_string); + + + + + +extern void GH3X2X_AFE_ChipPro(void); +extern void GH3X2X_AFE_Init(void); +extern void GH3X2X_AFE_StartSampling(GU8 SlotCfgEnable); +extern void GH3X2X_AFE_StopSampling(void); +extern void GH3X2X_AFE_SwitchSlot(GU8 SlotCfgEnable); + +extern void GH3x2xSetPpgCtrlReg(GU8 uchPpgCtrlReg, GU8 uchSlot, GU16 usValue); +extern GU16 GH3x2xGetPpgCtrlReg(GU8 uchPpgCtrlReg, GU8 uchSlot); + +GU16 GH3X2X_AFE_SetLedDrvCurrent(GU8 uchCurrent_mA, GU8 uchDrvNum, GS8 chECODE); +GF32 GH3X2X_AFE_GetLedDrvCurrent(GU16 usDrvCode, GU8 uchDrvNum, GS8 chECODE); +void GH3X2X_AFE_GetEfuseCode(GS8* pchLedDrvEcode,GS8* pchTiaEcode,GS8* pchEcgEcode); +GF32 GH3X2X_AFE_GetTiaCalCode(GS8 chECODE); +GF32 GH3X2X_AFE_GetEcgCalCode(GS8 chECODE); +GCHAR *GH3X2X_GetAfeLibVersion(void); +GU8 GH3X2X_AFE_GetChipId(void); +GS8 GH3X2X_AFE_CheckChipId(void); +void GH3X2X_AFE_LoadEfuse(GU8* puchEfuseBuffer,GU16 EfuseByteLen); +GS8 GH3X2X_AFE_CheckEfuseCrc(void); +void GH3X2X_AFE_WriteRegBitField(GU16 usRegAddr, GU8 uchLsb, GU8 uchMsb, GU16 usValue); +GU16 GH3X2X_AFE_ReadRegBitField(GU16 usRegAddr, GU8 uchLsb, GU8 uchMsb); +GU8 GH3X2X_AFE_GetSoftEvent(void); +void GH3X2X_AFE_SetSoftEvent(GU32 unEvent); +void GH3X2X_AFE_ClearSoftEvent(GU32 unEvent); +void GH3X2X_AFE_StartFunction(GU32 unFuncMode); + +void GH3x2x_AFESetAgcReg(GU8 uchAgcReg, GU8 uchSlot, GU16 usValue); +GU16 GH3x2x_AFEGetAgcReg(GU8 uchAgcReg, GU8 uchSlot); +void *GH3X2X_Memcpy(void *pDest, const void *pSrc, GU32 unByteSize); +void *GH3X2X_Memset(void* pDest, GCHAR chVal, GU32 unByteSize); +void GH3X2X_RecordAgcInfo(void); +void GH3X2X_UpdateAgcInfo(void); +/*********************************************** master-slaver interface lib function *********************************/ +#define GH3X2X_INFO_LOG(...) do {\ + char GH3X2X_AFE_GH3X2X_INFO_LOG[128] = {0};\ + snprintf(GH3X2X_AFE_GH3X2X_INFO_LOG, 128, __VA_ARGS__);\ + GH3X2X_AFE_Log((char *)GH3X2X_AFE_GH3X2X_INFO_LOG);\ + } while(0) + + + + +#endif + + + + + + + + + + + + + + + diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_ecg.h b/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_ecg.h new file mode 100644 index 000000000..50d3c8d4c --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_ecg.h @@ -0,0 +1,110 @@ +#ifndef __GH3X2X_AFE_ECG_H__ +#define __GH3X2X_AFE_ECG_H__ +#include "gh3x2x_afe_drv.h" + +/** + * @brief Downsample Function +*/ +typedef enum +{ + DOWNSAMPLE_ECG = 0, + DOWNSAMPLE_PPG, +}EmDownSampleFunction; + +/** + * @brief Downsample type +*/ +typedef enum +{ + DOWNSAMPLE_DEFAULT = 0, + DOWNSAMPLE_800HZ_TO_500HZ = 1, + DOWNSAMPLE_800HZ_TO_250HZ = 2, + DOWNSAMPLE_400HZ_TO_250HZ = 3, + DOWNSAMPLE_320HZ_TO_250HZ = 4, + DOWNSAMPLE_256HZ_TO_250HZ = 5, +}EmDownSampleType; + +typedef struct +{ + GS32 snRsXbuf[100/1 + 1]; + GS32 snBufHead; + GS32 snRsFirState; + GU32 nRsIcounter; + GU32 nRrsDcounter; + GU8 uchFlagFrPrev; + GU32 nRsLastRaw; + GU32 fDownStep; + GU8 uchLinearInterState; + GU8 uchLinearDataUpdate; +} STGh3x2xRsInfo; + + +typedef struct +{ + GS32 snCounter; + GS32 sniqCounter; + long long snniVal; + long long snnqVal; + GU8 uchFlagFrPrev; + GU8 uchFastRecoryHistory; + long long snniqAmp[5]; +} STGh3x2xSoftLeadOffDetInfo; + + +typedef struct +{ + GU8 uchRsFirOrder; + GU8 uchRsI; + GU8 uchRsD; + GU8 uchRsFirCoefNum; + GU8 uchRsBufSize; + GU8 uchRsEnable; + GU32 ufStep; + GS32* rsFirCoef; + GU8 uchDownSampleType; +} STGh3x2xDownSampleCalParamInfo; + +#define __SUPPORT_ECG_PPG_DOWNSAMP__ 0 + +/* ecg sample event type */ +#define ECG_SAMPLE_EVENT_TYPE_SAMPLE (0x01) /**< sample evt type sample config */ +#define ECG_SAMPLE_EVENT_TYPE_SLOT (0x02) /**< sample evt type slot config */ +#define ECG_SAMPLE_EVENT_TYPE_LEAD (0x04) /**< sample evt type lead irq */ +#define ECG_SAMPLE_EVENT_ALL (ECG_SAMPLE_EVENT_TYPE_SAMPLE | ECG_SAMPLE_EVENT_TYPE_SLOT | \ + ECG_SAMPLE_EVENT_TYPE_LEAD) /**< sample evt all */ + +#define GH3X2X_ECG_CTRL_REG_ADDR (0x01EA) +#define GH3X2X_ECG_FAST_RECV_EN_LSB (10) /**< ecg fast recv en lsb @GH3X2X_ECG_CTRL_REG */ +#define GH3X2X_ECG_FAST_RECV_EN_MSB (10) /**< ecg fast recv en msb @GH3X2X_ECG_CTRL_REG */ +/// ecg fast recover enable config +#define ECG_FAST_RECV_EN_CONFIG(en) do {\ + GH3X2X_AFE_WriteRegBitField(GH3X2X_ECG_CTRL_REG_ADDR, \ + GH3X2X_ECG_FAST_RECV_EN_LSB, GH3X2X_ECG_FAST_RECV_EN_MSB, (en)); \ + } while (0) + +#define GH3X2X_ADT_LEADON_CR_REG_ADDR (0x0400) +#define GH3X2X_ECG_LEAD_DET_EN_LSB (0) /**< ecg lead det en lsb @GH3X2X_ADT_LEADON_CR_REG */ +#define GH3X2X_ECG_LEAD_DET_EN_MSB (0) /**< ecg lead det en msb @GH3X2X_ADT_LEADON_CR_REG */ + + /// ecg lead detect enable config +#define ECG_LEAD_DET_EN_CONFIG(en) do {\ + GH3X2X_AFE_WriteRegBitField(GH3X2X_ADT_LEADON_CR_REG_ADDR, \ + GH3X2X_ECG_LEAD_DET_EN_LSB, GH3X2X_ECG_LEAD_DET_EN_MSB, (en)); \ + } while (0) + + +#define GET_ECG_LEAD_DET_EN_VAL() (GH3X2X_AFE_ReadRegBitField(GH3X2X_ADT_LEADON_CR_REG_ADDR, \ + GH3X2X_ECG_LEAD_DET_EN_LSB, GH3X2X_ECG_LEAD_DET_EN_MSB)) + + + +GU8 GH3X2X_AFE_EcgRsHandle(GU8* puchFifoBuffer, GU16* pusFifoBufferLen, GU8 uchEcgSlotNum, GU16 usEcgSampleRate); +GS32 GH3X2X_LeadOffDetectInit(void); +void GH3X2X_ECGResampleConfig(GU16 usEcgSampleRate); +void GH3X2X_PPGResampleConfig(GU16 usEcgSampleRate); +GU8 GH3X2X_LeadOffDetect(GU8* puchFifoBuffer, GU16* pusFifoBufferLen, GU8 uchEcgSlotNum); +void GH3X2X_AFE_Leadon_hook(void); +void GH3X2X_AFE_Leadoff_hook(void); +void GH3x2xSetEcgOutputFs(GU16 usEcgOutputFs); + +#endif diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_user.h b/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_user.h new file mode 100644 index 000000000..f22e31afd --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_user.h @@ -0,0 +1,57 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2025-01-13 10:11:20 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2025-01-17 15:57:59 + * @FilePath: /sdk615/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_user.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +#ifndef __GH3X2X_AFE_USER_H__ +#define __GH3X2X_AFE_USER_H__ +#include "gh3x2x_afe_drv.h" + + +#define GH3X2X_CHIP_ID GH3020_ID +#define GH3X2X_AFE_MP_MODE GH3X2X_MP_ENABLE + + +/****** communication type config **************************/ +#define GH3X2X_AFE_COM_INTERFACE_TYPE GH3X2X_AFE_COM_INTERFACE_I2C +#define GH3X2X_AFE_SPI_TYPE GH3X2X_AFE_SPI_SOFTWARE_CS + + +/****** I2C device id ***************************************/ +#define GH3X2X_AFE_I2C_DEVICE_CTRL_PIN_STATUS GH3X2X_PIN_STATUS_CS_0_MISO_0 + + + +/****** chip process type config ***************************/ +#define GH3X2X_AFE_PRO_TYPE GH3X2X_AFE_PRO_BY_INT + + + +/****** chip reset type config ***************************/ +#define GH3X2X_AFE_RESET_TYPE GH3X2X_AFE_RESET_SOFTWARE + + + + + + + + + +#endif + + + + + + + + + + + + + diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_version.h b/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_version.h new file mode 100644 index 000000000..a5b762085 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_version.h @@ -0,0 +1,45 @@ + +/** + * @copyright (c) 2003 - 2022, Goodix Co., Ltd. All rights reserved. + * + * @file gh3x2x_afe_version.h + * + * @brief gh3x2x afe driver version and change log + * + * @par history: + * @verbatim + * Date Version Notes + * 2021-11-04 v3.2.4.2 1.add calibration code + * 2021-11-05 v3.2.4.4 1.fix Efuse calibration bug + * 2021-11-05 v3.2.4.5 1.add Ffuse Crc Process + * 2.add Check Chip Id process + * + * 2021-11-05 v3.2.4.6 1.update Head file + * 2021-11-05 v3.2.4.7 1.add ecg lead off det lib + * 2021-11-05 v3.2.4.8 1.add 5Hz adt + * 2023-12-06 v3.2.4.9 1.update ecg and agc + * @endverbatim */ + +#ifndef _GH3X2X_AFE_VERSION_H_ +#define _GH3X2X_AFE_VERSION_H_ + + +#define GH3X2X_DRV_MAJOR_VERSION_NUMBER 3 /**< major version number */ +#define GH3X2X_DRV_MINOR_VERSION_NUMBER 2 /**< minor version number */ +#define GH3X2X_DRV_REVISION_VERSION_NUMBER 4 /**< revision version number */ +#define GH3X2X_DRV_FIXED_VERSION_NUMBER 9 /**< fixed version number */ + +#define GH3X2X_TO_STRING(x) #x /**< number to char */ +#define GH3X2X_STR(x) GH3X2X_TO_STRING(x) /**< number to char */ + +/// makeup version string +#define GH3X2X_VERSION_STRING "v" GH3X2X_STR(GH3X2X_DRV_MAJOR_VERSION_NUMBER)\ + "." GH3X2X_STR(GH3X2X_DRV_MINOR_VERSION_NUMBER)\ + "." GH3X2X_STR(GH3X2X_DRV_REVISION_VERSION_NUMBER)\ + "." GH3X2X_STR(GH3X2X_DRV_FIXED_VERSION_NUMBER)\ + " (build:"__DATE__"_"__TIME__")" + + +#endif /* _GH3X2X_AFE_VERSION_H_ */ + +/********END OF FILE********* Copyright (c) 2003 - 2022, Goodix Co., Ltd. ********/ diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_hal.h b/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_hal.h new file mode 100644 index 000000000..fce1cdf13 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_hal.h @@ -0,0 +1,34 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2024-06-07 11:18:26 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2025-01-13 14:09:50 + * @FilePath: /FD230/code/sdk/drivers/peripheral/ppg/hx3695/hx3695_hal.h + * @Description: + * + * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved. + */ +#ifndef GH_3X2X_HAL_H__ +#define GH_3X2X_HAL_H__ +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#include "stdint.h" + +typedef uint32_t PPG_CMD_TYPE_T ; + +void ppg_send_cmd_to_gh3x2x_driver(char* mode, uint8_t enable); + +uint32_t tyhx_poweron(void); +uint32_t tyhx_poweroff(void); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_adt.c b/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_adt.c new file mode 100644 index 000000000..561922b67 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_adt.c @@ -0,0 +1,156 @@ +/** + * @copyright (c) 2003 - 2022, Goodix Co., Ltd. All rights reserved. + * + * @file gh3x2x_afe_adt.c + * + * @brief gh3x2x led agc process functions + * + * @version + * + */ + + +#include +#include "gh3x2x_afe_adt.h" + +#define GH3X2X_MOVINF_AVA_WINDOW_SIZE 6 + + + +EMWearDetectType g_uchWearDetectStatus = WEAR_DETECT_WEAR_ON; + +GU32 g_punGh3x2xMovingAvaFilterBuf[GH3X2X_MOVINF_AVA_WINDOW_SIZE]; +GU8 g_uchGh3x2xMovingAvaFilterPointCnt; +GU8 g_Gh3x2xFilterHaveOutputFlag; + + + +void Gh3x2xMovingAvaFilterInit(void) +{ + g_uchGh3x2xMovingAvaFilterPointCnt = 0; + g_Gh3x2xFilterHaveOutputFlag = 0; +} +GU8 Gh3x2xMovingAvaFilter(GU32 *Rawdata, GU8 uchBypass) +{ + GU32 unSum = 0; + + if(uchBypass) + { + return 1; + } + else + { + if(g_uchGh3x2xMovingAvaFilterPointCnt >= GH3X2X_MOVINF_AVA_WINDOW_SIZE) + { + for(GU8 uchCnt = 1; uchCnt < GH3X2X_MOVINF_AVA_WINDOW_SIZE; uchCnt ++) + { + g_punGh3x2xMovingAvaFilterBuf[uchCnt - 1] = g_punGh3x2xMovingAvaFilterBuf[uchCnt]; + } + g_uchGh3x2xMovingAvaFilterPointCnt = GH3X2X_MOVINF_AVA_WINDOW_SIZE - 1; + } + g_punGh3x2xMovingAvaFilterBuf[g_uchGh3x2xMovingAvaFilterPointCnt] = Rawdata[0]; + g_uchGh3x2xMovingAvaFilterPointCnt ++; + + if(g_uchGh3x2xMovingAvaFilterPointCnt > 1) + { + for(GU8 uchCnt = 0; uchCnt < g_uchGh3x2xMovingAvaFilterPointCnt - 1; uchCnt ++) + { + unSum += g_punGh3x2xMovingAvaFilterBuf[uchCnt]; + } + Rawdata[0] = unSum/(g_uchGh3x2xMovingAvaFilterPointCnt - 1); + } + return 1; + } +} + + + + + + + + + +GS8 GH3x2xAdtAlgoInit(void) +{ + Gh3x2xMovingAvaFilterInit(); + g_uchWearDetectStatus = WEAR_DETECT_WEAR_ON; + return GH3X2X_AFE_RET_OK; +} +GS8 GH3x2xAdtAlgoDeinit(void) +{ + return GH3X2X_AFE_RET_OK; +} + +void GH3x2xAdtAlgoExe(GU32* punRawdata,EMWearStatus* pemWearStatus) +{ + + GU32 unCurrentFrameRawdata; + + GU32 unRawDataBeforeFilter; + unCurrentFrameRawdata = *punRawdata; + unRawDataBeforeFilter = *punRawdata; + GH3X2X_INFO_LOG("[GH3x2xAdtAlgoExe] punFrameRawdata = %d\r\n", unCurrentFrameRawdata); + + Gh3x2xMovingAvaFilter(&unCurrentFrameRawdata, 0); + GH3X2X_INFO_LOG("[GH3x2xAdtAlgoExe] punFrameRawdata after filter = %d\r\n", unCurrentFrameRawdata); + + + + GS32 snDiffRawdata; + + GH3X2X_INFO_LOG("[GH3x2xAdtAlgoExe] start check...\r\n"); + + snDiffRawdata = (GS32)unRawDataBeforeFilter - (GS32)unCurrentFrameRawdata; + + if(WEAR_DETECT_WEAR_ON == g_uchWearDetectStatus) + { + + *pemWearStatus = WEAR_STATUS_WEAR_OFF; + if((unRawDataBeforeFilter > __HARD_ADT_WAER_ON_THRD__)&&((snDiffRawdata > (GS32)__HARD_ADT_WAER_ON_DIFF_THRD__))) + { + *pemWearStatus = WEAR_STATUS_WEAR_ON; + g_uchWearDetectStatus = WEAR_DETECT_WEAR_OFF; + GH3X2X_INFO_LOG("[GH3x2xAdtAlgoExe] wear on !\r\n"); + } + else + { + if(unRawDataBeforeFilter > __HARD_ADT_WAER_ON_THRD__) + { + GH3X2X_INFO_LOG("[GH3x2xAdtAlgoExe] wear on condition is not match ! r = %d, r_diff = %d\r\n",unCurrentFrameRawdata,snDiffRawdata); + } + } + if(snDiffRawdata > 30000) + { + GH3X2X_INFO_LOG("[GH3x2xAdtAlgoExe]ppg 5Hz diff big event, Rawdata = %d, unRawdataDiff = %d\r\n",*punRawdata,snDiffRawdata); + } + } + else if(WEAR_DETECT_WEAR_OFF == g_uchWearDetectStatus) + { + *pemWearStatus = WEAR_STATUS_WEAR_ON; + if(unRawDataBeforeFilter < __HARD_ADT_WAER_OFF_THRD__) + { + *pemWearStatus = WEAR_STATUS_WEAR_OFF; + g_uchWearDetectStatus = WEAR_DETECT_WEAR_ON; + GH3X2X_INFO_LOG("[GH3x2xAdtAlgoExe]ppg 5Hz wear off event, Rawdata = %d, unRawdataDiff = %d\r\n",*punRawdata,snDiffRawdata); + GH3X2X_INFO_LOG("[GH3x2xAdtAlgoExe] wear off !\r\n"); + } + } +} + + + + + + + + + + + + + + + + + diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_agc.c b/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_agc.c new file mode 100644 index 000000000..7cfbe6d8e --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_agc.c @@ -0,0 +1,1131 @@ +/** + * @copyright (c) 2003 - 2022, Goodix Co., Ltd. All rights reserved. + * + * @file gh3x2x_afe_agc.c + * + * @brief gh3x2x led agc process functions + * + * @version + * + */ + + +#include +#include "gh3x2x_afe_agc.h" +#include "gh3x2x_afe_drv.h" + +#define __GH3X2X_AGC_GENERAL_TRIG_H_THD__ ((8388608 + 8388608*0.85f)) +#define __GH3X2X_AGC_GENERAL_TRIG_L_THD__ ((8388608 + 8388608*0.15f)) +#define __GH3X2X_AGC_GENERAL_IDEAL_VALUE__ ((8388608 + 8388608*0.56f)) +#define __GH3X2X_AGC_SPO2_TRIG_H_THD__ ((8388608 + 8388608*0.9f)) +#define __GH3X2X_AGC_SPO2_TRIG_L_THD__ ((8388608 + 8388608*0.5f)) +#define __GH3X2X_AGC_SPO2_IDEAL_VALUE__ ((8388608 + 8388608*0.7f)) +#define __GH3X2X_AGC_CONVERGENCE_LEVEL__ (16) // The values that can be set are 8, 16 and 32, and the recommended value is 16. The larger the value, the smaller the convergence range of AGC. + +//sub channel + +#define GH3X2X_NEW_AGC_SUB_CHNNL_ANAYLSIS_TIME_SEC 1 + +#define GH3X2X_AGC_REG_AGC_EN 0 +#define GH3X2X_AGC_REG_LED_CURRENT_UP_LIMIT 1 +#define GH3X2X_AGC_REG_LED_CURRENT_DOWN_LIMIT 2 +#define GH3X2X_AGC_REG_LED_CURRENT_DRV0 3 +#define GH3X2X_AGC_REG_LED_CURRENT_DRV1 4 +#define GH3X2X_AGC_REG_TIA_GAIN_RX0 5 +#define GH3X2X_AGC_REG_TIA_GAIN_RX1 6 +#define GH3X2X_AGC_REG_TIA_GAIN_RX2 7 +#define GH3X2X_AGC_REG_TIA_GAIN_RX3 8 +#define GH3X2X_AGC_REG_AGC_SRC 9 +#define GH3X2X_AGC_REG_BG_CANCEL_RX0 10 +#define GH3X2X_AGC_REG_BG_CANCEL_RX1 11 +#define GH3X2X_AGC_REG_BG_CANCEL_RX2 12 +#define GH3X2X_AGC_REG_BG_CANCEL_RX3 13 +#define GH3X2X_AGC_REG_SR_MULIPLIPER 14 +#define GH3X2X_AGC_ECG_PPG_RX_EN 15 + + +#if __SUPPORT_SOFT_AGC_CONFIG__ +//main chnl +STGh3x2xNewAgcMainChnlInfo g_pstGh3x2xNewAgcMainChnlInfoEntity[GH3X2X_NEW_AGC_SLOT_NUM_LIMIT]; +STGh3x2xNewAgcMainChnlMeanInfo g_pstGh3x2xNewAgcMainChnlMeanInfoEntity[GH3X2X_NEW_AGC_SLOT_NUM_LIMIT]; +STGh3x2xNewAgcMainChnlIdaelAdjInfo g_pstGh3x2xNewAgcMainChnlIdaelAdjInfoEntity[GH3X2X_NEW_AGC_SLOT_NUM_LIMIT]; +//sub chnl +#if GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT > 0 +STGh3x2xNewAgcSubChnlRxInfo g_pstGh3x2xNewAgcSubChnlRxInfoEntity[GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT]; +#endif + + +STGh3x2xNewAgcMainChnlSat g_pstGh3x2xNewAgcMainChnlSat; +const GU32 g_unNewAgcSpo2Trig_H_Thd = __GH3X2X_AGC_SPO2_TRIG_H_THD__; +const GU32 g_unNewAgcSpo2Trig_L_Thd = __GH3X2X_AGC_SPO2_TRIG_L_THD__; +const GU32 g_unNewAgcSpo2Ideal_value = __GH3X2X_AGC_SPO2_IDEAL_VALUE__; +const GU32 g_unNewAgcGeneTrig_H_Thd = __GH3X2X_AGC_GENERAL_TRIG_H_THD__; +const GU32 g_unNewAgcGeneTrig_L_Thd = __GH3X2X_AGC_GENERAL_TRIG_L_THD__; +const GU32 g_unNewAgcGeneIdeal_value = __GH3X2X_AGC_GENERAL_IDEAL_VALUE__; +const GU8 g_uchAgcConvergence_level = __GH3X2X_AGC_CONVERGENCE_LEVEL__; + + +// soft agc parameter +static STSoftAgcCfg g_stSoftAgcCfg; +extern const GU16 g_usGH3x2xTiaGainR[]; + +GU8 g_Gh3x2xNewAgcInitFlag = 0; + +void GH3X2X_LedAgcPramConfig(STSoftAgcCfg* stSoftAgcCfg) +{ + g_stSoftAgcCfg.uchSlotxSoftAgcAdjEn = stSoftAgcCfg->uchSlotxSoftAgcAdjEn; //bit0: slot0 + g_stSoftAgcCfg.uchSlotxSoftBgAdjEn = stSoftAgcCfg->uchSlotxSoftBgAdjEn; + g_stSoftAgcCfg.stAmbSlotCtrl.uchAmbSampleEn = stSoftAgcCfg->stAmbSlotCtrl.uchAmbSampleEn; + g_stSoftAgcCfg.uchSpo2RedSlotCfgEn = stSoftAgcCfg->uchSpo2RedSlotCfgEn; + g_stSoftAgcCfg.uchSpo2IrSlotCfgEn = stSoftAgcCfg->uchSpo2IrSlotCfgEn; + g_stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg32uA = stSoftAgcCfg->stSoftAgcGainLimit.uchGainLimitBg32uA; + g_stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg64uA = stSoftAgcCfg->stSoftAgcGainLimit.uchGainLimitBg64uA; + g_stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg128uA = stSoftAgcCfg->stSoftAgcGainLimit.uchGainLimitBg128uA; + g_stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg256uA = stSoftAgcCfg->stSoftAgcGainLimit.uchGainLimitBg256uA; + g_stSoftAgcCfg.unAgcTrigThd_H = stSoftAgcCfg->unAgcTrigThd_H; + g_stSoftAgcCfg.unAgcTrigThd_L = stSoftAgcCfg->unAgcTrigThd_L; + g_stSoftAgcCfg.unAgcRestrainThd_H = stSoftAgcCfg->unAgcRestrainThd_H; + g_stSoftAgcCfg.unAgcRestrainThd_L = stSoftAgcCfg->unAgcRestrainThd_L; + + GH3X2X_INFO_LOG("uchSlotxSoftAgcAdjEn = 0x%X, uchSlotxSoftBgAdjEn = 0x%X\r\n",(int)g_stSoftAgcCfg.uchSlotxSoftAgcAdjEn,(int)g_stSoftAgcCfg.uchSlotxSoftBgAdjEn); + GH3X2X_INFO_LOG("uchAmbSampleEn = 0x%X, uchAmbSlot = 0x%X\r\n",(int)g_stSoftAgcCfg.stAmbSlotCtrl.uchAmbSampleEn,(int)g_stSoftAgcCfg.stAmbSlotCtrl.uchAmbSlot); + GH3X2X_INFO_LOG("uchSpo2RedSlotCfgEn = 0x%X,uchSpo2IrSlotCfgEn = 0x%X\r\n",(int)g_stSoftAgcCfg.uchSpo2RedSlotCfgEn,(int)g_stSoftAgcCfg.uchSpo2IrSlotCfgEn); + GH3X2X_INFO_LOG("stSoftAgcGainLimit = 0x%X,0x%X,0x%X,0x%X\r\n",g_stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg32uA,g_stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg64uA,g_stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg128uA,g_stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg256uA); + GH3X2X_INFO_LOG("unAgcTrigThd_H = %d,unAgcTrigThd_L = %d\r\n",(int)g_stSoftAgcCfg.unAgcTrigThd_H,(int)g_stSoftAgcCfg.unAgcTrigThd_L); + GH3X2X_INFO_LOG("unAgcRestrainThd_H = %d,unAgcRestrainThd_L = %d\r\n",(int)g_stSoftAgcCfg.unAgcRestrainThd_H,(int)g_stSoftAgcCfg.unAgcRestrainThd_L); + +} + +void GH3X2X_StoreRxTiaGainAfterAgc(GU8 uchGain, GU8 uchSlotNo, GU8 uchAdcNo, GU8* puchGainRecord) +{ + puchGainRecord[uchSlotNo*4 + uchAdcNo] = uchGain; +} + +void GH3X2X_StoreDrvCurrentAfterAgc(GU8 DrvCurrent, GU8 uchSlotNo, GU8 uchDrvIndex, GU16* puchDrvCurrentRecord) +{ + if(!uchDrvIndex) + { + puchDrvCurrentRecord[uchSlotNo] = (puchDrvCurrentRecord[uchSlotNo]&0xFF00)|DrvCurrent; + } + else + { + puchDrvCurrentRecord[uchSlotNo] = (puchDrvCurrentRecord[uchSlotNo]&0x00FF)|(DrvCurrent<<8); + } +} + + +void GH3x2xNewAgcModuleReset(void) +{ + g_Gh3x2xNewAgcInitFlag = 0; + GH3X2X_Memset((GU8*)g_pstGh3x2xNewAgcMainChnlInfoEntity,0,(GU16)GH3X2X_NEW_AGC_SLOT_NUM_LIMIT*sizeof(STGh3x2xNewAgcMainChnlInfo)); + GH3X2X_Memset( (GU8*)(&g_pstGh3x2xNewAgcMainChnlSat),0,sizeof(STGh3x2xNewAgcMainChnlSat)); // init variable + GH3X2X_Memset((GU8*)g_pstGh3x2xNewAgcMainChnlMeanInfoEntity,0,(GU16)GH3X2X_NEW_AGC_SLOT_NUM_LIMIT*sizeof(STGh3x2xNewAgcMainChnlMeanInfo)); + GH3X2X_Memset((GU8*)g_pstGh3x2xNewAgcMainChnlIdaelAdjInfoEntity,0,(GU16)GH3X2X_NEW_AGC_SLOT_NUM_LIMIT*sizeof(STGh3x2xNewAgcMainChnlIdaelAdjInfo)); + + #if GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT > 0 + Gh3x2xNewAgcSubChnlModuleReset(); + #endif +} + +void GH3X2X_NewAgcRecoveryAgcRegToMainChnl(GU8 uchSlotIdx, STGh3x2xNewAgcMainChnlInfo *pstAgcMainChnlInfo) +{ + GH3x2x_AFESetAgcReg(GH3X2X_AGC_REG_LED_CURRENT_UP_LIMIT, uchSlotIdx, pstAgcMainChnlInfo ->uchBakRegLedCurrentMax); + GH3x2x_AFESetAgcReg(GH3X2X_AGC_REG_LED_CURRENT_DOWN_LIMIT, uchSlotIdx, pstAgcMainChnlInfo ->uchBakRegLedCurrentMin); + GH3x2x_AFESetAgcReg(GH3X2X_AGC_REG_AGC_SRC, uchSlotIdx, pstAgcMainChnlInfo ->uchBakRegAgcSrc); + GH3X2X_INFO_LOG("[NewAgc] recover agc src:agc_src = %d, SlotNo = %d\r\n",pstAgcMainChnlInfo ->uchBakRegAgcSrc,uchSlotIdx); +} + +GU8 GH3X2X_NewAgcFindSubChnlSlotInfo(GU8 uchSlot) +{ + for(GU8 uchSlotCnt = 0; uchSlotCnt < GH3X2X_NEW_AGC_SLOT_NUM_LIMIT; uchSlotCnt ++) + { + STGh3x2xNewAgcMainChnlInfo *pstAgcMainChnlInfo = &g_pstGh3x2xNewAgcMainChnlInfoEntity[uchSlotCnt]; + if(pstAgcMainChnlInfo ->uchEnable) + { + if(uchSlot == (pstAgcMainChnlInfo ->uchSlotAdc >> 2)) + { + return uchSlotCnt; + } + } + } + return 0; +} + +GU16 GH3x2xCalTrigerUpLimitForBiggerGain(GU8 uchCurrentGain ,GU8 uchSlotNo) +{ + GU32 unTempRawdata; + GU32 unTempTrigThd_H; + + GU8 uchSlotCnt = GH3X2X_NewAgcFindSubChnlSlotInfo(uchSlotNo); + STGh3x2xNewAgcMainChnlInfo *pstAgcMainChnlInfo = &g_pstGh3x2xNewAgcMainChnlInfoEntity[uchSlotCnt]; + if(pstAgcMainChnlInfo->uchSpo2ChnlIndex) + { + unTempTrigThd_H = g_unNewAgcSpo2Trig_H_Thd; + }else + { + unTempTrigThd_H = g_unNewAgcGeneTrig_H_Thd; + } + + if(12 <= uchCurrentGain) + { + return 0xFFFF; + } + else + { + unTempRawdata = unTempTrigThd_H - 8388608; + unTempRawdata = 8388608 + (GU32)(((float)unTempRawdata)/(float)1.3*(float)g_usGH3x2xTiaGainR[uchCurrentGain]/(float)g_usGH3x2xTiaGainR[uchCurrentGain + 1]); + return unTempRawdata>>8; + } +} + + +#if GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT > 0 +void GH3x2xNewAgcSubChnlClearAnalysisCntAndSetGain(GU8 uchSlotNo, GU8 uchRxEn ,GU8 uchNextGain) +{ + for(GU8 uchRxCnt = 0; uchRxCnt < 4; uchRxCnt ++) + { + if(uchRxEn&(1 << uchRxCnt)) + { + for(GU8 uchChnlCnt = 0; uchChnlCnt < GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT; uchChnlCnt ++) + { + STGh3x2xNewAgcSubChnlRxInfo *pstSTGh3x2xNewAgcSubChnlRxInfo = &(g_pstGh3x2xNewAgcSubChnlRxInfoEntity[uchChnlCnt]); + if(pstSTGh3x2xNewAgcSubChnlRxInfo->uchEn) + { + if(((uchSlotNo << 2) + uchRxCnt) == pstSTGh3x2xNewAgcSubChnlRxInfo ->uchSlotAdcNo) + { + pstSTGh3x2xNewAgcSubChnlRxInfo ->usAnalysisCnt = 0; + if(0xFF != uchNextGain) + { + GH3x2x_AFESetAgcReg(GH3X2X_AGC_REG_TIA_GAIN_RX0 + uchRxCnt, uchSlotNo, 0); + pstSTGh3x2xNewAgcSubChnlRxInfo ->uchCurrentGain = uchNextGain; + pstSTGh3x2xNewAgcSubChnlRxInfo ->usTrigeUpLimitForBiggerGain = GH3x2xCalTrigerUpLimitForBiggerGain(uchNextGain,pstSTGh3x2xNewAgcSubChnlRxInfo->uchSlotAdcNo >> 2); + } + } + } + } + } + } +} +#endif + + +void GH3x2xNewAgcMeanInfoReset(GU8 uchSlotEnChange) +{ + for(GU8 uchSlotCnt = 0; uchSlotCnt < 8; uchSlotCnt++) + { + if( uchSlotEnChange & (1<> 2) & 0x0f); + GU8 uchEnable = g_pstGh3x2xNewAgcMainChnlInfoEntity[uchAgcSlotCnt].uchEnable; + if( uchEnable ) + { + if( uchSlotIdx == uchSlotCnt) + { + g_pstGh3x2xNewAgcMainChnlMeanInfoEntity[uchAgcSlotCnt].usAnalysisCnt = 0; + #if GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT > 0 + GH3x2xNewAgcSubChnlClearAnalysisCntAndSetGain(uchSlotIdx, 0x0F, 0xFF); //clear all rx analysis cnt in this slot + #endif + } + } + } + } + } +} + +GU8 GH3x2xGetDrvCurrent(GU8 uchSlotIdx ,GU8 uchAgcEn) +{ + GU8 uchTempDrv; + if(2 == uchAgcEn) + { + uchTempDrv = GH3x2x_AFEGetAgcReg(GH3X2X_AGC_REG_LED_CURRENT_DRV1, uchSlotIdx); + } + else + { + uchTempDrv = GH3x2x_AFEGetAgcReg(GH3X2X_AGC_REG_LED_CURRENT_DRV0, uchSlotIdx); + } + return uchTempDrv; +} + +void GH3x2xNewAgcChnlInfoInit(STGh3x2xAgcInfo *STGh3x2xAgcInfo) +{ + if(0 == GH3X2X_NEW_AGC_SLOT_NUM_LIMIT) + { + return; + } + if(0 == g_Gh3x2xNewAgcInitFlag) + { + GU8 uchNewAgcSlotCnt = 0; + for(GU8 uchSlotCnt = 0; uchSlotCnt < 8; uchSlotCnt ++) + { + if((g_stSoftAgcCfg.uchSlotxSoftAgcAdjEn & (1 << uchSlotCnt))) + { + if(uchNewAgcSlotCnt < GH3X2X_NEW_AGC_SLOT_NUM_LIMIT) + { + g_pstGh3x2xNewAgcMainChnlInfoEntity[uchNewAgcSlotCnt].uchEnable = 1; + g_pstGh3x2xNewAgcMainChnlInfoEntity[uchNewAgcSlotCnt].uchSlotAdc = (uchSlotCnt << 2); + + /******* slot function Distinguish START******************************************************/ + if((g_stSoftAgcCfg.uchSpo2RedSlotCfgEn & (1 << uchSlotCnt))||(g_stSoftAgcCfg.uchSpo2IrSlotCfgEn & (1 << uchSlotCnt))) + { + g_pstGh3x2xNewAgcMainChnlInfoEntity[uchNewAgcSlotCnt].uchSpo2ChnlIndex = 1; + GH3X2X_INFO_LOG("[NewAgc] uchNewAgcSpo2SlotCnt = %d\r\n",uchNewAgcSlotCnt); + } + /******* slot function Distinguish END******************************************************/ + GH3X2X_INFO_LOG("[NewAgc] uchNewAgcSlotCnt = %d\r\n",uchNewAgcSlotCnt); + uchNewAgcSlotCnt ++; + } + else + { + GH3X2X_INFO_LOG("[NewAgc] error !!! main chnl info is no enough! \r\n"); + while(1); + } + } + } + g_Gh3x2xNewAgcInitFlag = 1; + } + + for(GU8 uchSlotCnt = 0; uchSlotCnt < GH3X2X_NEW_AGC_SLOT_NUM_LIMIT; uchSlotCnt ++) + { + STGh3x2xNewAgcMainChnlInfo *pstAgcMainChnlInfo = &g_pstGh3x2xNewAgcMainChnlInfoEntity[uchSlotCnt]; + //GH3X2X_INFO_LOG_PARAM("AGC_InitValue %d: Enable = %d, AgcAdjEn = %d\r\n",uchSlotCnt, pstAgcMainChnlInfo->uchEnable,g_stSoftAgcCfg.uchSlotxSoftAgcAdjEn); + if(pstAgcMainChnlInfo->uchEnable) + { + GU8 uchSlotIdx; + uchSlotIdx = pstAgcMainChnlInfo ->uchSlotAdc >> 2; + //GH3X2X_INFO_LOG_PARAM("AGC_InitFlag%d: SlotCfgX=%d, Vaule = %d\r\n",uchSlotCnt, uchSlotIdx, pstAgcMainChnlInfo->uchHaveBakRegFlag); + if(0 == pstAgcMainChnlInfo ->uchHaveBakRegFlag) + { + GU8 uchBgCancel; + GU8 uchGainLimit; + GU16 usSampleRate; + GU16 usEcgPpgRxEn; + + //bak reg + pstAgcMainChnlInfo ->uchBakRegAgcEn = GH3x2x_AFEGetAgcReg(GH3X2X_AGC_REG_AGC_EN, uchSlotIdx); + pstAgcMainChnlInfo ->uchBakRegAgcSrc = GH3x2x_AFEGetAgcReg(GH3X2X_AGC_REG_AGC_SRC, uchSlotIdx); + pstAgcMainChnlInfo ->uchSlotAdc = (uchSlotIdx << 2) + pstAgcMainChnlInfo ->uchBakRegAgcSrc; + pstAgcMainChnlInfo ->uchBakRegLedCurrentMax = GH3x2x_AFEGetAgcReg(GH3X2X_AGC_REG_LED_CURRENT_UP_LIMIT, uchSlotIdx); + pstAgcMainChnlInfo ->uchBakRegLedCurrentMin = GH3x2x_AFEGetAgcReg(GH3X2X_AGC_REG_LED_CURRENT_DOWN_LIMIT, uchSlotIdx); + pstAgcMainChnlInfo ->uchBakTiaGain = GH3x2x_AFEGetAgcReg(GH3X2X_AGC_REG_TIA_GAIN_RX0 + pstAgcMainChnlInfo ->uchBakRegAgcSrc, uchSlotIdx); + pstAgcMainChnlInfo ->uchCurrentTiaGain = pstAgcMainChnlInfo ->uchBakTiaGain; + pstAgcMainChnlInfo ->uchCurrentDrv = GH3x2xGetDrvCurrent(uchSlotIdx, pstAgcMainChnlInfo->uchBakRegAgcEn); + //GH3X2X_StoreDrvCurrentAfterAgc(pstAgcMainChnlInfo ->uchCurrentDrv, uchSlotIdx,g_pstGh3x2xAgcInfo->uchDrvCurrentAfterSoftAgc); + uchBgCancel = GH3x2x_AFEGetAgcReg(GH3X2X_AGC_REG_BG_CANCEL_RX0 + pstAgcMainChnlInfo ->uchBakRegAgcSrc, uchSlotIdx); + GH3X2X_StoreRxTiaGainAfterAgc(pstAgcMainChnlInfo->uchBakTiaGain, uchSlotIdx, pstAgcMainChnlInfo->uchBakRegAgcSrc, STGh3x2xAgcInfo->uchTiaGainAfterSoftAgc); + if(0 == uchBgCancel) + { + uchGainLimit = g_stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg32uA; + } + else if(1 == uchBgCancel) + { + uchGainLimit = g_stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg64uA; + } + else if(2 == uchBgCancel) + { + uchGainLimit = g_stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg128uA; + } + else + { + uchGainLimit = g_stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg256uA; + } + GH3X2X_INFO_LOG("[NewAgc] uchGainLimit = %d, uchSlotIdx = %d\r\n",uchGainLimit, uchSlotIdx); + pstAgcMainChnlInfo ->uchTiaGainUpLimit = uchGainLimit; + usSampleRate = 1000/(GH3x2x_AFEGetAgcReg(GH3X2X_AGC_REG_SR_MULIPLIPER, uchSlotIdx) + 1); + usEcgPpgRxEn = GH3x2x_AFEGetAgcReg(GH3X2X_AGC_ECG_PPG_RX_EN, uchSlotIdx); + GH3X2X_INFO_LOG("[NewAgc] usEcgPpgRxEn = 0x%X\r\n",usEcgPpgRxEn); + if(usEcgPpgRxEn&0x0001) // ecg is enable + { + usEcgPpgRxEn = ((usEcgPpgRxEn>>1) & (~0x0008)); //clear RX3 enable bit + } + else + { + usEcgPpgRxEn = (usEcgPpgRxEn>>1); + } + usEcgPpgRxEn &= (~(1 << pstAgcMainChnlInfo ->uchBakRegAgcSrc)); //clear main channel RX enable bit + + g_pstGh3x2xNewAgcMainChnlMeanInfoEntity[uchSlotCnt].usSampleRate = usSampleRate; //init + GH3X2X_INFO_LOG("[AgcInit] SlotCnt = %d, SampleRate = %d\r\n", uchSlotCnt, usSampleRate); + //sub channel slot +#if GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT > 0 + GH3x2xNewAgcSetNewSubChnl(uchSlotIdx,usEcgPpgRxEn,STGh3x2xAgcInfo); +#endif + pstAgcMainChnlInfo ->uchHaveBakRegFlag = 1; + GH3x2x_AFESetAgcReg(GH3X2X_AGC_REG_AGC_EN, uchSlotIdx, 0); // disable hardware agc + } + else + { + pstAgcMainChnlInfo ->uchCurrentTiaGain = GH3x2x_AFEGetAgcReg(GH3X2X_AGC_REG_TIA_GAIN_RX0 + pstAgcMainChnlInfo ->uchBakRegAgcSrc, uchSlotIdx); + pstAgcMainChnlInfo ->uchCurrentDrv = GH3x2xGetDrvCurrent(uchSlotIdx, pstAgcMainChnlInfo->uchBakRegAgcEn); + //GH3X2X_INFO_LOG_PARAM("Drv Gian inite read %d: IniteDrv = %d, IniteGain = %d\r\n",uchSlotIdx, pstAgcMainChnlInfo ->uchCurrentDrv, pstAgcMainChnlInfo ->uchCurrentTiaGain); + ////get initial DRV and current in case them change before StartSampling() +// GH3X2X_NewAgcRecoveryAgcRegToMainChnl(uchSlotIdx,pstAgcMainChnlInfo); + } + } + } +} + + +GU32 GH32x2xMedSel(GU32 unData0, GU32 unData1, GU32 unData2) +{ + if((unData0 >= unData1)&&(unData0 <= unData2)) + { + return unData0; + } + if((unData0 >= unData2)&&(unData0 <= unData1)) + { + return unData0; + } + if((unData1 >= unData0)&&(unData1 <= unData2)) + { + return unData1; + } + if((unData1 >= unData2)&&(unData1 <= unData0)) + { + return unData1; + } + return unData2; +} + +float GH3X2X_CalcfRelativeVpp(GU32 unRawdata, GU8 uchDrv, GU8 uchGain) +{ + return ((float)unRawdata/(float)uchDrv/(float)g_usGH3x2xTiaGainR[uchGain]); +} + +void GH3X2X_StoreTiaGainAfterAgc(GU16 usGainRegValue, GU8 uchSlotNo, GU8* puchGainRecord) +{ + for(GU8 uchAdcCnt = 0; uchAdcCnt < 4; uchAdcCnt ++) + { + puchGainRecord[uchSlotNo*4 + uchAdcCnt] = (usGainRegValue>>(uchAdcCnt*4))&0x000F; + GH3X2X_INFO_LOG("StoreTiaGainAfterAgc slot no = %d, adc no = %d, usGainRegValue = %d\r\n", uchSlotNo,uchAdcCnt,usGainRegValue); + } +} + +void GH3X_AgcGetThreshold( GU8 uchSpo2ChnlIndex, GU32* punTemp_H_Thd, GU32* punTemp_L_Thd ) +{ + if(uchSpo2ChnlIndex) // is spo2 slot + { + *punTemp_H_Thd = g_unNewAgcSpo2Trig_H_Thd; + *punTemp_L_Thd = g_unNewAgcSpo2Trig_L_Thd; + }else + { + *punTemp_H_Thd = g_unNewAgcGeneTrig_H_Thd; + *punTemp_L_Thd = g_unNewAgcGeneTrig_L_Thd; + } +} + +#if GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT > 0 +void Gh3x2xNewAgcSubChnlModuleReset(void) +{ + #if GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT > 0 + GH3X2X_Memset((GU8*)g_pstGh3x2xNewAgcSubChnlRxInfoEntity,0,(GU16)GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT*sizeof(STGh3x2xNewAgcSubChnlRxInfo)); + #endif +} + +GU8 GH3x2xNewAgcSetNewSubChnl(GU8 uchSlotNo, GU8 uchRxEn, STGh3x2xAgcInfo *STGh3x2xAgcInfo) +{ + GU8 uchSetSuccess = 1; + for(GU8 uchRxCnt = 0; uchRxCnt < 4; uchRxCnt ++) + { + if(uchRxEn&(1 << uchRxCnt)) + { + uchSetSuccess = 0; + for(GU8 uchChnlCnt = 0; uchChnlCnt < GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT; uchChnlCnt ++) + { + STGh3x2xNewAgcSubChnlRxInfo *pstSTGh3x2xNewAgcSubChnlRxInfo = &(g_pstGh3x2xNewAgcSubChnlRxInfoEntity[uchChnlCnt]); + if(0 == pstSTGh3x2xNewAgcSubChnlRxInfo->uchEn) + { + pstSTGh3x2xNewAgcSubChnlRxInfo->uchEn = 1; + pstSTGh3x2xNewAgcSubChnlRxInfo->uchSlotAdcNo = (uchSlotNo << 2) + uchRxCnt; + //read current gain + pstSTGh3x2xNewAgcSubChnlRxInfo ->uchCurrentGain = GH3x2x_AFEGetAgcReg(GH3X2X_AGC_REG_TIA_GAIN_RX0 + uchRxCnt, uchSlotNo); + GH3X2X_INFO_LOG("[NewAgc] Sub chnl current Gain = %d, Slot = %d, Rx = %d\r\n",pstSTGh3x2xNewAgcSubChnlRxInfo ->uchCurrentGain,uchSlotNo,uchRxCnt); + pstSTGh3x2xNewAgcSubChnlRxInfo ->usTrigeUpLimitForBiggerGain = GH3x2xCalTrigerUpLimitForBiggerGain(pstSTGh3x2xNewAgcSubChnlRxInfo ->uchCurrentGain, uchSlotNo); + GH3X2X_INFO_LOG("[NewAgc] usTrigeUpLimitForBiggerGain = %d, Slot = %d, Rx = %d\r\n",((GU32)pstSTGh3x2xNewAgcSubChnlRxInfo ->usTrigeUpLimitForBiggerGain)<<8,uchSlotNo,uchRxCnt); + GH3X2X_StoreRxTiaGainAfterAgc(pstSTGh3x2xNewAgcSubChnlRxInfo ->uchCurrentGain, uchSlotNo, uchRxCnt, STGh3x2xAgcInfo->uchTiaGainAfterSoftAgc); + uchSetSuccess = 1; + break; + } + } + if(0 == uchSetSuccess) + { + GH3X2X_INFO_LOG("[NewAgc] Set new sub chnl fail !!! Slot = %d, Rx = %d\r\n",uchSlotNo,uchRxCnt); + while(1); + } + } + } + return uchSetSuccess; +} +#endif + +#if GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT > 0 +void GH3X2X_NewAgcSubChnlGainAdj(GU8* puchReadFifoBuffer, GU16 usFifoLen, STGh3x2xAgcInfo *STGh3x2xAgcInfo) +{ + for(GU8 uchChnlCnt = 0; uchChnlCnt < GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT; uchChnlCnt ++) + { + GU16 usAnalysisDiscardLen; + GU16 usAnalysisEndLen; + GU8 uchSlotCnt; + GU8 uchSlotIdx; + GU8 uchAdcNo; + GU32 unTempTrigThd_L; + GU32 unTempTrigThd_H; + STGh3x2xNewAgcSubChnlRxInfo *pstSTGh3x2xNewAgcSubChnlRxInfo = &(g_pstGh3x2xNewAgcSubChnlRxInfoEntity[uchChnlCnt]); + uchSlotIdx = pstSTGh3x2xNewAgcSubChnlRxInfo ->uchSlotAdcNo >> 2; + uchAdcNo = pstSTGh3x2xNewAgcSubChnlRxInfo ->uchSlotAdcNo&0x03; + uchSlotCnt = GH3X2X_NewAgcFindSubChnlSlotInfo(uchSlotIdx); + GU16 usSampleRate = g_pstGh3x2xNewAgcMainChnlMeanInfoEntity[uchSlotCnt].usSampleRate; + GU8 uchTiaGainLimit = g_pstGh3x2xNewAgcMainChnlInfoEntity[uchSlotCnt].uchTiaGainUpLimit; + usAnalysisDiscardLen = (usSampleRate<<1)/5; // 2/5 Fs + usAnalysisEndLen = usAnalysisDiscardLen + usSampleRate * GH3X2X_NEW_AGC_SUB_CHNNL_ANAYLSIS_TIME_SEC; + + GH3X_AgcGetThreshold(g_pstGh3x2xNewAgcMainChnlInfoEntity[uchSlotCnt].uchSpo2ChnlIndex,&unTempTrigThd_H, &unTempTrigThd_L); + + if(pstSTGh3x2xNewAgcSubChnlRxInfo ->uchEn) + { + // prevent unRawdataSum(GU32) overflow + if( (usAnalysisEndLen - usAnalysisDiscardLen) > 200 ) + { + usAnalysisDiscardLen = usAnalysisEndLen - 200; // maximum number of accumulated rawdata is 200 + } + + for (GU16 usIndex = 0; usIndex < usFifoLen; usIndex += GH3X2X_AFE_FIFO_RAWDATA_SIZE) + { + GU32 unFifoVal; + GU8 uchSlotAdcNo; + GU32 unDataRaw; + unFifoVal = GH3X2X_AFE_MAKEUP_DWORD(puchReadFifoBuffer[usIndex], puchReadFifoBuffer[usIndex + 1], + puchReadFifoBuffer[usIndex + 2], puchReadFifoBuffer[usIndex + 3]); + uchSlotAdcNo = ((unFifoVal >> 27)&0x0000001F); + unDataRaw = GH3X2X_RAWDATA_CLEAR_ALL_FLAG(unFifoVal); + if(uchSlotAdcNo == pstSTGh3x2xNewAgcSubChnlRxInfo ->uchSlotAdcNo) + { + if(usAnalysisDiscardLen == pstSTGh3x2xNewAgcSubChnlRxInfo->usAnalysisCnt) //init + { + pstSTGh3x2xNewAgcSubChnlRxInfo ->unRawdataSum = 0; + pstSTGh3x2xNewAgcSubChnlRxInfo ->unLastLastRawdata = unDataRaw; + pstSTGh3x2xNewAgcSubChnlRxInfo ->unLastRawdata = unDataRaw; + pstSTGh3x2xNewAgcSubChnlRxInfo ->usMoreThanUpLimitPointCnt = 0; + pstSTGh3x2xNewAgcSubChnlRxInfo ->usMoreThanUpLimitPointCntForBiggerGain = 0; + } + if(pstSTGh3x2xNewAgcSubChnlRxInfo->usAnalysisCnt < usAnalysisEndLen) //analysising + { + GU32 unTempRawdata = GH32x2xMedSel(pstSTGh3x2xNewAgcSubChnlRxInfo ->unLastLastRawdata, pstSTGh3x2xNewAgcSubChnlRxInfo ->unLastRawdata, unDataRaw); + if(usAnalysisDiscardLen == pstSTGh3x2xNewAgcSubChnlRxInfo->usAnalysisCnt) + { + GH3X2X_INFO_LOG("[NewAgc] sub chnl unTempRawdata = %d, Slot = %d, rx = %d\r\n",unTempRawdata, uchSlotIdx, uchAdcNo); + } + pstSTGh3x2xNewAgcSubChnlRxInfo ->unRawdataSum += unTempRawdata; + if(unTempRawdata > unTempTrigThd_H) + { + pstSTGh3x2xNewAgcSubChnlRxInfo->usMoreThanUpLimitPointCnt ++; + } + if((unTempRawdata >> 8) > pstSTGh3x2xNewAgcSubChnlRxInfo->usTrigeUpLimitForBiggerGain) + { + pstSTGh3x2xNewAgcSubChnlRxInfo->usMoreThanUpLimitPointCntForBiggerGain ++; + } + pstSTGh3x2xNewAgcSubChnlRxInfo ->unLastLastRawdata = pstSTGh3x2xNewAgcSubChnlRxInfo ->unLastRawdata; + pstSTGh3x2xNewAgcSubChnlRxInfo ->unLastRawdata = unDataRaw; + pstSTGh3x2xNewAgcSubChnlRxInfo->usAnalysisCnt ++; + } + else //anlysis finished + { + GU32 unAvaRawdata; + GU16 unRealAnaylsisNum = usAnalysisEndLen - usAnalysisDiscardLen; + GU8 uchNextGain = 0xFF; + GU8 uchCurrentGain = pstSTGh3x2xNewAgcSubChnlRxInfo ->uchCurrentGain; + unAvaRawdata = pstSTGh3x2xNewAgcSubChnlRxInfo ->unRawdataSum/unRealAnaylsisNum; + GH3X2X_INFO_LOG("[NewAgc] sub chnl rawdata ava = %d,DownLimit = %d, Slot = %d, rx = %d\r\n",unAvaRawdata, unTempTrigThd_L,uchSlotIdx, uchAdcNo); + GH3X2X_INFO_LOG("[NewAgc] usMoreThanUpLimitPointCnt = %d,UpLimit = %d, Slot = %d, rx = %d\r\n",pstSTGh3x2xNewAgcSubChnlRxInfo ->usMoreThanUpLimitPointCnt, unTempTrigThd_H,uchSlotIdx, uchAdcNo); + GH3X2X_INFO_LOG("[NewAgc] usMoreThanUpLimitPointCntForBiggerGain = %d,UpLimit = %d, Slot = %d, rx = %d\r\n",pstSTGh3x2xNewAgcSubChnlRxInfo ->usMoreThanUpLimitPointCntForBiggerGain, ((GU32)pstSTGh3x2xNewAgcSubChnlRxInfo->usTrigeUpLimitForBiggerGain)<<8, uchSlotIdx, uchAdcNo); + if(pstSTGh3x2xNewAgcSubChnlRxInfo ->usMoreThanUpLimitPointCnt > (unRealAnaylsisNum >> 3)) // 1/8 points is bigger than trige up limit + { + if(uchCurrentGain > 0) + { + uchNextGain = uchCurrentGain - 1; + } + } + if((pstSTGh3x2xNewAgcSubChnlRxInfo ->usMoreThanUpLimitPointCntForBiggerGain < (unRealAnaylsisNum >> 3))&&(unAvaRawdata < unTempTrigThd_L)) + { + if(uchCurrentGain < uchTiaGainLimit) + { + uchNextGain = uchCurrentGain + 1; + } + } + if(0xFF != uchNextGain) + { + GH3X2X_INFO_LOG("[NewAgc] sub chnl gain change: NewGain = %d, OldGain = %d, Slot = %d, rx = %d\r\n",uchNextGain,uchCurrentGain, uchSlotIdx, uchAdcNo); + GH3x2x_AFESetAgcReg(GH3X2X_AGC_REG_TIA_GAIN_RX0 + uchAdcNo, uchSlotIdx, uchNextGain); + pstSTGh3x2xNewAgcSubChnlRxInfo ->uchCurrentGain = uchNextGain; + pstSTGh3x2xNewAgcSubChnlRxInfo ->usTrigeUpLimitForBiggerGain = GH3x2xCalTrigerUpLimitForBiggerGain(uchNextGain, uchSlotIdx); + GH3X2X_StoreRxTiaGainAfterAgc(uchNextGain, uchSlotIdx, uchAdcNo, STGh3x2xAgcInfo->uchTiaGainAfterSoftAgc); + } + pstSTGh3x2xNewAgcSubChnlRxInfo->usAnalysisCnt = 0; + } + } + } + } + } +} + +#endif + + +/*********************************************self-test function start*****************************************/ +#define GH3X2X_SPO2_SELF_TEST 0 + +#if GH3X2X_SPO2_SELF_TEST +const GU32 g_uchSpo2AgcSelftestSlotAdc = 0x01; //slot0, adc1 +const GU32 g_usSpo2AgcFifoLen = 25*4; +const GU32 g_unSpo2AgcRawdata[] = +{ + 10111744,9818116,10074798,9832931,10038819,9812989,10067119,9791632,10220862,9843610,9888564,9974512,10041146,10117796,9858828,10260863,9900963,10159857,10259720,10054459,10247477,9957985,10078474,9916146,9821879 +}; + +GU8 g_uchSpo2AgcFifoBuffer[4*100]; + +void GH3X2X_Spo2AgcFifoDataGen(void) +{ + for (GU16 usIndex = 0; usIndex < g_usSpo2AgcFifoLen; usIndex += GH3X2X_AFE_FIFO_RAWDATA_SIZE) + { + if(usIndex >= sizeof(g_uchSpo2AgcFifoBuffer)) + { + break; + } + g_uchSpo2AgcFifoBuffer[usIndex + 0] = (g_uchSpo2AgcSelftestSlotAdc<<3); + g_uchSpo2AgcFifoBuffer[usIndex + 1] = (0x000000FF&(g_unSpo2AgcRawdata[usIndex/4] >> 16)); + g_uchSpo2AgcFifoBuffer[usIndex + 2] = (0x000000FF&(g_unSpo2AgcRawdata[usIndex/4] >> 8)); + g_uchSpo2AgcFifoBuffer[usIndex + 3] = (0x000000FF&(g_unSpo2AgcRawdata[usIndex/4] >> 0)); + } +} +#endif +/*********************************************self-test function end*****************************************/ + + +/**************************************************************** +* Description: calculate mean value of main channel +* Input: rawdata +* Return: none +******************************************************************/ +static void GH3X2X_NewAgcMainChnlMeanValueCal(GU8* puchReadFifoBuffer, GU16 usFifoLen, GU32 *punRawdataMean, GU8 *pAdjFlag) +{ + for(GU8 uchSlotCnt = 0; uchSlotCnt < GH3X2X_NEW_AGC_SLOT_NUM_LIMIT; uchSlotCnt ++) + { + STGh3x2xNewAgcMainChnlInfo *pstAgcMainChnlInfo = &g_pstGh3x2xNewAgcMainChnlInfoEntity[uchSlotCnt]; + GU8 uchMainChnlSlotAdcNo = pstAgcMainChnlInfo ->uchSlotAdc; + + if(pstAgcMainChnlInfo ->uchEnable) // is enabled slot + { + GU32 unTemp_Trig_H_Thd; + GU32 unTemp_Trig_L_Thd; + GU32 unTemp_Ideal_value; + GU16 usAnalysisEndLen; + GU16 usAnalysisDiscardLenAdjust = 0; + GU16 usAnalysisDiscardLenTrige; + GU32 TrigeMean = 0; + + if(pstAgcMainChnlInfo->uchSpo2ChnlIndex) // is spo2 slot + { + unTemp_Ideal_value= g_unNewAgcSpo2Ideal_value; + }else + { + unTemp_Ideal_value= g_unNewAgcGeneIdeal_value; + } + GH3X_AgcGetThreshold( pstAgcMainChnlInfo->uchSpo2ChnlIndex, &unTemp_Trig_H_Thd, &unTemp_Trig_L_Thd); + + STGh3x2xNewAgcMainChnlMeanInfo *pstNewAgcMainChnlMeanInfo = &g_pstGh3x2xNewAgcMainChnlMeanInfoEntity[uchSlotCnt]; + STGh3x2xNewAgcMainChnlIdaelAdjInfo *pstNewAgcMainChnlIdaelAdjInfo = &g_pstGh3x2xNewAgcMainChnlIdaelAdjInfoEntity[uchSlotCnt]; + GU16 usSampleRate = pstNewAgcMainChnlMeanInfo->usSampleRate; + usAnalysisEndLen = (usSampleRate<<2)/5; // 4/5 Fs + usAnalysisDiscardLenTrige = (usSampleRate<<1)/5; // drop the first 2/5 data + //have agc motion at last fifo read period or first init + if(pstNewAgcMainChnlMeanInfo->uchHaveAgcAtLastReadPrd) + { + usAnalysisDiscardLenAdjust = (usSampleRate<<1)/5; // drop the first 2/5 data + //// After AGC, the previous data is drop to calcluate precise mean + if(!pstNewAgcMainChnlMeanInfo->uchDropFlag) + { // The frame count is only cleared for the first time to prevent data num cannot to be SampleRate + pstNewAgcMainChnlMeanInfo->usAnalysisCnt = 0; + pstNewAgcMainChnlMeanInfo->uchDropFlag = 1; + } + } + //The data fluctuates when initializing the early stage + if(!pstNewAgcMainChnlIdaelAdjInfo->uchIniteFirst) + { + usAnalysisDiscardLenAdjust = (usSampleRate<<1)/5; // drop the first 2/5 data + } + + // prevent unSumAdjust(GU32) overflow + if( (usAnalysisEndLen - usAnalysisDiscardLenAdjust) > 200 ) + { + usAnalysisDiscardLenAdjust = usAnalysisEndLen - 200; // maximum number of accumulated rawdata is 200 + } + + if( (usAnalysisEndLen - usAnalysisDiscardLenTrige) > 200 ) + { + usAnalysisDiscardLenTrige = usAnalysisEndLen - 200; + } + + for (GU16 usIndex = 0; usIndex < usFifoLen; usIndex += GH3X2X_AFE_FIFO_RAWDATA_SIZE) + { + GU32 unFifoVal; + GU8 uchSlotAdcNo; + GU32 unDataRaw; + unFifoVal = GH3X2X_AFE_MAKEUP_DWORD(puchReadFifoBuffer[usIndex], puchReadFifoBuffer[usIndex + 1], + puchReadFifoBuffer[usIndex + 2], puchReadFifoBuffer[usIndex + 3]); + uchSlotAdcNo = ((unFifoVal >> 27)&0x0000001F); + unDataRaw = GH3X2X_RAWDATA_CLEAR_ALL_FLAG(unFifoVal); + //GH3X2X_INFO_LOG_SPO2("uchSlotAdcNo = %d\r\n",uchSlotAdcNo); + //GH3X2X_INFO_LOG_SPO2("uchMainChnlSlotAdcNo = %d\r\n",uchMainChnlSlotAdcNo); + if(uchSlotAdcNo == uchMainChnlSlotAdcNo) + { + // begin Saturation judge + { + GU16 usSat_Check_Num_Max = (usSampleRate<<2) + usSampleRate; //// 5 seconds window + g_pstGh3x2xNewAgcMainChnlSat.Sat_CheckCnt[uchSlotCnt]++; + if( unDataRaw > unTemp_Trig_H_Thd) + { + g_pstGh3x2xNewAgcMainChnlSat.Sat_cnt[uchSlotCnt]++; + } + //// as soon as posible set the Saturation flag + if( g_pstGh3x2xNewAgcMainChnlSat.Sat_cnt[uchSlotCnt] >= (usSat_Check_Num_Max>>4) ) // about 8% of all checked data + { + g_pstGh3x2xNewAgcMainChnlSat.Sat_flag |= (1<= usSat_Check_Num_Max ) + { + g_pstGh3x2xNewAgcMainChnlSat.Sat_cnt[uchSlotCnt] = 0; + g_pstGh3x2xNewAgcMainChnlSat.Sat_CheckCnt[uchSlotCnt] = 0; + } + } + // end Saturation judge + + //// begin mean calculate + ////GH3X2X_INFO_LOG_PARAM("slot = %d, uchSlotAdcNo = %d\r\n",uchSlotCnt,uchSlotAdcNo); + + if(usAnalysisDiscardLenAdjust == pstNewAgcMainChnlMeanInfo->usAnalysisCnt) //init + { + pstNewAgcMainChnlMeanInfo->unSumAdjust = 0; + pstNewAgcMainChnlMeanInfo->unMaxRawdata = 0; + pstNewAgcMainChnlMeanInfo->unMinRawdata = 16777216; + } + + if(usAnalysisDiscardLenTrige == pstNewAgcMainChnlMeanInfo->usAnalysisCnt) //init + { + pstNewAgcMainChnlMeanInfo->unSumTrige = 0; + } + + if(pstNewAgcMainChnlMeanInfo->usAnalysisCnt < usAnalysisEndLen) //analysising + { + pstNewAgcMainChnlMeanInfo->unSumAdjust += unDataRaw; + pstNewAgcMainChnlMeanInfo->unSumTrige += unDataRaw; + pstNewAgcMainChnlMeanInfo->usAnalysisCnt++; + pstNewAgcMainChnlMeanInfo->unMaxRawdata = ((unDataRaw > pstNewAgcMainChnlMeanInfo->unMaxRawdata)? unDataRaw: pstNewAgcMainChnlMeanInfo->unMaxRawdata ); // Max of rawdata + pstNewAgcMainChnlMeanInfo->unMinRawdata = ((unDataRaw < pstNewAgcMainChnlMeanInfo->unMinRawdata)? unDataRaw: pstNewAgcMainChnlMeanInfo->unMinRawdata ); // Min of rawdata + } + else //anlysis finished calculate mean and judge whether AGC + { + // mean value to calculate gain and current + if(usAnalysisEndLen > usAnalysisDiscardLenAdjust) + { + punRawdataMean[uchSlotCnt] = pstNewAgcMainChnlMeanInfo->unSumAdjust/(usAnalysisEndLen - usAnalysisDiscardLenAdjust); + TrigeMean = pstNewAgcMainChnlMeanInfo->unSumTrige / (usAnalysisEndLen - usAnalysisDiscardLenTrige); + }else // The normal case will not be executed, in case the division by 0 in abnormal case + { + punRawdataMean[uchSlotCnt] = unDataRaw; + TrigeMean = unDataRaw; + } + pstNewAgcMainChnlMeanInfo ->unRawdataMean = punRawdataMean[uchSlotCnt]; + pstNewAgcMainChnlMeanInfo->usAnalysisCnt=0; + // The mean calculation key variable is cleared (Prevent mean calculation from being too small:Accumulation lost some data, but numble of raw is all) + usAnalysisDiscardLenAdjust = 0; + pstNewAgcMainChnlMeanInfo->uchHaveAgcAtLastReadPrd = 0; // clear after caculate mean!!! + //// end mean calculate + + ///////////////////// whether AGC and adjust the mean value to calculate gain and current + if( (TrigeMean < unTemp_Trig_L_Thd) || (TrigeMean > unTemp_Trig_H_Thd) ) + { + *pAdjFlag |= (1<unMaxRawdata > unTemp_Trig_H_Thd) + { + /////////// Pay attention to data truncation, use 64-bi + unTempMean = (GS64)unTemp_Ideal_value*(GS64)(pstNewAgcMainChnlMeanInfo->unMaxRawdata)/15099494; // to adjust the max data to (0.8*2^23 + 2^23) + *pAdjFlag |= (1< unTemp_Ideal_value) + { + // adjust the mean value to calculate gain and current (reduce the DC amount) + punRawdataMean[uchSlotCnt] = ( (punRawdataMean[uchSlotCnt]>unTempMean)? punRawdataMean[uchSlotCnt]:unTempMean ); + *pAdjFlag |= (1<unMaxRawdata > unTemp_Trig_H_Thd) + { + punRawdataMean[uchSlotCnt] = unTempMean; // Increasing the mean value to reduce the DC amount + } + } + //////////////////////////////////////////////////// + //////////////begin ideal value adjust + if( (!((*pAdjFlag) & (1<unRawdataMean< ((unTemp_Ideal_value*(g_uchAgcConvergence_level-1))/g_uchAgcConvergence_level) ) \ + || (pstNewAgcMainChnlMeanInfo->unRawdataMean > ((unTemp_Ideal_value*(g_uchAgcConvergence_level+1))/g_uchAgcConvergence_level))) \ + &&( 10*pstNewAgcMainChnlMeanInfo->unMaxRawdata< 12*pstNewAgcMainChnlMeanInfo->unMinRawdata) ) + { + if( !pstNewAgcMainChnlIdaelAdjInfo->uchIniteFirst ) //// Inite First time + { + pstNewAgcMainChnlIdaelAdjInfo->uchIniteFirst = 1; + *pAdjFlag |= (1<uchSeconsCnt++; + if(pstNewAgcMainChnlIdaelAdjInfo->uchSeconsCnt >= 19) + { + *pAdjFlag |= (1<uchSeconsCnt = 0; + } + } + } + else + { + pstNewAgcMainChnlIdaelAdjInfo->uchSeconsCnt = 0; + } + } + else + { + pstNewAgcMainChnlIdaelAdjInfo->uchSeconsCnt = 0; + } + pstNewAgcMainChnlIdaelAdjInfo->uchIniteFirst = 1; //// Must be set to 1 after the first second!!! + ////end ideal value adjust + //GH3X2X_INFO_LOG_PARAM("Mean cal: Slot_num = %d, Rawmean = %d, Adjmean = %d, TrigeMean = %d, AdjFlag= %d\r\n", uchSlotCnt,pstNewAgcMainChnlMeanInfo->unRawdataMean, punRawdataMean[uchSlotCnt]); + //GH3X2X_INFO_LOG_PARAM("Sat flag: SatCnt = %d, SatCheck = %d, CheckMaxNum = %d, Satflag = %d\r\n", g_pstGh3x2xNewAgcMainChnlSat.Sat_cnt[uchSlotCnt], g_pstGh3x2xNewAgcMainChnlSat.Sat_CheckCnt[uchSlotCnt], g_pstGh3x2xNewAgcMainChnlSat.Sat_Check_Num_Max[uchSlotCnt], g_pstGh3x2xNewAgcMainChnlSat.Sat_flag); + //GH3X2X_INFO_LOG_PARAM("Ideal adjust: SeconsCnt = %d\r\n", pstNewAgcMainChnlIdaelAdjInfo->uchSeconsCnt); + //GH3X2X_INFO_LOG_PARAM("Adj flag: Slot_num = %d, Trigmean = %d, L_Thd = %d, H_Thd = %d, Adjflag = %d\r\n", uchSlotCnt,TrigeMean, unTemp_Trig_L_Thd, unTemp_Trig_H_Thd, *pAdjFlag); + g_pstGh3x2xNewAgcMainChnlSat.Sat_flag &= (~(1<uchBakTiaGain; + GU8 uchGainUpLimit = pstAgcMainChnlInfo->uchTiaGainUpLimit; + GU8 uchLedCurrentMin = pstAgcMainChnlInfo->uchBakRegLedCurrentMin; + GU8 uchLedCurrentMax = pstAgcMainChnlInfo->uchBakRegLedCurrentMax; + GU8 uchCurrentDrv = pstAgcMainChnlInfo->uchCurrentDrv; + GU8 uchCurrentTiaGain = pstAgcMainChnlInfo->uchCurrentTiaGain; + + GU8 uchNewGain = uchDefaultGain; + GU32 unIdealRawdata_no; + GU32 unTempDrvCurrent; + GU8 uchChangeFlag = 0; //bit0: drv current flag bit1: gain flag + GU8 uchCalFinish = 0; + GU32 unTrigUpLimit; + GU8 unCalNum = 12; + + if(0 != pstAgcMainChnlInfo->uchSpo2ChnlIndex) // is spo2 slot + { + unTrigUpLimit = g_unNewAgcSpo2Trig_H_Thd; + unIdealRawdata_no= g_unNewAgcSpo2Ideal_value - 8388608; + }else + { + unTrigUpLimit = g_unNewAgcGeneTrig_H_Thd; + unIdealRawdata_no = g_unNewAgcGeneIdeal_value - 8388608; + } + + //GH3X2X_INFO_LOG_PARAM("Drv cal: UpLimit = %d, Mean = %d, LastMean = %d\r\n",unTrigUpLimit, pstMainChnlExtralInfo->unRawdataMean, pstMainChnlExtralInfo->unLastRawdataMean); + // reduce rawdata as soon as posible + if((unTrigUpLimit < pstMainChnlExtralInfo->unRawdataMean)&&(unTrigUpLimit < pstMainChnlExtralInfo->unLastRawdataMean)&&(uchCurrentTiaGain > 0)) + { + uchNewGain = 0; + unTempDrvCurrent = uchLedCurrentMin; + uchCalFinish = 1; + } + pstMainChnlExtralInfo ->unLastRawdataMean = pstMainChnlExtralInfo ->unRawdataMean; + + if(0 == uchCalFinish) + { + //remove offset + if(CurRawdata > (8388608 + 2048)) //// Can't open DC Cance !!! + { + CurRawdata -= 8388608; + } + else + { + //The value may be less than 2^23, preventing division by 0 + CurRawdata = 2048; // Take an appropriately large number to prevent calculated DRV current overflow 32bit + } + //Rawdata stretch (The principle of magnification: the mean divided by the ideal target value is the data reduction factor ) + if(CurRawdata < 8000000) + { + } + else if(CurRawdata < 8100000) + { + CurRawdata = 8000000 + (CurRawdata - 8000000)*6; + } + else if(CurRawdata < 8200000) + { + CurRawdata = 8000000 + ((CurRawdata - 8000000)<<3); + } + else + { + // The more saturated the data, the bigger the stretch, the key is that the data is really saturated + CurRawdata = 8000000 + (CurRawdata - 8000000)*14; // Blood oxygen drops 1 times, heart rate drops 2.5 times + } + + //find new drv current and gain + do + { + unTempDrvCurrent = (GS64)(((GU32)uchCurrentDrv*(GU32)g_usGH3x2xTiaGainR[uchCurrentTiaGain]))* \ + (GS64)unIdealRawdata_no/g_usGH3x2xTiaGainR[uchNewGain]/CurRawdata; + +#if 0 + //GH3X2X_INFO_LOG_PARAM("Drv cal %d: CurrentDrv = %d, CurrentGain = %d, IdealRawdata_no = %d\r\n",uchMainChnlInfoIndex, uchCurrentDrv, uchCurrentTiaGain, unIdealRawdata_no); + //GH3X2X_INFO_LOG_PARAM("Drv cal %d: unTempDrvCurrent = %d, uchNewGain = %d, Meanraw = %d, CurRawdata = %d\r\n",uchMainChnlInfoIndex,unTempDrvCurrent, uchNewGain, pstMainChnlExtralInfo->unRawdataMean, CurRawdata); +#endif + + if(unTempDrvCurrent > uchLedCurrentMax) //drv is too big, need increase gain + { + if(uchNewGain < uchGainUpLimit) + { + uchNewGain ++ ; + } + else + { + unTempDrvCurrent = uchLedCurrentMax; + break; + } + } + else if(unTempDrvCurrent < uchLedCurrentMin) //drv is too small, need dncrease gain + { + if(uchNewGain > 0) + { + uchNewGain -- ; + } + else + { + unTempDrvCurrent = uchLedCurrentMin; + break; + } + } + else //got right drv + { + break; + } + unCalNum --; + } + while (unCalNum); + } + + puchIdealDrvCurrent[0] = (GU8)unTempDrvCurrent; + puchIdealGain[0] = (GU8)uchNewGain; + + if(puchIdealDrvCurrent[0] != uchCurrentDrv) + { + uchChangeFlag |= 0x01; + //GH3X2X_INFO_LOG_PARAM("Drv change %d: CurrentDrv = %d, IdealDrv = %d\r\n",uchMainChnlInfoIndex, uchCurrentDrv, puchIdealDrvCurrent[0]); + } + if(puchIdealGain[0] != uchCurrentTiaGain) + { + uchChangeFlag |= 0x02; + //GH3X2X_INFO_LOG_PARAM("Gain change %d: CurrentGain = %d, IdealGain = %d\r\n",uchMainChnlInfoIndex, uchCurrentTiaGain, puchIdealGain[0]); + } + + return uchChangeFlag; +} + +GU8 NewAgcMainChelFlag = 0; + +void GH3X2X_NewAgcMainChnlPro(GU8* puchReadFifoBuffer, GU16 usFifoLen, STGh3x2xAgcInfo *STGh3x2xAgcInfo) +{ + GU32 unNewAgcRawdataMeanChnl[8] = {0}; + GU8 uchAdjFlag = 0; // Local variables used as judgments must be initialized to 0 + GU8 uchNewDrvCurrent; + GU8 uchNewGain; + GU8 uchChangeFlag = 0; //bit0: drv current flag bit1: gain flag + + if(0 == GH3X2X_NEW_AGC_SLOT_NUM_LIMIT) + { + return; + } + +#if GH3X2X_SPO2_SELF_TEST + + GH3X2X_Spo2AgcFifoDataGen(); + puchReadFifoBuffer = g_uchSpo2AgcFifoBuffer; + usFifoLen = g_usSpo2AgcFifoLen; +#endif + + + GH3X2X_NewAgcMainChnlMeanValueCal( puchReadFifoBuffer,usFifoLen,unNewAgcRawdataMeanChnl,&uchAdjFlag); // caculate mean and whther adjust gain current + + for(GU8 uchSlotCnt = 0; uchSlotCnt < GH3X2X_NEW_AGC_SLOT_NUM_LIMIT; uchSlotCnt ++) + { + if( uchAdjFlag & (1<uchSlotAdc >> 2) & 0x0f); + if(uchChangeFlag&0x02) //write tia gain to chip + { + GH3x2x_AFESetAgcReg(GH3X2X_AGC_REG_TIA_GAIN_RX0 + pstAgcMainChnlInfo ->uchBakRegAgcSrc, uchSlotIdx, uchNewGain); + pstAgcMainChnlInfo->uchCurrentTiaGain = uchNewGain; + GH3X2X_StoreRxTiaGainAfterAgc(uchNewGain, uchSlotIdx, pstAgcMainChnlInfo ->uchBakRegAgcSrc, STGh3x2xAgcInfo->uchTiaGainAfterSoftAgc); + } + if(uchChangeFlag&0x01) //write drv current to chip + { + //change drv0/1 + pstAgcMainChnlInfo ->uchCurrentDrv = uchNewDrvCurrent; + + if((pstAgcMainChnlInfo ->uchBakRegAgcEn)&0x01) + { + GH3x2x_AFESetAgcReg(GH3X2X_AGC_REG_LED_CURRENT_DRV0, uchSlotIdx, uchNewDrvCurrent); + GH3X2X_StoreDrvCurrentAfterAgc(pstAgcMainChnlInfo ->uchCurrentDrv, uchSlotIdx,0,STGh3x2xAgcInfo->uchDrvCurrentAfterSoftAgc); + } + if((pstAgcMainChnlInfo ->uchBakRegAgcEn)&0x02) + { + GH3x2x_AFESetAgcReg(GH3X2X_AGC_REG_LED_CURRENT_DRV1, uchSlotIdx, uchNewDrvCurrent); + GH3X2X_StoreDrvCurrentAfterAgc(pstAgcMainChnlInfo ->uchCurrentDrv, uchSlotIdx,1,STGh3x2xAgcInfo->uchDrvCurrentAfterSoftAgc); + } + #if GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT > 0 + GH3x2xNewAgcSubChnlClearAnalysisCntAndSetGain(uchSlotIdx, 0x0F, 0xFF); //clear all rx analysis cnt in this slot + #endif + } + if(uchChangeFlag) + { + g_pstGh3x2xNewAgcMainChnlMeanInfoEntity[uchSlotCnt].uchHaveAgcAtLastReadPrd = 1; // current or gain change at last time + g_pstGh3x2xNewAgcMainChnlMeanInfoEntity[uchSlotCnt].uchDropFlag = 0; + NewAgcMainChelFlag |= (1<> (8*uchByteCnt))&0x00FF); + usByteOffset = (usRegPosi * 2) + uchByteCnt; + if(usByteOffset < sizeof(g_stSoftAgcCfg)) + { + GH3X2X_Memcpy(((GU8 *)(&g_stSoftAgcCfg)) + usByteOffset, (GU8*)(&uchByteVal), 1); + } + } +} + +/** + * @fn void GH3X2X_LedAgcReset(void) + * + * @brief reset agc parameter + * + * @attention None + * + * @param[in] None + * @param[out] None + * + * @return None + */ +void GH3X2X_LedAgcReset(void) +{ + GH3X2X_Memset(&g_stSoftAgcCfg, 0, sizeof(STSoftAgcCfg)); + GH3x2xNewAgcModuleReset(); +} + +/** + * @fn void GH3X2X_LedAgcProcess(GU8* puchReadFifoBuffer, GU16 usFifoLen) + * + * @brief led agc process function + * + * @attention None + * + * @param[in] puchReadFifoBuffer pointer to read fifo data buffer + * @param[in] usFifoLen read fifo data buffer length + * @param[out] None + * + * @return None + */ + +void GH3X2X_LedAgcProcess(GU8* puchReadFifoBuffer, GU16 usFifoLen, STGh3x2xAgcInfo *STGh3x2xAgcInfo) +{ + GH3X2X_UpdateAgcInfo(); + if(usFifoLen==0) + { + return; + } + + GH3X2X_NewAgcMainChnlPro(puchReadFifoBuffer, usFifoLen,STGh3x2xAgcInfo); + +#if GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT > 0 + GH3X2X_NewAgcSubChnlGainAdj(puchReadFifoBuffer, usFifoLen,STGh3x2xAgcInfo); +#endif + +} +#endif +#endif +/********END OF FILE********* Copyright (c) 2003 - 2022, Goodix Co., Ltd. ********/ diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_demo.c b/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_demo.c new file mode 100644 index 000000000..148fc9918 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_demo.c @@ -0,0 +1,94 @@ +#include "gh3x2x_afe_ecg.h" +#include "gh3x2x_afe_adt.h" +#include "gh3x2x_afe_agc.h" +#include "gh3x2x_afe_demo.h" + + + +GU32 g_unFuncMode = GH3X2X_NO_FUNCTION; + + + +void GH3X2X_AFE_StartFunction(GU32 unFuncMode) +{ + if(unFuncMode & (GH3X2X_FUNCTION_ADT)) + { + GH3x2xAdtAlgoInit(); + GH3X2X_AFE_WriteRegBitField(GH3X2X_AFE_REG_SLOT_EN_ADDR,GH3X2X_ADT_SLOT_NUM,GH3X2X_ADT_SLOT_NUM,1); + } + + if(unFuncMode & (GH3X2X_FUNCTION_ECG)) + { + GH3X2X_LeadOffDetectInit(); + GH3X2X_AFE_WriteRegBitField(GH3X2X_AFE_REG_SLOT_EN_ADDR,GH3X2X_ECG_SLOT_NUM,GH3X2X_ECG_SLOT_NUM,1); + ECG_FAST_RECV_EN_CONFIG(1); + } + + if(g_unFuncMode == GH3X2X_NO_FUNCTION) + { + GH3X2X_AFE_WriteRegBitField(GH3X2X_AFE_REG_START_ADDR,GH3X2X_AFE_REG_START_LSB,GH3X2X_AFE_REG_START_MSB,1); + } + g_unFuncMode |= unFuncMode; + +} + + +void GH3X2X_AFE_StopFunction(GU32 unFuncMode) +{ + if(unFuncMode & (GH3X2X_FUNCTION_ADT)) + { + GH3X2X_AFE_WriteRegBitField(GH3X2X_AFE_REG_SLOT_EN_ADDR,GH3X2X_ADT_SLOT_NUM,GH3X2X_ADT_SLOT_NUM,0); + GH3x2xAdtAlgoDeinit(); + } + if(unFuncMode & (GH3X2X_FUNCTION_ECG)) + { + GH3X2X_AFE_WriteRegBitField(GH3X2X_AFE_REG_SLOT_EN_ADDR,GH3X2X_ECG_SLOT_NUM,GH3X2X_ECG_SLOT_NUM,0); + ECG_FAST_RECV_EN_CONFIG(0); + + } + g_unFuncMode &= (~unFuncMode); + if(g_unFuncMode == GH3X2X_NO_FUNCTION) + { + GH3X2X_AFE_WriteRegBitField(GH3X2X_AFE_REG_START_ADDR,GH3X2X_AFE_REG_START_LSB,GH3X2X_AFE_REG_START_MSB,0); + } + +} + + +void GH3X2X_AFE_Leadon_hook(void) +{ + GH3X2X_AFE_StartFunction(GH3X2X_FUNCTION_ECG); +} + +void GH3X2X_AFE_Leadoff_hook(void) +{ + GH3X2X_AFE_StopFunction(GH3X2X_FUNCTION_ECG); + ECG_LEAD_DET_EN_CONFIG(0);// enable lead detect + ECG_LEAD_DET_EN_CONFIG(1);// enable lead detect + +} + + +void GH3X2X_DemoLedAgcPramConfig(void) +{ + static STSoftAgcCfg stSoftAgcCfg; + + stSoftAgcCfg.uchSlotxSoftAgcAdjEn = 1; //bit0-bit7: slot0 -slot7 + stSoftAgcCfg.uchSlotxSoftBgAdjEn = 0; + stSoftAgcCfg.stAmbSlotCtrl.uchAmbSampleEn = 0; + stSoftAgcCfg.uchSpo2RedSlotCfgEn = 2; //bit0-bit7: slot0 -slot7 for spo2 red + stSoftAgcCfg.uchSpo2IrSlotCfgEn = 4; //bit0-bit7: slot0 -slot7 for spo2 ir + stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg32uA = 8; + stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg64uA = 6; + stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg128uA = 5; + stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg256uA = 4; + stSoftAgcCfg.unAgcTrigThd_H = (GU32)(8388608 + 8388608*0.85f); + stSoftAgcCfg.unAgcTrigThd_L = (GU32)(8388608 + 8388608*0.15f); + stSoftAgcCfg.unAgcRestrainThd_H = 12868608; + stSoftAgcCfg.unAgcRestrainThd_L = 10692608; + + GH3X2X_LedAgcPramConfig(&stSoftAgcCfg); +} + + + diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_drv.c b/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_drv.c new file mode 100644 index 000000000..b0e72b3f7 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_drv.c @@ -0,0 +1,1544 @@ +/** + * @copyright (c) 2019 - 2024, Goodix Co., Ltd. All rights reserved. + * + * @file gh3x2x_afe_drv.c + * + * @brief gh3x2x driver example code + * + * @author Gooidx Iot Team + * + * @attention + * This file just show how to init and control gh3x2x sampling. + */ +#include "stdio.h" +#include "gh3x2x_afe_drv.h" +#include "gh3x2x_afe_user.h" +#include "gh3x2x_afe_ecg.h" +#include "gh3x2x_afe_agc.h" +#include "gh3x2x_afe_adt.h" +#include "gh3x2x_afe_demo.h" + +#include "custom_utils.h" + + +#define SWAP_SIZE_OF_GU16 (2) +#define SWAP_INDEX_OF_NEXT_BYTE (1) + +#define GH3X2X_I2C_BUS I2C_BUS_2 + +//extern void GH3X2X_SoftLedADJAutoADJInt(void); +//extern void GH3X2X_LedAgcProcess(GU8* puchReadFifoBuffer, GU16 usFifoLen); +//extern void GH3X2X_LedAgcReset(void); +//extern void GH3X2X_LedAgcPramWrite(void); +//extern void GH3X2X_LedAgcInit(void); + +STGh3x2xAgcInfo g_stGh3x2xAgcInfo = {0}; +STGh3x2xAgcInfo *g_pstGh3x2xAgcInfo = &g_stGh3x2xAgcInfo; + +GU8 g_uchNeedWakeUpGh3x2xAfe = 1; // 0: do not need wake up gh3x2x 1: need wake up gh3x2x +GU8 g_uchGh3x2xAfeIntCallBackIsCalled = 0; //0: no new interrupt 1: have new interrupt + +/*********************************************** reg cfg package *******************************************/ +STGH3X2X_AFEReg GH3X2X_AFE_reg_list[] = +{ +// {0x0000, 0x0610}, {0x0004, 0x001F}, {0x0006, 0x0001}, {0x000A, 0x0010}, {0x000E, 0x000D}, {0x0100, 0x0100}, +// {0x010A, 0x27FC}, {0x0110, 0x0F65}, {0x0114, 0x00AA}, {0x011E, 0x021F}, {0x0120, 0x041F}, {0x0122, 0x137F}, +// {0x0126, 0xC77C}, {0x012C, 0x0C10}, {0x012E, 0x2222}, {0x0130, 0x00AA}, {0x013A, 0x010C}, {0x013C, 0x0400}, +// {0x01EC, 0x027C}, {0x01EE, 0x00AC}, {0x0200, 0x0120}, {0x0208, 0x0551}, {0x0280, 0x0A00}, {0x0282, 0xF530}, +// {0x0284, 0x9388}, {0x0286, 0xC45C}, {0x0288, 0xA328}, {0x0408, 0x0001}, {0x0410, 0x49F0}, {0x0412, 0x0082}, +// {0x0414, 0x49F0}, {0x0416, 0x0082}, {0x0422, 0x0011}, {0x0424, 0x0901}, {0x0426, 0x0108}, {0x0428, 0x0102}, +// {0x0502, 0x4360}, {0x0504, 0x000A}, {0x0588, 0x0008}, {0x0692, 0x0233}, {0x0694, 0x0400}, {0x0698, 0x2310}, +// {0x0700, 0x0000}, + +// {0x0000, 0x0602}, {0x0004, 0x0013}, {0x0006, 0x0201}, {0x000A, 0x005F}, {0x000E, 0x000D}, {0x0074, 0x0048}, +// {0x0100, 0x0100}, {0x010A, 0x0462}, {0x010C, 0x0000}, {0x010E, 0x0000}, {0x0110, 0x0000}, {0x0120, 0x0400}, +// {0x0126, 0xC73C}, {0x0128, 0x0404}, {0x012A, 0x0404}, {0x012C, 0x0C10}, {0x012E, 0x2222}, {0x0130, 0x00AA}, +// {0x0136, 0x00FF}, {0x013A, 0x000C}, {0x013C, 0x0400}, {0x01EA, 0x0033}, {0x01EC, 0x0030}, {0x01EE, 0x0098}, +// {0x0200, 0x1020}, {0x0402, 0x5555}, {0x0404, 0x4120}, {0x0406, 0x0041}, {0x0408, 0x0001}, {0x0410, 0x49F0}, +// {0x0412, 0x0082}, {0x0414, 0x49F0}, {0x0416, 0x0082}, {0x0422, 0x0011}, {0x0424, 0x0901}, {0x0426, 0x0109}, +// {0x0428, 0x0108}, {0x0480, 0x6550}, {0x0502, 0x4C66}, {0x0506, 0x0020}, {0x0588, 0x0008}, {0x0692, 0x0233}, +// {0x0694, 0x0404}, {0x0698, 0x3310}, {0x069A, 0x1101}, {0x0700, 0x0000}, {0x0400, 0x5557}, {0x1000, 0x0000}, +// {0x1002, 0x3197}, {0x1004, 0x0000}, {0x1006, 0x6C91}, {0x1008, 0x2CE1}, {0x100A, 0x0001}, {0x10E0, 0x0000}, +// {0x10E2, 0xFFFF}, {0x10E4, 0xFFFF}, {0x10E6, 0xFFFF}, {0x10E8, 0x0202}, {0x10EA, 0x0202}, {0x10EC, 0x0202}, +// {0x10EE, 0x0202}, {0x1120, 0x005F}, {0x1122, 0x0005}, {0x1124, 0x0000}, {0x2000, 0x0004}, {0x2002, 0x2A22}, +// {0x2004, 0x3A32}, {0x20EE, 0x0001}, {0x20F0, 0x001C}, {0x2880, 0x0005}, {0x288E, 0x00FA}, {0x3000, 0x0101}, +// {0x3002, 0x0000}, {0x3004, 0x49F0}, {0x3006, 0x0082}, {0x4500, 0x46C9}, {0x4502, 0x0F0F}, {0x4504, 0x0002}, +// {0x4506, 0x0140}, {0xFFFF, 0x0001} + + {0x0000, 0x0610}, {0x0004, 0x001F}, {0x0006, 0x0001}, {0x000A, 0x0050}, {0x000E, 0x000D}, {0x0100, 0x0100}, + {0x010A, 0x277C}, {0x0110, 0x0D14}, {0x0112, 0x5555}, {0x0114, 0x00AA}, {0x011E, 0x0019}, {0x0120, 0x0400}, + {0x0122, 0x0CFF}, {0x0126, 0xC704}, {0x0128, 0x0001}, {0x012A, 0x0000}, {0x012C, 0x0C10}, {0x012E, 0x4442}, + {0x0130, 0x0002}, {0x0136, 0x0003}, {0x013A, 0x010C}, {0x013C, 0x0400}, {0x01EC, 0x0136}, {0x01EE, 0x00AC}, + {0x0200, 0x0120}, {0x0208, 0x0551}, {0x0280, 0x0A00}, {0x0282, 0xF530}, {0x0284, 0x9388}, {0x0286, 0xC45C}, + {0x0288, 0xA328}, {0x0408, 0x0001}, {0x0410, 0x49F0}, {0x0412, 0x0082}, {0x0414, 0x49F0}, {0x0416, 0x0082}, + {0x0422, 0x0011}, {0x0424, 0x0901}, {0x0426, 0x0108}, {0x0428, 0x0102}, {0x0502, 0x4F60}, {0x0504, 0x000A}, + {0x0588, 0x0008}, {0x0692, 0x0233}, {0x0694, 0x0400}, {0x0698, 0x2310}, {0x0700, 0x0000}, {0x1000, 0x0000}, + {0x1002, 0x3197}, {0x1004, 0x0000}, {0x1006, 0x6904}, {0x1008, 0x2AF6}, {0x100A, 0x0001}, {0x10E0, 0x0000}, + {0x10E2, 0xFFFF}, {0x10E4, 0xFFFF}, {0x10E6, 0xFFFF}, {0x10E8, 0x0202}, {0x10EA, 0x0202}, {0x10EC, 0x0202}, + {0x10EE, 0x0202}, {0x1100, 0x0004}, {0x1102, 0x0000}, {0x1120, 0x0050}, {0x1122, 0x0005}, {0x1124, 0x0000}, + {0x1140, 0x0000}, {0x1142, 0x00C8}, {0x1144, 0x0001}, {0x1160, 0x0001}, {0x1162, 0x0000}, {0x1164, 0x0000}, + {0x1166, 0x4568}, {0x1168, 0xCCCC}, {0x116A, 0x00EC}, {0x116C, 0x3333}, {0x116E, 0x0093}, {0x1170, 0x5C00}, + {0x1172, 0x00C4}, {0x1174, 0x2800}, {0x1176, 0x00A3}, {0x2000, 0x0001}, {0x2002, 0x0022}, {0x2022, 0x0004}, + {0x2024, 0x0901}, {0x2026, 0x1911}, {0x2880, 0x0005}, {0x2882, 0x0019}, {0x3000, 0x0001}, {0x3002, 0x0000}, + {0x3004, 0x49F0}, {0x3006, 0x0082}, {0xFFFF, 0x0001} +}; + +GU16 GH3X2X_AFE_reg_list_len = sizeof(GH3X2X_AFE_reg_list) / sizeof(GH3X2X_AFE_reg_list[0]); + + +void GH3X2X_SwapLittleBigEndianData(GU8 *puchDataBuffer, GU16 usDataLength) +{ + GU16 usIndex = 0; + + for (usIndex = 0; usIndex < (usDataLength / SWAP_SIZE_OF_GU16); usIndex++) + { + puchDataBuffer[usIndex * SWAP_SIZE_OF_GU16] ^= \ + puchDataBuffer[usIndex * SWAP_SIZE_OF_GU16 + SWAP_INDEX_OF_NEXT_BYTE]; + puchDataBuffer[usIndex * SWAP_SIZE_OF_GU16 + SWAP_INDEX_OF_NEXT_BYTE] ^= \ + puchDataBuffer[usIndex * SWAP_SIZE_OF_GU16]; + puchDataBuffer[usIndex * SWAP_SIZE_OF_GU16] ^= \ + puchDataBuffer[usIndex * SWAP_SIZE_OF_GU16 + SWAP_INDEX_OF_NEXT_BYTE]; + } +} + + +#if ( GH3X2X_AFE_COM_INTERFACE_TYPE == GH3X2X_AFE_COM_INTERFACE_SPI ) + + +/** + * @fn static void GH3X2X_AFE_SpiSendCmd(GU8 uchCmd) + * + * @brief Send cmd via spi + * + * @attention None + * + * @param[in] uchCmd spi cmd + * @param[out] None + * + * @return None + */ +#if (GH3X2X_AFE_SPI_TYPE == GH3X2X_AFE_SPI_SOFTWARE_CS) +void GH3X2X_AFE_SpiSendCmd(GU8 uchCmd) +{ + GU8 uchBuffArr[1]; + + hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_LOW); + uchBuffArr[0] = uchCmd; + hal_gh3x2x_afe_spi_write(uchBuffArr, 1); + hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_HIGH); + hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_END_DELAY_X_US); +} +#endif + +#if (GH3X2X_AFE_SPI_TYPE == GH3X2X_AFE_SPI_HARDWEAR_CS) +void GH3X2X_AFE_SpiSendCmdHardwareCs(GU8 uchCmd) +{ + GU8 uchBuffArr[1]; + uchBuffArr[0] = uchCmd; + hal_gh3x2x_afe_spi_write(uchBuffArr, 1); +} +#endif + + +/** + * @fn static void GH3X2X_AFE_SpiWriteReg(GU16 usRegAddr, GU16 usRegValue) + * + * @brief Write register via spi + * + * @attention None + * + * @param[in] usRegAddr register addr + * @param[in] usRegValue register data + * @param[out] None + * + * @return None + */ +#if (GH3X2X_AFE_SPI_TYPE == GH3X2X_AFE_SPI_SOFTWARE_CS) +void GH3X2X_AFE_SpiWriteReg(GU16 usRegAddr, GU16 usRegValue) +{ + GU8 uchBuffArr[7]; + + hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_LOW); + uchBuffArr[0] = GH3X2X_AFE_SPI_CMD_WRITE; + uchBuffArr[1] = GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(usRegAddr); + uchBuffArr[2] = GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(usRegAddr); + uchBuffArr[3] = 0; + uchBuffArr[4] = 2; + uchBuffArr[5] = GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(usRegValue); + uchBuffArr[6] = GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(usRegValue); + hal_gh3x2x_afe_spi_write(uchBuffArr, 7); + hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_WAIT_DELAY_X_US); + hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_HIGH); + hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_END_DELAY_X_US); +} +#endif + +#if (GH3X2X_AFE_SPI_TYPE == GH3X2X_AFE_SPI_HARDWEAR_CS) +void GH3X2X_AFE_SpiWriteRegHardwareCs(GU16 usRegAddr, GU16 usRegValue) +{ + GU8 puchWriteBuf[7]; + puchWriteBuf[0] = 0xF0; + puchWriteBuf[1] = usRegAddr>>8; + puchWriteBuf[2] = usRegAddr&0x00FF; + puchWriteBuf[3] = 0; + puchWriteBuf[4] = 2; + puchWriteBuf[5] = usRegValue>>8; + puchWriteBuf[6] = usRegValue&0x00FF; + hal_gh3x2x_afe_spi_write(puchWriteBuf, 7); +} +#endif + + + + + + + +/** + * @fn static GU16 GH3X2X_AFE_SpiReadReg(GU16 usRegAddr) + * + * @brief Read register via spi + * + * @attention None + * + * @param[in] usRegAddr register addr + * @param[out] None + * + * @return register data + */ + +#if (GH3X2X_AFE_SPI_TYPE == GH3X2X_AFE_SPI_SOFTWARE_CS) +GU16 GH3X2X_AFE_SpiReadReg(GU16 usRegAddr) +{ + GU8 uchBuffArr[3] = {0}; + + hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_LOW); + uchBuffArr[0] = GH3X2X_AFE_SPI_CMD_WRITE; + uchBuffArr[1] = GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(usRegAddr); + uchBuffArr[2] = GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(usRegAddr); + hal_gh3x2x_afe_spi_write(uchBuffArr, 3); + hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_WAIT_DELAY_X_US); + hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_HIGH); + hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_END_DELAY_X_US); + hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_LOW); + uchBuffArr[0] = GH3X2X_AFE_SPI_CMD_READ; + hal_gh3x2x_afe_spi_write(uchBuffArr, 1); + hal_gh3x2x_afe_spi_read(uchBuffArr, 2); + hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_WAIT_DELAY_X_US); + hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_HIGH); + hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_END_DELAY_X_US); + return GH3X2X_AFE_MAKEUP_WORD(uchBuffArr[0], uchBuffArr[1]); +} + +/** + * @fn void GH3X2X_SpiReadRegs(GU16 usRegAddr, GU16 *pusRegValueBuffer, GU8 uchLen) + * + * @brief Read multi register via spi + * + * @attention None + * + * @param[in] usRegAddr register addr + * @param[in] pusRegValueBuffer pointer to register value buffer + * @param[in] uchLen registers len + * @param[out] None + * + * @return None + */ +void GH3X2X_AFE_SpiReadRegs(GU16 usRegAddr, GU16 *pusRegValueBuffer, GU8 uchLen) +{ + GU8 uchBuffArr[3] = {0}; + + hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_LOW); + uchBuffArr[0] = GH3X2X_AFE_SPI_CMD_WRITE; + uchBuffArr[1] = GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(usRegAddr); + uchBuffArr[2] = GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(usRegAddr); + hal_gh3x2x_afe_spi_write(uchBuffArr, 3); + hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_WAIT_DELAY_X_US); + hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_HIGH); + hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_END_DELAY_X_US); + hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_LOW); + uchBuffArr[0] = GH3X2X_AFE_SPI_CMD_READ; + hal_gh3x2x_afe_spi_write(uchBuffArr, 1); + hal_gh3x2x_afe_spi_read((GU8 *)pusRegValueBuffer, uchLen * 2); + GH3X2X_SwapLittleBigEndianData((GU8 *)pusRegValueBuffer, (GU16)((GU16)uchLen * 2)); + hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_WAIT_DELAY_X_US); + hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_HIGH); + hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_END_DELAY_X_US); +} + +#endif + +#if (GH3X2X_AFE_SPI_TYPE == GH3X2X_AFE_SPI_HARDWEAR_CS) +GU16 GH3X2X_AFE_SpiReadRegHardwareCs(GU16 usRegAddr) +{ + GU8 puchWriteBuf[7]; + GU8 puchReadBuf[2]; + puchWriteBuf[0] = 0xF0; + puchWriteBuf[1] = usRegAddr>>8; + puchWriteBuf[2] = usRegAddr&0x00FF; + hal_gh3x2x_afe_spi_write(puchWriteBuf, 3); + hal_gh3x2x_afe_spi_write_F1_and_read(puchReadBuf, 2); + return ((((GU16)puchReadBuf[0])<<8) + puchReadBuf[1]); +} + + + +void GH3X2X_AFE_SpiReadRegsHardwareCs(GU16 usRegAddr, GU16 *pusRegValueBuffer, GU8 uchLen) +{ + GU8 puchWriteBuf[3]; + puchWriteBuf[0] = 0xF0; + puchWriteBuf[1] = usRegAddr>>8; + puchWriteBuf[2] = usRegAddr&0x00FF; + hal_gh3x2x_afe_spi_write(puchWriteBuf, 3); + hal_gh3x2x_afe_spi_write_F1_and_read((GU8 *)pusRegValueBuffer, uchLen * 2); + GH3X2X_SwapLittleBigEndianData((GU8 *)pusRegValueBuffer, (GU16)((GU16)uchLen * 2)); +} + + +#endif + + + + + +/** + * @fn static void GH3X2X_AFE_SpiReadFifo(GU8 *puchDataBuffer, GU16 usLen) + * + * @brief Read fifo via spi + * + * @attention None + * + * @param[in] puchDataBuffer pointer to buffer for fifo rawdata + * @param[in] usLen fifo bytes len + * @param[out] None + * + * @return None + */ + +#if (GH3X2X_AFE_SPI_TYPE == GH3X2X_AFE_SPI_SOFTWARE_CS) +static void GH3X2X_AFE_SpiReadFifo(GU8 *puchDataBuffer, GU16 usLen) +{ + GU8 uchBuffArr[3] = {0}; + + hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_LOW); + uchBuffArr[0] = GH3X2X_AFE_SPI_CMD_WRITE; + uchBuffArr[1] = GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(GH3X2X_AFE_FIFO_REG_ADDR); + uchBuffArr[2] = GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(GH3X2X_AFE_FIFO_REG_ADDR); + hal_gh3x2x_afe_spi_write(uchBuffArr, 3); + hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_WAIT_DELAY_X_US); + hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_HIGH); + hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_END_DELAY_X_US); + hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_LOW); + uchBuffArr[0] = GH3X2X_AFE_SPI_CMD_READ; + hal_gh3x2x_afe_spi_write(uchBuffArr, 1); + hal_gh3x2x_afe_spi_read(puchDataBuffer, usLen); + hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_WAIT_DELAY_X_US); + hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_HIGH); + hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_END_DELAY_X_US); +} + +#endif + + +#if (GH3X2X_AFE_SPI_TYPE == GH3X2X_AFE_SPI_HARDWEAR_CS) +void GH3X2X_AFE_SpiReadFifoHardwareCs(GU8 *puchDataBuffer, GU16 usLen) +{ + GU8 puchWriteBuf[3]; + puchWriteBuf[0] = 0xF0; + puchWriteBuf[1] = 0xAAAA>>8; + puchWriteBuf[2] = 0xAAAA&0x00FF; + hal_gh3x2x_afe_spi_write(puchWriteBuf, 3); + hal_gh3x2x_afe_spi_write_F1_and_read(puchDataBuffer, usLen); +} +#endif + +#endif + +#if ( GH3X2X_AFE_COM_INTERFACE_TYPE == GH3X2X_AFE_COM_INTERFACE_I2C ) + +/** + * @fn static void GH3X2X_AFE_I2cSendCmd(GU8 uchCmd) + * + * @brief Send cmd via i2c + * + * @attention None + * + * @param[in] uchCmd i2c cmd + * @param[out] None + * + * @return None + */ +void GH3X2X_AFE_I2cSendCmd(GU8 uchCmd) +{ + GU8 uchBuffArr[3] = {0}; + + uchBuffArr[0] = GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(GH3X2X_AFE_I2C_CMD_ADDR); + uchBuffArr[1] = GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(GH3X2X_AFE_I2C_CMD_ADDR); + uchBuffArr[2] = uchCmd; + hal_gh3x2x_afe_i2c_write(GH3X2X_AFE_I2C_DEVICE_ADDR, uchBuffArr, 3); + // custom_i2c_write_reg(GH3X2X_AFE_I2C_DEVICE_ADDR, GH3X2X_AFE_I2C_CMD_ADDR, 1 , &uchCmd, 1, GH3X2X_I2C_BUS); +} + +/** + * @fn static void GH3X2X_AFE_I2cWriteReg(GU16 usRegAddr, GU16 usRegValue) + * + * @brief Write register via i2c + * + * @attention None + * + * @param[in] usRegAddr register addr + * @param[in] usRegValue register data + * @param[out] None + * + * @return None + */ +void GH3X2X_AFE_I2cWriteReg(GU16 usRegAddr, GU16 usRegValue) +{ + GU8 uchBuffArr[4] = {0}; + + uchBuffArr[0] = GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(usRegAddr); + uchBuffArr[1] = GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(usRegAddr); + uchBuffArr[2] = GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(usRegValue); + uchBuffArr[3] = GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(usRegValue); + hal_gh3x2x_afe_i2c_write(GH3X2X_AFE_I2C_DEVICE_ADDR, uchBuffArr, 4); + // custom_i2c_write_reg(GH3X2X_AFE_I2C_DEVICE_ADDR, usRegAddr, 1 , &usRegValue, szieof(usRegValue), GH3X2X_I2C_BUS); +} + + + +/** + * @fn static GU16 GH3X2X_I2cReadReg(GU16 usRegAddr) + * + * @brief Read register via i2c + * + * @attention None + * + * @param[in] usRegAddr register addr + * @param[out] None + * + * @return register data + */ +GU16 GH3X2X_AFE_I2cReadReg(GU16 usRegAddr) +{ + GU8 uchCmdBuffArr[2] = {0}; + GU8 uchReadBuffArr[2] = {0}; + + uchCmdBuffArr[0] = GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(usRegAddr); + uchCmdBuffArr[1] = GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(usRegAddr); + hal_gh3x2x_afe_i2c_read(GH3X2X_AFE_I2C_DEVICE_ADDR, uchCmdBuffArr, 2, uchReadBuffArr, 2); + + // custom_i2c_read_regs(GH3X2X_AFE_I2C_DEVICE_ADDR, usRegAddr, 1 , uchReadBuffArr, sizeof(uchReadBuffArr), GH3X2X_I2C_BUS); + + return GH3X2X_AFE_MAKEUP_WORD(uchReadBuffArr[0], uchReadBuffArr[1]); +} + +/** + * @fn void GH3X2X_I2cReadRegs(GU16 usRegAddr, GU16 *pusRegValueArr, GU8 uchLen) + * + * @brief Read multi register via i2c + * + * @attention None + * + * @param[in] usRegAddr register addr + * @param[in] pusRegValueBuffer pointer to register value buffer + * @param[in] uchLen registers len + * @param[out] None + * + * @return None + */ +void GH3X2X_I2cReadRegs(GU16 usRegAddr, GU16 *pusRegValueArr, GU8 uchLen) +{ + GU8 uchBuffArr[2] = {0}; + + // uchBuffArr[0] = GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(usRegAddr); + // uchBuffArr[1] = GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(usRegAddr); + + custom_i2c_read_regs(GH3X2X_AFE_I2C_DEVICE_ADDR, usRegAddr,1, pusRegValueArr, uchLen ,GH3X2X_I2C_BUS); + + // hal_gh3x2x_afe_i2c_read(GH3X2X_AFE_I2C_DEVICE_ADDR, uchBuffArr, 2, \ + // (GU8 *)pusRegValueArr, uchLen * 2); + GH3X2X_SwapLittleBigEndianData((GU8 *)pusRegValueArr, (GU16)uchLen * 2); +} + + + + +/** + * @fn static void GH3X2X_I2cReadFifo(GU8 *puchDataBuffer, GU16 usLen) + * + * @brief Read fifo via i2c + * + * @attention None + * + * @param[in] puchDataBuffer pointer to buffer for fifo rawdata + * @param[in] usLen fifo bytes len + * @param[out] None + * + * @return None + */ +void GH3X2X_AFE_I2cReadFifo(GU8 *puchDataBuffer, GU16 usLen) +{ + GU8 uchCmdBuffArr[2] = {0}; + + uchCmdBuffArr[0] = GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(GH3X2X_AFE_FIFO_REG_ADDR); + uchCmdBuffArr[1] = GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(GH3X2X_AFE_FIFO_REG_ADDR); + hal_gh3x2x_afe_i2c_read(GH3X2X_AFE_I2C_DEVICE_ADDR, uchCmdBuffArr, 2, puchDataBuffer, usLen); +} + +#endif + +/** + * @fn void GH3X2X_WriteRegBitField(GU16 usRegAddr, GU8 uchLsb, GU8 uchMsb, GU16 usValue) + * + * @brief write register bit field via i2c or spi + * + * @attention None + * + * @param[in] usRegAddr register addr + * @param[in] uchLsb lsb of bit field + * @param[in] uchMsb msb of bit field + * @param[in] usRegValue register data + * @param[out] None + * + * @return None + */ +void GH3X2X_AFE_WriteRegBitField(GU16 usRegAddr, GU8 uchLsb, GU8 uchMsb, GU16 usValue) +{ + GU16 usMakData = ((((GU16)0x0001) << (uchMsb - uchLsb + 1)) - 1) << uchLsb; + GU16 usRegData = 0; + usRegData = GH3X2X_AFE_READ_REG(usRegAddr); + GH3X2X_VAL_CLEAR_BIT(usRegData, usMakData); + GH3X2X_VAL_SET_BIT(usRegData, (usValue << uchLsb) & usMakData); + GH3X2X_AFE_WRITE_REG(usRegAddr, usRegData); +} + +/** + * @fn GU16 GH3X2X_AFE_READ_REGBitField(GU16 usRegAddr, GU8 uchLsb, GU8 uchMsb) + * + * @brief Read register bit field via i2c or spi + * + * @attention None + * + * @param[in] usRegAddr register addr + * @param[in] uchLsb lsb of bit field + * @param[in] uchMsb msb of bit field + * @param[out] None + * + * @return register bit field data + */ +GU16 GH3X2X_AFE_ReadRegBitField(GU16 usRegAddr, GU8 uchLsb, GU8 uchMsb) +{ + GU16 usMakData = ((((GU16)0x0001) << (uchMsb - uchLsb + 1)) - 1) << uchLsb; + GU16 usRegData = 0; + usRegData = GH3X2X_AFE_READ_REG(usRegAddr); + GH3X2X_AFE_VAL_GET_BIT(usRegData, usMakData); + usRegData >>= uchLsb; + return usRegData; +} + + +void GH3X2X_AFE_SetNeedWakeUpGh3x2xFlag(GU8 uchFlag) +{ + g_uchNeedWakeUpGh3x2xAfe = uchFlag; +} + +GU8 GH3X2X_AFE_GetNeedWakeUpGh3x2xFlag(void) +{ + return g_uchNeedWakeUpGh3x2xAfe; +} + + + +void GH3X2X_AFE_ExitLowPowerMode(void) +{ + GH3X2X_AFE_SEND_CMD(GH3X2X_AFE_CMD_WAKEUP); + hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_WAKE_UP_CMD_DELAY_X_US); +} + +void GH3X2X_AFE_EnterLowPowerMode(void) +{ + GH3X2X_AFE_SEND_CMD(GH3X2X_AFE_CMD_SLEEP); + GH3X2X_AFE_SetNeedWakeUpGh3x2xFlag(1); +} + + +void GH3X2X_AFE_ClearEvent(GU16 usEvent) +{ + GH3X2X_AFE_WRITE_REG(GH3X2X_AFE_REG_INT_EVENT_ADDR,usEvent); +} + + + + + + + + +/** + * @fn void GH3X2X_AFE_SendRegPackage(STGH3X2X_AFEReg* GH3X2X_AFE_reg_list, GU16 reg_list_len) + * + * @brief send register package (for initialize GH3X2X_AFE chip) + * + * @attention + * + * @param[in] GH3X2X_AFE_reg_list reg list that will be written to GH3X2X_AFE + * @param[in] reg_list_len reg count that contained in reg list + * @param[out] None + * + * @return None + */ +void GH3X2X_AFE_SendRegPackage(STGH3X2X_AFEReg* GH3X2X_AFE_reg_list, GU16 reg_list_len) +{ + GU16 luwIndex = 0; + + if ((GH3X2X_AFE_reg_list != NULL) && (reg_list_len > 0)) + { + for (luwIndex = 0; luwIndex < reg_list_len; luwIndex++) + { + if (GH3X2X_AFE_REG_IS_VALID(GH3X2X_AFE_reg_list->usRegAddr)) + { + GH3X2X_AFE_WRITE_REG(GH3X2X_AFE_reg_list->usRegAddr, GH3X2X_AFE_reg_list->usRegData); + } + GH3X2X_AFE_reg_list++; + } + } + + if(GH3X2X_AFE_PRO_TYPE == GH3X2X_AFE_PRO_BY_POLLING) + { + //int pin should not action when poling mode + GH3X2X_AFE_WRITE_REG(GH3X2X_AFE_REG_INT_EVENT_EN_ADDR, 0); + } + +} + + + +/** + * @fn GS8 GH3X2X_HardReset(void) + * + * @brief Gh3x2x softreset via i2c/spi, can read&write reg with gh3x2x after reset + * + * @attention None + * + * @param[in] None + * @param[out] None + * + * @return None + * @retval #GH3X2X_RET_OK return successfully + * @retval #GH3X2X_RET_GENERIC_ERROR reset pin control function not register + */ +void GH3X2X_AFE_Reset(void) +{ + GH3X2X_AFE_ClearEvent(0xFFFF); + #if(GH3X2X_AFE_RESET_TYPE == GH3X2X_AFE_RESET_HARDWARE) + hal_gh3x2x_afe_reset_pin_ctrl(0); + hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_HARD_RESET_DELAY_X_US); + hal_gh3x2x_afe_reset_pin_ctrl(1); + #else + GH3X2X_AFE_SEND_CMD(GH3X2X_AFE_CMD_RESET); + #endif + hal_gh3x2x_afe_DelayMs(10); +} + + + +/** + * @fn GS8 GH3X2X_CommunicateConfirm(void) + * + * @brief Communication operation interface confirm + * + * @attention None + * + * @param[in] None + * @param[out] None + * + * @return None + */ +void GH3X2X_AFE_CommunicateConfirm(void) +{ + GU16 uchReadData; + GU16 uchWriteData; + + if (GH3X2X_AFE_READ_REG(GH3X2X_AFE_REG_CHIP_READY_CODE_REG_ADDR) == 0xAA55) + { + uchReadData = GH3X2X_AFE_READ_REG(GH3X2X_AFE_REG_SLOT_TMR0_REG_ADDR); + GH3X2X_INFO_LOG("slot_time0 reg = %d\r\n", (int)uchReadData); + uchWriteData = ~uchReadData; + GH3X2X_AFE_WRITE_REG(GH3X2X_AFE_REG_SLOT_TMR0_REG_ADDR, uchWriteData); + uchReadData = GH3X2X_AFE_READ_REG(GH3X2X_AFE_REG_SLOT_TMR0_REG_ADDR); + GH3X2X_INFO_LOG("slot_time0 reg = %d\r\n", (int)uchReadData); + if (uchWriteData == uchReadData) + { + uchWriteData = ~uchReadData; + GH3X2X_AFE_WRITE_REG(GH3X2X_AFE_REG_SLOT_TMR0_REG_ADDR, uchWriteData); + } + else + { + GH3X2X_INFO_LOG("[%s]read fail or write fail!!! \r\n", __FUNCTION__); + while(1); + } + } + else + { + GH3X2X_INFO_LOG("[%s]ready code reg is error !!! \r\n", __FUNCTION__); + while(1); + } + + GH3X2X_INFO_LOG("[%s]Comunication confirm ok. \r\n", __FUNCTION__); + + + + +} + + + + + + + +/*********************************************** init function*******************************************/ + +/** + * @fn void GH3X2X_AFE_Init(void) + * + * @brief init GH3X2X_AFE chip + * + * @attention + * + * @param[in] None + * @param[out] None + * + * @return None + */ +void GH3X2X_AFE_Init(void) +{ + /* Step 1: init communicate interface. */ + #if(GH3X2X_AFE_COM_INTERFACE_TYPE == GH3X2X_AFE_COM_INTERFACE_SPI) + hal_gh3x2x_afe_spi_init(); + #else + hal_gh3x2x_afe_i2c_init(); + #endif + + /* Step 2: init interupt pin */ + #if(GH3X2X_AFE_PRO_TYPE == GH3X2X_AFE_PRO_BY_INT) + hal_gh3x2x_afe_int_init(); + #endif + + + /* Step 3: Reset GH3X2X_AFE chip */ + #if(GH3X2X_AFE_RESET_TYPE == GH3X2X_AFE_RESET_HARDWARE) + hal_gh3x2x_afe_reset_pin_init(); + #endif + GH3X2X_AFE_Reset(); + + /* Step 4: Check conmunication and chip id is ok or not */ + GH3X2X_AFE_CommunicateConfirm(); + GH3X2X_AFE_CheckChipId(); + GH3X2X_AFE_CheckEfuseCrc(); + + + /* Step 5: Init GH3X2X_AFE chip */ + GH3X2X_AFE_SendRegPackage(GH3X2X_AFE_reg_list, GH3X2X_AFE_reg_list_len); + + /* Step 6: agc module reset and set parm*/ + GH3X2X_LedAgcReset(); + GH3X2X_DemoLedAgcPramConfig(); + //GH3X2X_LedAgcPramWrite(); + + /* Step 7: enter low power mode */ + GH3X2X_AFE_EnterLowPowerMode(); + +} + +/*********************************************** sample control handle function*******************************************/ + +/** + * @fn void GH3X2X_AFE_StartSampling(GU8 SlotCfgEnable) + * + * @brief start sample + * + * @attention + * + * @param[in] SlotCfgEnable slot enable bit bit0 control slot0, bit1 control slot1, bit2 control slot2... + * @param[out] None + * + * @return None + */ +void GH3X2X_AFE_StartSampling(GU8 SlotCfgEnable) +{ + GH3X2X_AFE_ExitLowPowerMode(); + + //agc init + GH3X2X_LedAgcInit(g_pstGh3x2xAgcInfo); + + //write slot enable + GH3X2X_AFE_WRITE_REG(GH3X2X_AFE_REG_SLOT_EN_ADDR, (GU16)SlotCfgEnable); + //start sample + GH3X2X_AFE_WriteRegBitField(GH3X2X_AFE_REG_START_ADDR,GH3X2X_AFE_REG_START_LSB,GH3X2X_AFE_REG_START_MSB,1); + + GH3X2X_AFE_EnterLowPowerMode(); +} + +/** + * @fn void GH3X2X_AFE_StopSampling(void) + * + * @brief stop sample + * + * @attention + * + * @param[in] None + * @param[out] None + * + * @return None + */ +void GH3X2X_AFE_StopSampling(void) +{ + GH3X2X_AFE_ExitLowPowerMode(); + + //stop sample + GH3X2X_AFE_WriteRegBitField(GH3X2X_AFE_REG_START_ADDR,GH3X2X_AFE_REG_START_LSB,GH3X2X_AFE_REG_START_MSB,0); + + GH3X2X_AFE_EnterLowPowerMode(); +} + +/** + * @fn void GH3X2X_AFE_SwitchSlot(GU8 SlotCfgEnable) + * + * @brief switch sample slot. + * + * @attention this function can only be used during sampling, after call GH3X2X_AFE_StartSampling + * + * @param[in] SlotCfgEnable slot enable bit bit0 control slot0, bit1 control slot1, bit2 control slot2... + * @param[out] None + * + * @return None + */ +void GH3X2X_AFE_SwitchSlot(GU8 SlotCfgEnable) +{ + GH3X2X_AFE_ExitLowPowerMode(); + + //write slot enable + GH3X2X_AFE_WRITE_REG(GH3X2X_AFE_REG_SLOT_EN_ADDR, (GU16)SlotCfgEnable); + + GH3X2X_AFE_EnterLowPowerMode(); +} + +/********************************* interrupt handle:fifo read and analysis ***************************/ +#define GH3X2X_AFE_READ_FIFO_BUF_LEN (800) +GU32 GH3X2X_AFE_ReadFifoBuffer[(GU16)GH3X2X_AFE_READ_FIFO_BUF_LEN]; + +/* + FIFO rawdata decode +*/ +typedef struct +{ + GU32 uiAdcCode; //sampling rawdata of ADC + GU8 ubSlotNo; //slot number + GU8 ubAdcNo; //adc number + GU8 ubFlagLedAdjIsAgc_EcgRecover; //adj flag of ppg data or fast recover flag of ecg data + GU8 ubFlagLedAdjAgcUp; //adj up flag of ppg data +}StFifoDataInformation; + +/** + * @fn GU32 EndienRev32(GU32 luiTempData) + * + * @brief reverse data endien + * + * @attention + * + * @param[in] luiTempData input data + * @param[out] None + * + * @return output data + */ +static GU32 EndienRev32(GU32 luiTempData) +{ + GU8 *lpubIn; + GU8 *lpubOut; + + GU32 luiOutData; + + lpubIn = (GU8 *)(&luiTempData); + lpubOut = (GU8 *)(&luiOutData); + + for(GU8 i = 0; i < 4; i ++) + { + lpubOut[i] = lpubIn[3 - i]; + } + + return luiOutData; +} + +void GH3X2X_UpdateAgcInfo(void) +{ + GH3X2X_Memcpy(g_pstGh3x2xAgcInfo->uchTiaGainRecord, g_pstGh3x2xAgcInfo->uchTiaGainAfterSoftAgc, sizeof(g_pstGh3x2xAgcInfo->uchTiaGainRecord)); + GH3X2X_Memcpy(g_pstGh3x2xAgcInfo->uchDrvCurrentRecord, g_pstGh3x2xAgcInfo->uchDrvCurrentAfterSoftAgc, sizeof(g_pstGh3x2xAgcInfo->uchDrvCurrentRecord)); + + +} + +void GH3X2X_RecordAgcInfo(void) +{ + GU16 usDrv0CurRegData = 0; + GU16 usDrv0CurRegAddr = 0; + GU16 usDrv1CurRegData = 0; + GU16 usDrv1CurRegAddr = 0; + GU16 uchTIAData = 0; + + // record TIA + for (GU8 uchSlotIndex = 0; uchSlotIndex < 8; uchSlotIndex++) + { + uchTIAData = GH3X2X_AFE_READ_REG(0x0112 + (uchSlotIndex * 0x001C)); + + for (GU8 nAdcCnt = 0; nAdcCnt < 4; nAdcCnt++) + { + uchTIAData = (GU8)(((uchTIAData) >> (4 * nAdcCnt)) & 0x000F); + g_pstGh3x2xAgcInfo->uchTiaGainAfterSoftAgc[uchSlotIndex*4 + nAdcCnt] = uchTIAData; + } + } + + //Record Drv + usDrv0CurRegAddr = 0x011E; + usDrv1CurRegAddr = 0x0120; + for (GU8 uchSlotIndexCnt = 0; uchSlotIndexCnt < 8; uchSlotIndexCnt++) + { + usDrv0CurRegData = (GH3X2X_AFE_READ_REG(usDrv0CurRegAddr + (uchSlotIndexCnt * 0x001C)) & 0xFF); + usDrv1CurRegData = (GH3X2X_AFE_READ_REG(usDrv1CurRegAddr + (uchSlotIndexCnt * 0x001C)) & 0xFF); + g_pstGh3x2xAgcInfo->uchDrvCurrentAfterSoftAgc[uchSlotIndexCnt] = (GU16)(usDrv0CurRegData << 0x0); + g_pstGh3x2xAgcInfo->uchDrvCurrentAfterSoftAgc[uchSlotIndexCnt] |= (GU16)(usDrv1CurRegData << 0x0); + } +} + +/** + * @fn void GH3X2X_AFE_FifoDataAnalysis(GU16 luwFifoDataCnt) + * + * @brief analysis fifo data + * + * @attention + * + * @param[in] luwFifoDataCnt the number of rawdata + * @param[out] None + * + * @return None + */ +void GH3X2X_AFE_FifoDataAnalysis(GU16 luwFifoDataCnt) +{ + StFifoDataInformation stTempFifoInfo = {0}; + GU16 luwFifoCnt = 0; + + GU32 luiTempFifoData = 0; + + GH3X2X_INFO_LOG("Received rawdata sample num = %d \r\n", (int)luwFifoDataCnt); + + for(luwFifoCnt = 0; luwFifoCnt < luwFifoDataCnt; luwFifoCnt++) + { + luiTempFifoData = EndienRev32(GH3X2X_AFE_ReadFifoBuffer[luwFifoCnt]); //big endien -> little endien + + stTempFifoInfo.uiAdcCode = ((luiTempFifoData >> 0) & 0x00FFFFFF); + stTempFifoInfo.ubSlotNo = ((luiTempFifoData >> 29) & 0x00000007); + stTempFifoInfo.ubAdcNo = ((luiTempFifoData >> 27) & 0x00000003); + stTempFifoInfo.ubFlagLedAdjIsAgc_EcgRecover = ((luiTempFifoData >> 26) & 0x00000001); + stTempFifoInfo.ubFlagLedAdjAgcUp = ((luiTempFifoData >> 25) & 0x00000001); + #if GH3X2X_ADT_FUNC_ENABLE + if(stTempFifoInfo.ubSlotNo == GH3X2X_ADT_SLOT_NUM && stTempFifoInfo.ubAdcNo == GH3X2X_ADT_ADC_NUM) + { + EMWearStatus emWearStatus; + GH3x2xAdtAlgoExe(&stTempFifoInfo.uiAdcCode,&emWearStatus); + } + #endif + GH3X2X_INFO_LOG("Received rawdata:slot:%d,adc:%d,data:%d\r\n", stTempFifoInfo.ubSlotNo, stTempFifoInfo.ubAdcNo,stTempFifoInfo.uiAdcCode); + //GH3X2X_INFO_LOG("drv = %d, g0 = %d,g1 = %d,g2 = %d,g0 = %d\r\n",(int)g_pstGh3x2xAgcInfo->uchDrvCurrentRecord[0],(int)g_pstGh3x2xAgcInfo->uchTiaGainRecord[0],(int)g_pstGh3x2xAgcInfo->uchTiaGainRecord[1],g_pstGh3x2xAgcInfo->uchTiaGainRecord[2],g_pstGh3x2xAgcInfo->uchTiaGainRecord[3]); + + + + /******************************** add your fifo date process code******************************/ + //you can combine frame rawdata according to stTempFifoInfo + //and then excute algorithm calculate + + + } +} + + +/** + * @fn void GH3X2X_AFE_ChipPro(void) + * + * @brief interrupt handle function + * + * @attention + * + * @param[in] None + * @param[out] None + * + * @return None + */ +void GH3X2X_AFE_ChipPro(void) +{ + GU16 luwGH3X2X_AFEFifoLen = 0; + GU16 luwGotEvent = 0; + + +#if (GH3X2X_AFE_PRO_TYPE == GH3X2X_AFE_PRO_BY_INT) + if(0 == g_uchGh3x2xAfeIntCallBackIsCalled) + { + GH3X2X_INFO_LOG("InterruptProcess:invalid call, do not process.\r\n"); + return; + } + g_uchGh3x2xAfeIntCallBackIsCalled = 0; + +#endif + + if (GH3X2X_AFE_GetNeedWakeUpGh3x2xFlag()) + { + GH3X2X_AFE_ExitLowPowerMode(); + } + + + luwGH3X2X_AFEFifoLen = 0; + + //read event + luwGotEvent = GH3X2X_AFE_READ_REG(GH3X2X_AFE_REG_INT_EVENT_ADDR); + GH3X2X_INFO_LOG("Received irq = %d \r\n", (int)luwGotEvent); + //clear event + GH3X2X_AFE_WRITE_REG(GH3X2X_AFE_REG_INT_EVENT_ADDR,luwGotEvent); //clear event + + //read fifo use + luwGH3X2X_AFEFifoLen = GH3X2X_AFE_READ_REG(GH3X2X_AFE_REG_FIFO_USE_ADDR); + if(luwGH3X2X_AFEFifoLen > GH3X2X_AFE_READ_FIFO_BUF_LEN) + { + luwGH3X2X_AFEFifoLen = GH3X2X_AFE_READ_FIFO_BUF_LEN; + } + + // read fifo data + if(0 != luwGH3X2X_AFEFifoLen) + { + GH3X2X_AFE_READ_FIFO((GU8 *)GH3X2X_AFE_ReadFifoBuffer,luwGH3X2X_AFEFifoLen * 4); + } + + + //ECG_LEAD OFF DET & resample + #if GH3X2X_ECG_FUNC_ENABLE + + GU16 luwGH3X2X_AFEFifoByteLen = luwGH3X2X_AFEFifoLen * 4; + luwGotEvent &= (~GH3X2X_AFE_EVENT_BIT(GH3X2X_AFE_EVENT_LEAD_OFF)); + + GU8 lubRet = GH3X2X_LeadOffDetect((GU8 *)GH3X2X_AFE_ReadFifoBuffer, &luwGH3X2X_AFEFifoByteLen, 0); + if(lubRet != 0) + { + luwGotEvent |= (GH3X2X_AFE_EVENT_BIT(GH3X2X_AFE_EVENT_LEAD_OFF)); + } + + GH3X2X_INFO_LOG("before Rs luwGH3X2X_AFEFifoLen = %d\r\n",luwGH3X2X_AFEFifoLen); + GH3X2X_AFE_EcgRsHandle((GU8 *)GH3X2X_AFE_ReadFifoBuffer, &luwGH3X2X_AFEFifoByteLen,0,GH3X2X_ECG_DOWN_FS); + luwGH3X2X_AFEFifoLen = luwGH3X2X_AFEFifoByteLen/4; + GH3X2X_INFO_LOG("after Rs luwGH3X2X_AFEFifoLen = %d\r\n",luwGH3X2X_AFEFifoLen); + #endif + + if(0 != (luwGotEvent & GH3X2X_AFE_EVENT_BIT(GH3X2X_AFE_EVENT_WEAR_ON))) + { + GH3X2X_INFO_LOG("Received wear on event\r\n"); + } + + if(0 != (luwGotEvent & GH3X2X_AFE_EVENT_BIT(GH3X2X_AFE_EVENT_WEAR_OFF))) + { + GH3X2X_INFO_LOG("Received wear off event\r\n"); + } + + if(0 != (luwGotEvent & GH3X2X_AFE_EVENT_BIT(GH3X2X_AFE_EVENT_LEAD_ON))) + { + GH3X2X_INFO_LOG("Received lead on event\r\n"); + GH3X2X_AFE_Leadon_hook(); + } + + if(0 != (luwGotEvent & GH3X2X_AFE_EVENT_BIT(GH3X2X_AFE_EVENT_LEAD_OFF))) + { + GH3X2X_INFO_LOG("Received lead off event\r\n"); + GH3X2X_AFE_Leadoff_hook(); + + } + + if(0 != (luwGotEvent & GH3X2X_AFE_EVENT_BIT(GH3X2X_AFE_EVENT_LED_TUNE_FAIL))) + { + GH3X2X_INFO_LOG("Received tune fail event\r\n"); + } + + if(0 != (luwGotEvent & GH3X2X_AFE_EVENT_BIT(GH3X2X_AFE_EVENT_LED_TUNE_DONE))) + { + GH3X2X_INFO_LOG("Received tune done event\r\n"); + } + + + //you can add some code to adjust ppg sample parameter, such as led drv current GU16 usTempDrvCurrent; + + //GH3x2xSetPpgCtrlReg(GH3X2X_AFE_PPG_CTRL_REG_AGC_EN,1,0); + //GH3x2xSetPpgCtrlReg(GH3X2X_AFE_PPG_CTRL_REG_LED_CURRENT_DRV0,1,60); + //GH3X2X_INFO_LOG("change slot0 drv0 current.\r\n"); + //GH3X2X_INFO_LOG("Get slot0 drv0 current = %d.\r\n",(int)GH3x2xGetPpgCtrlReg(GH3X2X_AFE_PPG_CTRL_REG_LED_CURRENT_DRV0,0)); + + GH3X2X_LedAgcProcess((GU8 *)GH3X2X_AFE_ReadFifoBuffer, luwGH3X2X_AFEFifoLen * 4, g_pstGh3x2xAgcInfo); + + GH3X2X_AFE_EnterLowPowerMode(); + + + if(0 != luwGH3X2X_AFEFifoLen) + { + GH3X2X_AFE_FifoDataAnalysis(luwGH3X2X_AFEFifoLen); + } +} + +const GU16 g_usGH3x2xTiaGainR[] = +{ + 10, + 25, + 50, + 75, + 100, + 250, + 500, + 750, + 1000, + 1250, + 1500, + 1750, + 2000, +}; + +const GU16 g_usGH3x2xSlotRegBase[8] = +{ + 0x0100, + 0x011C, + 0x0138, + 0x0154, + 0x0170, + 0x018C, + 0x01A8, + 0x01C4, +}; + + +const STGh3x2xAgcReg g_pstGH3x2xAgcReg[] = +{ + {0x10, 9, 8}, //0: agc en + {0x22, 7, 0}, //1: led current up limit + {0x22, 15, 8}, //2: led current down limit + {0x1E, 7, 0}, //3: led current drv0 + {0x20, 7, 0}, //4: led current drv1 + {0x12, 3, 0}, //5: rx0 tia gain + {0x12, 7, 4}, //6: rx1 tia gain + {0x12, 11, 8}, //7: rx2 tia gain + {0x12, 15, 12}, //8: rx3 tia gain + {0x10, 7,6}, //9: agc src + {0x1A, 1,0}, //10: rx0 bg cancel + {0x1A, 3,2}, //11: rx1 bg cancel + {0x1A, 5,4}, //12: rx2 bg cancel + {0x1A, 7,6}, //13: rx2 bg cancel + {0x0A, 15,8}, //14: sr mulipliper + {0x0A, 5,1}, //15: ecg en& rx0~rx1 en +}; + +void GH3x2x_AFESetAgcReg(GU8 uchAgcReg, GU8 uchSlot, GU16 usValue) +{ + GH3X2X_AFE_WriteRegBitField(g_usGH3x2xSlotRegBase[uchSlot] + g_pstGH3x2xAgcReg[uchAgcReg].uchAddrOffset, g_pstGH3x2xAgcReg[uchAgcReg].uchLsb, g_pstGH3x2xAgcReg[uchAgcReg].uchMsb, usValue); +} + +GU16 GH3x2x_AFEGetAgcReg(GU8 uchAgcReg, GU8 uchSlot) +{ + return GH3X2X_AFE_ReadRegBitField(g_usGH3x2xSlotRegBase[uchSlot] + g_pstGH3x2xAgcReg[uchAgcReg].uchAddrOffset, g_pstGH3x2xAgcReg[uchAgcReg].uchLsb, g_pstGH3x2xAgcReg[uchAgcReg].uchMsb); +} + +/** + * @fn void GH3X2X_AFE_GetEfuseCode(GS8* pchLedDrvEcode,GS8* pchTiaEcode,GS8* pchEcgEcode) + * + * @brief: Get Efuse Code + * + * @attention + * + * @param[in] + * @param[out] pchLedDrvEcode + * pchTiaEcode + * pchEcgEcode + * @return : none + */ +void GH3X2X_AFE_GetEfuseCode(GS8* pchLedDrvEcode,GS8* pchTiaEcode,GS8* pchEcgEcode) +{ + GU16 usRegVal; + GH3X2X_AFE_WRITE_REG(GH3X2X_EFUSE_CTRL_CMD_REG_ADDR,0x0020); + GH3X2X_AFE_WRITE_REG(GH3X2X_EFUSE_CTRL_CMD_REG_ADDR,0x0030); + + while(0 == GH3X2X_AFE_ReadRegBitField(GH3X2X_EFUSE_CTRL_STATUS_REG_ADDR,0,0)); + usRegVal = GH3X2X_AFE_READ_REG(GH3X2X_EFUSE_CTRL_RDATA_1_REG_ADDR); + *pchLedDrvEcode = (GS8)GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(usRegVal); + *pchTiaEcode = (GS8)GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(usRegVal); + *pchEcgEcode = (GS8)GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(GH3X2X_AFE_READ_REG(GH3X2X_EFUSE_CTRL_RDATA_2_REG_ADDR)); +} + + +/** + * @fn GU16 GH3X2X_AFE_SetLedDrvCurrent(GU8 uchCurrent_mA,GU8 uchDrvNum, GS8 chECODE) + * + * @brief: led drv calibration + * + * @attention + * + * @param[in] GU8 uchCurrent_mA:led drv current, unit: mA + GU8 uchDrvNum :led Drv num,0 or 1 + GS8 chECODE :Led Drv Ecode from efuse + * @param[out] None + * + * @return : Drv code + */ +GU16 GH3X2X_AFE_SetLedDrvCurrent(GU8 uchCurrent_mA, GU8 uchDrvNum, GS8 chECODE) +{ + GF32 fEr; + GF32 fY; + GU8 uchN; + GU16 usDrvCode; + GU16 usDrvScale; + + if(uchDrvNum == 0) + { + fY = 0.1; + usDrvScale = GH3X2X_AFE_ReadRegBitField(GH3X2X_LED_DRV_AD_REG_REG_ADDR,GH3X2X_DRV0_FULL_SCAL_CURRENT_LSB,GH3X2X_DRV0_FULL_SCAL_CURRENT_MSB); + } + else + { + fY = 0.01; + usDrvScale = GH3X2X_AFE_ReadRegBitField(GH3X2X_LED_DRV_AD_REG_REG_ADDR,GH3X2X_DRV1_FULL_SCAL_CURRENT_LSB,GH3X2X_DRV1_FULL_SCAL_CURRENT_MSB); + + } + uchN = 1 << (3 - usDrvScale); + + fEr = (GF32)((GF32)chECODE/256) + 1.0f; + usDrvCode = (GU16)(0.5f+((GF32)fEr*255*(GF32)uchN)/(0.225f/((GF32)uchCurrent_mA/1000) - fY)); + + return usDrvCode; +} + + +/** + * @fn GF32 GH3X2X_AFE_GetLedDrvCurrent(GU16 usDrvCode, GU8 uchDrvNum, GS8 chECODE) + * + * @brief: get led drv calibration current + * + * @attention + * + * @param[in] GU16 usDrvCode :led drv code + GU8 uchDrvNum :led Drv num,0 or 1 + GS8 chECODE :Led Drv Ecode from efuse + * @param[out] None + * + * @return : calibration current + */ + +GF32 GH3X2X_AFE_GetLedDrvCurrent(GU16 usDrvCode, GU8 uchDrvNum, GS8 chECODE) +{ + GF32 fEr; + GF32 fY; + GU8 uchN; + GF32 fDrvCurrent; + GU16 usDrvScale; + + if(uchDrvNum == 0) + { + fY = 0.1; + usDrvScale = GH3X2X_AFE_ReadRegBitField(GH3X2X_LED_DRV_AD_REG_REG_ADDR,GH3X2X_DRV0_FULL_SCAL_CURRENT_LSB,GH3X2X_DRV0_FULL_SCAL_CURRENT_MSB); + } + else + { + fY = 0.01; + usDrvScale = GH3X2X_AFE_ReadRegBitField(GH3X2X_LED_DRV_AD_REG_REG_ADDR,GH3X2X_DRV1_FULL_SCAL_CURRENT_LSB,GH3X2X_DRV1_FULL_SCAL_CURRENT_MSB); + } + uchN = 1 << (3 - usDrvScale); + fEr = (GF32)((GF32)chECODE/256) + 1; + fDrvCurrent = 0.225f/(fEr*255*(GF32)uchN/(GF32)usDrvCode + fY); + return fDrvCurrent*1000; + +} + +/** + * @fn GF32 GH3X2X_AFE_GetTiaCalCode(GS8 chECODE) + + * + * @brief: Get Tia Calibration Code + * + * @attention + * + * @param[in] GS8 chECODE :Tia Ecode from efuse + * @param[out] None + * + * @return : calibration Code + */ +GF32 GH3X2X_AFE_GetTiaCalCode(GS8 chECODE) +{ + GF32 fEr; + fEr = (GF32)((GF32)chECODE/512) + 1; + return fEr; +} + +/** + * @fn GF32 GH3X2X_AFE_GetEcgCalCode(GS8 chECODE) + + * + * @brief: Get ECG Calibration Code + * + * @attention + * + * @param[in] GS8 chECODE :ECG Ecode from efuse + * @param[out] None + * + * @return : calibration Code + */ +GF32 GH3X2X_AFE_GetEcgCalCode(GS8 chECODE) +{ + GF32 fEr; + fEr = (GF32)((GF32)chECODE/1024) + 1; + return fEr; +} + + +/** + * @fn GCHAR *GH3X2X_GetAfeLibVersion(void) + * + * @brief Get afe driver version + * + * @attention None + * + * @param[in] None + * @param[out] None + * + * @return library version string + */ +GCHAR *GH3X2X_GetAfeLibVersion(void) +{ + return (GCHAR *)GH3X2X_VERSION_STRING; +} + + +GU8 GH3X2X_AFE_GetChipId(void) +{ + return (GU8)GH3X2X_AFE_ReadRegBitField(GH3X2X_WHO_AM_I_REG_ADDR,GH3X2X_WHO_AM_I_LSB,GH3X2X_WHO_AM_I_MSB); +} + +GS8 GH3X2X_AFE_CheckChipId(void) +{ + GS8 chRet = GH3X2X_AFE_RET_OK; + GS8 chipd_id = GH3X2X_AFE_GetChipId(); + if(GH3X2X_CHIP_ID != chipd_id) + { + GH3X2X_INFO_LOG("wrong chip id!!\r\n"); + chRet = GH3X2X_AFE_RET_GENERIC_ERROR; + } + else + { + GH3X2X_INFO_LOG("check chip id success!! 0x%x\r\n",chipd_id); + } + return chRet; +} + +/** + * @fn void *GH3X2X_Memcpy(void *pDest, const void *pSrc, GU32 unByteSize) + * + * @brief memcpy() Re-implementation + * + * @attention None + * + * @param[in] pSrc pointer to source buffer + * @param[in] unByteSize source buffer byte size + * @param[out] pDest pointer to destination buffer + * + * @return pointer to destination buffer + */ +void *GH3X2X_Memcpy(void *pDest, const void *pSrc, GU32 unByteSize) +{ + GU8 *puchSrc = (GU8 *)pSrc; + GU8 *puchDest = (GU8 *)pDest; + GU32 unAlign = ((GU32)puchDest | (GU32)puchSrc) << 30; + + if ((pDest == GH3X2X_PTR_NULL) || (pSrc == GH3X2X_PTR_NULL) || (0 == unByteSize)) + { + return GH3X2X_PTR_NULL; + } + if (unAlign == 0) // if align 4 + { + while (unByteSize >= 4) + { + *(GU32 *)puchDest = *(GU32 *)puchSrc; + puchSrc += 4; + puchDest += 4; + unByteSize -= 4; + } + } + while (unByteSize) // bytes + { + *(GU8 *)puchDest = *(GU8 *)puchSrc; + puchSrc++; + puchDest++; + unByteSize--; + } + return pDest; +} + +/** + * @fn void *GH3X2X_Memset(void* pDest, GCHAR chVal, GU32 unByteSize) + * + * @brief memset() Re-implementation + * + * @attention None + * + * @param[in] chVal char val for set + * @param[in] unByteSize source buffer len + * @param[out] pDest pointer to destination buffer + * + * @return pointer to destination buffer + */ +void *GH3X2X_Memset(void* pDest, GCHAR chVal, GU32 unByteSize) +{ + GU8 *puchDest = (GU8 *)pDest; + GU32 unAlign = ((GU32)puchDest) << 30; + GU32 unWordVal = GH3X2X_AFE_MAKEUP_DWORD(chVal, chVal, chVal, chVal); + + if (pDest == GH3X2X_PTR_NULL) + { + return GH3X2X_PTR_NULL; + } + if (unAlign == 0) // if align 4 + { + while (unByteSize >= 4) + { + *(GU32 *)puchDest = unWordVal; + puchDest += 4; + unByteSize -= 4; + } + } + while (unByteSize) // bytes + { + *(GU8 *)puchDest = (GU8)chVal; + puchDest++; + unByteSize--; + } + return pDest; +} + +GU8 _crc8(GU8 *ptr,GS32 len) +{ + GS32 i; + GU8 crc = 0x00; + while(len--) + { + crc ^= *ptr++; + for(i=8;i>0;--i) + { + if(crc&0x80) + { + crc = (crc<<1)^0x31; + } + else + { + crc = (crc<<1); + } + crc = crc & 0xff; + } + } + return (GU8)(crc); +} + +void GH3X2X_AFE_LoadEfuse(GU8* puchEfuseBuffer,GU16 EfuseByteLen) +{ + if(EfuseByteLen < 24) + { + GH3X2X_INFO_LOG("EfuseByteLen is too short!!\r\n"); + return; + } + + GU16 usRegVal; + GH3X2X_AFE_WriteRegBitField(GH3X2X_EFUSE_CTRL_CMD_REG_ADDR,GH3X2X_EFUSE_MODE_LSB,GH3X2X_EFUSE_MODE_MSB,0); + GH3X2X_AFE_WriteRegBitField(GH3X2X_EFUSE_CTRL_CMD_REG_ADDR,GH3X2X_EFUSE_CHOOSE_LSB,GH3X2X_EFUSE_CHOOSE_MSB,0); + GH3X2X_AFE_WriteRegBitField(GH3X2X_EFUSE_CTRL_CMD_REG_ADDR,GH3X2X_EFUSE_CLK_EN_LSB,GH3X2X_EFUSE_CLK_EN_MSB,1); + GH3X2X_AFE_WriteRegBitField(GH3X2X_EFUSE_CTRL_CMD_REG_ADDR,GH3X2X_EFUSE_START_LSB,GH3X2X_EFUSE_START_MSB,1); + while(0 == GH3X2X_AFE_ReadRegBitField(GH3X2X_EFUSE_CTRL_STATUS_REG_ADDR,0,0)); + for(GU8 i = 0; i < 4; i++) + { + usRegVal = GH3X2X_AFE_READ_REG(GH3X2X_EFUSE_CTRL_RDATA_0_REG_ADDR + 2 * i); + puchEfuseBuffer[2*i] = (GU8)GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(usRegVal); + puchEfuseBuffer[2*i + 1] = (GU8)GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(usRegVal); + } + + GH3X2X_AFE_WriteRegBitField(GH3X2X_EFUSE_CTRL_CMD_REG_ADDR,GH3X2X_EFUSE_CHOOSE_LSB,GH3X2X_EFUSE_CHOOSE_MSB,1); + GH3X2X_AFE_WriteRegBitField(GH3X2X_EFUSE_CTRL_CMD_REG_ADDR,GH3X2X_EFUSE_START_LSB,GH3X2X_EFUSE_START_MSB,1); + while(0 == GH3X2X_AFE_ReadRegBitField(GH3X2X_EFUSE_CTRL_STATUS_REG_ADDR,0,0)); + for(GU8 i = 0; i < 4; i++) + { + usRegVal = GH3X2X_AFE_READ_REG(GH3X2X_EFUSE_CTRL_RDATA_0_REG_ADDR + 2 * i); + puchEfuseBuffer[8 + 2*i] = (GU8)GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(usRegVal); + puchEfuseBuffer[8 + 2*i + 1] = (GU8)GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(usRegVal); + } + + GH3X2X_AFE_WriteRegBitField(GH3X2X_EFUSE_CTRL_CMD_REG_ADDR,GH3X2X_EFUSE_CHOOSE_LSB,GH3X2X_EFUSE_CHOOSE_MSB,2); + GH3X2X_AFE_WriteRegBitField(GH3X2X_EFUSE_CTRL_CMD_REG_ADDR,GH3X2X_EFUSE_START_LSB,GH3X2X_EFUSE_START_MSB,1); + while(0 == GH3X2X_AFE_ReadRegBitField(GH3X2X_EFUSE_CTRL_STATUS_REG_ADDR,0,0)); + for(GU8 i = 0; i < 4; i++) + { + usRegVal = GH3X2X_AFE_READ_REG(GH3X2X_EFUSE_CTRL_RDATA_0_REG_ADDR + 2 * i); + puchEfuseBuffer[16 + 2*i] = (GU8)GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(usRegVal); + puchEfuseBuffer[16 + 2*i + 1] = (GU8)GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(usRegVal); + } + + +} + +GS8 GH3X2X_AFE_CheckEfuseCrc(void) +{ + GS8 chRet = GH3X2X_AFE_RET_OK; + GU8 uchEfuseBuffArr[24]; + GH3X2X_AFE_LoadEfuse(uchEfuseBuffArr,24); + GU8 uchCrcArr[3]; + uchCrcArr[0] = _crc8(uchEfuseBuffArr,7); + uchCrcArr[1] = _crc8((uchEfuseBuffArr + 8),3); + uchCrcArr[2] = _crc8((uchEfuseBuffArr + 12),10); + if(uchCrcArr[0] != uchEfuseBuffArr[7] || uchCrcArr[1] != uchEfuseBuffArr[11] ||uchCrcArr[2] != uchEfuseBuffArr[22]) + { + GH3X2X_INFO_LOG("Efuse crc error!!\r\n"); + chRet = GH3X2X_AFE_RET_GENERIC_ERROR; + } + return chRet; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_lead_off.c b/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_lead_off.c new file mode 100644 index 000000000..b1e628af0 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_lead_off.c @@ -0,0 +1,748 @@ +#include "gh3x2x_afe_ecg.h" +#include "gh3x2x_afe_demo.h" + +#define RESAMPLE_800HZ_TO_500HZ 0 +#define RESAMPLE_800HZ_TO_250HZ 0 +#define RESAMPLE_320HZ_TO_250HZ 1 +#define RESAMPLE_256HZ_TO_250HZ 0 + + +#if __SUPPORT_ECG_PPG_DOWNSAMP__ +#define RESAMPLE_400HZ_TO_250HZ 1 +#else +#define RESAMPLE_400HZ_TO_250HZ 0 +#endif + +#define GH3X2X_PPG_START_SLOT 1 +#define GH3X2X_ECG_START_SLOT 0 + +#define GH3X2X_AFE_GET_ECG_CHANNEL_MAP(slotNum) (((slotNum << 5) | (3 <<3)) &0xF8) +#define GH3X2X_AFE_GET_PPG_CHANNEL_MAP(slotNum) (((slotNum << 5) | (0 <<3)) &0xF8) + +STGh3x2xSoftLeadOffDetInfo g_pstGh3x2xSoftLeadOffDetInfoEntity[1]; +STGh3x2xRsInfo g_pstGh3x2xEcgRsInfoEntity[1]; +const GU8 g_uchGh3x2xEcgChnlNumLimit = 1; +STGh3x2xSoftLeadOffDetInfo * const g_pstGh3x2xSoftLeadOffDetInfo = g_pstGh3x2xSoftLeadOffDetInfoEntity; +STGh3x2xRsInfo * const g_pstGh3x2xEcgRsInfo = g_pstGh3x2xEcgRsInfoEntity; + + +#if __SUPPORT_ECG_PPG_DOWNSAMP__ +#define GH3X2X_PPG_DOWNSAMP_CHNL_NUM 1 +const GU32 g_uchPPGDownSampleChnlNumLimit = GH3X2X_PPG_DOWNSAMP_CHNL_NUM; +STGh3x2xRsInfo g_pstGh3x2xPPGRsInfoEntity[GH3X2X_PPG_DOWNSAMP_CHNL_NUM]; +STGh3x2xRsInfo * const g_pstGh3x2xPPGRsInfo = g_pstGh3x2xPPGRsInfoEntity; +#endif + +//Ecg sample rate from hardware +static GU16 g_usEcgInputFs = GH3X2X_ECG_FS; // ecg sample rate 800/320/256 +static GU16 g_usEcgOutputFs = GH3X2X_ECG_DOWN_FS; // ecg down sample rate 500/250 + +/// down sample lead module(ECG PPG) +static GU8 g_uchDownSampleModule = DOWNSAMPLE_ECG; + +#define ADCREF 1800 +#define ADC_OFFSET (1<<23) +#define PI 3.14159265 +#define ABS(x) ( (x)>0?(x):(-(x)) ) +#define AMP_NUM 5 +#define IQ_NUM 48 + +const int winCoef[IQ_NUM / 2] = { 0, 9580474, 38150933, 85201535, 149892663, 231069901, 327284639, 436819923, 557721094, 687830666, 824826833, 966264894, 1109620882, 1252336609, 1391865307, 1525717084, 1651503351, 1766979451, 1870084709, 1958979209, 2032076627, 2088072537, 2125967693, 2145085852}; +#define winAmpCoef 4082 +//unsigned char gscFlagFrPrev = 0; +GU32 g_nLeadOffDetIqAmpThr = 1500;//unit: uv +long long g_lLeadOffDetIqAmp; +long long g_lLeadOffDetIqAmpThrRaw; +long long g_lLeadOffDetIqAmpFrThrRaw; + +GU32 g_nLeadOffDetIqAmpDiffThr = 1000;//unit: uv +long long g_lLeadOffDetIqAmpDiff; +long long g_lLeadOffDetIqAmpDiffThrRaw; +long long g_lLeadOffDetIqAmpDiffFrThrRaw; + +int COND_VAL_VALID_TIME = 1; +GU32 g_nLeadOffDetValThr = 80;//unit: mv +int g_LeadOffDetValThrRaw; + +#define SHIFTBITS 30 + +#if RESAMPLE_800HZ_TO_500HZ + const int rsFirCoef_800_500hz[] = { 58200, 102435, 156130, 215460, 274735, 326585, 362380, 372790, 348645, 281870, 166550, 0, -216285, -475850, -766815, -1071825, -1368460, -1630170, -1827760, -1931325, -1912605, + -1747635, -1419445, -920670, -255820, 557070, 1485515, 2482735, 3488860, 4433375, 5238695, 5824850, 6114965, 6041350, 5551740, 4615280, 3227790, 1415785, -761100, -3209770, -5805610, -8396875, -10811545, -12866385, + -14377925, -15174745, -15110485, -14076620, -12014295, -8924190, -4873605, 0, 5489625, 11323885, 17176845, 22682405, 27452740, 31100030, 33260510, 33619540, 31936265, 28066360, 21981325, 13782945, 3711580, -7852615, + -20396185, -33286830, -45795550, -57125820, -66448630, -72941905, -75832375, -74437800, -68207360, -56757870, -39903755, -17678885, 9651270, 41588185, 77410100, 116192965, 156841955, 198132190, 238757000, 277381455, 312698655, 343486005, 368658785, 387318230, 398791740, 402663190 }; +#endif +#if RESAMPLE_800HZ_TO_250HZ + const int rsFirCoef_800_250hz[] = { -74905, -95385, -116975, -138740, -159540, -178080, -192900, -202440, -205060, -199120, -183040, -155365, -114830, -60455, 8370, 91845, 189655, 300920, 424150, 557225, 697345, 841065, 984315, 1122440, 1250290, 1362325, + 1452720, 1515555, 1544935, 1535220, 1481220, 1378385, 1223050, 1012615, 745780, 422705, 45175, -383265, -857210, -1369370, -1910565, -2469770, -3034240, -3589685, -4120510, -4610090, -5041145, -5396125, -5657660, -5809045, -5834740, -5720895, -5455890, + -5030825, -4440010, -3681420, -2757070, -1673325, -441140, 923805, 2401100, 3965690, 5588100, 7234765, 8868540, 10449275, 11934545, 13280495, 14442770, 15377525, 16042520, 16398240, 16409055, 16044325, 15279560, 14097430, 12488725, 10453225, 8000385, + 5149865, 1931900, -1612575, -5431990, -9464450, -13638290, -17872830, -22079425, -26162660, -30021820, -33552510, -36648435, -39203325, -41112955, -42277200, -42602135, -42002095, -40401670, -37737600, -33960495, -29036370, -22947970, -15695790, + -7298825, 2204995, 12758710, 24286615, 36694830, 49872305, 63692080, 78012930, 92681285, 107533410, 122397830, 137097950, 151454790, 165289835, 178427925, 190700125, 201946505, 212018845, 220783110, 228121755, 233935695, 238146055, 240695490, 241549195 }; +#endif + +#if RESAMPLE_400HZ_TO_250HZ +//const int rsFirCoef_250hz1[] = { 0,-24495,-56710,-95045,-136775,-178125,-214440,-240490,-250920,-240760,-205965,-144050,-54555,60475,196250,345190,497105,639650,759070,841160,872410,841285,739500,563245,314150,0,-365010,-760510,-1160685,-1535620,-1853070,-2080745,-2188790,-2152475,-1954770,-1588670,-1058960,-383360,407260,1269625,2149850,2986210,3712890,4264415,4580525,4611280,4321835,3696680,2742865,1491895,0,-1653335,-3368750,-5032125,-6521320,-7714135,-8497040,-8774130,-8475685,-7565610,-6047220,-3966715,-1413955,1479820,4547350,7593800,10407850,12774895,14491705,15381495,15308470,14190830,12011055,8822720,4752940,0,-5174080,-10455925,-15497715,-19937805,-23423930,-25637735,-26318950,-25287690,-22463185,-17877445,-11682610,-4150955,4332910,13287805,22159230,30349170,37251070,42288110,44952645,44844420,41705155,35447110,26173540,14189250,0,-15699840,-32051440,-48066690,-62673020,-74765800,-83265770,-87178475,-85652480,-78033065,-63908265,-43144325,-15908305,17323970,55775495,98391360,143876925,190749335,237400000,282164985,323399855,359555130,389248460,411329760,424935830,429531605}; +const int rsFirCoef_250hz2[] = {-20165,29190,117750,248970,420650,623445,839855,1044105,1203060,1278285,1229350,1018175,614220,0,-823490,-1832200,-2975865,-4177020,-5332555,-6318335,-6996880,-7227970,-6881615,-5852620,-4075600,-1539030,1703020,5523035,9717440,14010255,18063685,21495860,23905235,24900525,24134595,21339975,16363405,9196555,0,-10882185,-22919440,-35404830,-47478995,-58167535,-66430495,-71221570,-71553685,-66566985,-55594615,-38221750,-14333265,15853795,51776230,92531020,136902815,183411755,230379530,276010140,318480795,356037520,387089565,410296710,424643805,429497860,}; +#endif + +#if RESAMPLE_320HZ_TO_250HZ + const int rsFirCoef_320_250hz[] = {79095,936340,341760,-2712470,-2547785,4817105,8099190,-5170865,-17933790,0,30974265,15517780,-42765395,-45670380,44706790,92106715,-24021395,-152053275,-36768905,217784250,166596045,-277901355,-451953470,320248390,1667310365,2147483647,}; +#endif +#if RESAMPLE_256HZ_TO_250HZ + const int rsFirCoef_256_250hz[]={194000,77770,-331070,-632290,-254280,769680,1439880,622640,-1454740,-2779600,-1303600,2436730,4847325,2461115,-3753755,-7872475,-4310105,5424840,12120690,7126740,-7444180,-17902495,-11265025,9777230,25594875,17187555,-12359260,-35689230,-25526795,15096890,48893725,37213545,-17872685,-66356185,-53763065,20552645,90184745,77974330,-22995885,-124828195,-115908245,25065740,181561700,183974820,-26641130,-299102515,-347934030,27626950,749679370,1463910805,1761638120,}; +#endif + +GS32* rsFirCoef; +GS32* rsFirCoef1; + +STGh3x2xDownSampleCalParamInfo pstECGDownSampCalParamInfo[1]; +#if __SUPPORT_ECG_PPG_DOWNSAMP__ +STGh3x2xDownSampleCalParamInfo pstPPGDownSampCalParamInfo[1]; +#endif + +void GH3X2X_DownSampleMarcoIni(GU16 usEcgSampleRate) +{ + switch (g_usEcgInputFs) + { + case 800: + if( usEcgSampleRate == 500) + { + pstECGDownSampCalParamInfo->uchDownSampleType = DOWNSAMPLE_800HZ_TO_500HZ; + } + else + { + pstECGDownSampCalParamInfo->uchDownSampleType = DOWNSAMPLE_800HZ_TO_250HZ; + } + break; + case 320: + if( usEcgSampleRate == 250) + { + pstECGDownSampCalParamInfo->uchDownSampleType = DOWNSAMPLE_320HZ_TO_250HZ; + } + break; + case 256: + if( usEcgSampleRate == 250) + { + pstECGDownSampCalParamInfo->uchDownSampleType = DOWNSAMPLE_256HZ_TO_250HZ; + } + break; + default: // do nothing + break; + } + + // ppg downsample ini + #if __SUPPORT_ECG_PPG_DOWNSAMP__ + pstPPGDownSampCalParamInfo->uchDownSampleType = DOWNSAMPLE_400HZ_TO_250HZ; + #endif +} + +void RsFirResetSingle(GU8 uchChipIndex, GU8 uchMode) +{ + STGh3x2xRsInfo * pstRsInfo; + GU8 uchChnNum = 0; + #if __SUPPORT_ECG_PPG_DOWNSAMP__ + if(DOWNSAMPLE_PPG == uchMode) + { + pstRsInfo = g_pstGh3x2xPPGRsInfo; + uchChnNum = g_uchPPGDownSampleChnlNumLimit; + } + #endif + + if(DOWNSAMPLE_ECG == uchMode) + { + pstRsInfo = g_pstGh3x2xEcgRsInfo; + uchChnNum = uchChipIndex+1; + } + + for( GU8 i=0; iuchDownSampleType) + { + pstECGDownSampCalParamInfo->rsFirCoef= (GS32*)rsFirCoef_800_500hz; + pstECGDownSampCalParamInfo->uchRsFirOrder = 182; + pstECGDownSampCalParamInfo->uchRsI = 5; + pstECGDownSampCalParamInfo->uchRsD = 8; + pstECGDownSampCalParamInfo->uchRsEnable = 1; + } + #endif + } + else if(usEcgSampleRate == 250) + { + #if RESAMPLE_800HZ_TO_250HZ + if(DOWNSAMPLE_800HZ_TO_250HZ == pstECGDownSampCalParamInfo->uchDownSampleType) + { + pstECGDownSampCalParamInfo->rsFirCoef= (GS32*)rsFirCoef_800_250hz; + pstECGDownSampCalParamInfo->uchRsFirOrder = 250; + pstECGDownSampCalParamInfo->uchRsI = 5; + pstECGDownSampCalParamInfo->uchRsD = 16; + pstECGDownSampCalParamInfo->uchRsEnable = 1; + } + #endif + + #if RESAMPLE_320HZ_TO_250HZ + if(DOWNSAMPLE_320HZ_TO_250HZ == pstECGDownSampCalParamInfo->uchDownSampleType) + { + pstECGDownSampCalParamInfo->rsFirCoef= (GS32*)rsFirCoef_320_250hz; + pstECGDownSampCalParamInfo->uchRsFirOrder = 50; + pstECGDownSampCalParamInfo->uchRsI = 1; + pstECGDownSampCalParamInfo->uchRsD = 1; + pstECGDownSampCalParamInfo->uchRsEnable = 1; + pstECGDownSampCalParamInfo->ufStep = 128; + } + #endif + + #if RESAMPLE_256HZ_TO_250HZ + if(DOWNSAMPLE_256HZ_TO_250HZ == pstECGDownSampCalParamInfo->uchDownSampleType) + { + pstECGDownSampCalParamInfo->rsFirCoef= (GS32*)rsFirCoef_256_250hz; + pstECGDownSampCalParamInfo->uchRsFirOrder = 100; + pstECGDownSampCalParamInfo->uchRsI = 1; + pstECGDownSampCalParamInfo->uchRsD = 1; + pstECGDownSampCalParamInfo->uchRsEnable = 1; + pstECGDownSampCalParamInfo->ufStep = 1024; + } + #endif + } + else + { + pstECGDownSampCalParamInfo->uchRsEnable = 0; + return; + } + + if(pstECGDownSampCalParamInfo->uchRsFirOrder % 2) + { + pstECGDownSampCalParamInfo->uchRsFirCoefNum = ((pstECGDownSampCalParamInfo->uchRsFirOrder+1)/2) ; + } + else + { + pstECGDownSampCalParamInfo->uchRsFirCoefNum = ((pstECGDownSampCalParamInfo->uchRsFirOrder+2)/2); + } + pstECGDownSampCalParamInfo->uchRsBufSize = (pstECGDownSampCalParamInfo->uchRsFirOrder / pstECGDownSampCalParamInfo->uchRsI + 1); +} + +#if __SUPPORT_ECG_PPG_DOWNSAMP__ +void GH3X2X_PPGResampleConfig(GU16 usPPGSampleRate) +{ + RsFirReset(DOWNSAMPLE_PPG); + GH3X2X_DownSampleMarcoIni(usPPGSampleRate); + if(usPPGSampleRate == 250) + { + #if RESAMPLE_400HZ_TO_250HZ + pstPPGDownSampCalParamInfo->rsFirCoef = (GS32*)rsFirCoef_250hz2; + pstPPGDownSampCalParamInfo->uchRsFirOrder = 126; + pstPPGDownSampCalParamInfo->uchRsI = 5; + pstPPGDownSampCalParamInfo->uchRsD = 8; + pstPPGDownSampCalParamInfo->uchRsEnable = 1; + #else + pstPPGDownSampCalParamInfo->uchRsEnable = 0; + #endif + } + else + { + pstPPGDownSampCalParamInfo->uchRsEnable = 0; + return; + } + + if(pstPPGDownSampCalParamInfo->uchRsFirOrder % 2) + { + pstPPGDownSampCalParamInfo->uchRsFirCoefNum = ((pstPPGDownSampCalParamInfo->uchRsFirOrder+1)/2) ; + } + else + { + pstPPGDownSampCalParamInfo->uchRsFirCoefNum = ((pstPPGDownSampCalParamInfo->uchRsFirOrder+2)/2); + } + pstPPGDownSampCalParamInfo->uchRsBufSize = (pstPPGDownSampCalParamInfo->uchRsFirOrder / pstPPGDownSampCalParamInfo->uchRsI + 1); +} +#else +void GH3X2X_PPGResampleConfig(GU16 usPPGSampleRate) +{ + return; +} +#endif + +void GH3X2X_LeadOffDetectResetSingleChip(GU8 uchChipIndex) +{ + int i; + STGh3x2xSoftLeadOffDetInfo * pstSoftLeadOffDetInfo = g_pstGh3x2xSoftLeadOffDetInfo + uchChipIndex; + pstSoftLeadOffDetInfo -> snCounter = 0; + pstSoftLeadOffDetInfo -> sniqCounter = 0; + pstSoftLeadOffDetInfo -> snniVal = 0; + pstSoftLeadOffDetInfo -> snnqVal = 0; + pstSoftLeadOffDetInfo -> uchFastRecoryHistory = 0; + for (i = 0; i < AMP_NUM; i++) + pstSoftLeadOffDetInfo -> snniqAmp[i] = 0; +} + +void GH3X2X_LeadOffDetectReset(void) +{ + GH3X2X_LeadOffDetectResetSingleChip(0); +} + +void GH3X2X_ConfigLeadOffThr(GU32 uIQAmpThr, GU32 uIQAmpDiffThr,GU32 uValThr) +{ + g_nLeadOffDetIqAmpThr = uIQAmpThr; + g_lLeadOffDetIqAmp = ((long long)g_nLeadOffDetIqAmpThr * 20 * ADC_OFFSET / ADCREF/1000*IQ_NUM*1000/winAmpCoef); + g_lLeadOffDetIqAmpThrRaw = (g_lLeadOffDetIqAmp*g_lLeadOffDetIqAmp); + g_lLeadOffDetIqAmpFrThrRaw = (g_lLeadOffDetIqAmp*g_lLeadOffDetIqAmp / 20 / 20); + + g_nLeadOffDetIqAmpDiffThr = uIQAmpDiffThr; + g_lLeadOffDetIqAmpDiff = ((long long)g_nLeadOffDetIqAmpDiffThr * 20 * ADC_OFFSET / ADCREF/1000*IQ_NUM*1000/winAmpCoef); + g_lLeadOffDetIqAmpDiffThrRaw = (g_lLeadOffDetIqAmpDiff*g_lLeadOffDetIqAmpDiff); + g_lLeadOffDetIqAmpDiffFrThrRaw = (g_lLeadOffDetIqAmpDiff*g_lLeadOffDetIqAmpDiff / 20 / 20); + + g_nLeadOffDetValThr = uValThr; + g_LeadOffDetValThrRaw = (g_nLeadOffDetValThr * (20 * ADC_OFFSET / ADCREF)); +} + +GS32 GH3X2X_LeadOffDetectInit(void) +{ + GH3X2X_ECGResampleConfig(g_usEcgOutputFs); + + #if __SUPPORT_ECG_PPG_DOWNSAMP__ + GH3X2X_PPGResampleConfig(GH3X2X_PPG_DOWN_FS); + #endif + + GH3X2X_ConfigLeadOffThr(g_nLeadOffDetIqAmpThr, g_nLeadOffDetIqAmpDiffThr, g_nLeadOffDetValThr); + GH3X2X_LeadOffDetectReset(); + return 0; +} + +/** + * @fn GU8 GH3X2X_LeadOffDetect(GU8* puchFifoBuffer, GU16 usFifoBufferLen) + * + * @brief Lead off Detection, suppose the increment of normal ECG value in LEADOFF_DET_POINT_NUM+1 samples point + * not exceed LEADOFF_DET_THR_mV + * + * @attention None + * + * @param[in] puchFifoBuffer pointer to read fifo data buffer + * @param[in] usFifoBufferLen read fifo buffer len + * @param[out] None + * + * @return lead off status output + * @retval #0 not detect lead off + * @retval bit0=1 AdcValue larger than thresh + * @retval bit1=1 IQ Value larger than thresh + */ + +GU8 GH3X2X_LeadOffDetectSingleChip(GU8* puchFifoBuffer, GU16* pusFifoBufferLen, GU8 unChipIndex, GU8 uchEcgSlotNum) +{ + GU16 usByteIndexTmp = 0; + GS32 j; + GU8 uchRet = 0; + GU32 fifoVal; + GS32 adcVal; + GU8 flagFastRecovery; + GS32 absAdcVal; //ABS of adcVal + GS64 temp; + + STGh3x2xSoftLeadOffDetInfo * pstSoftLeadOffDetInfo = g_pstGh3x2xSoftLeadOffDetInfo + unChipIndex; + + for (usByteIndexTmp = 0; usByteIndexTmp < *pusFifoBufferLen; usByteIndexTmp += GH3X2X_AFE_FIFO_RAWDATA_SIZE) + { + if (GH3X2X_AFE_CHANNEL_MAP_GET(puchFifoBuffer[usByteIndexTmp]) == GH3X2X_AFE_GET_ECG_CHANNEL_MAP(uchEcgSlotNum)) + { + fifoVal = GH3X2X_AFE_MAKEUP_DWORD(puchFifoBuffer[usByteIndexTmp], puchFifoBuffer[usByteIndexTmp + 1],puchFifoBuffer[usByteIndexTmp + 2], puchFifoBuffer[usByteIndexTmp + 3]); + adcVal = (GS32)((fifoVal & 0x00FFFFFF)) - ADC_OFFSET; + flagFastRecovery = (fifoVal >> 26) & 0x01; + if(flagFastRecovery) + { + pstSoftLeadOffDetInfo->uchFastRecoryHistory = 1; + //GH3X2X_INFO_LOG("has fast recovery!!!!\r\n"); + } + if(0 == pstSoftLeadOffDetInfo->uchFastRecoryHistory) + { + //GH3X2X_INFO_LOG("Warning: No fast recovery!!!!\r\n"); + continue; + } + if (pstSoftLeadOffDetInfo-> uchFlagFrPrev != flagFastRecovery) + { + GH3X2X_LeadOffDetectReset(); + pstSoftLeadOffDetInfo->uchFastRecoryHistory = 1; + } + pstSoftLeadOffDetInfo-> uchFlagFrPrev = flagFastRecovery; + + //sample counter + if (pstSoftLeadOffDetInfo -> snCounter < 20000) + pstSoftLeadOffDetInfo -> snCounter++; + + if (flagFastRecovery == 0 && pstSoftLeadOffDetInfo -> snCounter>COND_VAL_VALID_TIME) + { + absAdcVal = ABS(adcVal); + if (absAdcVal > g_LeadOffDetValThrRaw) + uchRet |= 0x01; + } + if (pstSoftLeadOffDetInfo -> sniqCounter < IQ_NUM / 2) + { + temp = (GS64)adcVal*winCoef[pstSoftLeadOffDetInfo -> sniqCounter]; + } + else + { + temp = (GS64)adcVal*winCoef[IQ_NUM-1 - pstSoftLeadOffDetInfo -> sniqCounter]; + } + switch (pstSoftLeadOffDetInfo -> sniqCounter%4) + { + case 0: + pstSoftLeadOffDetInfo -> snniVal += temp; + break; + case 1: + pstSoftLeadOffDetInfo -> snnqVal += temp; + break; + case 2: + pstSoftLeadOffDetInfo -> snniVal -= temp; + break; + case 3: + pstSoftLeadOffDetInfo -> snnqVal -= temp; + break; + default: + break; + } + if (pstSoftLeadOffDetInfo -> sniqCounter == (IQ_NUM - 1)) + { + for (j = AMP_NUM-1; j >0; j--) + { + pstSoftLeadOffDetInfo -> snniqAmp[j] = pstSoftLeadOffDetInfo -> snniqAmp[j - 1]; + } + pstSoftLeadOffDetInfo -> snniVal = pstSoftLeadOffDetInfo -> snniVal >> 31; + pstSoftLeadOffDetInfo -> snnqVal = pstSoftLeadOffDetInfo -> snnqVal >> 31; + pstSoftLeadOffDetInfo -> snniqAmp[0] = pstSoftLeadOffDetInfo -> snniVal*(int)pstSoftLeadOffDetInfo -> snniVal + pstSoftLeadOffDetInfo -> snnqVal*(int)pstSoftLeadOffDetInfo -> snnqVal; + pstSoftLeadOffDetInfo -> snniVal = 0; + pstSoftLeadOffDetInfo -> snnqVal = 0; + + if (flagFastRecovery == 0) + { + if (pstSoftLeadOffDetInfo -> snniqAmp[0] > g_lLeadOffDetIqAmpThrRaw && pstSoftLeadOffDetInfo -> snniqAmp[1] > g_lLeadOffDetIqAmpThrRaw) + uchRet |= 0x02; + + if ((pstSoftLeadOffDetInfo -> snniqAmp[0] - pstSoftLeadOffDetInfo -> snniqAmp[2]) > g_lLeadOffDetIqAmpDiffThrRaw && (pstSoftLeadOffDetInfo -> snniqAmp[1] - pstSoftLeadOffDetInfo -> snniqAmp[2]) > g_lLeadOffDetIqAmpDiffThrRaw) + { + if(pstSoftLeadOffDetInfo ->snCounter > 2 * IQ_NUM) + { + uchRet |= 0x04; + } + } + } + else + { + if (pstSoftLeadOffDetInfo -> snniqAmp[0] > g_lLeadOffDetIqAmpFrThrRaw && pstSoftLeadOffDetInfo -> snniqAmp[1] > g_lLeadOffDetIqAmpFrThrRaw) + uchRet |= 0x08; + } + } + pstSoftLeadOffDetInfo -> sniqCounter++; + pstSoftLeadOffDetInfo -> sniqCounter = pstSoftLeadOffDetInfo -> sniqCounter%(IQ_NUM); + } // end of if (GH3X2X_AFE_CHANNEL_MAP_GET(puchFifoBuffer[usByteIndexTmp]) == g_uchEcgLeadChannelMap) + } // end of for (usByteIndexTmp = 0; usByteIndexTmp < usFifoBufferLen; usByteIndexTmp += GH3X2X_AFE_FIFO_RAWDATA_SIZE) + + return uchRet; +} + + + +void GH3x2xSetEcgOutputFs(GU16 usEcgOutputFs) +{ + g_usEcgOutputFs = usEcgOutputFs; +} + +GU8 GH3X2X_LeadOffDetect(GU8* puchFifoBuffer, GU16* pusFifoBufferLen, GU8 uchEcgSlotNum) +{ + GU8 uchRet = 0; + uchRet |= GH3X2X_LeadOffDetectSingleChip(puchFifoBuffer, pusFifoBufferLen, 0, uchEcgSlotNum); + if(g_uchGh3x2xEcgChnlNumLimit > 1) + { + uchRet |= GH3X2X_LeadOffDetectSingleChip(puchFifoBuffer, pusFifoBufferLen, 1, uchEcgSlotNum); + } + return uchRet; +} + +void GH3X2X_DownSampleCal( GU8 *puchFifoBuffer, GU16 usByteIndexTmp, GU16 *usRawdataBufIdx, GU16 usSampleRate, STGh3x2xRsInfo * pstRsInfo ,STGh3x2xDownSampleCalParamInfo * pstDownSampCalParamInfo) +{ + GU32 fifoVal; + GS32 adcVal; + GU8 chNo; + GU8 flagFastRecovery; + GS32 j; + + fifoVal = GH3X2X_AFE_MAKEUP_DWORD(puchFifoBuffer[usByteIndexTmp], puchFifoBuffer[usByteIndexTmp + 1], puchFifoBuffer[usByteIndexTmp + 2], puchFifoBuffer[usByteIndexTmp + 3]); + chNo = (fifoVal >> 27); + adcVal = (GS32)((fifoVal & 0x00FFFFFF)) - ADC_OFFSET; + + if(g_uchDownSampleModule == DOWNSAMPLE_ECG) + { + flagFastRecovery = (fifoVal >> 26) & 0x01; + if (pstRsInfo ->uchFlagFrPrev != flagFastRecovery) + { + GH3X2X_ECGResampleConfig(usSampleRate); + } + pstRsInfo ->uchFlagFrPrev = flagFastRecovery; + } + + #if __SUPPORT_ECG_PPG_DOWNSAMP__ + else if(g_uchDownSampleModule == DOWNSAMPLE_PPG) + { + flagFastRecovery = (fifoVal >> 26) & 0x01; + if (pstRsInfo ->uchFlagFrPrev != 1) + { + if(usSampleRate) + { + GH3X2X_PPGResampleConfig(usSampleRate); + } + } + pstRsInfo ->uchFlagFrPrev = 1; + } + #endif + + // ECG downsample + #if RESAMPLE_320HZ_TO_250HZ || RESAMPLE_256HZ_TO_250HZ + if((DOWNSAMPLE_320HZ_TO_250HZ == pstECGDownSampCalParamInfo->uchDownSampleType) || (DOWNSAMPLE_256HZ_TO_250HZ == pstECGDownSampCalParamInfo->uchDownSampleType)) + { + GS32 LinerAdcVal; + if(pstDownSampCalParamInfo->uchRsEnable) + { + GS32 k; + GS64 y; + + //?? + if (pstRsInfo ->snRsFirState > 0) + { + pstRsInfo ->snBufHead = pstRsInfo ->snBufHead - 1; + pstRsInfo ->snBufHead = pstRsInfo ->snBufHead < 0 ? (pstDownSampCalParamInfo->uchRsBufSize - 1) : pstRsInfo ->snBufHead; + pstRsInfo ->snRsXbuf[pstRsInfo ->snBufHead] = adcVal; + } + else + { + for (j = 0; j < pstDownSampCalParamInfo->uchRsFirOrder / pstDownSampCalParamInfo->uchRsI + 1; j++) + pstRsInfo ->snRsXbuf[j] = adcVal; + pstRsInfo ->snBufHead = pstDownSampCalParamInfo->uchRsBufSize - 1; + } + + k = pstRsInfo ->snBufHead; + y = 0; + for (j = 1; j < pstDownSampCalParamInfo->uchRsFirCoefNum; j = j + 1) // + { + y += ((GS64)pstRsInfo ->snRsXbuf[k] * pstDownSampCalParamInfo->rsFirCoef[j]); + k = (k + 1) % pstDownSampCalParamInfo->uchRsBufSize; + } + for (; j <(pstDownSampCalParamInfo->uchRsFirOrder+1); j = j + 1) // + { + y += ((GS64)pstRsInfo ->snRsXbuf[k] * pstDownSampCalParamInfo->rsFirCoef[pstDownSampCalParamInfo->uchRsFirOrder - j]); + k = (k + 1) % pstDownSampCalParamInfo->uchRsBufSize; + } + + y = y >> SHIFTBITS; + k = (GS32)y + ADC_OFFSET; // + if (k < 0) + k = 0; + else if (k>=(ADC_OFFSET * 2)) + k = (ADC_OFFSET * 2-1); + + // ??????? + if(pstRsInfo->uchLinearInterState >0) + { + #if RESAMPLE_320HZ_TO_250HZ + if(DOWNSAMPLE_320HZ_TO_250HZ == pstECGDownSampCalParamInfo->uchDownSampleType) + { + if(pstRsInfo->fDownStep <=100) + { + LinerAdcVal = ((GU32)k*pstRsInfo->fDownStep + (100-pstRsInfo->fDownStep)*pstRsInfo->nRsLastRaw)/100; + pstRsInfo->nRsLastRaw = (GU32)k; + pstRsInfo->fDownStep = pstRsInfo->fDownStep + pstDownSampCalParamInfo->ufStep - 100; + pstRsInfo->uchLinearDataUpdate = 1; + } + else + { + pstRsInfo->nRsLastRaw = (GU32)k; + pstRsInfo->fDownStep = pstRsInfo->fDownStep - 100; + pstRsInfo->uchLinearDataUpdate = 0; + } + } + #endif + + #if RESAMPLE_256HZ_TO_250HZ + if(DOWNSAMPLE_256HZ_TO_250HZ == pstECGDownSampCalParamInfo->uchDownSampleType) + { + if(pstRsInfo->fDownStep <=1000) + { + LinerAdcVal = (GU32)(((GS64)(k)*(GS64)(pstRsInfo->fDownStep) + (GS64)((1000-pstRsInfo->fDownStep)*(GS64)(pstRsInfo->nRsLastRaw)))/1000); + pstRsInfo->nRsLastRaw = (GU32)k; + pstRsInfo->fDownStep = pstRsInfo->fDownStep + pstDownSampCalParamInfo->ufStep - 1000; + pstRsInfo->uchLinearDataUpdate = 1; + } + else + { + pstRsInfo->nRsLastRaw = (GU32)k; + pstRsInfo->fDownStep = pstRsInfo->fDownStep - 1000; + pstRsInfo->uchLinearDataUpdate = 0; + } + } + #endif + } + else + { + LinerAdcVal = (GU32)k; + pstRsInfo->nRsLastRaw = (GU32)k; + pstRsInfo->fDownStep = pstRsInfo->fDownStep + pstDownSampCalParamInfo->ufStep; + pstRsInfo->uchLinearInterState =1; + pstRsInfo->uchLinearDataUpdate = 1; + } + + if(pstRsInfo->uchLinearDataUpdate == 1) + { + fifoVal = (((GU8)chNo)<<27) + (((GU8)flagFastRecovery)<<26) + ((GU32)LinerAdcVal/5); + puchFifoBuffer[*usRawdataBufIdx] = GH3X2X_AFE_GET_BYTE3_FROM_DWORD(fifoVal); + puchFifoBuffer[*usRawdataBufIdx + 1] = GH3X2X_AFE_GET_BYTE2_FROM_DWORD(fifoVal); + puchFifoBuffer[*usRawdataBufIdx + 2] = GH3X2X_AFE_GET_BYTE1_FROM_DWORD(fifoVal); + puchFifoBuffer[*usRawdataBufIdx + 3] = GH3X2X_AFE_GET_BYTE0_FROM_DWORD(fifoVal); + + *usRawdataBufIdx += GH3X2X_AFE_FIFO_RAWDATA_SIZE; + } + } + } + #endif + + #if RESAMPLE_800HZ_TO_500HZ ||RESAMPLE_800HZ_TO_250HZ || (RESAMPLE_400HZ_TO_250HZ & (__SUPPORT_ECG_PPG_DOWNSAMP__)) + if((DOWNSAMPLE_800HZ_TO_500HZ == pstECGDownSampCalParamInfo->uchDownSampleType)||(DOWNSAMPLE_800HZ_TO_250HZ == pstECGDownSampCalParamInfo->uchDownSampleType)||(DOWNSAMPLE_400HZ_TO_250HZ == pstECGDownSampCalParamInfo->uchDownSampleType)) + { + if(pstDownSampCalParamInfo->uchRsEnable) + { + GS32 k; + GS64 y; + GS32 delta; + if (pstRsInfo ->snRsFirState > 0) + { + pstRsInfo ->snBufHead = pstRsInfo ->snBufHead - 1; + pstRsInfo ->snBufHead = pstRsInfo ->snBufHead < 0 ? (pstDownSampCalParamInfo->uchRsBufSize - 1) : pstRsInfo ->snBufHead; + pstRsInfo ->snRsXbuf[pstRsInfo ->snBufHead] = adcVal; + pstRsInfo ->nRsIcounter += pstDownSampCalParamInfo->uchRsI; + } + else + { + for (j = 0; j < pstDownSampCalParamInfo->uchRsFirOrder / pstDownSampCalParamInfo->uchRsI + 1; j++) + pstRsInfo ->snRsXbuf[j] = adcVal; + pstRsInfo ->nRsIcounter = 0; + pstRsInfo ->snRsFirState = 1; + pstRsInfo ->snBufHead = pstDownSampCalParamInfo->uchRsBufSize - 1; + } + + if (pstRsInfo ->nRrsDcounter >= pstRsInfo ->nRsIcounter && pstRsInfo ->nRrsDcounter < (pstRsInfo ->nRsIcounter + pstDownSampCalParamInfo->uchRsI)) + { + delta = pstRsInfo ->nRrsDcounter - pstRsInfo ->nRsIcounter; + k = pstRsInfo ->snBufHead; + y = 0; + for (j = delta; j < pstDownSampCalParamInfo->uchRsFirCoefNum; j = j + pstDownSampCalParamInfo->uchRsI) + { + y += ((GS64)pstRsInfo ->snRsXbuf[k] * pstDownSampCalParamInfo->rsFirCoef[j]); + k = (k + 1) % pstDownSampCalParamInfo->uchRsBufSize; + } + for (j = j; j <(pstDownSampCalParamInfo->uchRsFirOrder+1); j = j + pstDownSampCalParamInfo->uchRsI) + { + y += ((GS64)pstRsInfo ->snRsXbuf[k] * pstDownSampCalParamInfo->rsFirCoef[pstDownSampCalParamInfo->uchRsFirOrder - j]); + k = (k + 1) % pstDownSampCalParamInfo->uchRsBufSize; + } + pstRsInfo ->nRrsDcounter += pstDownSampCalParamInfo->uchRsD; + + y = y >> SHIFTBITS; + k = (GS32)y + ADC_OFFSET; + if (k < 0) + k = 0; + else if (k>=(ADC_OFFSET * 2)) + k = (ADC_OFFSET * 2-1); + fifoVal = (((GU8)chNo)<<27) + (((GU8)flagFastRecovery)<<26) + ((GU32)k); + puchFifoBuffer[*usRawdataBufIdx] = GH3X2X_AFE_GET_BYTE3_FROM_DWORD(fifoVal); + puchFifoBuffer[*usRawdataBufIdx + 1] = GH3X2X_AFE_GET_BYTE2_FROM_DWORD(fifoVal); + puchFifoBuffer[*usRawdataBufIdx + 2] = GH3X2X_AFE_GET_BYTE1_FROM_DWORD(fifoVal); + puchFifoBuffer[*usRawdataBufIdx + 3] = GH3X2X_AFE_GET_BYTE0_FROM_DWORD(fifoVal); + *usRawdataBufIdx += GH3X2X_AFE_FIFO_RAWDATA_SIZE; + } + } + } +#endif +} + +void GH3X2X_EcgPPGRsHandleSingleChip(GU8 *puchFifoBuffer, GU16 *pusFifoBufferLen, GU8 uchChipIndex, GU8 uchEcgSlotNum ,GU16 usSampleRate) +{ + GU16 usByteIndexTmp = 0; + GU16 usRawdataBufIdx = 0; + GU8 usCheckDataType = 0; // 1:ECG 2:PPG 0:other + + for (usByteIndexTmp = 0; usByteIndexTmp < *pusFifoBufferLen; usByteIndexTmp += GH3X2X_AFE_FIFO_RAWDATA_SIZE) + { + if (GH3X2X_AFE_CHANNEL_MAP_GET(puchFifoBuffer[usByteIndexTmp]) == GH3X2X_AFE_GET_ECG_CHANNEL_MAP((GU8)(GH3X2X_ECG_START_SLOT + uchEcgSlotNum))) + { + STGh3x2xRsInfo * pstRsInfo_ECG = g_pstGh3x2xEcgRsInfo + uchChipIndex; + g_uchDownSampleModule = DOWNSAMPLE_ECG; + GH3X2X_DownSampleCal( puchFifoBuffer, usByteIndexTmp, &usRawdataBufIdx, usSampleRate,pstRsInfo_ECG,pstECGDownSampCalParamInfo); + usCheckDataType =1; + } + + #if __SUPPORT_ECG_PPG_DOWNSAMP__ + if(g_uchPPGDownSampleChnlNumLimit && pstPPGDownSampCalParamInfo->uchRsEnable==1) + { + for(GU8 uchPPGSlotNumTmp = 0; uchPPGSlotNumTmp < g_uchPPGDownSampleChnlNumLimit; uchPPGSlotNumTmp++) + { + if (GH3X2X_AFE_CHANNEL_MAP_GET(puchFifoBuffer[usByteIndexTmp]) == GH3X2X_AFE_GET_PPG_CHANNEL_MAP((GU8)(GH3X2X_PPG_START_SLOT + uchPPGSlotNumTmp))) + { + STGh3x2xRsInfo * pstRsInfo_PPG = g_pstGh3x2xPPGRsInfo + uchPPGSlotNumTmp; + g_uchDownSampleModule = DOWNSAMPLE_PPG; + GH3X2X_DownSampleCal(puchFifoBuffer, usByteIndexTmp, &usRawdataBufIdx, usSampleRate,pstRsInfo_PPG,pstPPGDownSampCalParamInfo); + usCheckDataType =2; + } + } + } + #endif + if(!usCheckDataType) + { + if(pstECGDownSampCalParamInfo->uchRsEnable) + { + //this rawdata is not ECG data + puchFifoBuffer[usRawdataBufIdx] = puchFifoBuffer[usByteIndexTmp]; + puchFifoBuffer[usRawdataBufIdx + 1] = puchFifoBuffer[usByteIndexTmp + 1]; + puchFifoBuffer[usRawdataBufIdx + 2] = puchFifoBuffer[usByteIndexTmp + 2]; + puchFifoBuffer[usRawdataBufIdx + 3] = puchFifoBuffer[usByteIndexTmp + 3]; + usRawdataBufIdx += GH3X2X_AFE_FIFO_RAWDATA_SIZE; + } + } + usCheckDataType = 0; + } // end of for (usByteIndexTmp = 0; usByteIndexTmp < usFifoBufferLen; usByteIndexTmp += GH3X2X_AFE_FIFO_RAWDATA_SIZE) + *pusFifoBufferLen = usRawdataBufIdx; +} + +GU8 GH3X2X_AFE_EcgRsHandle(GU8* puchFifoBuffer, GU16* pusFifoBufferLen, GU8 uchEcgSlotNum, GU16 usEcgSampleRate) +{ + if(pstECGDownSampCalParamInfo->uchRsEnable == 1) + { + GH3X2X_EcgPPGRsHandleSingleChip(puchFifoBuffer, pusFifoBufferLen, 0,uchEcgSlotNum,usEcgSampleRate); + return 1; + } + else + { + return 0; + } +} + +/********END OF FILE********* Copyright (c) 2003 - 2022, Goodix Co., Ltd. ********/ + + diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_user.c b/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_user.c new file mode 100644 index 000000000..8190fedb9 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_user.c @@ -0,0 +1,484 @@ +#include "gh3x2x_afe_user.h" +#include "gh3x2x_afe_drv.h" +#include "pinctrl_porting.h" +#include "hal_gpio.h" +#include "i2c.h" +#include "pm_definition.h" +#if GH3X2X_AFE_MP_MODE +// #include "gh3x2x_mp_common.h" +#endif + +#include "los_tick.h" +#include "debug_print.h" + +#ifdef GOODIX_DEMO_PLATFORM +#include "gh3x2x_demo_goodix_PLATFORM.h" +#else + +#include "spi.h" + +#define GOODIX_PLATFORM_SPI_WRITE_ENTITY(write_buffer, length) +#define GOODIX_PLATFORM_SPI_READ_ENTITY() +#define GOODIX_PLATFORM_SPI_CS_CTRL_ENTITY() +#define GOODIX_PLATFORM_SPI_RESET_PIN_ENTITY() +#define GOODIX_PLATFORM_INT_HANDLER_CALL_BACK_ENTITY() +#define GOODIX_PLATFORM_LOG_ENTITY() +#define GOODIX_PLATFORM_DELAY_US_ENTITY() +#define GOODIX_PLATFORM_DELAY_MS_ENTITY() +#define GOODIX_PLATFORM_DELAY_MS_ENTITY() +#define GOODIX_PLATFORM_INT_INIT_ENTITY() +#define GOODIX_PLATFORM_RESET_PIN_INIT_ENTITY() +#define GOODIX_PLATFORM_SPI_INIT_ENTITY() +#define GOODIX_PLATFORM_I2C_WRITE_ENTITY(device_id, write_buffer,length) +#define GOODIX_PLATFORM_I2C_INIT_ENTITY() +#define GOODIX_PLATFORM_I2C_READ_ENTITY(device_id, write_buffer, write_length, read_buffer, read_length) +#endif + +#define GH3X2X_CS S_MGPIO3 +#define GH3X2X_CLK S_MGPIO2 +#define GH3X2X_MOSI S_MGPIO1 +#define GH3X2X_MISO S_MGPIO0 + +#define GH3X2X_SPI_BUS SPI_BUS_0 +#define GH3X2X_I2C_BUS I2C_BUS_2 + +/** + * @fn void hal_gh3x2x_afe_DelayUs(GU16 usUsec) + * + * @brief Delay in us,user should register this function into driver lib + * + * @attention None + * + * @param[in] None + * @param[out] None + * + * @return None + */ + +void hal_gh3x2x_afe_DelayUs(GU16 usUsec) +{ + // GH3X2X_AFE_UNUSED_VAR(usUsec); + // GOODIX_PLATFORM_DELAY_US_ENTITY(); + LOS_Udelay(usUsec); + +} + +/** + * @fn void hal_gh3x2x_afe_BspDelayMs(GU16 usMsec) + * + * @brief Delay in ms + * + * @attention None + * + * @param[in] None + * @param[out] None + * + * @return None + */ +void hal_gh3x2x_afe_DelayMs(GU16 usMsec) +{ + // GH3X2X_AFE_UNUSED_VAR(usMsec); + // GOODIX_PLATFORM_DELAY_MS_ENTITY(); + LOS_Mdelay(usMsec); +} + + + + + + +#if ( GH3X2X_AFE_COM_INTERFACE_TYPE == GH3X2X_AFE_COM_INTERFACE_I2C ) + +/* i2c interface */ +/** + * @fn void hal_gh3x2x_afe_i2c_init(void) + * + * @brief hal i2c init for gh3x2x_afe + * + * @attention None + * + * @param[in] None + * @param[out] None + * + * @return None + */ +void hal_gh3x2x_afe_i2c_init(void) +{ + + /* code implement by user */ + GOODIX_PLATFORM_I2C_INIT_ENTITY(); + +} + +/** + * @fn uint8_t hal_gh3x2x_afe_i2c_write(uint8_t device_id, const uint8_t write_buffer[], uint16_t length) + * + * @brief hal i2c write for gh3x2x_afe + * + * @attention device_id is 8bits, if platform i2c use 7bits addr, should use (device_id >> 1) + * + * @param[in] device_id device addr + * @param[in] write_buffer write data buffer + * @param[in] length write data len + * @param[out] None + * + * @return status + * @retval #1 return successfully + * @retval #0 return error + */ +GU8 hal_gh3x2x_afe_i2c_write(GU8 device_id, const GU8 write_buffer[], GU16 length) +{ + uint8_t cnt = pm_veto_get_id_cnt(PM_ID_HEART); + if (cnt == 0) + { + uapi_pm_add_sleep_veto(PM_ID_HEART); + } + uint8_t ret = 1; + + /* code implement by user */ + + // GOODIX_PLATFORM_I2C_WRITE_ENTITY(device_id, write_buffer,length); + i2c_data_t i2c_data; + i2c_data.send_buf = write_buffer; + i2c_data.send_len = length; + i2c_data.receive_buf = NULL; + i2c_data.receive_len = 0; + // custom_i2c_write_reg(BN02_I2C_ADDR, 0x00, 1, &data, 1, BN02_I2C_BUS); + errcode_t result = uapi_i2c_master_write(GH3X2X_I2C_BUS, device_id, &i2c_data); + if (result != ERRCODE_SUCC) + printf("i2c write data fail! ret=0x%x\n", result); + // custom_i2c_read_regs(device_id, reg_addr, 1 , pBuffer, buf_size, VC9202_I2C_BUS); + + cnt = pm_veto_get_id_cnt(PM_ID_HEART); + if (cnt == 1) + { + uapi_pm_remove_sleep_veto(PM_ID_HEART); + } + + + return ret; +} + +/** + * @fn uint8_t hal_gh3x2x_afe_i2c_read(uint8_t device_id, const uint8_t write_buffer[], uint16_t write_length, + * uint8_t read_buffer[], uint16_t read_length) + * + * @brief hal i2c read for gh3x2x_afe + * + * @attention device_id is 8bits, if platform i2c use 7bits addr, should use (device_id >> 1) + * + * @param[in] device_id device addr + * @param[in] write_buffer write data buffer + * @param[in] write_length write data len + * @param[in] read_length read data len + * @param[out] read_buffer pointer to read buffer + * + * @return status + * @retval #1 return successfully + * @retval #0 return error + */ +GU8 hal_gh3x2x_afe_i2c_read(GU8 device_id, const GU8 write_buffer[], GU16 write_length, GU8 read_buffer[], GU16 read_length) +{ + uint8_t cnt = pm_veto_get_id_cnt(PM_ID_HEART); + if (cnt == 0) + { + uapi_pm_add_sleep_veto(PM_ID_HEART); + } + uint8_t ret = 1; + + /* code implement by user */ + + // GOODIX_PLATFORM_I2C_READ_ENTITY(device_id, write_buffer, write_length, read_buffer, read_length); + + i2c_data_t i2c_data; + i2c_data.send_buf = write_buffer; + i2c_data.send_len = write_length; + i2c_data.receive_buf = read_buffer; + i2c_data.receive_len = read_length; + + errcode_t result = uapi_i2c_master_writeread(GH3X2X_I2C_BUS, device_id, &i2c_data); + if (result != ERRCODE_SUCC) + printf("i2c read data fail! ret=0x%x\n", result); + // custom_i2c_read_regs(device_id, reg_addr, 1 , pBuffer, buf_size, VC9202_I2C_BUS); + + cnt = pm_veto_get_id_cnt(PM_ID_HEART); + if (cnt == 1) + { + uapi_pm_remove_sleep_veto(PM_ID_HEART); + } + + return ret; +} + +#else + +/* spi interface */ +/** + * @fn void hal_gh3x2x_afe_spi_init(void) + * + * @brief hal spi init for gh3x2x_afe + * + * @attention None + * + * @param[in] None + * @param[out] None + * + * @return None + */ + +void hal_gh3x2x_afe_spi_init(void) +{ + /* init spi and cs pin */ + // GOODIX_PLATFORM_SPI_INIT_ENTITY(); + spi_bus_t bus; + spi_attr_t attr; + bus = SPI_BUS_0; + attr.is_slave = false; + attr.slave_num = 1; + attr.bus_clk = 40000000; + attr.freq_mhz = 10; + attr.clk_polarity = (uint32_t)SPI_CFG_CLK_CPOL_1; + attr.clk_phase = (uint32_t)SPI_CFG_CLK_CPHA_1; + attr.frame_format = SPI_CFG_FRAME_FORMAT_MOTOROLA_SPI; + attr.spi_frame_format = (uint32_t)HAL_SPI_FRAME_FORMAT_STANDARD; + attr.frame_size = (uint32_t)HAL_SPI_FRAME_SIZE_8; + attr.tmod = HAL_SPI_TRANS_MODE_TXRX; + attr.sste = SPI_CFG_SSTE_DISABLE; + attr.ndf = 1; + + uapi_spi_init(bus,&attr,NULL); +} + +/** + * @fn GU8 hal_gh3x2x_afe_spi_write(GU8 write_buffer[], GU16 length) + * + * @brief hal spi write for gh3x2x_afe + * + * @attention if __gh3x2x_afe_SPI_TYPE__ == __gh3x2x_afe_SPI_TYPE_SOFTWARE_CS__ , user need generate timming: write_buf[0](W) + write_buf[1](W) + ... + * @attention if __gh3x2x_afe_SPI_TYPE__ == __gh3x2x_afe_SPI_TYPE_HARDWARE_CS__ , user need generate timming: CS LOW + write_buf[0](W) + write_buf[1](W) + ... + CS HIGH + * + * @param[in] write_buffer write data buffer + * @param[in] length write data len + * @param[out] None + * + * @return status + * @retval #1 return successfully + * @retval #0 return error + */ +GU8 hal_gh3x2x_afe_spi_write(GU8 write_buffer[], GU16 length) +{ + GU8 ret = 1; + + + // GOODIX_PLATFORM_SPI_WRITE_ENTITY(write_buffer, length); + spi_xfer_data_t sdata ={0} ; + sdata.tx_buff = write_buffer; + sdata.tx_bytes = length; + sdata.rx_buff = NULL; + sdata.rx_bytes = 0; + + ret = uapi_spi_master_write(GH3X2X_SPI_BUS, &sdata, 0x100); + + + return ret; +} + + +#if (GH3X2X_AFE_SPI_TYPE == GH3X2X_AFE_SPI_SOFTWARE_CS) +/** + * @fn GU8 hal_gh3x2x_afe_spi_read(GU8 read_buffer[], GU16 length) + * + * @brief hal spi read for gh3x2x_afe + * + * @attention user need generate timming: read_buf[0](R) + write_buf[1](R) + ... + * + * @param[in] read_length read data len + * @param[out] read_buffer pointer to read buffer + * + * @return status + * @retval #1 return successfully + * @retval #0 return error + */ +GU8 hal_gh3x2x_afe_spi_read(GU8 read_buffer[], GU16 length) +{ + GU8 ret = 1; + // GH3X2X_AFE_UNUSED_VAR(read_buffer); + // GH3X2X_AFE_UNUSED_VAR(length); + // GOODIX_PLATFORM_SPI_READ_ENTITY(); + + spi_xfer_data_t sdata ={0} ; + sdata.tx_buff = NULL; + sdata.tx_bytes = 0; + sdata.rx_buff = read_buffer; + sdata.rx_bytes = length; + + ret = uapi_spi_master_read(GH3X2X_SPI_BUS, &sdata, 0x100); + + return ret; +} +#elif (GH3X2X_AFE_SPI_TYPE == GH3X2X_AFE_SPI_HARDWEAR_CS) +/** + * @fn GU8 hal_gh3x2x_afe_spi_write_F1_and_read(GU8 read_buffer[], GU16 length) + * + * @brief hal spi write F1 and read for gh3x2x_afe + * + * @attention user need generate timming: CS LOW + F1(W) + read_buf[0](R) + read_buf[1](R) + ... + CS HIGH + * + * @param[in] write_buf write data + * @param[in] length write data len + * + * @return status + * @retval #1 return successfully + * @retval #0 return error + */ +GU8 hal_gh3x2x_afe_spi_write_F1_and_read(GU8 read_buffer[], GU16 length) +{ + GU8 ret = 1; + GH3X2X_AFE_UNUSED_VAR(read_buffer); + GH3X2X_AFE_UNUSED_VAR(length); + GOODIX_PLATFORM_SPI_READ_ENTITY(); + + return ret; +} +#endif + +/** + * @fn void hal_gh3x2x_afe_spi_cs_ctrl(GU8 cs_pin_level) + * + * @brief hal spi cs pin ctrl for gh3x2x_afe + * + * @attention pin level set 1 [high level] or 0 [low level] + * + * @param[in] cs_pin_level spi cs pin level + * @param[out] None + * + * @return None + */ + + + +#if (GH3X2X_AFE_SPI_TYPE == GH3X2X_AFE_SPI_SOFTWARE_CS) +void hal_gh3x2x_afe_spi_cs_ctrl(GU8 cs_pin_level) +{ + // GH3X2X_AFE_UNUSED_VAR(cs_pin_level); + // GOODIX_PLATFORM_SPI_CS_CTRL_ENTITY(); + + uapi_pin_set_mode(GH3X2X_CS, (pin_mode_t)HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(GH3X2X_CS, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(GH3X2X_CS, cs_pin_level); + +} +#endif + +#endif + +#if (GH3X2X_AFE_RESET_TYPE == GH3X2X_AFE_RESET_HARDWARE) +/** + * @fn void hal_gh3x2x_afe_int_init(void) + * + * @brief gh3x2x_afe int init + * + * @attention None + * + * @param[in] None + * @param[out] None + * + * @return None + */ + + + +void hal_gh3x2x_afe_reset_pin_init(void) +{ + GOODIX_PLATFORM_RESET_PIN_INIT_ENTITY(); +} + +/** + * @fn void hal_gh3x2x_afe_reset_pin_ctrl(GU8 pin_level) + * + * @brief hal reset pin ctrl for gh3x2x_afe + * + * @attention pin level set 1 [high level] or 0 [low level] + * + * @param[in] pin_level reset pin level + * @param[out] None + * + * @return None + */ + +void hal_gh3x2x_afe_reset_pin_ctrl(GU8 pin_level) +{ + GH3X2X_AFE_UNUSED_VAR(pin_level); + GOODIX_PLATFORM_SPI_RESET_PIN_ENTITY(); +} + +#endif + +/** + * @fn void hal_gh3x2x_afe_int_init(void) + * + * @brief gh3x2x_afe int init + * + * @attention None + * + * @param[in] None + * @param[out] None + * + * @return None + */ + + +void hal_gh3x2x_afe_int_init(void) +{ + GOODIX_PLATFORM_INT_INIT_ENTITY(); +} + +#if (GH3X2X_AFE_PRO_BY_INT == GH3X2X_AFE_PRO_TYPE) +/** + * @fn void hal_gh3x2x_afe_int_handler_call_back(void) + * + * @brief call back of gh3x2x_afe int handler + * + * @attention None + * + * @param[in] None + * @param[out] None + * + * @return None + */ +void hal_gh3x2x_afe_int_handler_call_back(void) +{ +/****************** DO NOT MODITY ****************************************************************/ + GH3X2X_AFE_SetNeedWakeUpGh3x2xFlag(0); //not need wake up gh3x2x_afe when process int event + g_uchGh3x2xAfeIntCallBackIsCalled = 1; +#if GH3X2X_AFE_MP_MODE + GH3X2X_MP_SET_INT_FLAG(); //gh3x2x mp test must call it +#endif +/****************** DO NOT MODITY ****************************************************************/ + + + + GOODIX_PLATFORM_INT_HANDLER_CALL_BACK_ENTITY(); +} + +#endif + +/** + * @fn void GH3X2X_AFE_Log(char *log_string) + * + * @brief for debug version, log + * + * @attention this function must define that use debug version lib + * + * @param[in] log_string pointer to log string + * @param[out] None + * + * @return None + */ +void GH3X2X_AFE_Log(GCHAR *log_string) +{ + // GH3X2X_AFE_UNUSED_VAR(log_string); + // GOODIX_PLATFORM_LOG_ENTITY(); + PRINT("%s", log_string); +} + diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_hal.c b/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_hal.c new file mode 100644 index 000000000..d1eea6e1d --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_hal.c @@ -0,0 +1,114 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2024-03-13 15:08:38 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2025-01-17 17:57:09 + * @FilePath: /FD230/code/sdk/drivers/peripheral/ppg/hx3695/hx3695_hal.c + * @Description: + * + * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved. + */ + +#include +#include +#include +#include +#include +#include "pm_control.h" +#include "pinctrl_porting.h" +#include "hal_gpio.h" + +// S_AGPIO_L26 心率复位 PPG reset +#define GPIO_PIN_PRG_RESET S_AGPIO_L26 +// S_AGPIO_R0 PRG_LED_POWER ON 心率等电源控制脚 +#define GPIO_PIN_PRG_LED_ON S_AGPIO_R0 + +uint32_t tyhx_poweron(void) +{ + + uapi_pin_set_mode(S_AGPIO_L24, (pin_mode_t)HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(S_AGPIO_L24, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(S_AGPIO_L24, GPIO_LEVEL_LOW); + LOS_Mdelay(1); + uapi_pin_set_mode(S_MGPIO0, (pin_mode_t)HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(S_MGPIO0, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(S_MGPIO0, GPIO_LEVEL_LOW); + LOS_Mdelay(1); + uapi_pin_set_mode(GPIO_PIN_PRG_LED_ON, (pin_mode_t)HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(GPIO_PIN_PRG_LED_ON, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(GPIO_PIN_PRG_LED_ON, GPIO_LEVEL_HIGH); + LOS_Mdelay(1); + uapi_pin_set_mode(GPIO_PIN_PRG_RESET, (pin_mode_t)HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(GPIO_PIN_PRG_RESET, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(GPIO_PIN_PRG_RESET, GPIO_LEVEL_HIGH); + + LOS_Mdelay(50); + return 0; +} +uint32_t tyhx_poweroff(void) +{ + uapi_pin_set_mode(GPIO_PIN_PRG_RESET, (pin_mode_t)HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(GPIO_PIN_PRG_RESET, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(GPIO_PIN_PRG_RESET, GPIO_LEVEL_LOW); + + uapi_pin_set_mode(GPIO_PIN_PRG_LED_ON, (pin_mode_t)HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(GPIO_PIN_PRG_LED_ON, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(GPIO_PIN_PRG_LED_ON, GPIO_LEVEL_LOW); + LOS_Mdelay(50); + return 0; +} + +void ppg_send_cmd_to_gh3x2x_driver(char* mode, uint8_t enable) +{ + // work_mode md = 1; + // if (strcmp(mode, "hrs") == 0) { + // md = WORK_MODE_HR; + // } else if (strcmp(mode, "hrv") == 0) { + // md = WORK_MODE_HRV; + // } else if (strcmp(mode, "spo2") == 0) { + // md = WORK_MODE_SPO2; + // } else if (strcmp(mode, "leaklight") == 0) { + // md = WORK_MODE_UNDEFINED; + // } else if (strcmp(mode, "graycard") == 0) { + // md = WORK_MODE_UNDEFINED; + // } else if (strcmp(mode, "ledoff") == 0) { + // md = WORK_MODE_UNDEFINED; + // } else if (strcmp(mode, "wear") == 0) { + // md = WORK_MODE_WEAR; + // } else if (strcmp(mode, "single") == 0) { + // md = WORK_MODE_UNDEFINED; + // }else if (strcmp(mode, "factory") == 0) { + // md = WORK_MODE_UNDEFINED; + // }else if (strcmp(mode, "fpc") == 0) { + // md = WORK_MODE_UNDEFINED; + // }else if (strcmp(mode, "int") == 0) { + // if(vc921x_device) + // vc921x_device->ops->dev_irq_handler(0,0); + // return; + // } + + // if (enable == 1) + // { + // // ppg_service_running_stat = true; + // uapi_pm_control(PM_APP_WAKE_NEEDED); + // tyhx_poweron(); + + // vc921x_device = get_vc921x_device(); + // if(!vc921x_device) + // { + // printf("get_vc921x_device failed !!!\n"); + // tyhx_poweroff(); + // return; + // } + // InitParamTypeDef pInit_Param = {0}; + // pInit_Param.sampling_gap_time = 400; + // pInit_Param.work_mode = md; + // vc921x_device->ops->dev_init(&pInit_Param); + + // } else { + + // uapi_pm_control(PM_APP_WAKE_NONEED); + // vc921x_device->ops->stop_work(); + // tyhx_poweroff(); + // } +} \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/ppg/service/ppg_service.cpp b/code/sdk/zhihui/drivers/ppg/service/ppg_service.cpp index 40f29c89f..7644bdaef 100644 --- a/code/sdk/zhihui/drivers/ppg/service/ppg_service.cpp +++ b/code/sdk/zhihui/drivers/ppg/service/ppg_service.cpp @@ -52,6 +52,9 @@ extern "C" { #elif defined(PPG_VC921X) #include "vc921x_hal.h" #include "vc921x_user_app.h" +#elif defined(PPG_GH3X2X) +#include "gh3x2x_hal.h" +#include "gh3x2x_afe_drv.h" #else #include "hx3695_hal.h" #include "hx3695.h" @@ -464,6 +467,14 @@ errcode_t uapi_ppg_service_init(void) tyhx_poweroff(); return ERRCODE_FAIL; } +#elif defined(PPG_GH3X2X) + if (GH3X2X_AFE_CheckChipId() != 0) + { + //TODO 没找到3695,退出线程 + PRINT("PPG_GH3X2X not exist!\r\n"); + tyhx_poweroff(); + return ERRCODE_FAIL; + } #endif tyhx_poweroff(); diff --git a/code/sdk/zhihui/drivers/slip/cat1Service/cat1_ctl.cpp b/code/sdk/zhihui/drivers/slip/cat1Service/cat1_ctl.cpp index cc4bc6c0b..c9c3ad86b 100644 --- a/code/sdk/zhihui/drivers/slip/cat1Service/cat1_ctl.cpp +++ b/code/sdk/zhihui/drivers/slip/cat1Service/cat1_ctl.cpp @@ -89,8 +89,10 @@ bool uapi_cat1_get_power_stat(void) { #if defined(BOARD_FD230) return ( GPIO_LEVEL_HIGH == uapi_gpio_get_output_val(S_AGPIO_L23)); -#elif defined(BOARD_L22) || defined(BOARD_W9) +#elif defined(BOARD_L22) return ( GPIO_LEVEL_HIGH == uapi_gpio_get_output_val(S_AGPIO_L14)); +#elif defined(BOARD_W9) + return ( GPIO_LEVEL_HIGH == uapi_gpio_get_output_val(S_AGPIO_L17)); #endif } diff --git a/code/sdk/zhihui/services/battery/service/battery_driver.cpp b/code/sdk/zhihui/services/battery/service/battery_driver.cpp index 7b2766992..2ca706fc6 100644 --- a/code/sdk/zhihui/services/battery/service/battery_driver.cpp +++ b/code/sdk/zhihui/services/battery/service/battery_driver.cpp @@ -750,7 +750,7 @@ bool batteryservice_get_voltage_by_channel(float *voltage, uint8_t channel) #define GPIO_PIN_CHARGE_STAT S_AGPIO_L29 void disable_charge(void) { -#ifdef BOARD_FD230 +#if defined(BOARD_FD230) || defined(BOARD_W9) // PRINT("disable_charge\r\n"); uapi_pin_set_mode(GPIO_PIN_ENABLE_CHARGE, (pin_mode_t)HAL_PIO_FUNC_GPIO); uapi_gpio_set_dir(GPIO_PIN_ENABLE_CHARGE, GPIO_DIRECTION_OUTPUT); @@ -763,7 +763,7 @@ void disable_charge(void) void enable_charge(void) { -#ifdef BOARD_FD230 +#if defined(BOARD_FD230) || defined(BOARD_W9) // PRINT("enable_charge\r\n"); uapi_pin_set_mode(GPIO_PIN_ENABLE_CHARGE, (pin_mode_t)HAL_PIO_FUNC_GPIO); uapi_gpio_set_dir(GPIO_PIN_ENABLE_CHARGE, GPIO_DIRECTION_OUTPUT); @@ -777,7 +777,7 @@ void enable_charge(void) void enable_02c(void) { -#ifdef BOARD_FD230 +#if defined(BOARD_FD230) || defined(BOARD_W9) // PRINT("enable_charge_02c\r\n"); uapi_pin_set_mode(GPIO_PIN_ENABLE_CHARGE_0_2C, (pin_mode_t)HAL_PIO_FUNC_GPIO); uapi_gpio_set_dir(GPIO_PIN_ENABLE_CHARGE_0_2C, GPIO_DIRECTION_OUTPUT); @@ -797,7 +797,7 @@ uint8_t get_02c_value(void) } void disable_02c(void) { -#ifdef BOARD_FD230 +#if defined(BOARD_FD230) || defined(BOARD_W9) // PRINT("disable_charge_02c\r\n"); uapi_pin_set_mode(GPIO_PIN_ENABLE_CHARGE_0_2C, (pin_mode_t)HAL_PIO_FUNC_GPIO); uapi_gpio_set_dir(GPIO_PIN_ENABLE_CHARGE_0_2C, GPIO_DIRECTION_OUTPUT); diff --git a/code/sdk/zhihui/services/factorytest_service/factorytest_protocol.c b/code/sdk/zhihui/services/factorytest_service/factorytest_protocol.c index a590391c7..e12969eb1 100644 --- a/code/sdk/zhihui/services/factorytest_service/factorytest_protocol.c +++ b/code/sdk/zhihui/services/factorytest_service/factorytest_protocol.c @@ -2,7 +2,7 @@ * @Author: penglei 1624952103@qq.com * @Date: 2024-06-17 14:31:08 * @LastEditors: penglei 1624952103@qq.com - * @LastEditTime: 2025-01-09 16:57:54 + * @LastEditTime: 2025-01-16 10:01:35 * @FilePath: /FD230/code/sdk/application/wearable/service/factorytest_service/factorytest_protocol.c * @Description: * @@ -61,7 +61,14 @@ #ifdef ENABLE_HP4507 #include "hp4570.h" #endif - +#ifdef PPG_VC9202 +#include "vc9202_user.h" +#endif +#ifdef SUPPORT_GNSS +#include "gnss_ctl.h" +#include "NMEA0183.h" +static gps_data_t send_gps_data = {0}; +#endif #pragma pack(1) typedef struct factorytest_cmd_header_t { @@ -1753,7 +1760,29 @@ void factorytest_protocol_soft_test_decode(uint8_t submode,uint8_t testitem,uint 1); LOS_Mdelay(100); uapi_poweroff_device(); + } else if(testitem == 0x06) + { + //切换vbus供电测电流 + uint8_t send_data = 0x00; +#ifdef ENABLE_HP4507 + hp45xxx_init(HP4570C9); + hp45xxx_set_batfet_dis(true); + // hp45xxx_set_ceb_en(true); + hp45xxx_set_hiz_en(false); + LOS_Mdelay(50); + if (hp45xxx_read_status_vbus_pg()) + PRINT("VBUS is in Power Good state\n"); + else + PRINT("VBUS is not in Power Good state\n"); + +#endif + factorytest_protocol_replymsg(BLE_TEST_CMD_MODE_SOFT_TEST, + BLE_TEST_CMD_SOFT_TEST_SUB_MODE_PM, + 0x06, + &send_data, + 1); } + break; @@ -2210,6 +2239,87 @@ void factorytest_protocol_soft_test_decode(uint8_t submode,uint8_t testitem,uint break; + case BLE_TEST_CMD_SOFT_TEST_SUB_MODE_GPS: + + if (testitem == 0x01) + { + //定位 + uint8_t send_data = 0; + bool flag = 0; + char tmp[1024]={0}; + char time[10]={0}; +#ifdef SUPPORT_GNSS + gnss_start(); + LOS_Msleep(100); + do{ + gps_data_t *gps_data = getGPSGlobaldata(); + if(gps_data == NULL) + { + PRINT("gps_data == NULL \n"); + return; + } + if (gps_data->last_gps_time_ms > 0) + { + memcpy_s(&send_gps_data,sizeof(gps_data_t),gps_data,sizeof(gps_data_t)); + } + if(send_gps_data.status > 1) + { + flag = 1; + } + else + { + LOS_Msleep(1000); + send_data++; + } + memset_s(tmp,sizeof(tmp),0,sizeof(tmp)); + dump_location_data_to_factory(&send_gps_data,tmp,sizeof(tmp)); + memset_s(time,sizeof(time),0,sizeof(time)); + sprintf_s(time,sizeof(time),"%d",send_data); + strcat_s(tmp,sizeof(tmp),time); + // PRINT("send_gps_data.status : %d time : %d\n",send_gps_data.status,send_data); + // PRINT("tmp : %s size : %d\n",tmp,strlen(tmp)); + factorytest_protocol_replymsg(BLE_TEST_CMD_MODE_SOFT_TEST, + BLE_TEST_CMD_SOFT_TEST_SUB_MODE_GPS, + 0x01, + (uint8_t*)tmp, + strlen(tmp)); + }while(send_data <= 2 * 60 && !flag); + // PRINT("定位超时 关闭GPS\n"); + gnss_stop(); +#endif + + } else if(testitem == 0x02) + { + //获取可见星 有效星 信号增益 定位精度 + uint8_t send_data[7] = {0}; +#ifdef SUPPORT_GNSS + // if(send_gps_data) + { + send_data[0] = send_gps_data.num_sats; + send_data[1] = send_gps_data.th001_valid_star_count; + send_data[2] = send_gps_data.th000_signal_vga; + send_data[3] = (uint8_t)(((uint32_t)send_gps_data.th001_quality & 0xFF000000) >> 24); + send_data[4] = (uint8_t)(((uint32_t)send_gps_data.th001_quality & 0x00FF0000) >> 16); + send_data[5] = (uint8_t)(((uint32_t)send_gps_data.th001_quality & 0x0000FF00) >> 8); + send_data[6] = (uint8_t)(((uint32_t)send_gps_data.th001_quality & 0x000000FF) >> 0); + + // PRINT("gps_data->num_sats : %d,gps_data->th001_valid_star_count : %d,gps_data->th000_signal_vga : %d,gps_data->th001_quality : %f\n", + // send_gps_data.num_sats,send_gps_data.th001_valid_star_count, + // send_gps_data.th000_signal_vga,send_gps_data.th001_quality + // ); + // PRINT("%2X %2X %2X\r\n",send_data[0],send_data[1],send_data[2]); + // PRINT("%2X %2X %2X %2X \r\n",send_data[3],send_data[4],send_data[5],send_data[6]); + } +#endif + factorytest_protocol_replymsg(BLE_TEST_CMD_MODE_SOFT_TEST, + BLE_TEST_CMD_SOFT_TEST_SUB_MODE_GPS, + 0x02, + send_data, + sizeof(send_data)); + } + + break; + default: printf(""); break; @@ -2247,7 +2357,7 @@ errcode_t factorytest_protocol_decode(uint8_t *buf, uint16_t event_size) printf("crc16 0x%04X vs 0x%04X\n",crc16,crc16_2); - // if( crc16 == crc16_2) //校验通过,开始正式解析 + if( crc16 == crc16_2) //校验通过,开始正式解析 { if(factorytest_mode_flag == 0 && header.submod != BLE_TEST_CMD_COMMON_SUB_MODE_SWITCH_MODE) return ERRCODE_FAIL; diff --git a/code/sdk/zhihui/services/factorytest_service/factorytest_protocol.h b/code/sdk/zhihui/services/factorytest_service/factorytest_protocol.h index b8198b4fc..d238728fd 100644 --- a/code/sdk/zhihui/services/factorytest_service/factorytest_protocol.h +++ b/code/sdk/zhihui/services/factorytest_service/factorytest_protocol.h @@ -95,6 +95,9 @@ extern "C" { #define BLE_TEST_CMD_SOFT_TEST_SUB_MODE_SPEAKER 0x1B //软件测试 子模式ID 气压计 #define BLE_TEST_CMD_SOFT_TEST_SUB_MODE_LQBP 0x1C +//软件测试 子模式ID GPS +#define BLE_TEST_CMD_SOFT_TEST_SUB_MODE_GPS 0x1D + //软件测试 子模式ID 通讯录 #define BLE_TEST_CMD_SOFT_TEST_SUB_MODE_CONTACTS 0x30 //软件测试 子模式ID 支付宝 diff --git a/code/sdk/zhihui/services/gnss/inc/NMEA0183.h b/code/sdk/zhihui/services/gnss/inc/NMEA0183.h index 32c18e3a1..ba7690ca7 100644 --- a/code/sdk/zhihui/services/gnss/inc/NMEA0183.h +++ b/code/sdk/zhihui/services/gnss/inc/NMEA0183.h @@ -259,6 +259,8 @@ void dump_location_data(gps_data_t *locationdata); void dump_location_data_to_buf(gps_data_t *locationdata,char* buf,int max_buflen); gps_data_t * getGPSGlobaldata(void); +void dump_location_data_to_factory(gps_data_t *locationdata,char* buf,int max_buflen); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/code/sdk/zhihui/services/gnss/src/NMEA0183.c b/code/sdk/zhihui/services/gnss/src/NMEA0183.c index 7dbf6fda0..bf27cbe7c 100644 --- a/code/sdk/zhihui/services/gnss/src/NMEA0183.c +++ b/code/sdk/zhihui/services/gnss/src/NMEA0183.c @@ -1194,6 +1194,225 @@ void dump_location_data_to_buf(gps_data_t *locationdata,char* buf,int max_buflen #endif free(tmpbuf); } + +void dump_location_data_to_factory(gps_data_t *locationdata,char* buf,int max_buflen) +{ + + char *tmpbuf=(char*)malloc(DUMP_BUF_SIZE); + if (tmpbuf == NULL) return; +#ifndef NOUTILS + + // memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE); + // sprintf_s(tmpbuf,DUMP_BUF_SIZE,"xx卫星[卫星数](strid,snr):\n"); + + if (locationdata->starcountP>0) + { + memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE); + sprintf_s(tmpbuf,DUMP_BUF_SIZE,"G,%d", + locationdata->starcountP); + strcat_s(buf,max_buflen,tmpbuf); + for(int i=0;i<5;i++) + { + // printf("i : %d locationdata->startsP[i].starID : %d \n",i,locationdata->startsP[i].starID); + if (i< locationdata->startsP[i].starID>0) + { + memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE); + sprintf_s(tmpbuf,DUMP_BUF_SIZE,",%d,%d", + locationdata->startsP[i].starID, + locationdata->startsP[i].snr); + strcat_s(buf,max_buflen,tmpbuf); + } + else + { + memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE); + sprintf_s(tmpbuf,DUMP_BUF_SIZE,",0,0"); + strcat_s(buf,max_buflen,tmpbuf); + } + } + } + else + { + memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE); + sprintf_s(tmpbuf,DUMP_BUF_SIZE,"G,0,0,0,0,0,0,0,0,0,0,0"); + strcat_s(buf,max_buflen,tmpbuf); + } + + strcat_s(buf,max_buflen,";"); + + + if (locationdata->starcountB>0) + { + memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE); + sprintf_s(tmpbuf,DUMP_BUF_SIZE,"B,%d", + locationdata->starcountB); + strcat_s(buf,max_buflen,tmpbuf); + for(int i=0;i<5;i++) + { + // printf("i : %d locationdata->startsB[i].starID : %d \n",i,locationdata->startsB[i].starID); + if (i< locationdata->startsB[i].starID>0) + { + memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE); + sprintf_s(tmpbuf,DUMP_BUF_SIZE,",%d,%d", + locationdata->startsB[i].starID, + locationdata->startsB[i].snr); + strcat_s(buf,max_buflen,tmpbuf); + } + else + { + memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE); + sprintf_s(tmpbuf,DUMP_BUF_SIZE,",0,0"); + strcat_s(buf,max_buflen,tmpbuf); + } + } + } + else + { + memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE); + sprintf_s(tmpbuf,DUMP_BUF_SIZE,"B,0,0,0,0,0,0,0,0,0,0,0"); + strcat_s(buf,max_buflen,tmpbuf); + } + + strcat_s(buf,max_buflen,";"); + + if (locationdata->starcountN>0) + { + memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE); + sprintf_s(tmpbuf,DUMP_BUF_SIZE,";N,%d", + locationdata->starcountN); + strcat_s(buf,max_buflen,tmpbuf); + for(int i=0;i<5;i++) + { + // printf("i : %d locationdata->startsN[i].starID : %d \n",i,locationdata->startsN[i].starID); + if (i< locationdata->startsN[i].starID>0) + { + memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE); + sprintf_s(tmpbuf,DUMP_BUF_SIZE,",%d,%d", + locationdata->startsN[i].starID, + locationdata->startsN[i].snr); + strcat_s(buf,max_buflen,tmpbuf); + } + else + { + memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE); + sprintf_s(tmpbuf,DUMP_BUF_SIZE,",0,0"); + strcat_s(buf,max_buflen,tmpbuf); + } + } + } + else + { + memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE); + sprintf_s(tmpbuf,DUMP_BUF_SIZE,"N,0,0,0,0,0,0,0,0,0,0,0"); + strcat_s(buf,max_buflen,tmpbuf); + } + + strcat_s(buf,max_buflen,";"); + + if (locationdata->starcountL>0) + { + memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE); + sprintf_s(tmpbuf,DUMP_BUF_SIZE,"L,%d", + locationdata->starcountL); + strcat_s(buf,max_buflen,tmpbuf); + for(int i=0;i<5;i++) + { + // printf("i : %d locationdata->startsL[i].starID : %d \n",i,locationdata->startsL[i].starID); + if (i< locationdata->startsL[i].starID>0) + { + memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE); + sprintf_s(tmpbuf,DUMP_BUF_SIZE,",%d,%d", + locationdata->startsL[i].starID, + locationdata->startsL[i].snr); + strcat_s(buf,max_buflen,tmpbuf); + } + else + { + memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE); + sprintf_s(tmpbuf,DUMP_BUF_SIZE,",0,0"); + strcat_s(buf,max_buflen,tmpbuf); + } + } + } + else + { + memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE); + sprintf_s(tmpbuf,DUMP_BUF_SIZE,"L,0,0,0,0,0,0,0,0,0,0,0"); + strcat_s(buf,max_buflen,tmpbuf); + } + + strcat_s(buf,max_buflen,";"); + + if (locationdata->starcountQ>0) + { + memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE); + sprintf_s(tmpbuf,DUMP_BUF_SIZE,"Q,%d", + locationdata->starcountQ); + strcat_s(buf,max_buflen,tmpbuf); + for(int i=0;i<5;i++) + { + // printf("i : %d locationdata->startsQ[i].starID : %d \n",i,locationdata->startsQ[i].starID); + if (i< locationdata->startsQ[i].starID>0) + { + memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE); + sprintf_s(tmpbuf,DUMP_BUF_SIZE,",%d,%d", + locationdata->startsQ[i].starID, + locationdata->startsQ[i].snr); + strcat_s(buf,max_buflen,tmpbuf); + } + else + { + memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE); + sprintf_s(tmpbuf,DUMP_BUF_SIZE,",0,0"); + strcat_s(buf,max_buflen,tmpbuf); + } + } + } + else + { + memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE); + sprintf_s(tmpbuf,DUMP_BUF_SIZE,"Q,0,0,0,0,0,0,0,0,0,0,0"); + strcat_s(buf,max_buflen,tmpbuf); + } + + strcat_s(buf,max_buflen,";"); + + if (locationdata->starcountA>0) + { + memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE); + sprintf_s(tmpbuf,DUMP_BUF_SIZE,"A,%d", + locationdata->starcountA); + strcat_s(buf,max_buflen,tmpbuf); + for(int i=0;i<5;i++) + { + // printf("i : %d locationdata->startsA[i].starID : %d \n",i,locationdata->startsA[i].starID); + if (i< locationdata->startsA[i].starID>0) + { + memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE); + sprintf_s(tmpbuf,DUMP_BUF_SIZE,",%d,%d", + locationdata->startsA[i].starID, + locationdata->startsA[i].snr); + strcat_s(buf,max_buflen,tmpbuf); + } + else + { + memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE); + sprintf_s(tmpbuf,DUMP_BUF_SIZE,",0,0"); + strcat_s(buf,max_buflen,tmpbuf); + } + } + } + else + { + memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE); + sprintf_s(tmpbuf,DUMP_BUF_SIZE,"A,0,0,0,0,0,0,0,0,0,0,0"); + strcat_s(buf,max_buflen,tmpbuf); + } + strcat_s(buf,max_buflen,";"); +#endif + free(tmpbuf); +} + + #define MSGBUF_LEN 1024 void dump_location_data(gps_data_t*locationdata) { diff --git a/code/sdk/zhihui/utils/custom_utils.c b/code/sdk/zhihui/utils/custom_utils.c index 5d81c5cef..77d8df903 100644 --- a/code/sdk/zhihui/utils/custom_utils.c +++ b/code/sdk/zhihui/utils/custom_utils.c @@ -2712,11 +2712,17 @@ error: uint32_t custom_i2c_suspend(void) { i2c_save_reg(I2C_BUS_2); +#ifdef ENABLE_BN02 + i2c_save_reg(I2C_BUS_0); +#endif return 0; } uint32_t custom_i2c_resume(void) { i2c_recovery_reg(I2C_BUS_2); +#ifdef ENABLE_BN02 + i2c_recovery_reg(I2C_BUS_0); +#endif return 0; } diff --git a/code/sdk/zhihui/utils/custom_utils_at_cmd.c b/code/sdk/zhihui/utils/custom_utils_at_cmd.c index 0f1f7afed..97b4f1f72 100644 --- a/code/sdk/zhihui/utils/custom_utils_at_cmd.c +++ b/code/sdk/zhihui/utils/custom_utils_at_cmd.c @@ -431,7 +431,7 @@ static uint32_t custom_at_message_test(uint8_t *para, uint32_t paraLen, char *st return ERRCODE_SUCC; } #include "cywee_hal.h" -#include "hx3695_hrs_agc.h" + static uint32_t custom_gsensor_getdata(uint8_t *para, uint32_t paraLen, char *strCommonCmd) { // gsenson_t *t; -- 2.17.1