Host software for the MAXREFDES220 Heart Rate Monitor Smart Sensor. Hosted on the MAX32630FTHR.

Dependencies:   max32630fthr USBDevice

Fork of MAXREFDES220_HEART_RATE_MONITOR by Maxim Integrated

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

/media/uploads/phonemacro/maxrefdes220_pinouts_heart_rate_monitor.jpg

Revision:
8:0f55f59ca341
Parent:
7:3e2a5545f1d8
Child:
10:022b2cad9e9b
--- a/Interfaces/SmartSensor/SSInterface.cpp	Mon May 28 17:31:55 2018 -0700
+++ b/Interfaces/SmartSensor/SSInterface.cpp	Mon Jul 02 21:07:27 2018 +0000
@@ -37,10 +37,12 @@
 #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),
-	irq_evt(1000000, "irq")
+	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));
@@ -51,8 +53,8 @@
 
 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),
-	irq_evt(1000000, "irq")
+	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));
@@ -67,62 +69,55 @@
 
 SS_STATUS SSInterface::reset_to_main_app()
 {
-	irq_pin.disable_irq();
-#if 1
-	SS_STATUS status = exit_from_bootloader();
-	irq_pin.enable_irq();
-	return status;
-#else
+	disable_irq();
+#if defined(BOOTLOADER_USES_MFIO)
 	reset_pin.output();
 	cfg_mfio(PIN_OUTPUT);
 	reset_pin.write(0);
 	wait_ms(SS_RESET_TIME);
 	mfio_pin.write(1);
 	reset_pin.write(1);
-	wait_ms(SS_STARTUP_TIME);
+	wait_ms(SS_STARTUP_TO_MAIN_APP_TIME);
 	cfg_mfio(PIN_INPUT);
 	reset_pin.input();
-	irq_pin.enable_irq();
+	enable_irq();
 	// Verify we exited bootloader mode
 	if (in_bootldr_mode() == 0)
 		return SS_SUCCESS;
 	else
 		return SS_ERR_UNKNOWN;
+#else
+	SS_STATUS status = exit_from_bootloader();
+	enable_irq();
+	return status;
 #endif
 }
 
 SS_STATUS SSInterface::reset_to_bootloader()
 {
-	irq_pin.disable_irq();
-#if 0
-	uint8_t cmd_bytes[] = { SS_FAM_W_MODE, SS_CMDIDX_MODE };
-	uint8_t data[] = { SS_MASK_MODE_BOOTLDR };
-
-	SS_STATUS status = ss_int->write_cmd(
-			&cmd_bytes[0], ARRAY_SIZE(cmd_bytes),
-			&data[0], ARRAY_SIZE(data),
-			SS_STARTUP_TIME);
-	if (status == SS_SUCCESS)
-		in_bootldr = true;
-	return status;
-#else
+	disable_irq();
+#if defined(BOOTLOADER_USES_MFIO)
 	reset_pin.output();
 	cfg_mfio(PIN_OUTPUT);
 	reset_pin.write(0);
 	wait_ms(SS_RESET_TIME);
 	mfio_pin.write(0);
 	reset_pin.write(1);
-	wait_ms(SS_STARTUP_TIME);
+	wait_ms(SS_STARTUP_TO_BTLDR_TIME);
 	cfg_mfio(PIN_INPUT);
 	reset_pin.input();
+	enable_irq();
 	stay_in_bootloader();
+
 	// Verify we entered bootloader mode
 	if (in_bootldr_mode() < 0)
 		return SS_ERR_UNKNOWN;
 	return SS_SUCCESS;
+#else
+	stay_in_bootloader();
+	enable_irq();
+	return SS_SUCCESS;
 #endif
-
-	irq_pin.disable_irq();
 }
 
 SS_STATUS SSInterface::exit_from_bootloader()
@@ -179,6 +174,7 @@
 		mfio_pin.input();
 		mfio_pin.mode(PullUp);
 	} else {
+		disable_irq();
 		mfio_pin.output();
 	}
 }
@@ -243,6 +239,38 @@
     return &fw_version[0];
 }
 
+const char* SSInterface::get_ss_algo_version()
+{
+    uint8_t cmd_bytes[3];
+    uint8_t rxbuf[4];
+
+	int bootldr = in_bootldr_mode();
+
+	if (bootldr > 0) {
+		cmd_bytes[0] = SS_FAM_R_BOOTLOADER;
+		cmd_bytes[1] = SS_CMDIDX_BOOTFWVERSION;
+		cmd_bytes[2] = 0;
+	} else if (bootldr == 0) {
+		cmd_bytes[0] = SS_FAM_R_IDENTITY;
+		cmd_bytes[1] = SS_CMDIDX_ALGOVER;
+		cmd_bytes[2] = SS_CMDIDX_AVAILSENSORS;
+	} else {
+		return plat_name;
+	}
+
+    SS_STATUS status = read_cmd(
+             &cmd_bytes[0], ARRAY_SIZE(cmd_bytes),
+             0, 0,
+             &rxbuf[0], ARRAY_SIZE(rxbuf));
+
+    if (status == SS_SUCCESS) {
+        snprintf(algo_version, sizeof(algo_version),
+            "%d.%d.%d", rxbuf[1], rxbuf[2], rxbuf[3]);
+		pr_info("algo_version:%s\r\n", fw_version);
+    }
+
+    return &algo_version[0];
+}
 const char* SSInterface::get_ss_platform_name()
 {
     uint8_t cmd_bytes[] = { SS_FAM_R_IDENTITY, SS_CMDIDX_PLATTYPE };
@@ -386,17 +414,21 @@
 	int retries = 4;
 
     int ret = m_i2cBus->write(SS_I2C_8BIT_SLAVE_ADDR, (char*)cmd_bytes, cmd_bytes_len, (data_len != 0));
-
+    printf("ret1 : %d\rt\n",ret);
     if (data_len != 0) {
         ret |= m_i2cBus->write(SS_I2C_8BIT_SLAVE_ADDR, (char*)data, data_len, false);
+        printf("ret2 : %d\rt\n",ret);
     }
 
 	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));
+    	printf("ret3 : %d\rt\n",ret);
 	    if (data_len != 0) {
 	        ret |= m_i2cBus->write(SS_I2C_8BIT_SLAVE_ADDR, (char*)data, data_len, false);
+	        printf("ret4 : %d\rt\n",ret);
 	    }
 	}
 
@@ -736,6 +768,22 @@
 	return status;
 }
 
+SS_STATUS SSInterface::get_log_len(int *log_len)
+{
+	uint8_t cmd_bytes[] = { SS_FAM_R_LOG, SS_CMDIDX_R_LOG_LEN };
+	uint8_t rxbuf[2] = {0};
+
+	SS_STATUS status = read_cmd(&cmd_bytes[0], ARRAY_SIZE(cmd_bytes),
+								0, 0,
+								&rxbuf[0], ARRAY_SIZE(rxbuf), 1);
+
+	if (status == SS_SUCCESS) {
+		*log_len = (rxbuf[1] << 8) | rxbuf[0];
+	}
+
+	return status;
+}
+
 SS_STATUS SSInterface::read_fifo_data(
 	int num_samples, int sample_size,
 	uint8_t* databuf, int databuf_sz)
@@ -754,6 +802,22 @@
 	return status;
 }
 
+SS_STATUS SSInterface::read_ss_log(int num_bytes, uint8_t *log_buf, int log_buf_sz)
+{
+	int bytes_to_read = num_bytes + 1; //+1 for status byte
+	assert_msg((bytes_to_read <= log_buf_sz), "log_buf too small");
+
+	uint8_t cmd_bytes[] = { SS_FAM_R_LOG, SS_CMDIDX_R_LOG_DATA };
+
+	pr_info("[reading %d bytes (%d samples)\r\n", bytes_to_read, bytes_to_read);
+
+	SS_STATUS status = read_cmd(&cmd_bytes[0], ARRAY_SIZE(cmd_bytes),
+								0, 0,
+								log_buf, bytes_to_read, 5);
+
+	return status;
+}
+
 static uint8_t databuf[512];
 void SSInterface::ss_execute_once(){
 
@@ -765,18 +829,19 @@
 	uint8_t cmd_bytes[] = { SS_FAM_R_STATUS, SS_CMDIDX_STATUS };
 	uint8_t rxbuf[2] = {0};
 
-	irq_evt.start();
+	//irq_evt.start();
 
-	irq_pin.disable_irq();
+	disable_irq();
 
 	SS_STATUS status = read_cmd(&cmd_bytes[0], ARRAY_SIZE(cmd_bytes),
 								0, 0,
 								&rxbuf[0], ARRAY_SIZE(rxbuf));
+	pr_info("ss_int: %2X", rxbuf[1]);
 
 	if (status != SS_SUCCESS) {
 		pr_err("Couldn't read status byte of SmartSensor!");
-		irq_pin.enable_irq();
-		irq_evt.stop();
+		enable_irq();
+		//irq_evt.stop();
 		return;
 	}
 
@@ -790,14 +855,44 @@
 		pr_err("SmartSensor Input FIFO overflow!");
 	}
 
+	if (rxbuf[1] & SS_MASK_STATUS_LOG_OVR) {
+		pr_err("SmartSensor log overflow!");
+	}
+
+	if (rxbuf[1] & SS_MASK_STATUS_LOG_RDY) {
+		pr_err("SmartSensor Log ready");
+		int log_len;
+		status = get_log_len(&log_len);
+		if (status != SS_SUCCESS)
+		{
+			pr_err("Couldn't read log lenght");
+			enable_irq();
+			//irq_evt.stop();
+			return;
+		}
+
+		assert_msg((log_len <= sizeof(databuf)), "log size in SS longer than buffer");
+		status = read_ss_log(log_len, &databuf[0], sizeof(databuf));
+		if (status != SS_SUCCESS)
+		{
+			pr_err("Couldn't read from SmartSensor Log");
+			enable_irq();
+			//irq_evt.stop();
+			return;
+		}
+
+		databuf[log_len] = 0;
+		Peripherals::usbSerial()->printf("\r\n%s", (char *)databuf);
+	}
+
 	if (rxbuf[1] & SS_MASK_STATUS_DATA_RDY) {
 		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();
+			enable_irq();
+			//irq_evt.stop();
 			return;
 		}
 
@@ -815,13 +910,11 @@
 		if (status != SS_SUCCESS)
 		{
 			pr_err("Couldn't read from SmartSensor Output FIFO");
-			irq_pin.enable_irq();
-			irq_evt.stop();
+			enable_irq();
+			//irq_evt.stop();
 			return;
 		}
 
-		pr_info("read %d samples\r\n", num_samples);
-
 		//Skip status byte
 		uint8_t *data_ptr = &databuf[1];
 
@@ -855,8 +948,8 @@
 			}
 		}
 	}
-	irq_pin.enable_irq();
-	irq_evt.stop();
+	enable_irq();
+	//irq_evt.stop();
 }
 
 void SSInterface::ss_clear_interrupt_flag(){
@@ -875,8 +968,8 @@
 bool SSInterface::reset_mfio_irq(){
 	bool ret = mfio_int_happened;
 	mfio_int_happened = false;
-	irq_pin.disable_irq();
+	disable_irq();
 	irq_pin.fall(callback(this, &SSInterface::irq_handler));
-	irq_pin.enable_irq();
+	enable_irq();
 	return ret;
 }