/*---------------------------------------------------------------------------- * Copyright (c) TJD Technologies Co., Ltd. 2020. All rights reserved. * * Description: hr_drv_HX3602.c * * Author: liangjianfei * * Create: 2024-4-26 *--------------------------------------------------------------------------*/ #include #include #include #include #include #include "hr_drv_HX3602.h" #include "hrs3602_reg_init.h" #include "hr_port.h" #include "tyhx_hrs_alg.h" #include "sys_config.h" #define ENABLE_PRINT_INFO 1 #if ENABLE_PRINT_INFO #define static_print_info(...) sys_hr_log_i(__VA_ARGS__) //一般信息打印宏控制 #define static_print_warn(...) sys_hr_log_w(__VA_ARGS__) //警告信息打印一般常开 #define static_print_error(...) sys_hr_log_e(__VA_ARGS__) //错误信息打印一般常开 #else #define static_print_info(...) #define static_print_warn(...) #define static_print_error(...) #endif static hr_wear_status_t wear_status = MSG_CHECK_INIT; static hr_wear_status_t wear_status_pre = MSG_CHECK_INIT; const uint32_t hx3602_wear_thre_high = 5000; const uint32_t hx3602_wear_thre_low = 4000; const uint32_t hx3602_agc_adj_thre_high = 450000; const uint32_t hx3602_agc_adj_thre_low = 150000; static int32_t check_touch_data_min = 300000; static int32_t check_touch_data_max = 0; static int32_t check_touch_data_fifo[8] = {0}; static uint8_t agc_cnt = 0; static uint8_t agc_offset = 0; static uint8_t check_touch_cnt = 0; /********************************************************************************************************************** * LOCAL FUNCTIONS */ static bool Hrs3602_write_reg(uint8_t addr, uint8_t data) { if(hrsensor_write_reg(addr, data) != 0){ return -1; } return 0; } static bool Hrs3602_read_reg(uint8_t addr, uint8_t *recvbuf) { if(hrsensor_read_reg(addr, recvbuf, 1) != 0){ return -1; } return 0; } static bool Hrs3602_brust_read_reg(uint8_t addr, uint8_t *buf, uint8_t length) { if(hrsensor_read_reg(addr, buf, length) != 0){ return -1; } return 0; } static void Hrs3602_driv_init(void) { wear_status = MSG_CHECK_INIT; wear_status_pre = MSG_CHECK_INIT; agc_cnt = 0; agc_offset = 0; check_touch_cnt = 10; } static void Hrs3602_read_data_packet(void) { uint8_t databuf1[6] = {0}; uint8_t databuf2[6] = {0}; int32_t P0 = 0, P1 = 0, P2 = 0, P3 = 0; Hrs3602_brust_read_reg(0xa0, databuf1, 6); Hrs3602_brust_read_reg(0xa6, databuf2, 6); P0 = ((databuf1[0]) | (databuf1[1] << 8) | (databuf1[2] << 16)); P1 = ((databuf1[3]) | (databuf1[4] << 8) | (databuf1[5] << 16)); P2 = ((databuf2[0]) | (databuf2[1] << 8) | (databuf2[2] << 16)); P3 = ((databuf2[3]) | (databuf2[4] << 8) | (databuf2[5] << 16)); Hrs3602_brust_read_reg(0xa0, databuf1, 6); Hrs3602_brust_read_reg(0xa6, databuf2, 6); // DEBUG_PRINTF("%d %d %d %d" ,P0,P1,P2,P3); } static bool Hrs3602_read_hrs(int32_t *hrm_data, int32_t *als_data) { uint8_t databuf[6] = {0}; int32_t P0 = 0, P1 = 0; Hrs3602_brust_read_reg(0xa0, databuf, 6); P0 = ((databuf[0]) | (databuf[1] << 8) | (databuf[2] << 16)); P1 = ((databuf[3]) | (databuf[4] << 8) | (databuf[5] << 16)); // DEBUG_PRINTF(0," %d %d " , P0, P1); if (P0 > P1) { *hrm_data = P0 - P1; } else { *hrm_data = 0; } *als_data = P0; return 0; } static bool Hrs3602_read_ps1(int32_t *infrared_data) { uint8_t databuf[6] = {0}; int32_t P0 = 0, P1 = 0; Hrs3602_brust_read_reg(0xa6, databuf, 6); P0 = ((databuf[0]) | (databuf[1] << 8) | (databuf[2] << 16)); P1 = ((databuf[3]) | (databuf[4] << 8) | (databuf[5] << 16)); if (P0 > P1) { *infrared_data = P0 - P1; } else { *infrared_data = 0; } return 0; } static bool Hrs3602_chip_init(void) { int i = 0; uint8_t chip_id = 0; Hrs3602_read_reg(0x00, &chip_id); if (chip_id != 0x22) { return -1; } for (i = 0; i < INIT_ARRAY_SIZE; i++) { if (Hrs3602_write_reg(init_register_array[i][0], init_register_array[i][1]) != 0) { return -2; } } return 0; } static void Hrs3602_check_touch(int32_t infrared_data) { if (infrared_data > hx3602_wear_thre_high) { if (check_touch_cnt >= 20) { check_touch_cnt = 20; wear_status = MSG_TOUCH; if (wear_status != wear_status_pre) { Hrs3602_normal_power(); tyhx_hrs_alg_open_deep(); } } else { check_touch_cnt++; } } else if (infrared_data < hx3602_wear_thre_low) { if (check_touch_cnt <= 0) { check_touch_cnt = 0; wear_status = MSG_NO_TOUCH; if (wear_status != wear_status_pre) { Hrs3602_low_power(); } } else { check_touch_cnt--; } } } static void Hrs3602_check_touch_diff(int32_t infrared_data) { uint8_t ii = 0, jj = 0; int32_t ir_data_temp = 0; int32_t check_fifo[8]; int32_t check_data_sum = 0; int32_t check_data_ave = 0; for (ii = 0; ii < 7; ii++) { check_touch_data_fifo[ii] = check_touch_data_fifo[ii + 1]; check_fifo[ii] = check_touch_data_fifo[ii]; check_data_sum = check_data_sum + check_touch_data_fifo[ii]; } check_touch_data_fifo[7] = infrared_data; check_fifo[7] = check_touch_data_fifo[7]; check_data_sum = check_data_sum + check_touch_data_fifo[7]; for (ii = 0; ii < 7; ii++) { for (jj = 0; jj < 7 - ii; jj++) { if (check_fifo[jj] > check_fifo[jj + 1]) { ir_data_temp = check_fifo[jj]; check_fifo[jj] = check_fifo[jj + 1]; check_fifo[jj + 1] = ir_data_temp; } } } if (abs(check_fifo[7] - check_fifo[0]) < 4000 && check_fifo[0] > 0) { check_data_ave = check_data_sum >> 3; } if (check_data_ave < check_touch_data_min && check_data_ave > 0) { check_touch_data_min = check_data_ave; } if (check_data_ave > check_touch_data_max && check_data_ave > 0) { check_touch_data_max = check_data_ave; } if (check_touch_data_max > 0 && check_touch_data_min > 0 && check_touch_data_max > check_touch_data_min + hx3602_wear_thre_high) { if (infrared_data > check_touch_data_min + hx3602_wear_thre_high) { if (check_touch_cnt >= 20) { check_touch_cnt = 20; wear_status = MSG_TOUCH; if (wear_status != wear_status_pre) { Hrs3602_normal_power(); tyhx_hrs_alg_open_deep(); } } else { check_touch_cnt++; } } else if (infrared_data < check_touch_data_min + hx3602_wear_thre_low) { if (check_touch_cnt <= 0) { check_touch_cnt = 0; wear_status = MSG_NO_TOUCH; if (wear_status != wear_status_pre) { Hrs3602_low_power(); } } else { check_touch_cnt--; } } } else { if (infrared_data > hx3602_wear_thre_high) { if (check_touch_cnt >= 20) { check_touch_cnt = 20; wear_status = MSG_TOUCH; if (wear_status != wear_status_pre) { Hrs3602_normal_power(); tyhx_hrs_alg_open_deep(); } } else { check_touch_cnt++; } } else if (infrared_data < hx3602_wear_thre_low) { if (check_touch_cnt <= 0) { check_touch_cnt = 0; wear_status = MSG_NO_TOUCH; if (wear_status != wear_status_pre) { Hrs3602_low_power(); } } else { check_touch_cnt--; } } } } static void Hrs3602_alg_config(void) { /*para init begin ....*/ uint32_t prf_temp_clk_num = 0; /*temperatrue phase clk num in each prf */ uint32_t prf_hrs_clk_num = 0; /*hrs phase clk num in each prf */ uint32_t prf_ps_clk_num =0; /*ps phase clk num in each prf */ uint32_t prf_wait_clk_num =0; /*wait time clk num in each prf */ uint32_t en2rst_delay_clk_num =0; /*en signal to first reset delay time clk num in each prf */ uint16_t rst_clk_num = 0; uint16_t hrs_ckafe_clk_num = 0; uint16_t ps_ckafe_clk_num = 0; /*para init end ....*/ /*chip config begin ....*/ uint16_t sample_rate = 25; /*config the data rate of chip frog2 ,uint is Hz*/ uint32_t prf_clk_num = 2620000/sample_rate; /*period in clk num, num = Fclk/fs */ uint8_t temperature_enable = 0; /*temperature test function enable , 1 mean enable ; 0 mean disable */ uint8_t hrs_enable = 1; /*hrs function enable , 1 mean enable ; 0 mean disable */ uint8_t ps_enable = 1; /*ps function enable , 1 mean enable ; 0 mean disable */ uint8_t temperature_adc_osr = 0; /* 0 = 128 ; 1 = 256 ; 2 = 512 ; 3 = 1024 ;*/ uint8_t hrs_adc_osr = 3; /* 0 = 128 ; 1 = 256 ; 2 = 512 ; 3 = 1024 ;*/ uint8_t ps_adc_osr = 3; /* 0 = 128 ; 1 = 256 ; 2 = 512 ; 3 = 1024 ;*/ uint8_t led_dr_cfg = 3 ; /* 0 = 12.5mA ; 1 = 25mA ; 2 =50mA(default) 3 = 100mA*/ uint8_t tia_res = 2 ; /* 0 = 54k(default) ; 1 = 108k ; 2 =216k 3 = 432k */ en2rst_delay_clk_num = 64 ; /* 0 ~ 127 clk num config */ rst_clk_num = 6 ; /* range from 0 to 7 ; 0=1 , 1=3, 2=7,....,7=255 */ hrs_ckafe_clk_num = 128 ; /* hrm phase led on time : 0~ 255 , 实际宽度10位,低两位默认为0*/ ps_ckafe_clk_num = 10 ; /* ps phase led on time : 0~ 255 , 实际宽度10位,低两位默认为0*/ /*红外离pd远的要适当调大, 比如苹果结构距离9mm的, 可以设置到96以上*/ /*计算PRF_WAIT的时间*/ if(temperature_enable == 1) { prf_temp_clk_num = (en2rst_delay_clk_num + 10) + 2*((2<>8); Hrs3602_write_reg(0x0c, prf_wait_clk_num>>16); Hrs3602_write_reg(0x11, rst_clk_num); Hrs3602_write_reg(0x12, en2rst_delay_clk_num); //GPIO config Hrs3602_write_reg(0xc0, (0x84 | led_dr_cfg)); /* led dr config , 0x84 = 12.5mA , 0x85 = 25mA ,0x86 = 50 mA ,0x87 = 100mA */ Hrs3602_write_reg(0xc2, (0x00 | tia_res)); /* tia res config , 0x00 = 54K , 0x01 = 108K ,0x02 = 216K ,0x03 = 432K */ /*register configration end ....*/ Hrs3602_write_reg(0x09, 0x02 ); #ifdef IR_CHECK_TOUCH Hrs3602_write_reg(0X14, 0x80); Hrs3602_write_reg(0X15, 0x40); #else Hrs3602_write_reg(0X14, 0x40); Hrs3602_write_reg(0X15, 0x40); #endif #ifdef TIMER_READ_MODE Hrs3602_write_reg( 0x07, 0x00 ); Hrs3602_write_reg( 0x08, 0x00 ); // self clear int #else //int mode Hrs3602_write_reg( 0x07, 0x01 ); Hrs3602_write_reg( 0x08, 0x00 ); // self clear int #endif return ; } static hr_wear_status_t Hrs3602_agc(int32_t als_raw_data, int32_t infrared_data) { #ifdef CHECK_TOUCH_DIFF Hrs3602_check_touch_diff(infrared_data); #else Hrs3602_check_touch(infrared_data); #endif if (wear_status == MSG_TOUCH) { if (als_raw_data > hx3602_agc_adj_thre_high) { if (agc_cnt == 3) { agc_cnt = 0; if (agc_offset < 32) { agc_offset++; Hrs3602_write_reg(0x15, (0x40 | agc_offset)); } } else { agc_cnt++; } } else if (als_raw_data < hx3602_agc_adj_thre_low) { if (agc_cnt == 3) { agc_cnt = 0; if (agc_offset > 0) { agc_offset--; Hrs3602_write_reg(0x15, (0x40 | agc_offset)); } } else { agc_cnt++; } } } else { agc_cnt = 0; agc_offset = 0; } wear_status_pre = wear_status; // DEBUG_PRINTF("min=%d ir=%d status=%d offset=%d" ,check_touch_data_min, infrared_data, wear_status, agc_offset); return wear_status; } /********************************************************************************************************************** * PUBLIC FUNCTIONS */ void Hrs3602_wear_config(void) { /*para init begin ....*/ uint32_t prf_temp_clk_num = 0; /*temperatrue phase clk num in each prf */ uint32_t prf_hrs_clk_num = 0; /*hrs phase clk num in each prf */ uint32_t prf_ps_clk_num =0; /*ps phase clk num in each prf */ uint32_t prf_wait_clk_num =0; /*wait time clk num in each prf */ uint32_t en2rst_delay_clk_num =0; /*en signal to first reset delay time clk num in each prf */ uint16_t rst_clk_num = 0; uint16_t hrs_ckafe_clk_num = 0; uint16_t ps_ckafe_clk_num = 0; uint16_t sample_rate = 25; /*config the data rate of chip frog2 ,uint is Hz*/ uint32_t prf_clk_num = 2620000/sample_rate; /*period in clk num, num = Fclk/fs */ uint8_t temperature_enable = 0; /*temperature test function enable , 1 mean enable ; 0 mean disable */ uint8_t hrs_enable = 0; /*hrs function enable , 1 mean enable ; 0 mean disable */ uint8_t ps_enable = 1; /*ps function enable , 1 mean enable ; 0 mean disable */ uint8_t temperature_adc_osr = 0; /* 0 = 128 ; 1 = 256 ; 2 = 512 ; 3 = 1024 ;*/ uint8_t hrs_adc_osr = 3; /* 0 = 128 ; 1 = 256 ; 2 = 512 ; 3 = 1024 ;*/ uint8_t ps_adc_osr = 3; /* 0 = 128 ; 1 = 256 ; 2 = 512 ; 3 = 1024 ;*/ uint8_t led_dr_cfg = 3 ; /* 0 = 12.5mA ; 1 = 25mA ; 2 =50mA(default) 3 = 100mA*/ uint8_t tia_res = 2 ; /* 0 = 54k(default) ; 1 = 108k ; 2 =216k 3 = 432k */ en2rst_delay_clk_num = 64 ; /* 0 ~ 127 clk num config */ rst_clk_num = 6 ; /* range from 0 to 7 ; 0=1 , 1=3, 2=7,....,7=255 */ hrs_ckafe_clk_num = 4 ; /* hrm phase led on time : 0~ 255 , 实际宽度10位,低两位默认为0*/ ps_ckafe_clk_num = 16 ; /* ps phase led on time : 0~ 255 , 实际宽度10位,低两位默认为0*/ /*计算PRF_WAIT的时间*/ if(temperature_enable == 1) { prf_temp_clk_num = (en2rst_delay_clk_num + 10) + 2*((2<>8); Hrs3602_write_reg(0x0c, prf_wait_clk_num>>16); Hrs3602_write_reg(0x11, rst_clk_num); Hrs3602_write_reg(0x12, en2rst_delay_clk_num); //GPIO config Hrs3602_write_reg(0xc0, (0x84 | led_dr_cfg)); /* led dr config , 0x84 = 12.5mA , 0x85 = 25mA ,0x86 = 50 mA ,0x87 = 100mA */ Hrs3602_write_reg(0xc2, (0x00 | tia_res)); /* tia res config , 0x00 = 54K , 0x01 = 108K ,0x02 = 216K ,0x03 = 432K */ /*register configration end ....*/ Hrs3602_write_reg(0x09, 0x02); #ifdef IR_CHECK_TOUCH Hrs3602_write_reg(0X14, 0x80); Hrs3602_write_reg(0X15, 0x40); #else Hrs3602_write_reg(0X14, 0x40); Hrs3602_write_reg(0X15, 0x40); #endif Hrs3602_write_reg(0x16, 0x04); Hrs3602_write_reg(0x07, 0x00); Hrs3602_write_reg(0x08, 0x00); return ; } void Hrs3602_write_efuse(void) { Hrs3602_write_reg(0x85, 0x20); Hrs3602_write_reg(0x7f, 0x10); Hrs3602_write_reg(0x80, 0x08); Hrs3602_write_reg(0x81, 0x44); Hrs3602_write_reg(0x82, 0x40); Hrs3602_write_reg(0x85, 0x00); } void Hrs3602_chip_disable(void) { Hrs3602_write_reg(0x09, 0x03); } void Hrs3602_low_power(void) { Hrs3602_write_reg(0x02, 0x70); Hrs3602_write_reg(0x15, 0x40); // Hrs3602_write_reg(0xc0, 0x87); /* led dr config , 0x84 = 12.5mA , 0x85 = 25mA ,0x86 = 50 mA ,0x87 = 100mA */ Hrs3602_write_reg(0x16, 0x31); // detect interval is 1s when loss } void Hrs3602_normal_power(void) { Hrs3602_write_reg(0x02, 0x77); // Hrs3602_write_reg(0xc0, 0x87); Hrs3602_write_reg(0x16, 0x00); // detect interval is 40mS } void Hrs3602_int_clear(void) { Hrs3602_write_reg(0x06, 0x7f); return; } int tjd_hrx3602_init(void) { int ret; if((ret = Hrs3602_chip_init()) != 0){ static_print_info("Hrs3602_chip_init fail"); return -1; }else{ static_print_info("Hrs3602_chip_init succ"); } Hrs3602_alg_config(); Hrs3602_driv_init(); tyhx_hrs_alg_open(); //算法初始化 return 0; } hrsensor_data_t tjd_hrx3602_processing_handle(int16_t *gsensor_data) { int32_t hrm_raw_data; int32_t als_raw_data; int32_t infrared_data; hrsensor_data_t hrsensor_data; hr_wear_status_t wear_status = MSG_NO_TOUCH; hrs_results_t hr_alg_results = {MSG_HRS_ALG_NOT_OPEN, 0, 0, 0, 0, 0, 0, 0}; bp_results_t bp_alg_results = {MSG_BP_ALG_NOT_OPEN, 0, 0, 0, 0, false}; Hrs3602_read_hrs(&hrm_raw_data, &als_raw_data); Hrs3602_read_ps1(&infrared_data); // static_print_info("hrm_raw_data:%d als_raw_data:%d", hrm_raw_data, als_raw_data); // static_print_info("gsensor_data:%d %d %d\n", gsensor_data[0], gsensor_data[1], gsensor_data[2]); wear_status = Hrs3602_agc(als_raw_data, infrared_data); if (wear_status == MSG_TOUCH) { tyhx_hrs_alg_send_data(&hrm_raw_data, 1, gsensor_data+0,gsensor_data+1,gsensor_data+2); hr_alg_results = tyhx_hrs_alg_get_results(); bp_alg_results = tyhx_alg_get_bp_results(); } // static_print_info("HR=%d, wear_status=%d", hr_alg_results.hr_result, wear_status); hrsensor_data.wear_status = wear_status; hrsensor_data.hr_result = hr_alg_results.hr_result; hrsensor_data.sbp_result = bp_alg_results.sbp; hrsensor_data.dbp_result = bp_alg_results.dbp; return hrsensor_data; }