Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
MAX8614X.cpp
00001 /******************************************************************************* 00002 * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. 00003 * 00004 * Permission is hereby granted, free of charge, to any person obtaining a 00005 * copy of this software and associated documentation files (the "Software"), 00006 * to deal in the Software without restriction, including without limitation 00007 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 00008 * and/or sell copies of the Software, and to permit persons to whom the 00009 * Software is furnished to do so, subject to the following conditions: 00010 * 00011 * The above copyright notice and this permission notice shall be included 00012 * in all copies or substantial portions of the Software. 00013 * 00014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00015 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 00017 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES 00018 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 00019 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 00020 * OTHER DEALINGS IN THE SOFTWARE. 00021 * 00022 * Except as contained in this notice, the name of Maxim Integrated 00023 * Products, Inc. shall not be used except as stated in the Maxim Integrated 00024 * Products, Inc. Branding Policy. 00025 * 00026 * The mere transfer of this software does not imply any licenses 00027 * of trade secrets, proprietary technology, copyrights, patents, 00028 * trademarks, maskwork rights, or any other form of intellectual 00029 * property whatsoever. Maxim Integrated Products, Inc. retains all 00030 * ownership rights. 00031 ******************************************************************************* 00032 */ 00033 #include "MAX8614X.h" 00034 00035 #define pr_err(fmt, args...) if(1) printf(fmt " (%s:%d)\n", ##args, __func__, __LINE__) 00036 #define pr_info(fmt, args...) if(1) printf(fmt " (%s:%d)\n", ##args, __func__, __LINE__) 00037 #define pr_debug(fmt, args...) if(0) printf(fmt " (%s:%d)\n", ##args, __func__, __LINE__) 00038 00039 #define ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0])) 00040 00041 MAX8614X::MAX8614X(SPI &spiBus, DigitalOut &cs, PinName pin) 00042 :m_ir(pin), m_spiBus(spiBus), m_cs(cs) 00043 { 00044 m_cs = 1; 00045 } 00046 00047 int MAX8614X::readRegister(uint8_t reg, uint8_t *data, int len) 00048 { 00049 m_cs = 0; 00050 00051 m_spiBus.write(reg); 00052 m_spiBus.write(0x80); 00053 00054 int i = 0; 00055 for(; i < len; i++) { /*TODO: make len unsigned*/ 00056 data[i] = m_spiBus.write(0x00); 00057 } 00058 00059 m_cs = 1; 00060 return 0; /*TODO: handle error cases*/ 00061 } 00062 00063 int MAX8614X::writeRegister(uint8_t reg, const uint8_t data) 00064 { 00065 m_cs = 0; 00066 00067 m_spiBus.write(reg); 00068 m_spiBus.write(0x00); 00069 m_spiBus.write(data); 00070 00071 m_cs = 1; 00072 00073 return 0; /*TODO: handle error cases*/ 00074 } 00075 00076 int MAX8614X::writeBlock(const RegisterMap reg_block[], unsigned int size) 00077 { 00078 unsigned int i; 00079 int ret = 0; 00080 00081 for (i = 0; i < size; i++) { 00082 ret = writeRegister((Registers) reg_block[i].addr, 00083 reg_block[i].val); 00084 if (ret < 0) { 00085 pr_err("writeRegister failed. ret: %d", ret); 00086 return ret; 00087 } 00088 } 00089 00090 return ret; 00091 } 00092 00093 int MAX8614X::get_part_info(uint8_t *part_id, uint8_t *rev_id) 00094 { 00095 uint32_t i; 00096 int ret; 00097 uint8_t buf[2]; 00098 const uint8_t max8614x_part_ids[] = { 00099 MAX86140_PART_ID_VAL, 00100 MAX86141_PART_ID_VAL, 00101 MAX86142_PART_ID_VAL, 00102 MAX86143_PART_ID_VAL, 00103 }; 00104 00105 ret = readRegister(MAX8614X_REV_ID_REG, buf, 2); 00106 if (ret < 0) { 00107 pr_err("readRegister failed. ret: %d", ret); 00108 return ret; 00109 } 00110 00111 for (i = 0; i < ARRAY_SIZE(max8614x_part_ids); i++) { 00112 if (buf[1] == max8614x_part_ids[i]) { 00113 *rev_id = buf[0]; 00114 *part_id = buf[1]; 00115 return 0; 00116 } 00117 } 00118 00119 // Unsupported part 00120 return -1; 00121 } 00122 00123 int MAX8614X::get_num_samples_in_fifo() 00124 { 00125 int fifo_ovf_cnt; 00126 uint8_t fifo_data[4]; 00127 uint32_t num_samples; 00128 int ret; 00129 00130 ret = readRegister(MAX8614X_OVF_CNT_REG, fifo_data, 2); 00131 if (ret < 0) { 00132 pr_err("readRegister failed. ret: %d", ret); 00133 return ret; 00134 } 00135 00136 fifo_ovf_cnt = fifo_data[0] & MAX8614X_OVF_CNT_MASK; 00137 num_samples = fifo_data[1]; 00138 00139 if (num_samples >= MAX8614X_MAX_FIFO_DEPTH) { 00140 pr_err("# FIFO is Full. OVF: %d num_samples: %lu", 00141 fifo_ovf_cnt, num_samples); 00142 } 00143 00144 return num_samples; 00145 } 00146 00147 int MAX8614X::read_fifo_data(uint8_t *fifo_data, int num_samples) 00148 { 00149 uint16_t num_bytes = num_samples * MAX8614X_DATA_WORD_SIZE; 00150 int ret = 0; 00151 00152 fifo_data[0] = MAX8614X_FIFO_DATA_REG; 00153 ret = readRegister(MAX8614X_FIFO_DATA_REG, fifo_data, num_bytes); 00154 if (ret < 0) { 00155 pr_err("readRegister failed. ret: %d", ret); 00156 return ret; 00157 } 00158 00159 return ret; 00160 } 00161 00162 void MAX8614X::fifo_irq_handler() 00163 { 00164 uint8_t fifo_buf[MAX8614X_MAX_FIFO_DEPTH * MAX8614X_DATA_WORD_SIZE] = {0}; 00165 int ret; 00166 int num_samples = 0; 00167 static int last_samples[DATA_TYPE_PPG2_LEDC4]; 00168 fifo_data_t fifo_data; 00169 uint16_t idx; 00170 int i; 00171 static ppg_data_t ppg_data; 00172 static uint32_t ppg_data_ack = 0; 00173 const uint32_t ir_green_red_ppg_type = ((1 << DATA_TYPE_PPG1_LEDC1) | 00174 (1 << DATA_TYPE_PPG1_LEDC2) | 00175 (1 << DATA_TYPE_PPG1_LEDC3)); 00176 00177 num_samples = get_num_samples_in_fifo(); 00178 if (num_samples <= 0) { 00179 pr_debug("get_num_samples_in_fifo failed. err: %d", num_samples); 00180 return; 00181 } 00182 00183 ret = read_fifo_data(fifo_buf, num_samples); 00184 if (ret < 0) { 00185 pr_debug("read_fifo_data failed. ret: %d", ret); 00186 return; 00187 } 00188 00189 for (i = 0; i < num_samples; i++) { 00190 idx = MAX8614X_DATA_WORD_SIZE * i; 00191 fifo_data.raw = fifo_buf[idx + 0] << 16 00192 | fifo_buf[idx + 1] << 8 00193 | fifo_buf[idx + 2]; 00194 if (fifo_data.type == DATA_TYPE_INVALID_DATA || fifo_data.type == 0) { 00195 pr_err("Received invalid data. data: %X, i: %d", 00196 (unsigned int)fifo_data.raw, i); 00197 00198 continue; 00199 } 00200 pr_debug("\ttype: %lu, val: %lu (%lX)", 00201 fifo_data.type, fifo_data.val, fifo_data.val); 00202 00203 if (fifo_data.type > DATA_TYPE_PPG2_LEDC3) { 00204 pr_err("Wrong Data Type: -> Type: %lu, val:%lu, Raw:%lu", 00205 fifo_data.type, fifo_data.val, fifo_data.raw); 00206 continue; 00207 } 00208 00209 if (fifo_data.type > 0 && fifo_data.type < DATA_TYPE_PPG2_LEDC3) { 00210 last_samples[fifo_data.type] = fifo_data.val; 00211 } 00212 00213 if (fifo_data.type == DATA_TYPE_PPG1_LEDC1) { 00214 max8614x_agc_handler(&led_ctrl, last_samples); 00215 } 00216 00217 if (fifo_data.type == DATA_TYPE_PPG1_LEDC1) { 00218 ppg_data.ir = fifo_data.val; 00219 } else if (fifo_data.type == DATA_TYPE_PPG1_LEDC2) { 00220 ppg_data.red = fifo_data.val; 00221 } else if (fifo_data.type == DATA_TYPE_PPG1_LEDC3) { 00222 ppg_data.green = fifo_data.val; 00223 } 00224 00225 ppg_data_ack |= 1 << fifo_data.type; 00226 00227 if ((ppg_data_ack & ir_green_red_ppg_type) != ir_green_red_ppg_type ){ 00228 continue; 00229 } 00230 ppg_data_ack = 0; 00231 00232 ret = enqueue(&queue, &ppg_data); 00233 if (ret < 0) { 00234 pr_err("Enqueue data is failed. ret: %d, thrown: %d", 00235 ret, num_samples - i); 00236 return; 00237 } 00238 } 00239 } 00240 00241 int MAX8614X::enable_die_temp() 00242 { 00243 int ret = 0; 00244 00245 ret = writeRegister(MAX8614X_DIE_TEMP_CFG_REG, MAX8614X_DIE_TEMP_EN); 00246 if (ret < 0) { 00247 pr_err("SPI Communication error"); 00248 } 00249 00250 return ret; 00251 } 00252 00253 int MAX8614X::read_die_temp() 00254 { 00255 int ret = 0; 00256 uint8_t buf[2]; 00257 00258 ret = readRegister(MAX8614X_DIE_TEMP_INT_REG, buf, 2); 00259 if (ret < 0) { 00260 pr_err("Unable to read die_temp. ret: %d", ret); 00261 return ret; 00262 } 00263 00264 die_temp.frac = (uint8_t)buf[1] & MAX8614X_DIE_TEMP_FRAC_MASK; 00265 die_temp.tint = (uint8_t)buf[0]; 00266 00267 pr_debug("Die temp: %d - %d, %d", die_temp.val, buf[0], buf[1]); 00268 return enable_die_temp(); 00269 } 00270 00271 void MAX8614X::irq_handler(void) 00272 { 00273 int ret; 00274 int_status_t status; 00275 00276 ret = readRegister(MAX8614X_INT_STATUS1_REG, status.val, 2); 00277 if (ret < 0) { 00278 pr_err("readRegister failed. ret: %d", ret); 00279 } 00280 pr_debug("Status reg: %X %X", status.val[0], status.val[1]); 00281 00282 if (status.a_full || status.data_rdy) { 00283 fifo_irq_handler(); 00284 } 00285 00286 if (status.die_temp_rdy) { 00287 pr_debug("Pwr_rdy interrupt was triggered."); 00288 } 00289 00290 if (status.pwr_rdy) { 00291 pr_info("Pwr_rdy interrupt was triggered."); 00292 } 00293 00294 if (status.die_temp_rdy) { 00295 read_die_temp(); 00296 } 00297 00298 if (status.vdd_oor) { 00299 vdd_oor_cnt++; 00300 pr_info("VDD Out of range cnt: %d", vdd_oor_cnt); 00301 } 00302 if (status.sha_done) { 00303 shaComplete = true; 00304 printf("sha interrupt\n\r"); 00305 } 00306 } 00307 bool MAX8614X::isShaComplete(void) 00308 { 00309 return shaComplete; 00310 } 00311 void MAX8614X::clearShaComplete(void) 00312 { 00313 shaComplete = false; 00314 } 00315 int MAX8614X::reset() 00316 { 00317 int ret = 0; 00318 00319 ret = writeRegister(MAX8614X_SYSTEM_CTRL_REG, 00320 MAX8614X_SYSTEM_RESET_MASK); 00321 if (ret < 0) { 00322 pr_err("writeRegister failed. ret: %d", ret); 00323 return ret; 00324 } 00325 00326 ret = queue_reset(&queue); 00327 if (ret < 0) { 00328 pr_err("queue_reset failed. ret: %d", ret); 00329 return ret; 00330 } 00331 00332 led_control_reset(&led_ctrl); 00333 00334 return ret; 00335 } 00336 00337 int MAX8614X::poweroff() 00338 { 00339 int ret = 0; 00340 00341 ret = writeRegister(MAX8614X_SYSTEM_CTRL_REG, 00342 MAX8614X_SYSTEM_SHDN_MASK); 00343 if (ret < 0) { 00344 pr_err("writeRegister failed. ret: %d", ret); 00345 return ret; 00346 } 00347 00348 return ret; 00349 } 00350 00351 int MAX8614X::init() 00352 { 00353 int ret = RTN_NO_ERROR; 00354 uint8_t part_id, rev_id; 00355 void *queue_buf = NULL; 00356 00357 ret = get_part_info(&part_id, &rev_id); 00358 if (ret < 0) { 00359 pr_err("MAX8614X is not detected. Part_id: 0x%X, Rev_Id: 0x%X", 00360 part_id, rev_id); 00361 ret = RTN_ERR_NOT_8614x; 00362 goto fail; 00363 } 00364 pr_info("MAX8614X detected. Part_id: 0x%X, Rev_Id: 0x%X", part_id, rev_id); 00365 00366 queue_buf = malloc(sizeof(ppg_data_t) * MAX8614X_DRIVER_FIFO_SZ); 00367 if (queue_buf == NULL) { 00368 pr_err("malloc failed. ret: %d", ret); 00369 ret = RTN_ERR_MEM_ALLOC_FAIL; 00370 goto fail; 00371 } 00372 00373 ret = queue_init(&queue, queue_buf, 00374 sizeof(ppg_data_t), sizeof(ppg_data_t) * MAX8614X_DRIVER_FIFO_SZ); 00375 if (ret < 0) { 00376 pr_err("queue_init failed"); 00377 ret = RTN_ERR_QUEUE_INIT; 00378 free(queue_buf); 00379 goto fail; 00380 } 00381 00382 ret = writeRegister(MAX8614X_SYSTEM_CTRL_REG, 00383 MAX8614X_SYSTEM_RESET_MASK); 00384 if (ret < 0) { 00385 pr_err("writeRegister failed. ret: %d", ret); 00386 goto fail; 00387 } 00388 00389 die_temp.frac = 0; 00390 die_temp.tint = 0; 00391 00392 led_control_init(&led_ctrl); /*TODO: after porting agc, test */ 00393 00394 m_ir.fall(Callback<void()>(this, &MAX8614X::irq_handler)); 00395 00396 return ret; 00397 fail: 00398 pr_err("Init failed. ret: %d", ret); 00399 return ret; 00400 } 00401 00402 int MAX8614X::sensor_enable(int enable) 00403 { 00404 int ret = RTN_NO_ERROR; 00405 uint8_t led_seq[3]; 00406 00407 RegisterMap_t ppg_init_cfg[] = { 00408 { MAX8614X_SYSTEM_CTRL_REG, MAX8614X_SYSTEM_RESET_MASK}, 00409 { MAX8614X_PPG_CFG1_REG, MAX8614X_PPG_LED_PW_115_2_US_MASK // PPG_LED_PW = 3 (115.2us) 00410 | MAX8614X_PPG1_ADC_RGE_32768_MASK // PPG1_ADC_RGE = 3(32768nA) 00411 | MAX8614X_PPG2_ADC_RGE_32768_MASK }, // PPG2_ADC_RGE = 3(32768nA) 00412 { MAX8614X_PPG_CFG2_REG, MAX8614X_PPG_SR_100_SPS}, // PPG_SR: 3 (100Hz), SMP_AVE=0 00413 { MAX8614X_LED_SEQ1_REG, 0x21}, 00414 { MAX8614X_LED_SEQ2_REG, 0x03}, 00415 { MAX8614X_LED1_PA_REG, 0x80}, 00416 { MAX8614X_LED2_PA_REG, 0x80}, 00417 { MAX8614X_LED3_PA_REG, 0x80}, 00418 { MAX8614X_LED_RANGE1_REG, MAX8614X_LED1_RGE_25mA_MASK 00419 | MAX8614X_LED2_RGE_25mA_MASK 00420 | MAX8614X_LED3_RGE_25mA_MASK}, 00421 { MAX8614X_FIFO_CFG1_REG, 0x0C}, 00422 { MAX8614X_FIFO_CFG2_REG, MAX8614X_FLUSH_FIFO_MASK 00423 | MAX8614X_FIFO_STAT_CLR_MASK 00424 | MAX8614X_A_FULL_TYPE_MASK // Try 0 00425 | MAX8614X_FIFO_RO_MASK 00426 | MAX8614X_FIFO_EN_MASK}, 00427 { MAX8614X_INT_ENABLE1_REG, MAX8614X_INT1_EN_A_FULL_MASK 00428 | MAX8614X_INT1_EN_DIE_TEMP_MASK 00429 | MAX8614X_INT1_EN_VDD_OOR_MASK}, 00430 }; 00431 00432 if (enable) { 00433 /* Read current sequence settings, and check what modes are open */ 00434 led_seq[0] = MAX8614X_LED_SEQ1_REG; 00435 ret |= readRegister(MAX8614X_LED_SEQ1_REG, led_seq, 3); 00436 if (ret < 0) { 00437 pr_err("readRegister failed. ret: %d", ret); 00438 return ret; 00439 } 00440 00441 pr_debug("0-Sequence registers: %X %X %X", led_seq[0], led_seq[1], led_seq[2]); 00442 ret |= writeBlock(ppg_init_cfg, ARRAY_SIZE(ppg_init_cfg)); 00443 led_seq[0] = MAX8614X_INT_STATUS1_REG; 00444 ret |= readRegister(MAX8614X_INT_STATUS1_REG, led_seq, 3); // Mert: the len was 3 ?! 00445 pr_debug("1-Sequence registers: %X %X %X", led_seq[0], led_seq[1], led_seq[2]); 00446 if (ret < 0) { 00447 pr_err("readRegister failed. ret: %d", ret); 00448 return ret; 00449 } 00450 agc_enable(1); 00451 pr_debug("Wrote register settings. ret: %d", ret); 00452 } else { 00453 ret = reset(); 00454 if (ret < 0) { 00455 pr_err("reset failed. ret: %d", ret); 00456 return ret; 00457 } 00458 00459 ret = poweroff(); 00460 if (ret < 0) { 00461 pr_err("poweroff failed. ret: %d", ret); 00462 return ret; 00463 } 00464 } 00465 00466 return RTN_NO_ERROR; 00467 } 00468 00469 int MAX8614X::agc_enable(int agc_enable) 00470 { 00471 int ret = RTN_NO_ERROR; 00472 led_ctrl.agc_is_enabled = !!agc_enable; 00473 led_ctrl.lpm_is_enabled = !!agc_enable; 00474 ret = led_prox_init(&led_ctrl, led_ctrl.lpm_is_enabled); 00475 return ret; 00476 } 00477 00478 int MAX8614X::dequeue_from_fifo_queue(uint32_t *ir, uint32_t *red, uint32_t *green) 00479 { 00480 int ret; 00481 ppg_data_t ppg_data; 00482 00483 ret = dequeue(&queue, &ppg_data); 00484 if (ret < 0) { 00485 return RTN_ERR_QUEUE_EMPTY; 00486 } 00487 00488 pr_debug("%lu %lu %lu", ppg_data.ir, ppg_data.red, ppg_data.green); 00489 00490 *ir = ppg_data.ir; 00491 *red = ppg_data.red; 00492 *green = ppg_data.green; 00493 00494 return RTN_NO_ERROR; 00495 } 00496 00497 int MAX8614X::dump_registers() 00498 { 00499 int ret = 0; 00500 uint8_t reg_addr; 00501 uint8_t val; 00502 00503 for (reg_addr = 0x00; reg_addr <= 0x42; reg_addr++) { 00504 ret |= readRegister(reg_addr, &val, 1); 00505 printf("{%02X,%02X},", reg_addr, val); 00506 } 00507 00508 for (reg_addr = 0xF0; reg_addr != 0x00; reg_addr++) { 00509 ret |= readRegister(reg_addr, &val, 1); 00510 printf("{%02X,%02X},", reg_addr, val); 00511 } 00512 00513 return ret; 00514 } 00515 00516 const char * MAX8614X::get_sensor_part_name() 00517 { 00518 return "max86141"; 00519 } 00520 00521 const char * MAX8614X::get_sensor_name() 00522 { 00523 return "ppg"; 00524 }
Generated on Fri Sep 2 2022 22:34:53 by
1.7.2