OB1203 basic mbed driver
Embed:
(wiki syntax)
Show/hide line numbers
OB1203.cpp
00001 #include "OB1203.h" 00002 #include "mbed.h" 00003 00004 extern Serial pc; 00005 00006 // // 00007 OB1203::OB1203(I2C *i2c_obj) 00008 { 00009 i2c = i2c_obj; 00010 } 00011 00012 00013 void OB1203::reset() 00014 { 00015 /*POR reset*/ 00016 writeRegister(OB1203_ADDR,REG_MAIN_CTRL_0,SW_RESET); 00017 wait_ms(POR_TIME_MS); 00018 } 00019 00020 00021 void OB1203::writeRegister(int addr, char reg, char val) { 00022 /*writes 1 byte to a single register*/ 00023 char writeData[2]; 00024 writeData[0] = reg; 00025 writeData[1] = val; 00026 i2c->write(addr,writeData, 2); 00027 } 00028 00029 00030 void OB1203::writeBlock(int addr, char startReg, char *data, char numBytes) { 00031 /*writes data from an array beginning at the startReg*/ 00032 // pc.printf("entering writeBlock with data %02x %02x\r\n",data[0],data[1]); 00033 char writeData[numBytes+1]; 00034 writeData[0]=startReg; 00035 for(int n=1;n<numBytes+1;n++) { 00036 writeData[n]=data[n-1]; 00037 } 00038 i2c->write(addr,writeData,numBytes+1); 00039 } 00040 00041 00042 void OB1203::readBlock(int addr, char startReg, char *data, int numBytes) 00043 { 00044 char writeData[1]; 00045 writeData[0] = startReg; 00046 i2c->write(addr,writeData,1,true); 00047 i2c->read(addr,data,numBytes); 00048 // wait_us(800); 00049 // for(int n=0;n<numBytes;n++) 00050 // { 00051 // i2c->read(addr,data+n,1,1); 00052 // wait_us(20); 00053 // } 00054 } 00055 00056 uint16_t OB1203::get_status() 00057 { 00058 char writeData[1]; //declare array of size 1 00059 writeData[0] = REG_STATUS_0; 00060 char data[2]; //declare array of size 1 00061 i2c->write(OB1203_ADDR,writeData,1,true); 00062 i2c->read(OB1203_ADDR,data,2); 00063 return (data[0]<<8 | data[1]); 00064 } 00065 00066 bool OB1203::dataIsNew() 00067 { 00068 int status_reg_vals; 00069 status_reg_vals = get_status(); 00070 return ((status_reg_vals & 0x0100)>>8) || (status_reg_vals & 0x0091); 00071 } 00072 00073 bool OB1203::lsIsNew() 00074 { 00075 int status_reg_vals; 00076 status_reg_vals = get_status(); 00077 return ((status_reg_vals & 0x0100)>>8); 00078 } 00079 00080 bool OB1203::psIsNew() 00081 { 00082 int status_reg_vals; 00083 status_reg_vals = get_status(); 00084 return (status_reg_vals & 0x0001); 00085 } 00086 00087 bool OB1203::tempIsNew() 00088 { 00089 int status_reg_vals; 00090 status_reg_vals = get_status(); 00091 return (status_reg_vals & 0x0080); 00092 } 00093 00094 bool OB1203::bioIsNew() 00095 { 00096 int status_reg_vals; 00097 status_reg_vals = get_status(); 00098 return (status_reg_vals & 0x0010); 00099 } 00100 00101 void OB1203::setOscTrim() 00102 { 00103 char writeData[1]; 00104 writeData[0] = osc_trim; 00105 // pc.printf("writing %02x to REG %02x\r\n",osc_trim,REG_OSC_TRIM); 00106 writeBlock(OB1203_ADDR,REG_OSC_TRIM,writeData,1); 00107 } 00108 00109 void OB1203::setMainConfig() 00110 { 00111 char writeData[2]; 00112 writeData[0] = ls_sai | ls_mode | ls_en; //MAIN_CTRL_0 00113 writeData[1] = temp_en | ps_sai_en | ppg_ps_mode | ppg_ps_en; //MAIN_CTRL_1 00114 // pc.printf("main config 1 to write %02x\r\n",writeData[1]); 00115 writeBlock(OB1203_ADDR,REG_MAIN_CTRL_0,writeData,2); 00116 } 00117 00118 00119 void OB1203::setIntConfig() 00120 { 00121 char writeData[3]; 00122 writeData[0] = ls_int_sel | ls_var_mode | ls_int_en; 00123 writeData[1] = afull_int_en | ppg_int_en | ps_logic_mode | ps_int_en; 00124 writeData[2] = ls_persist | ps_persist; 00125 writeBlock(OB1203_ADDR,REG_INT_CFG_0,writeData,3); //default 00126 } 00127 00128 00129 void OB1203::setLSthresh() 00130 { 00131 char writeData[6]; 00132 writeData[0] = (char) (ls_thres_hi & 0x000000FF); 00133 writeData[1] = (char) ((ls_thres_hi & 0x0000FF00)>>8); 00134 writeData[2] = (char) ((ls_thres_hi & 0x00FF0000)>>16); 00135 writeData[3] = (char) (ls_thres_lo & 0x000000FF); 00136 writeData[4] = (char) ((ls_thres_lo & 0x0000FF00)>>8); 00137 writeData[5] = (char) ((ls_thres_lo & 0x00FF0000)>>16); 00138 writeBlock(OB1203_ADDR,REG_LS_THRES_HI,writeData,6); //default 00139 } 00140 00141 00142 void OB1203::setPSthresh() 00143 { 00144 char writeData[4]; 00145 writeData[0] = (char) (ps_thres_hi & 0x000FF); 00146 writeData[1] = (char) ((ps_thres_hi & 0xFF00)>>8); 00147 writeData[2] = (char) (ps_thres_lo & 0x000FF); 00148 writeData[3] = (char) ((ps_thres_lo & 0xFF00)>>8); 00149 writeBlock(OB1203_ADDR,REG_PS_THRES_HI,writeData,4); //default 00150 } 00151 00152 00153 void OB1203::setPScurrent() 00154 { 00155 char writeData[2]; 00156 writeData[0] = (char) (ps_current & 0x00FF); 00157 writeData[1] = (char) ((ps_current & 0xFF00)>>8); 00158 writeBlock(OB1203_ADDR,REG_PS_LED_CURR,writeData,2); 00159 } 00160 00161 00162 void OB1203::setPPGcurrent() 00163 { 00164 char writeData[4]; 00165 if(led_flip == LED_FLIP_OFF) { 00166 writeData[0] = (char) (ir_current & 0x00FF); 00167 writeData[1] = (char) ((ir_current & 0xFF00)>>8); 00168 writeData[2] = (char) (r_current & 0x00FF); 00169 writeData[3] = (char) ((r_current & 0xFF00)>>8); 00170 } else { 00171 writeData[2] = (char) (ir_current & 0x00FF); 00172 writeData[3] = (char) ((ir_current & 0xFF00)>>8); 00173 writeData[0] = (char) (r_current & 0x00FF); 00174 writeData[1] = (char) ((r_current & 0xFF00)>>8); 00175 } 00176 writeBlock(OB1203_ADDR,REG_PPG_IRLED_CURR,writeData,4); 00177 } 00178 00179 00180 void OB1203::setPPG_PSgain_cfg() 00181 { 00182 char writeData[2]; 00183 writeData[0] = ppg_ps_gain | ppg_LED_settling | ppg_ALC_track; 00184 writeData[1] = ppg_pow_save | led_flip | sig_out | diff | alc; 00185 writeBlock(OB1203_ADDR,REG_PPG_PS_GAIN,writeData,2); 00186 } 00187 00188 void OB1203::setPPGana_can() 00189 { 00190 char writeData[1]; 00191 writeData[0] = ch1_can_ana | ch2_can_ana; 00192 writeBlock(OB1203_ADDR,REG_PPG_CAN_ANA,writeData,1); 00193 } 00194 00195 void OB1203::setPPGavg_and_rate() 00196 { 00197 char writeData[2]; 00198 writeData[0] = ppg_avg | 0x0A; //use standard LED max settings 00199 writeData[1] = ppg_pwidth | ppg_freq | ppg_rate; 00200 writeBlock(OB1203_ADDR,REG_PPG_AVG,writeData,2); 00201 } 00202 00203 void OB1203::setBioTrim() 00204 { 00205 char writeData[1]; 00206 writeData[0] = bio_trim; 00207 writeBlock(OB1203_ADDR, REG_BIO_TRIM,writeData,1); 00208 } 00209 00210 void OB1203::setLEDTrim() 00211 { 00212 char writeData[1]; 00213 writeData[0] = led_trim; 00214 writeBlock(OB1203_ADDR, REG_LED_TRIM,writeData,1); 00215 } 00216 00217 void OB1203::setDigTrim() 00218 { 00219 char writeData[2]; 00220 writeData[0] = led1_trim; 00221 writeData[1] = led2_trim; 00222 writeBlock(OB1203_ADDR, REG_DIG_LED1_TRIM,writeData,2); 00223 } 00224 00225 void OB1203::setDigitalCan() 00226 { 00227 char writeData[2]; 00228 writeData[0] = (char)(ps_digital_can & 0x00FF); 00229 writeData[1] = (char)((ps_digital_can & 0xFF00)>>8); 00230 writeBlock(OB1203_ADDR,REG_PS_CAN_DIG,writeData,2); 00231 } 00232 00233 00234 void OB1203::setFifoConfig() 00235 { 00236 char writeData[1]; 00237 writeData[0] = fifo_rollover_en | fifo_afull_advance_warning; 00238 writeBlock(OB1203_ADDR,REG_FIFO_CFG,writeData,1); 00239 } 00240 00241 00242 void OB1203::resetFIFO() 00243 { 00244 char writeData[2]; 00245 writeData[0]=0; 00246 writeData[1]=0; 00247 writeBlock(OB1203_ADDR,REG_FIFO_WR_PTR,writeData,2);//set write and read pointer to zero--next sample is newest 00248 writeRegister(OB1203_ADDR,REG_MAIN_CTRL_1, (temp_en | ps_sai_en | ppg_ps_mode | 0) ); //turn PPG off MAIN_CTRL_1; 00249 writeRegister(OB1203_ADDR,REG_MAIN_CTRL_1, (temp_en | ps_sai_en | ppg_ps_mode | ppg_ps_en) ); //MAIN_CTRL_1; 00250 } 00251 00252 00253 void OB1203::init_rgb() 00254 { 00255 /*Configures ALS/RGB mode. PS and BIO off. 00256 Use: set class variables using header declarations. Then call this function.*/ 00257 char writeData[2]; 00258 writeBlock(OB1203_ADDR,REG_LS_RES_RATE,writeData,2); 00259 writeData[0] = ls_res | ls_rate; //LS_RES_RATE 00260 writeData[1] = ls_gain; //LS_GAIN 00261 writeBlock(OB1203_ADDR,REG_LS_RES_RATE,writeData,2); 00262 setLSthresh(); 00263 setIntConfig(); 00264 ppg_ps_en = PPG_PS_OFF; 00265 ls_en = LS_ON; 00266 setMainConfig(); 00267 } 00268 00269 00270 void OB1203::init_ps() 00271 { 00272 /*Configures PS mode but not thresholds or interrupts. RGB/ALS and BIO off. 00273 Use: set class variables using header declarations. Then call this function.*/ 00274 char writeData[2]; 00275 //PS settings 00276 setPScurrent(); 00277 writeData[0] = ps_can_ana | ps_pulses | 0x02; //PS_CAN_PULSES -->set hidden max current registers to allow higher LED powers 00278 writeData[1] = ps_pwidth | ps_rate; //PS_PWIDTH_RATE 00279 writeBlock(OB1203_ADDR,REG_PS_CAN_PULSES,writeData,2); 00280 //Digital crosstalk cancellation 00281 setDigitalCan(); //PS_CAN_DIG 00282 //set PS moving average and hysteresis 00283 writeData[0] = ps_avg_en | ps_hys_level; //PS_MOV_AVG_HYS 00284 writeBlock(OB1203_ADDR,REG_PS_MOV_AVG_HYS,writeData,1); 00285 //set PS interrupt thresholds 00286 setPSthresh(); 00287 //interrupt configuration 00288 ls_int_en = LS_INT_OFF; 00289 setIntConfig(); 00290 setPPG_PSgain_cfg(); 00291 setPScurrent(); 00292 //config PS 00293 ls_en = LS_OFF; 00294 ppg_ps_en = 1; 00295 ppg_ps_mode = PS_MODE; 00296 //setLEDTrim(); 00297 setMainConfig(); 00298 } 00299 00300 00301 void OB1203::init_ps_rgb() 00302 { 00303 reset(); 00304 char writeData[2]; 00305 writeData[0] = ls_res | ls_rate; //LS_RES_RATE 00306 writeData[1] = ls_gain; //LS_GAIN 00307 writeBlock(OB1203_ADDR,REG_LS_RES_RATE,writeData,2); 00308 writeData[0] = ps_can_ana | ps_pulses | 0x02; //PS_CAN_PULSES -->set hidden max current registers to allow higher LED powers 00309 writeData[1] = ps_pwidth | ps_rate; //PS_PWIDTH_RATE 00310 writeBlock(OB1203_ADDR,REG_PS_CAN_PULSES,writeData,2); 00311 setDigitalCan(); //PS_CAN_DIG 00312 //set PS moving average and hysteresis 00313 writeData[0] = ps_avg_en | ps_hys_level; //PS_MOV_AVG_HYS 00314 writeBlock(OB1203_ADDR,REG_PS_MOV_AVG_HYS,writeData,1); 00315 setIntConfig(); 00316 setPSthresh(); 00317 setPScurrent(); 00318 setLSthresh(); 00319 ls_en = LS_ON; 00320 ppg_ps_en = PPG_PS_ON; 00321 ppg_ps_mode = PS_MODE; 00322 //setLEDTrim(); 00323 setMainConfig(); 00324 } 00325 00326 00327 void OB1203::init_hr() 00328 { 00329 reset(); 00330 ps_int_en = PS_INT_OFF; 00331 ls_en = LS_OFF; 00332 setIntConfig(); 00333 char readData[1]; 00334 //readBlock(OB1203_ADDR,REG_PS_INT_CFG_1,readData,1); 00335 // pc.printf("int config 1 = %02X\r\n",readData[0]); 00336 setPPG_PSgain_cfg(); 00337 setPPGcurrent(); 00338 setPPGana_can(); 00339 setPPGavg_and_rate(); 00340 setFifoConfig(); 00341 ppg_ps_mode = HR_MODE; 00342 //setBioTrim(); 00343 //setLEDTrim(); 00344 setDigTrim(); 00345 setMainConfig(); 00346 } 00347 00348 void OB1203::init_spo2() 00349 { 00350 reset(); 00351 ps_int_en = PS_INT_OFF; 00352 ls_en = LS_OFF; 00353 setIntConfig(); 00354 char readData[1]; 00355 readBlock(OB1203_ADDR,REG_PS_INT_CFG_1,readData,1); 00356 // pc.printf("int config 1 = %02X\r\n",readData[0]); 00357 setPPG_PSgain_cfg(); 00358 setPPGcurrent(); 00359 setPPGana_can(); 00360 setPPGavg_and_rate(); 00361 setFifoConfig(); 00362 ppg_ps_mode = SPO2_MODE; 00363 //setLEDTrim(); 00364 setDigTrim(); 00365 //setBioTrim(); 00366 setMainConfig(); 00367 } 00368 00369 uint32_t OB1203::bytes2uint32(char *data, int start_byte) 00370 { 00371 //coverts a string of 3 bytes with LSB first into unsigned long MSB last 00372 return ((uint32_t)data[start_byte+2])<<16 | ((uint32_t)data[start_byte+1])<<8 | ((uint32_t)data[start_byte]) ; 00373 } 00374 00375 uint32_t OB1203::twoandhalfBytes2uint32(char *data, int start_byte) 00376 { 00377 //coverts a string of 3 bytes with LSB first into unsigned long MSB last 00378 return (uint32_t)( ((data[start_byte+2] & 0x0F)<<16) | (uint32_t(data[start_byte+1])<<8) | uint32_t(data[start_byte]) ) ; 00379 } 00380 00381 char OB1203::get_ls_data(uint32_t *data) 00382 { 00383 char byte_data[21]; 00384 readBlock(OB1203_ADDR,REG_STATUS_0,byte_data,21); 00385 #ifdef DEBUG 00386 pc.printf("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x $02x\r\n", 00387 byte_data[0],byte_data[1],byte_data[2],byte_data[3], 00388 byte_data[4],byte_data[5],byte_data[6],byte_data[7], 00389 byte_data[8],byte_data[9],byte_data[10],byte_data[11], 00390 byte_data[12],byte_data[13],byte_data[14],byte_data[15], 00391 byte_data[16],byte_data[17],byte_data[18]), 00392 byte_data[19],byte_data[20]; 00393 #endif 00394 00395 00396 //byte_data[0] is ps (not populated) 00397 data[1] = twoandhalfBytes2uint32(byte_data,4); //w 00398 data[2] = twoandhalfBytes2uint32(byte_data,7); //g 00399 data[3] = twoandhalfBytes2uint32(byte_data,10); //b 00400 data[4] = twoandhalfBytes2uint32(byte_data,13); //r 00401 data[5] = twoandhalfBytes2uint32(byte_data,16); //c 00402 data[6] = (uint32_t)((byte_data[20] & 0x0F)<<8) | (uint32_t)byte_data[19] ; //temp data 00403 return ( (byte_data[0] & LS_NEW_DATA) == 0x01 ? 1 : 0); //return 1 if new data or 0 if old data 00404 } 00405 00406 char OB1203::get_ps_data(uint32_t *data) 00407 { 00408 char byte_data[4]; 00409 readBlock(OB1203_ADDR,REG_STATUS_0,byte_data,4); 00410 #ifdef DEBUG 00411 pc.printf( "%02x %02x %02x %02x\r\n", byte_data[0], byte_data[1], byte_data[2], byte_data[3] ); 00412 #endif 00413 00414 data[0] = ((uint32_t)byte_data[3])<<8 | ((uint32_t)byte_data[2]); //ps data 00415 return ( (byte_data[1] & PS_NEW_DATA) == 0x01 ? 1 : 0); //return 1 if new data or 0 if old data 00416 } 00417 00418 char OB1203::get_ps_ls_data(uint32_t *data) 00419 { 00420 char byte_data[21]; 00421 readBlock(OB1203_ADDR,REG_STATUS_0,byte_data,21); 00422 #ifdef DEBUG 00423 pc.printf("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x $02x\r\n", 00424 byte_data[0],byte_data[1],byte_data[2],byte_data[3],byte_data[4], 00425 byte_data[5],byte_data[6],byte_data[7],byte_data[8],byte_data[9], 00426 byte_data[10],byte_data[11],byte_data[12],byte_data[13],byte_data[14], 00427 byte_data[15],byte_data[16],byte_data[17],byte_data[18] ), 00428 byte_data[19],byte_data[20]; 00429 #endif 00430 00431 data[0] = ((uint32_t)byte_data[3])<<8 | ((uint32_t)byte_data[2]); //ps 00432 data[1] = twoandhalfBytes2uint32(byte_data,4); //w 00433 data[2] = twoandhalfBytes2uint32(byte_data,7); //g 00434 data[3] = twoandhalfBytes2uint32(byte_data,10); //b 00435 data[4] = twoandhalfBytes2uint32(byte_data,13); //r 00436 data[5] = twoandhalfBytes2uint32(byte_data,16); //c 00437 data[6] = (uint32_t)((byte_data[20] & 0x0F)<<8) | (uint32_t)byte_data[19] ; //temp data 00438 return ( (byte_data[0] & LS_NEW_DATA) == 0x01 ? 1 : 0); //return 1 if new data or 0 if old data 00439 } 00440 00441 00442 void OB1203::getFifoInfo(char *fifo_info) 00443 { 00444 readBlock(OB1203_ADDR,REG_FIFO_WR_PTR,fifo_info,3); 00445 writePointer = fifo_info[0]; 00446 readPointer = fifo_info[1]; 00447 fifoOverflow = fifo_info[2]; 00448 } 00449 00450 00451 void OB1203::getNumFifoSamplesAvailable(char *fifo_info, char *sample_info) 00452 { 00453 /*sample_info [3] = {numSamplesHR, numSamplesSpO2, overflow*/ 00454 00455 getFifoInfo(fifo_info); 00456 uint8_t writePointer = fifo_info[0]; 00457 uint8_t readPointer = fifo_info [1]; 00458 uint8_t numSamples = writePointer; 00459 if (writePointer<readPointer) 00460 { 00461 numSamples += 32; 00462 } 00463 numSamples -= readPointer; 00464 sample_info[0] = numSamples; //num HR samples 00465 sample_info[1] = (numSamples>>1); //num SpO2 samples 00466 sample_info[2] = fifo_info[2]; 00467 } 00468 00469 00470 void OB1203::getFifoSamples(uint8_t numSamples, char *fifoData) 00471 { 00472 readBlock(OB1203_ADDR,REG_FIFO_DATA,fifoData,3*numSamples); 00473 } 00474 00475 00476 void OB1203::parseFifoSamples(char numSamples, char *fifoData, uint32_t *assembledData) 00477 { 00478 for (int n=0; n<numSamples; n++) 00479 { 00480 assembledData[n] = bytes2uint32(fifoData,3*n); 00481 } 00482 } 00483 00484 00485 char OB1203::get_part_ID(char *data) 00486 { 00487 readBlock(OB1203_ADDR,REG_PART_ID,data,1); 00488 return data[0]; 00489 } 00490 00491 00492 void OB1203::do_agc(uint32_t data, bool ch) 00493 { 00494 const uint32_t tol1 = TOL1; 00495 const uint32_t tol2 = TOL2; 00496 const uint16_t in_range_persist = IN_RANGE_PERSIST; 00497 static uint16_t in_range[2] = {0,0}; 00498 uint16_t maxCurrent[2]; 00499 if(led_flip == LED_FLIP_OFF) { 00500 maxCurrent[0] = IR_MAX_CURRENT; 00501 maxCurrent[1] = R_MAX_CURRENT; 00502 } else { 00503 maxCurrent[0] = R_MAX_CURRENT; 00504 maxCurrent[1] = IR_MAX_CURRENT; 00505 } 00506 const uint16_t step = STEP; 00507 const uint32_t targetCounts[2] = {IR_TARGET_COUNTS, R_TARGET_COUNTS}; 00508 //ch = 0 for IR, 1 for R (channel) 00509 if( data > targetCounts[ch] + (in_range[ch]>in_range_persist ? tol2: tol1) ) 00510 { 00511 if(data>targetCounts[ch] + tol2) 00512 in_range[ch]=0; 00513 00514 00515 if( (ch ? r_current : ir_current)>step) 00516 { 00517 (ch ? r_current : ir_current) -= step; 00518 update = 1; 00519 } 00520 } 00521 else if( data < targetCounts[ch] - (in_range[ch]>in_range_persist ? tol2 : tol1) ) 00522 { 00523 if(data<targetCounts[ch] - tol2) 00524 in_range[ch]=0; 00525 if( (ch ? r_current : ir_current) +step<maxCurrent[ch]) //no need to go to full current 00526 { 00527 (ch ? r_current : ir_current) += step; 00528 update = 1; 00529 } 00530 } 00531 else 00532 { 00533 if( (data > (targetCounts[ch]-tol1) ) && (data < (targetCounts[ch]+tol1)) ) 00534 in_range[ch]++; 00535 } 00536 }
Generated on Wed Jul 20 2022 11:26:56 by 1.7.2