From 6a973b2918dcd0b7d82000753f2e5a03a806139b Mon Sep 17 00:00:00 2001 From: 1624952103 Date: Fri, 12 Jun 2026 11:51:35 +0800 Subject: [PATCH] =?utf8?q?=E5=A2=9E=E5=8A=A0ECG=E7=94=B5=E6=9E=81=E8=A7=A6?= =?utf8?q?=E6=91=B8=E6=A0=87=E5=BF=97=E8=8E=B7=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- code/sdk/zhihui/drivers/ppg/hal/ppg_hal.c | 9 ++ code/sdk/zhihui/drivers/ppg/hal/ppg_hal.h | 3 + .../ppg/pah831x/pah_sensor/pah831x_main.c | 91 +++++++++++-------- .../ppg/pah831x/pah_sensor/pah831x_main.h | 3 + ...831x_reg_default_note_0109_2LED_20251226.h | 4 +- 5 files changed, 71 insertions(+), 39 deletions(-) diff --git a/code/sdk/zhihui/drivers/ppg/hal/ppg_hal.c b/code/sdk/zhihui/drivers/ppg/hal/ppg_hal.c index df95e009b..2570cb613 100644 --- a/code/sdk/zhihui/drivers/ppg/hal/ppg_hal.c +++ b/code/sdk/zhihui/drivers/ppg/hal/ppg_hal.c @@ -203,6 +203,15 @@ void ppg_get_ecg_afib(uint8_t *ecg_hr, uint8_t *afib_result, uint8_t *status, ui #endif } +uint8_t ppg_get_ecg_electrode_touch(void) +{ +#if defined PPG_PAH831X + return pah831x_get_ecg_electrode_touch(); +#else + return 0; +#endif +} + uint8_t ppg_get_wear_status(void) { uint8_t wear_status = 0; diff --git a/code/sdk/zhihui/drivers/ppg/hal/ppg_hal.h b/code/sdk/zhihui/drivers/ppg/hal/ppg_hal.h index 3112e9ba7..736c87c83 100644 --- a/code/sdk/zhihui/drivers/ppg/hal/ppg_hal.h +++ b/code/sdk/zhihui/drivers/ppg/hal/ppg_hal.h @@ -109,6 +109,9 @@ void ppg_get_ecg_afib(uint8_t *ecg_hr, uint8_t *afib_result, uint8_t *status, ui * touch_flag: 电极触摸标志 0 未触摸 1 已触摸 */ void ppg_get_ecg_bp(int *sbp, int *dbp, uint8_t *status, uint8_t *ecg_touch_flag); +/* ECG 电极触摸: 0 未触摸, 1 已触摸 */ +uint8_t ppg_get_ecg_electrode_touch(void); + #ifdef __cplusplus #if __cplusplus } diff --git a/code/sdk/zhihui/drivers/ppg/pah831x/pah_sensor/pah831x_main.c b/code/sdk/zhihui/drivers/ppg/pah831x/pah_sensor/pah831x_main.c index c282cd11a..fa3ac46a6 100644 --- a/code/sdk/zhihui/drivers/ppg/pah831x/pah_sensor/pah831x_main.c +++ b/code/sdk/zhihui/drivers/ppg/pah831x/pah_sensor/pah831x_main.c @@ -63,6 +63,9 @@ typedef enum TOUCH_STATUS__OFF, } touch_status; +/* 0x2F LOD: bit0=LA, bit3=RA; 测量模式下 1=lead-off, 0=contact */ +#define ECG_LOD_FLAG_LA 0x01u +#define ECG_LOD_FLAG_RA 0x08u typedef struct { @@ -87,8 +90,9 @@ typedef struct // ecg uint64_t ecg_prev_timestamp; - // touch + // touch: IR 佩戴 / ECG 电极(0=未触摸 1=已触摸) touch_status touch_status; + uint8_t ecg_electrode_touch; //Dri or Polling uint8_t work_mode; @@ -251,6 +255,9 @@ static void start_touch(main_state *this); static void read_fifo_callback(void *user_data, uint8_t *fifo, uint16_t data_count, float read_size_ratio); static void send_fifo_data(main_state *this, uint8_t *fifo, uint16_t data_count, float read_size_ratio); +static void ecg_electrode_touch_reset(void); +static void ecg_electrode_touch_update(const pah831x_int_flag *int_flag); +static touch_status ecg_electrode_touch_for_alg(void); static float update_sample_interval(main_state *this, uint64_t start_timestamp, uint64_t end_timestamp, uint32_t sample_num, float read_size_ratio); static void send_ppg_event(main_state *this, uint64_t timestamp, const pah831x_ppg_sample *ppg_sample); @@ -361,6 +368,7 @@ void pah831x_data_ready_interrupt(main_state *this) pah831x_int_flag int_flag; pah831x_read_int_flag(&_state.core, &int_flag); + ecg_electrode_touch_update(&int_flag); DEBUG_PRINT("int_flag(data[1],fifo,touch): 0x%02X, %d, %d,\n", int_flag.data[1], (int)PAH831X_HAS_FIFO_INT(int_flag), (int)PAH831X_HAS_TOUCH_INT(int_flag)); //uint16_t touch_value = 0 ; //bool touch_flag = false; @@ -473,6 +481,7 @@ void pah831x_polling(main_state *this) now_timestamp = pxi_get_tick_count(); pah831x_int_flag int_flag; pah831x_read_int_flag(&_state.core, &int_flag); + ecg_electrode_touch_update(&int_flag); DEBUG_PRINT("int_flag(data[1],fifo,touch): 0x%02X, %d, %d\n", int_flag.data[1], (int)PAH831X_HAS_FIFO_INT(int_flag), (int)PAH831X_HAS_TOUCH_INT(int_flag)); pah831x_read_touch_flag(&_state.core,&_state.core.touch_flag); pah831x_read_touch_value(&_state.core, &_state.core.touch_value); @@ -726,6 +735,33 @@ static void read_fifo_callback(void *user_data, uint8_t *fifo, uint16_t data_cou send_fifo_data(this, fifo, data_count, read_size_ratio); } +static void ecg_electrode_touch_reset(void) +{ + _state.ecg_electrode_touch = 0; +} + +static void ecg_electrode_touch_update(const pah831x_int_flag *int_flag) +{ + uint8_t lod; + + if (_state.ecg_reg_setting == PAH831X_ECG_REG_SETTING_IDLE) { + return; + } + + lod = int_flag->data[0]; + _state.ecg_electrode_touch = ((lod & (ECG_LOD_FLAG_LA | ECG_LOD_FLAG_RA)) == 0) ? 1 : 0; +} + +static touch_status ecg_electrode_touch_for_alg(void) +{ + return _state.ecg_electrode_touch ? TOUCH_STATUS__ON : TOUCH_STATUS__OFF; +} + +uint8_t pah831x_get_ecg_electrode_touch(void) +{ + return _state.ecg_electrode_touch; +} + static void send_fifo_data(main_state *this, uint8_t *fifo, uint16_t data_count, float read_size_ratio) { uint16_t ppg_sample_num = 0; @@ -784,7 +820,7 @@ static void send_fifo_data(main_state *this, uint8_t *fifo, uint16_t data_count, duration =(uint32_t)(this->task_timestamp - this->prev_task_timestamp ); _ecg_data_out.ecg_data_ready++; _ecg_data_out.duration = duration; - _ecg_data_out.is_touched = _state.core.touch_flag ? 1U : 0U; + _ecg_data_out.is_touched = ecg_electrode_touch_for_alg(); _ecg_data_out.ch_num = 1 ; _ecg_data_out.sample_num_per_ch = ecg_sample_num ; @@ -811,7 +847,7 @@ static void send_fifo_data(main_state *this, uint8_t *fifo, uint16_t data_count, duration =(uint32_t)(this->task_timestamp - this->prev_task_timestamp ); _ecg_data_out.ecg_data_ready++; _ecg_data_out.duration = duration; - _ecg_data_out.is_touched = _state.core.touch_flag ? 1U : 0U; + _ecg_data_out.is_touched = ecg_electrode_touch_for_alg(); _ecg_data_out.ch_num = 1 ; _ecg_data_out.sample_num_per_ch = ecg_sample_num ; _ppg_data_out.ppg_data_ready++; @@ -1021,33 +1057,15 @@ void set_ir_r_led_switch_status(bool status) _state.core.ir_r_led_switch_new_status = status; } -uint16_t get_pah831x_touch_value(void) +uint16_t get_pah831x_touch_value() { - uint16_t touch_value = 0; - - pah831x_read_touch_value(&_state.core, &touch_value); - return touch_value; -} - -static void pah831x_fill_ecg_touch_flag(uint8_t *touch_flag) -{ - bool flag = false; - - if (touch_flag == NULL) { - return; - } + uint16_t pah831x_touch_value = 0 ; - pah831x_read_touch_flag(&_state.core, &flag); - *touch_flag = flag ? 1U : 0U; + pah831x_read_touch_value(&_state.core, &pah831x_touch_value); + + return pah831x_touch_value ; } -static void pah831x_reset_ecg_touch_cache(void) -{ - _state.touch_status = TOUCH_STATUS__UNKNOWN; - _state.core.touch_flag = false; - _state.core.touch_value = 0; - _ecg_data_out.is_touched = 0; -} static void get_avg_hrs(uint8_t hrs) { @@ -1487,9 +1505,6 @@ static void pah831x_ecg_bp_timer_handler(void) ret_ecg_bp_status = pah_ecg_bp_get_status(); // LOG_PRINT("got_time_out =%d\n",got_time_out); - // LOG_PRINT("got_BP =%d\n",got_BP); - // LOG_PRINT("_ecg_data_out_alg.is_touched =%d\n",_ecg_data_out_alg.is_touched); - // LOG_PRINT("ECG_PPG_BP_CALI_cali_value = %d, %d, %d, %d,\n", cal_sbp_in,cal_dbp_in,CalValue_in,CalValue1_in); clear_ecg_data_ready(); clear_ppg_data_ready(); @@ -1772,6 +1787,7 @@ void pah831x_hr_start(void) void pah831x_ecg_bp_start(uint8_t cmd) { ret_ecg_bp_status = PAH_ECG_BP_STATUS_MEASURING; + ecg_electrode_touch_reset(); ecg_param_init = 0; if(cmd == 0) @@ -1786,14 +1802,12 @@ void pah831x_ecg_bp_start(uint8_t cmd) if(calibration_mode==ECG_PPG_BP_CALI) { pah831x_sensor_init(); - pah831x_reset_ecg_touch_cache(); pah831x_sensor_start(PAH831X_WORK_POLLING, PAH831X_INIT_ALWAYS_RUN, PAH831X_PPG_REG_SETTING_IDLE, PAH831X_ECG_REG_SETTING_2, 128, 3.90625f); ecg_bp_algorithm_init(); }else if(calibration_mode==ECG_PPG_BP_ESTIMATE) { pah831x_sensor_init(); - pah831x_reset_ecg_touch_cache(); pah831x_sensor_start(PAH831X_WORK_POLLING, PAH831X_INIT_ALWAYS_RUN, PAH831X_PPG_REG_SETTING_IDLE, PAH831X_ECG_REG_SETTING_2, 128, 3.90625f); ecg_bp_algorithm_init(); //calibration_mode = ECG_PPG_BP_ESTIMATE; @@ -1834,9 +1848,9 @@ void pah831x_ecg_afib_start(void) ret_ecg_afib_hr = 0; ret_ecg_afib_result = PAH_ECG_AFIB_RESULT_INVALID; ret_ecg_afib_status = PAH_ECG_AFIB_STATUS_MEASURING; + ecg_electrode_touch_reset(); ecg_afib_algorithm_init(); pah831x_sensor_init(); - pah831x_reset_ecg_touch_cache(); pah831x_sensor_start(PAH831X_WORK_POLLING ,PAH831X_INIT_ALWAYS_RUN,PAH831X_PPG_REG_SETTING_IDLE ,PAH831X_ECG_REG_SETTING_1,256,3.91f ); } @@ -1884,7 +1898,6 @@ void pah831x_ecgbp_stop(void) pah_sensor_stop(); ecg_bp_algorithm_close(); - pah831x_reset_ecg_touch_cache(); if(calibration_mode == ECG_PPG_BP_CALI) { @@ -1897,11 +1910,11 @@ void pah831x_ecg_afib_stop(void) pah_sensor_stop(); ecg_afib_algorithm_close(); ecg_afib_algorithm_init(); - pah831x_reset_ecg_touch_cache(); ret_ecg_afib_hr = 0; ret_ecg_afib_result = PAH_ECG_AFIB_RESULT_INVALID; ret_ecg_afib_status = PAH_ECG_AFIB_STATUS_IDLE; + ecg_electrode_touch_reset(); } void pah831x_stress_stop(void) @@ -2198,7 +2211,7 @@ uint8_t pah831x_get_hrv(void) return ret_hrv; } -void pah831x_get_ecg_afib(uint8_t *ecg_hr, uint8_t *afib_result, uint8_t *status, uint8_t *touch_flag) +void pah831x_get_ecg_afib(uint8_t *ecg_hr, uint8_t *afib_result, uint8_t *status ,uint8_t *touch_flag) { if (ecg_hr != NULL) { *ecg_hr = ret_ecg_afib_hr; @@ -2209,7 +2222,9 @@ void pah831x_get_ecg_afib(uint8_t *ecg_hr, uint8_t *afib_result, uint8_t *status if (status != NULL) { *status = ret_ecg_afib_status; } - pah831x_fill_ecg_touch_flag(touch_flag); + if (touch_flag != NULL) { + *touch_flag = pah831x_get_ecg_electrode_touch(); + } } void pah831x_get_ecg_bp(int *sbp, int *dbp, uint8_t *status, uint8_t *touch_flag) @@ -2218,7 +2233,9 @@ void pah831x_get_ecg_bp(int *sbp, int *dbp, uint8_t *status, uint8_t *touch_flag if (status != NULL) { *status = ret_ecg_bp_status; } - pah831x_fill_ecg_touch_flag(touch_flag); + if (touch_flag != NULL) { + *touch_flag = pah831x_get_ecg_electrode_touch(); + } } uint8_t pah831x_get_wear_status(void) diff --git a/code/sdk/zhihui/drivers/ppg/pah831x/pah_sensor/pah831x_main.h b/code/sdk/zhihui/drivers/ppg/pah831x/pah_sensor/pah831x_main.h index d287b01f5..6120f84f5 100644 --- a/code/sdk/zhihui/drivers/ppg/pah831x/pah_sensor/pah831x_main.h +++ b/code/sdk/zhihui/drivers/ppg/pah831x/pah_sensor/pah831x_main.h @@ -373,6 +373,9 @@ void pah831x_get_ecg_afib(uint8_t *ecg_hr, uint8_t *afib_result, uint8_t *status void pah831x_get_ecg_bp(int *sbp, int *dbp, uint8_t *status, uint8_t *touch_flag); +/* ECG 电极触摸: 0 未触摸, 1 已触摸 (LOD, 与 IR 佩戴无关) */ +uint8_t pah831x_get_ecg_electrode_touch(void); + void pah8311_get_bp(int *sbp,int *dbp); void pah831x_read_calidata(void); diff --git a/code/sdk/zhihui/drivers/ppg/pah831x/pah_sensor/pah831x_reg_default_note_0109_2LED_20251226.h b/code/sdk/zhihui/drivers/ppg/pah831x/pah_sensor/pah831x_reg_default_note_0109_2LED_20251226.h index 40020ca97..9534952da 100644 --- a/code/sdk/zhihui/drivers/ppg/pah831x/pah_sensor/pah831x_reg_default_note_0109_2LED_20251226.h +++ b/code/sdk/zhihui/drivers/ppg/pah831x/pah_sensor/pah831x_reg_default_note_0109_2LED_20251226.h @@ -1224,7 +1224,7 @@ static const uint8_t PAH831X_REG_ECG_1[][2] = { { 0x4F , 0x04 }, //R_NoTouchDetection_Count_Th[4:0] { 0x24 , 0x08 }, //RDB_ChT_report_divider[7:0] { 0x2E , 0x03 }, - { 0x1B , 0x30 }, + { 0x1B , 0x70 }, /* ECG measure: RDB_LOD_EnH; 产测用独立 reg 表 { 0x1B , 0x30 } */ { 0x68 , 0x00 }, { 0x7F , 0x01 }, { 0x05 , 0x80 }, @@ -1341,7 +1341,7 @@ static const uint8_t PAH831X_REG_ECG_2[][2] = { { 0x4F , 0x04 }, //R_NoTouchDetection_Count_Th[4:0] { 0x24 , 0x08 }, //RDB_ChT_report_divider[7:0] { 0x2E , 0x03 }, //{fp_lpf_mask_cnt[7:4], Reserved[3], fp_lpf_sel[2:1](0:128/1:256/2:512/3:1024Hz), fp_lpf_enh[0]} - { 0x1B , 0x21 }, //{Reserved[7], RDB_LOD_EnH[6], RDB_ECG_EnH[5], RDB_ChT_EnH[4], RDB_ChD_EnH[3], RDB_ChC_EnH[2], RDB_ChB_EnH[1], RDB_ChA_EnH[0]} + { 0x1B , 0x61 }, /* ECG+PPG BP: RDB_LOD_EnH { 0x1B , 0x21 } */ { 0x50 , 0x05 },//{1'b0, R_PPG_FIFO_Write_skip_A_EnH, R_AGC_DAC_TIA_A_EnH[1:0], R_AGC_PPG2_A_Sel, R_AGC_PPG1_A_Sel, R_PPG2_A_EnH, R_PPG1_A_EnH}; { 0x68 , 0x00 }, //{Dummy[5:0], RDB_ChF_EnH, RDB_ChE_EnH}; { 0x7F , 0x01 }, //Bank1 -- 2.17.1