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.
Dependencies: max32630fthr USBDevice
Fork of MAXREFDES220_HEART_RATE_MONITOR by
Finger Heart Rate Monitor and SpO2 Monitor
The MAXREFDES220 Smart Sensor FeatherWing board is a integrated solution for providing finger-based heart rate measurements and SpO2 (blood oxygen saturation). This evaluation board interfaces to the host computer using the I2C interface. Heart rate outpu is available in beats per minute (BPM) and SpO2 is reported in percentages.; the PPG (photoplethysmography) raw data is also available. The board has an MAX30101 chip which is a low power heart rate monitor with adjustable sample rates and adjustable LED currents. The low cost MAX32664 microcontroller is pre-flashed with C code for finger-based pulse rate and SpO2 monitoring. Bootloader software is included to allow for future algorithms or updates to the algorithm from Maxim Integrated.
Ordering information will be available soon.
Note: SpO2 values are not calibrated. Calibration should be performed using the final end product.
Warning
The MAXREFDES220 source code listed is dated and only compatible with the 1.2.8a.msbl. The latest sample host source code is available on the MAX32664 website.
MAXREFDES220 FeatherWing Pinout Connections
Diff: Interfaces/SmartSensor/SSInterface.cpp
- Revision:
- 5:e458409e913f
- Parent:
- 1:7a55c0c7d6d9
- Child:
- 7:3e2a5545f1d8
--- a/Interfaces/SmartSensor/SSInterface.cpp Thu May 24 14:51:55 2018 -0700 +++ b/Interfaces/SmartSensor/SSInterface.cpp Thu May 24 14:54:28 2018 -0700 @@ -35,9 +35,12 @@ #include "Peripherals.h" #include "assert.h" #include "utils.h" +#include "i2cm.h" SSInterface::SSInterface(I2C &i2cBus, PinName ss_mfio, PinName ss_reset) - :m_i2cBus(&i2cBus), m_spiBus(NULL), mfio_pin(ss_mfio), reset_pin(ss_reset), irq_pin(ss_mfio) + :m_i2cBus(&i2cBus), m_spiBus(NULL), + mfio_pin(ss_mfio), reset_pin(ss_reset), irq_pin(ss_mfio), + irq_evt(1000000, "irq") { reset_pin.input(); irq_pin.fall(callback(this, &SSInterface::irq_handler)); @@ -47,7 +50,9 @@ } SSInterface::SSInterface(SPI &spiBus, PinName ss_mfio, PinName ss_reset) - :m_i2cBus(NULL), m_spiBus(&spiBus), mfio_pin(ss_mfio), reset_pin(ss_reset), irq_pin(ss_mfio) + :m_i2cBus(NULL), m_spiBus(&spiBus), + mfio_pin(ss_mfio), reset_pin(ss_reset), irq_pin(ss_mfio), + irq_evt(1000000, "irq") { reset_pin.input(); irq_pin.fall(callback(this, &SSInterface::irq_handler)); @@ -139,7 +144,7 @@ } SS_STATUS SSInterface::self_test(int idx, uint8_t *result, int sleep_ms){ - uint8_t cmd_bytes[] = {SS_FAM_R_SELFTEST, idx}; + uint8_t cmd_bytes[] = { SS_FAM_R_SELFTEST, (uint8_t)idx }; uint8_t rxbuf[2]; SS_STATUS ret; @@ -256,6 +261,8 @@ if (total_len <= SS_SMALL_BUF_SIZE) { return write_cmd_small(cmd_bytes, cmd_bytes_len, data, data_len, sleep_ms); + } else if (total_len <= SS_MED_BUF_SIZE) { + return write_cmd_medium(cmd_bytes, cmd_bytes_len, data, data_len, sleep_ms); } else if (total_len <= SS_LARGE_BUF_SIZE) { return write_cmd_large(cmd_bytes, cmd_bytes_len, data, data_len, sleep_ms); } else { @@ -272,8 +279,14 @@ } pr_info("\r\n"); - int ret = 0; - ret |= m_i2cBus->write(SS_I2C_8BIT_SLAVE_ADDR, (char*)tx_buf, tx_len); + int ret = m_i2cBus->write(SS_I2C_8BIT_SLAVE_ADDR, (char*)tx_buf, tx_len); + + int retries = 4; + while (ret != 0 && retries-- > 0) { + pr_err("i2c wr retry\r\n"); + wait_ms(1); + ret = m_i2cBus->write(SS_I2C_8BIT_SLAVE_ADDR, (char*)tx_buf, tx_len); + } if (ret != 0) { pr_err("m_i2cBus->write returned %d\r\n", ret); @@ -283,10 +296,18 @@ wait_ms(sleep_ms); char status_byte; - ret |= m_i2cBus->read(SS_I2C_8BIT_SLAVE_ADDR, &status_byte, 1); + ret = m_i2cBus->read(SS_I2C_8BIT_SLAVE_ADDR, &status_byte, 1); + bool try_again = (status_byte == SS_ERR_TRY_AGAIN); + while ((ret != 0 || try_again) + && retries-- > 0) { + pr_info("i2c rd retry\r\n"); + wait_ms(sleep_ms); + ret = m_i2cBus->read(SS_I2C_8BIT_SLAVE_ADDR, &status_byte, 1); + try_again = (status_byte == SS_ERR_TRY_AGAIN); + } - if (ret != 0) { - pr_err("m_i2cBus->read returned %d\r\n", ret); + if (ret != 0 || try_again) { + pr_err("m_i2cBus->read returned %d, ss status_byte %d\r\n", ret, status_byte); return SS_ERR_UNAVAILABLE; } @@ -307,6 +328,18 @@ return status; } +SS_STATUS SSInterface::write_cmd_medium(uint8_t *cmd_bytes, int cmd_bytes_len, + uint8_t *data, int data_len, + int sleep_ms) +{ + uint8_t write_buf[SS_MED_BUF_SIZE]; + memcpy(write_buf, cmd_bytes, cmd_bytes_len); + memcpy(write_buf + cmd_bytes_len, data, data_len); + + SS_STATUS status = write_cmd(write_buf, cmd_bytes_len + data_len, sleep_ms); + return status; +} + SS_STATUS SSInterface::write_cmd_large(uint8_t *cmd_bytes, int cmd_bytes_len, uint8_t *data, int data_len, int sleep_ms) @@ -324,20 +357,30 @@ uint8_t *rxbuf, int rxbuf_sz, int sleep_ms) { - int ret = 0; - pr_info("read_cmd: "); for (int i = 0; i < cmd_bytes_len; i++) { pr_info("0x%02X ", cmd_bytes[i]); } pr_info("\r\n"); - ret |= m_i2cBus->write(SS_I2C_8BIT_SLAVE_ADDR, (char*)cmd_bytes, cmd_bytes_len, (data_len != 0)); + + int retries = 4; + + int ret = m_i2cBus->write(SS_I2C_8BIT_SLAVE_ADDR, (char*)cmd_bytes, cmd_bytes_len, (data_len != 0)); if (data_len != 0) { ret |= m_i2cBus->write(SS_I2C_8BIT_SLAVE_ADDR, (char*)data, data_len, false); } + while (ret != 0 && retries-- > 0) { + pr_err("i2c wr retry\r\n"); + wait_ms(1); + ret = m_i2cBus->write(SS_I2C_8BIT_SLAVE_ADDR, (char*)cmd_bytes, cmd_bytes_len, (data_len != 0)); + if (data_len != 0) { + ret |= m_i2cBus->write(SS_I2C_8BIT_SLAVE_ADDR, (char*)data, data_len, false); + } + } + if (ret != 0) { pr_err("m_i2cBus->write returned %d\r\n", ret); return SS_ERR_UNAVAILABLE; @@ -345,14 +388,19 @@ wait_ms(sleep_ms); - ret |= m_i2cBus->read(SS_I2C_8BIT_SLAVE_ADDR, (char*)rxbuf, rxbuf_sz); - - if (ret != 0) { - pr_err("m_i2cBus->read returned %d\r\n", ret); + ret = m_i2cBus->read(SS_I2C_8BIT_SLAVE_ADDR, (char*)rxbuf, rxbuf_sz); + bool try_again = (rxbuf[0] == SS_ERR_TRY_AGAIN); + while ((ret != 0 || try_again) && retries-- > 0) { + pr_info("i2c rd retry\r\n"); + wait_ms(sleep_ms); + ret = m_i2cBus->read(SS_I2C_8BIT_SLAVE_ADDR, (char*)rxbuf, rxbuf_sz); + try_again = (rxbuf[0] == SS_ERR_TRY_AGAIN); + } + if (ret != 0 || try_again) { + pr_err("m_i2cBus->read returned %d, ss status_byte %d\r\n", ret, rxbuf[0]); return SS_ERR_UNAVAILABLE; } - wait_ms(sleep_ms); pr_info("status_byte: %d\r\n", rxbuf[0]); pr_info("data: "); for (int i = 1; i < rxbuf_sz; i++) { @@ -384,7 +432,7 @@ status = read_cmd(&cmd_bytes2[0], ARRAY_SIZE(cmd_bytes2), 0, 0, - &rxbuf[0], ARRAY_SIZE(rxbuf)); + &rxbuf[0], reg_width + 1); if (status == SS_SUCCESS) { *val = 0; @@ -463,6 +511,7 @@ assert_msg((mode <= SS_MAX_SUPPORTED_MODE_NUM), "mode must be < SS_MAX_SUPPORTED_MODE_NUM, or update code to handle variable length mode values"); assert_msg((mode != 0), "Tried to enable sensor to mode 0, but mode 0 is disable"); + uint8_t cmd_bytes[] = { SS_FAM_W_SENSORMODE, (uint8_t)idx, (uint8_t)mode }; SS_STATUS status = write_cmd(&cmd_bytes[0], ARRAY_SIZE(cmd_bytes), 0, 0, SS_ENABLE_SENSOR_SLEEP_MS); @@ -497,7 +546,7 @@ uint8_t cmd_bytes[] = { SS_FAM_W_ALGOMODE, (uint8_t)idx, (uint8_t)mode }; - SS_STATUS status = write_cmd(&cmd_bytes[0], ARRAY_SIZE(cmd_bytes), 0, 0, SS_ENABLE_SENSOR_SLEEP_MS); + SS_STATUS status = write_cmd(&cmd_bytes[0], ARRAY_SIZE(cmd_bytes), 0, 0, 4*SS_ENABLE_SENSOR_SLEEP_MS); if (status == SS_SUCCESS) { algo_enabled_mode[idx] = mode; @@ -522,6 +571,31 @@ return status; } +SS_STATUS SSInterface::set_algo_cfg(int algo_idx, int cfg_idx, uint8_t *cfg, int cfg_sz) +{ + assert_msg((algo_idx <= SS_MAX_SUPPORTED_ALGO_NUM), "idx must be < SS_MAX_SUPPORTED_ALGO_NUM, or update code to handle variable length idx values"); + assert_msg((cfg_idx <= SS_MAX_SUPPORTED_ALGO_CFG_NUM), "idx must be < SS_MAX_SUPPORTED_ALGO_CFG_NUM, or update code to handle variable length idx values"); + + uint8_t cmd_bytes[] = { SS_FAM_W_ALGOCONFIG, (uint8_t)algo_idx, (uint8_t)cfg_idx }; + SS_STATUS status = write_cmd(&cmd_bytes[0], ARRAY_SIZE(cmd_bytes), + cfg, cfg_sz); + + return status; +} + +SS_STATUS SSInterface::get_algo_cfg(int algo_idx, int cfg_idx, uint8_t *cfg, int cfg_sz) +{ + assert_msg((algo_idx <= SS_MAX_SUPPORTED_ALGO_NUM), "idx must be < SS_MAX_SUPPORTED_ALGO_NUM, or update code to handle variable length idx values"); + assert_msg((cfg_idx <= SS_MAX_SUPPORTED_ALGO_CFG_NUM), "idx must be < SS_MAX_SUPPORTED_ALGO_CFG_NUM, or update code to handle variable length idx values"); + + uint8_t cmd_bytes[] = { SS_FAM_R_ALGOCONFIG, (uint8_t)algo_idx, (uint8_t)cfg_idx }; + SS_STATUS status = read_cmd(&cmd_bytes[0], ARRAY_SIZE(cmd_bytes), + 0, 0, + cfg, cfg_sz); + + return status; +} + SS_STATUS SSInterface::set_data_type(int data_type, bool sc_en) { assert_msg((data_type >= 0) && (data_type <= 3), "Invalid value for data_type"); @@ -557,6 +631,53 @@ return status; } +SS_STATUS SSInterface::set_fifo_thresh(int thresh) +{ + assert_msg((thresh > 0 && thresh <= 255), "Invalid value for fifo a full threshold"); + uint8_t cmd_bytes[] = { SS_FAM_W_COMMCHAN, SS_CMDIDX_FIFOAFULL }; + uint8_t data_bytes[] = { (uint8_t)thresh }; + + SS_STATUS status = write_cmd(&cmd_bytes[0], ARRAY_SIZE(cmd_bytes), + &data_bytes[0], ARRAY_SIZE(data_bytes)); + return status; +} + +SS_STATUS SSInterface::get_fifo_thresh(int *thresh) +{ + uint8_t cmd_bytes[] = { SS_FAM_R_COMMCHAN, SS_CMDIDX_FIFOAFULL }; + uint8_t rxbuf[2] = {0}; + + SS_STATUS status = read_cmd(&cmd_bytes[0], ARRAY_SIZE(cmd_bytes), + 0, 0, + &rxbuf[0], ARRAY_SIZE(rxbuf)); + + if (status == SS_SUCCESS) { + *thresh = rxbuf[1]; + } + + return status; +} + +SS_STATUS SSInterface::ss_comm_check() +{ + uint8_t cmd_bytes[] = { SS_FAM_R_IDENTITY, SS_CMDIDX_PLATTYPE }; + uint8_t rxbuf[2]; + + SS_STATUS status = read_cmd(&cmd_bytes[0], ARRAY_SIZE(cmd_bytes), + 0, 0, + &rxbuf[0], ARRAY_SIZE(rxbuf)); + + int tries = 4; + while (status == SS_ERR_TRY_AGAIN && tries--) { + wait_ms(1000); + status = read_cmd(&cmd_bytes[0], ARRAY_SIZE(cmd_bytes), + 0, 0, + &rxbuf[0], ARRAY_SIZE(rxbuf)); + } + + return status; +} + void SSInterface::fifo_sample_size(int data_type, int *sample_size) { *sample_size = 0; @@ -587,7 +708,7 @@ SS_STATUS status = read_cmd(&cmd_bytes[0], ARRAY_SIZE(cmd_bytes), 0, 0, - &rxbuf[0], ARRAY_SIZE(rxbuf)); + &rxbuf[0], ARRAY_SIZE(rxbuf), 1); if (status == SS_SUCCESS) { *num_samples = rxbuf[1]; @@ -605,23 +726,28 @@ uint8_t cmd_bytes[] = { SS_FAM_R_OUTPUTFIFO, SS_CMDIDX_READFIFO }; - pr_err("[reading %d bytes (%d samples)\r\n", bytes_to_read, num_samples); + pr_info("[reading %d bytes (%d samples)\r\n", bytes_to_read, num_samples); SS_STATUS status = read_cmd(&cmd_bytes[0], ARRAY_SIZE(cmd_bytes), 0, 0, - databuf, bytes_to_read, 15); + databuf, bytes_to_read, 5); return status; } -void SSInterface::irq_handler() -{ - uint8_t databuf[512]; +static uint8_t databuf[512]; +void SSInterface::ss_execute_once(){ + + if(m_irq_received_ == false) + return; + uint8_t sample_count; - + m_irq_received_ = false; uint8_t cmd_bytes[] = { SS_FAM_R_STATUS, SS_CMDIDX_STATUS }; uint8_t rxbuf[2] = {0}; + irq_evt.start(); + irq_pin.disable_irq(); SS_STATUS status = read_cmd(&cmd_bytes[0], ARRAY_SIZE(cmd_bytes), @@ -631,6 +757,7 @@ if (status != SS_SUCCESS) { pr_err("Couldn't read status byte of SmartSensor!"); irq_pin.enable_irq(); + irq_evt.stop(); return; } @@ -645,39 +772,37 @@ } if (rxbuf[1] & SS_MASK_STATUS_DATA_RDY) { - int num_samples; + int num_samples = 1; status = num_avail_samples(&num_samples); if (status != SS_SUCCESS) { pr_err("Couldn't read number of available samples in SmartSensor Output FIFO"); irq_pin.enable_irq(); + irq_evt.stop(); return; } - if (num_samples <= 0) - { - irq_pin.enable_irq(); - return; - } - - int sample_size; fifo_sample_size(data_type, &sample_size); - size_t bytes_to_read = num_samples * sample_size + 1; //+1 for status byte - if (bytes_to_read > sizeof(databuf)) { + int bytes_to_read = num_samples * sample_size + 1; //+1 for status byte + if ((uint32_t)bytes_to_read > sizeof(databuf)) { //Reduce number of samples to read to fit in buffer num_samples = (sizeof(databuf) - 1) / sample_size; } + wait_ms(5); status = read_fifo_data(num_samples, sample_size, &databuf[0], sizeof(databuf)); if (status != SS_SUCCESS) { pr_err("Couldn't read from SmartSensor Output FIFO"); irq_pin.enable_irq(); + irq_evt.stop(); return; } + pr_info("read %d samples\r\n", num_samples); + //Skip status byte uint8_t *data_ptr = &databuf[1]; @@ -712,6 +837,16 @@ } } irq_pin.enable_irq(); + irq_evt.stop(); +} + +void SSInterface::ss_clear_interrupt_flag(){ + m_irq_received_ = false; +} + +void SSInterface::irq_handler() +{ + m_irq_received_ = true; } void SSInterface::irq_handler_selftest(){