SparkFun Photodetector (MAX30101) Hookup Guide

Pages
Contributors: santaimpersonator
Favorited Favorite 0

Introduction

The SparkFun Photodetector - MAX30101 (Qwiic) is the successor to the MAX30105 particle sensor, a highly sensitive optical sensor. This tutorial will get you up and running to retrieve the raw data from the MAX30101 sensor.

SparkFun Photodetector Breakout - MAX30101 (Qwiic)

SparkFun Photodetector Breakout - MAX30101 (Qwiic)

SEN-16474
$22.50
1

The MAX30101 includes three LEDs and an optical detector in a single package, which can be utilized as a wearable, biosensor for pulse oximeter and heart-rate measurements. For accurate and reliable biometric readings, we recommend the SparkFun Pulse Oximeter and Heart Rate Sensor, which utilizes proprietary algorithms programmed on the MAX32664 Biometric Sensor Hub. Other possible applications include proximity sensing and particle detection by measuring the changes in light that is reflected back from the LEDs.

Required Materials

The Qwiic Photodetector Sensor does need a few additional items for you to get started. The RedBoard Qwiic will be used for the Arduino examples. A single board computer and the Qwiic pHAT are required for the Python examples (see note below). You may already have a few of these items, including the required Qwiic cable, so feel free to modify your cart based on your needs. Additionally, there are also options that are available as well (click button below to toggle options).

SparkFun Qwiic Cable Kit

SparkFun Qwiic Cable Kit

KIT-15081
$8.95
20
SparkFun RedBoard Qwiic

SparkFun RedBoard Qwiic

DEV-15123
$21.50
18
USB Micro-B Cable - 6 Foot

USB Micro-B Cable - 6 Foot

CAB-10215
$5.50
15
SparkFun Qwiic pHAT v2.0 for Raspberry Pi

SparkFun Qwiic pHAT v2.0 for Raspberry Pi

DEV-15945
$6.95
2
Qwiic Compatible Microcontrollers:
SparkFun RedBoard Qwiic

SparkFun RedBoard Qwiic

DEV-15123
$21.50
18
SparkFun RedBoard Turbo - SAMD21 Development Board

SparkFun RedBoard Turbo - SAMD21 Development Board

DEV-14812
$19.95
8
SparkFun Thing Plus - SAMD51

SparkFun Thing Plus - SAMD51

DEV-14713
$21.50
2

SparkFun Thing Plus - ESP32 WROOM

WRL-14689
7 Retired
In addition we also offer, Qwiic compatible stackable shields for microcontrollers and pHATs for single board computers (like the Raspberry Pi boards) that don't include a Qwiic connector.
SparkFun Qwiic Adapter

SparkFun Qwiic Adapter

DEV-14495
$1.60
4
SparkFun Qwiic Shield for Arduino

SparkFun Qwiic Shield for Arduino

DEV-14352
$7.50
9

SparkFun Qwiic Shield for Arduino Nano

DEV-16130
Retired

SparkFun Qwiic Shield for Thing Plus

DEV-16138
Retired
SparkFun Qwiic HAT for Raspberry Pi

SparkFun Qwiic HAT for Raspberry Pi

DEV-14459
$6.50
5
SparkFun Qwiic SHIM for Raspberry Pi

SparkFun Qwiic SHIM for Raspberry Pi

DEV-15794
$1.05
13
SparkFun Qwiic pHAT v2.0 for Raspberry Pi

SparkFun Qwiic pHAT v2.0 for Raspberry Pi

DEV-15945
$6.95
2
SparkFun Auto pHAT for Raspberry Pi

SparkFun Auto pHAT for Raspberry Pi

ROB-16328
$32.50
1
SparkFun Servo pHAT for Raspberry Pi

SparkFun Servo pHAT for Raspberry Pi

DEV-15316
$11.95
5

SparkFun Top pHAT for Raspberry Pi

DEV-16301

SparkFun Qwiic pHAT for Raspberry Pi

DEV-15351
Retired
You will also need a Qwiic cable to connect to your MAX30101 (Qwiic), choose a length that suits your needs.
Qwiic Cable - 50mm

Qwiic Cable - 50mm

PRT-14426
$0.95
Qwiic Cable - 100mm

Qwiic Cable - 100mm

PRT-14427
$1.50

Qwiic Cable - 500mm

PRT-14429
1 Retired

Qwiic Cable - 200mm

PRT-14428
Retired

Python Example: If you don't already have them, you will need an SBC (single board computer) such as a Raspberry Pi and standard peripherals or Jetson Nano and standard peripherals. An example setup is listed below.
NVIDIA Jetson Nano Developer Kit (V3)

NVIDIA Jetson Nano Developer Kit (V3)

DEV-16271
$149.00
14
Raspberry Pi 3 B+

Raspberry Pi 3 B+

DEV-14643
$35.00
39

SparkFun DLI Kit (without Jetson Nano)

KIT-16389
1 Retired
Multimedia Wireless Keyboard

Multimedia Wireless Keyboard

WIG-14271
$29.95 $19.95
4
pi-topCEED (Green)

pi-topCEED (Green)

KIT-14035
$114.95 $99.95
4

SparkFun Noobs Card for Raspberry Pi (16GB)

COM-15052

Rubber Band

Note: For the heart beat plotter examples, users will require a small to medium size rubber band.

rubber band in use
rubber band

Suggested Reading

If you're unfamiliar with serial terminals, jumper pads, or I2C be sure to checkout some of these foundational tutorials. The MAX30105 is designed for a handful of uses including Pulse Oximetry. If you're unfamiliar with optical pulse detection there are some very good application notes from TI and NXP that have great starter information.

Installing an Arduino Library

How do I install a custom Arduino library? It's easy! This tutorial will go over how to install an Arduino library using the Arduino Library Manager. For libraries not linked with the Arduino IDE, we will also go over manually installing an Arduino library.

Logic Levels

Learn the difference between 3.3V and 5V devices and logic levels.

I2C

An introduction to I2C, one of the main embedded communications protocols in use today.

Serial Terminal Basics

This tutorial will show you how to communicate with your serial devices using a variety of terminal emulator applications.

MAX30105 Particle and Pulse Ox Sensor Hookup Guide

The SparkFun MAX30105 Particle Sensor is a flexible and powerful sensor enabling sensing of distance, heart rate, particle detection, even the blinking of an eye. Get ready. Set. Shine!

How to Work with Jumper Pads and PCB Traces

Handling PCB jumper pads and traces is an essential skill. Learn how to cut a PCB trace, add a solder jumper between pads to reroute connections, and repair a trace with the green wire method if a trace is damaged.

RedBoard Qwiic Hookup Guide

This tutorial covers the basic functionality of the RedBoard Qwiic. This tutorial also covers how to get started blinking an LED and using the Qwiic system.

SparkFun Pulse Oximeter and Heart Rate Monitor Hookup Guide

Find out your oxygen saturation level or check out your heart rate using the MAX30101 biometric sensor and MAX32664 Biometric Hub via I2C!

Raspberry Pi SPI and I2C Tutorial

Learn how to use serial I2C and SPI buses on your Raspberry Pi using the wiringPi I/O library for C/C++ and spidev/smbus for Python.

Python Programming Tutorial: Getting Started with the Raspberry Pi

This guide will show you how to write programs on your Raspberry Pi using Python to control hardware.

Qwiic pHAT for Raspberry Pi Hookup Guide

Get started interfacing your Qwiic enabled boards with your Raspberry Pi. The Qwiic pHAT connects the I2C bus (GND, 3.3V, SDA, and SCL) on your Raspberry Pi to an array of Qwiic connectors.

Working with Qwiic on a Jetson Nano through Jupyter Notebooks

We created a few Jupyter Notebooks to make using our Qwiic boards with your Jetson Nano even easier!

Qwiic Connect System

The Qwiic Photodetector utilizes the Qwiic connect system. We recommend familiarizing yourself with the Logic Levels and I2C tutorials (above) before using it. Click on the banner above to learn more about our Qwiic products.

Note: First time Raspberry Pi users should also head over to the Raspberry Pi Foundation website and check out their quickstart guides:

We have also listed a few additional resources for users to familiarize themselves with the Raspberry Pi:

Hardware Overview

Dimensions

The Qwiic Photodetector Sensor is laid out on the standardized 1" x 1" (2.54 x 2.54 cm) Qwiic breakout board and includes the standard four 0.13" mounting holes, which are compatible with M3 screws.

Board Dimensions
Board layout. (Click to enlarge)

Power LED

There is a power status LED to help make sure that your Qwiic Photodetector Sensor is getting power. You can power the board either through the polarized Qwiic connector system or the breakout pins (3.3V and GND) provided. The Qwiic system is meant to run on 3.3V, be sure that you are NOT using another voltage when using the Qwiic system. A jumper is available on the back of the board to remove power to the LED for low-power applications (see Jumpers section below).

Power LED
Power LED. (Click to enlarge)

MAX30101

The MAX30101 includes three LEDs and an optical detector in a single package. Behind the window on the left, are red, green, and IR LEDs. While behind the window on the right, is a highly sensitive photon detector.

Close up photo of the MAX30101 sensor
Close up of the MAX30101 sensor. (Click to enlarge)

The working principle of the sensor is that the optical detector measures the changes in the reflected light that was emitted from the LEDs. This is great for various application like detecting particles or for photoplethysmography.

MAX30101 Sensor
MAX30101 sensor. (Click to enlarge)

(*For more details on the MAX30101, users can check out the datasheet.)

Characteristic Description
Power Supply Voltage: 1.7 - 2.0V
Supply Cuurent: 0.6 - 1.1mA
LED Driver:
  • Red/IR: 3.1-5V
  • Green: 4.5 - 5.5V
ADC Resolution: 18-bits (65536 Counts)
LEDs
Wavelength:
  • IR: 870 - 900nm
  • Red: 650 - 670nm
  • Green 530 - 545nm
Power:
  • IR: 6.5mW
  • Red: 9.8mW
  • Green 17.2mW
Photodetector Spectral Range: 640 - 980nm
Temperature Sensor Range: -40 - 85°C
Accuracy: ±1°C
I2C Address 0x57

Application Notes

Note: Particle detection, heart rate measurement, and photoplethysmography (for pulse oximetry) are applications of the MAX30101. These applications are detailed in the notes below; however, they require an understanding of the operating principles of the sensor and a conceptual knowledge of the application(s). Although, we provided the information below for interested users and may provide some examples of the application in our software; these applications are, unfortunately, not supported by SparkFun and the examples are primarily for demonstration purposes only.

Here are additional resources on how the MAX30101 functions for HR detection and pulse oximetry:

For more information on particulate matter and their detection, check out these resources:

Maxim's Original Firmware for the MAX30102 adapted in our Arduino Library:

Qwiic and I2C

I2C Address

The Qwiic Photodetector Sensor’s I2C address, 0x57, is factory set.

Qwiic Connectors

The simplest way to use the Qwiic Photodetector Sensor is through the Qwiic connect system. The connectors are polarized for the I2C connection and power. (*They are tied to the corresponding power and I2C breakout pins.)

Qwiic connectors
Qwiic connectors.

Breakout Pins

The board also provides six labeled breakout pins. You can connect these lines to the I2C bus of your microcontroller and power pins (3.3V and GND), if it doesn't have a Qwiic connector. The interrupt pin is also broken out to use for triggered events.

Breakout Pins
I2C Connections- The pins are tied to the Qwiic connectors.

Interrupt Pin

The interrupt pins (active high) are used to indicate various states of the ADXL313, depending on how they are configured and if they are enabled. The INT pins are pulled down with a 4.7kΩ resistor.

Jumpers

There are three jumpers on the board. Not sure how to cut a jumper? Read here!

Power LED

Cutting the LED jumper will remove the 1kΩ resistors and PWR LED from the 3.3V power. This is useful for low power applications

power LED jumper
Power LED jumper. (Click to enlarge)

I2C Pull-Up

Cutting the I2C jumper will remove the 2.2kΩ pull-up resistors from the I2C bus. If you have many devices on your I2C bus you may want to remove these jumpers. Be aware that these resistors are also part of the transistor logic level shifting circuit.

I2C jumper
I2C pull-up resistor jumper. (Click to enlarge)

Interrupt Pull-up

Cutting the INT jumper will remove the 4.7kΩ pull-up resistors from the interrupt pin.

interrupt jumper
Interrupt pull-up resistor jumper. (Click to enlarge)

Hardware Assembly

Arduino Examples

With the Qwiic connector system, assembling the hardware is simple. All you need to do is connect your SparkFun Photodetector -MAX30101 (Qwiic) to the RedBoard Qwiic with a Qwiic cable. Otherwise, you can use the I2C pins of your microcontroller; just be aware of logic levels.

Hardware assembly with RedBoard Qwiic
RedBoard Qwiic connected the Qwiic Photodetector with a Qwiic cable.

Note: This tutorial assumes users are familiar with Arduino products and are using the latest stable version of the Arduino IDE on your desktop. If this is your first time using the Arduino IDE, please review our tutorial on installing the Arduino IDE.

Python Examples

With the Qwiic connector system, assembling the hardware is simple. In addition to the SparkFun Photodetector -MAX30101 (Qwiic), you will need: a Qwiic cable, a SparkFun Qwiic pHAT for Raspberry Pi, single board computer, monitor, and standard peripherals. (*If you are unfamiliar with the Qwiic pHAT, you can find the Hookup Guide here.)

There are two single board computer (SBC) options that we have tested on:

Hardware assembly with Raspberry Pi 4 with Qwiic pHAT
Raspberry Pi 4 (with heat sink case) connected the Qwiic Photodetector.
Hardware assembly with Jetson Nano with Qwiic pHAT Jetson Nano connected the Qwiic Photodetector.

Note: This tutorial assumes users are familiar with using a Raspberry Pi and have the latest version of Raspbian OS (full... with recommended software) your Raspberry Pi. You can download the latest version of the Raspbian OS from the Raspberry Pi Foundation website.

If this is your first time using a Raspberry Pi, please head over to the Raspberry Pi Foundation website to use their quickstart guides. We have listed a few of them here:

  1. Setting up your Raspberry Pi
  2. Using your Raspberry Pi
  3. Documentation:
  4. Setup Documentation
    Installation Documentation
    Raspbian Documentation
    SD card Documentation

Note: This tutorial assumes users are familiar with using a Jetson Nano and you have the latest version of L4T OS your Jetson Nano. You can download the latest version of the L4T OS from the Jetson Download Center on Nvidia's website.

If this is your first time using a Jetson Nano, please head over to the Nvidia website to use their quickstart guides. We have listed a few of them here:

  1. Getting Started With Jetson Nano Developer Kit
  2. Jetson Nano Developer Kit User Guide
  3. Documentation:
  4. Jetson Nano Getting Started Guide
    Jetson Download Center
    Wiki: Jetson Nano
    Jetpack Software Documentation
    Nvidia Jetson Tutorials

Heart Beat Plotter and Heart Rate Examples

In both the Arduino and Python examples, there is are sample codes to demonstrate the MAX30101's biometric capability to detect a user's heart rate (or pulse). These are tricky examples to get working properly as the sensor can be finicky about the amount of pressure used along with the sensor's position on the finger.

rubber band in use
Using rubber band to attach MAX30101 sensor to a finger for Example 4 - Heart Beat Plotting in the Arduino examples.

Here are a few tips for users that may help:

  • Relax in a comfortable position and keep you arm, hand, and finger as still as possible.
  • A consistent amount of pressure should be used for more reliable readings.
    • Tape or a rubber band are recommended. The engineer for this product had the most success using a rubber band in this configuration:

      top view of rubber band on board bottom view of rubber band on board
      SparkFun Photodetector (MAX30101) with rubber band.

  • There is such a thing as too much pressure; use a fairly light amount of pressure. I found taping the board down, resting my arm on a table, and with just placing my finger's weight on the sensor worked fairly well for getting a consistent waveform.
  • The photodetector on the MAX30101 is highly sensitive and light passing from above the finger can also affect the sensor readings.
  • The sensor can be finicky for some users... and there isn't an easy way to troubleshoot this situation when you are getting poor readings. Keep trying. It took me 5 days of fiddling to get just the right combination of position and pressure for a proper reading. That being said, if you struggle that far, it will be a light bulb moment when you discover that combination and it becomes easier to repeat.
    • Try to get the plotter working first, with the blips/bumps as that is how the heart rate example calculates your pulse.

Arduino Library

Note: This example assumes you are using the latest version of the Arduino IDE on your desktop. If this is your first time using Arduino, please review our tutorial on installing the Arduino IDE. If you have not previously installed an Arduino library, please check out our installation guide.

(*Users can also check out the steps shown in the MAX30105 hookup guide. For the heart beat plotter example, the Arduino IDE must be version 1.6.6 or higher.)

We've written a library to easily get setup and take readings from the SparkFun Photodetector -MAX30101 (Qwiic). However, before we jump into getting data from the sensor, let's take a closer look at the available functions in the library. You can install this library through the Arduino Library Manager. Search for SparkFun MAX3010X Arduino Library and you should be able to install the latest version. If you prefer manually downloading the libraries from the GitHub repository, you can grab them here:

Let's get started by looking at the functions that set up the Qwiic Atmospheric Sensor:

Class

In the global scope, construct your sensor object (such as mySensor) without arguments.

MAX30105 mySensor;

Object Parameters and setup()

Rather that passing a bunch of data to the constructor, configuration is accomplished by setting the values of the MAX30105 type in the setup() function. They are exposed by being public: so use the myName.aVariable = someValue; syntax.

Settable variables of the class MAX30105:

language:c
// Status Registers
uint8_t MAX30105_INTSTAT1 =     0x00;
uint8_t MAX30105_INTSTAT2 =     0x01;
uint8_t MAX30105_INTENABLE1 =       0x02;
uint8_t MAX30105_INTENABLE2 =       0x03;

// FIFO Registers
uint8_t MAX30105_FIFOWRITEPTR =     0x04;
uint8_t MAX30105_FIFOOVERFLOW =     0x05;
uint8_t MAX30105_FIFOREADPTR =  0x06;
uint8_t MAX30105_FIFODATA =     0x07;

// Configuration Registers
uint8_t MAX30105_FIFOCONFIG =       0x08;
uint8_t MAX30105_MODECONFIG =       0x09;
uint8_t MAX30105_PARTICLECONFIG =   0x0A;    // Note, sometimes listed as "SPO2" config in datasheet (pg. 11)
uint8_t MAX30105_LED1_PULSEAMP =    0x0C;
uint8_t MAX30105_LED2_PULSEAMP =    0x0D;
uint8_t MAX30105_LED3_PULSEAMP =    0x0E;
uint8_t MAX30105_LED_PROX_AMP =     0x10;
uint8_t MAX30105_MULTILEDCONFIG1 = 0x11;
uint8_t MAX30105_MULTILEDCONFIG2 = 0x12;

// Die Temperature Registers
uint8_t MAX30105_DIETEMPINT =       0x1F;
uint8_t MAX30105_DIETEMPFRAC =  0x20;
uint8_t MAX30105_DIETEMPCONFIG =    0x21;

// Proximity Function Registers
uint8_t MAX30105_PROXINTTHRESH =    0x30;

// Part ID Registers
uint8_t MAX30105_REVISIONID =       0xFE;
uint8_t MAX30105_PARTID =           0xFF;    // Should always be 0x15. Identical to MAX30102.

// MAX30105 Commands
// Interrupt configuration (pg 13, 14)
uint8_t MAX30105_INT_A_FULL_MASK =      (byte)~0b10000000;
uint8_t MAX30105_INT_A_FULL_ENABLE =    0x80;
uint8_t MAX30105_INT_A_FULL_DISABLE =   0x00;

uint8_t MAX30105_INT_DATA_RDY_MASK = (byte)~0b01000000;
uint8_t MAX30105_INT_DATA_RDY_ENABLE =  0x40;
uint8_t MAX30105_INT_DATA_RDY_DISABLE = 0x00;

uint8_t MAX30105_INT_ALC_OVF_MASK = (byte)~0b00100000;
uint8_t MAX30105_INT_ALC_OVF_ENABLE =   0x20;
uint8_t MAX30105_INT_ALC_OVF_DISABLE = 0x00;

uint8_t MAX30105_INT_PROX_INT_MASK = (byte)~0b00010000;
uint8_t MAX30105_INT_PROX_INT_ENABLE = 0x10;
uint8_t MAX30105_INT_PROX_INT_DISABLE = 0x00;

uint8_t MAX30105_INT_DIE_TEMP_RDY_MASK = (byte)~0b00000010;
uint8_t MAX30105_INT_DIE_TEMP_RDY_ENABLE = 0x02;
uint8_t MAX30105_INT_DIE_TEMP_RDY_DISABLE = 0x00;

uint8_t MAX30105_SAMPLEAVG_MASK =   (byte)~0b11100000;
uint8_t MAX30105_SAMPLEAVG_1 =  0x00;
uint8_t MAX30105_SAMPLEAVG_2 =  0x20;
uint8_t MAX30105_SAMPLEAVG_4 =  0x40;
uint8_t MAX30105_SAMPLEAVG_8 =  0x60;
uint8_t MAX30105_SAMPLEAVG_16 =     0x80;
uint8_t MAX30105_SAMPLEAVG_32 =     0xA0;

uint8_t MAX30105_ROLLOVER_MASK =    0xEF;
uint8_t MAX30105_ROLLOVER_ENABLE = 0x10;
uint8_t MAX30105_ROLLOVER_DISABLE = 0x00;

uint8_t MAX30105_A_FULL_MASK =  0xF0;

// Mode configuration commands (page 19)
uint8_t MAX30105_SHUTDOWN_MASK =    0x7F;
uint8_t MAX30105_SHUTDOWN =         0x80;
uint8_t MAX30105_WAKEUP =           0x00;

uint8_t MAX30105_RESET_MASK =       0xBF;
uint8_t MAX30105_RESET =            0x40;

uint8_t MAX30105_MODE_MASK =        0xF8;
uint8_t MAX30105_MODE_REDONLY =     0x02;
uint8_t MAX30105_MODE_REDIRONLY =   0x03;
uint8_t MAX30105_MODE_MULTILED =    0x07;

// Particle sensing configuration commands (pgs 19-20)
uint8_t MAX30105_ADCRANGE_MASK =    0x9F;
uint8_t MAX30105_ADCRANGE_2048 =    0x00;
uint8_t MAX30105_ADCRANGE_4096 =    0x20;
uint8_t MAX30105_ADCRANGE_8192 =    0x40;
uint8_t MAX30105_ADCRANGE_16384 =   0x60;

uint8_t MAX30105_SAMPLERATE_MASK = 0xE3;
uint8_t MAX30105_SAMPLERATE_50 =    0x00;
uint8_t MAX30105_SAMPLERATE_100 =   0x04;
uint8_t MAX30105_SAMPLERATE_200 =   0x08;
uint8_t MAX30105_SAMPLERATE_400 =   0x0C;
uint8_t MAX30105_SAMPLERATE_800 =   0x10;
uint8_t MAX30105_SAMPLERATE_1000 = 0x14;
uint8_t MAX30105_SAMPLERATE_1600 = 0x18;
uint8_t MAX30105_SAMPLERATE_3200 = 0x1C;

uint8_t MAX30105_PULSEWIDTH_MASK = 0xFC;
uint8_t MAX30105_PULSEWIDTH_69 =    0x00;
uint8_t MAX30105_PULSEWIDTH_118 =   0x01;
uint8_t MAX30105_PULSEWIDTH_215 =   0x02;
uint8_t MAX30105_PULSEWIDTH_411 =   0x03;

//Multi-LED Mode configuration (pg 22)
uint8_t MAX30105_SLOT1_MASK =       0xF8;
uint8_t MAX30105_SLOT2_MASK =       0x8F;
uint8_t MAX30105_SLOT3_MASK =       0xF8;
uint8_t MAX30105_SLOT4_MASK =       0x8F;

uint8_t SLOT_NONE =                 0x00;
uint8_t SLOT_RED_LED =          0x01;
uint8_t SLOT_IR_LED =               0x02;
uint8_t SLOT_GREEN_LED =            0x03;
uint8_t SLOT_NONE_PILOT =           0x04;
uint8_t SLOT_RED_PILOT =            0x05;
uint8_t SLOT_IR_PILOT =             0x06;
uint8_t SLOT_GREEN_PILOT =      0x07;

uint8_t MAX_30105_EXPECTEDPARTID = 0x15;

Functions

The MAX30101 is highly configurable, and there are a large number of functions exposed in the library to the user. Checkout the MAX30105.h file for all the functions, but here are the major ones. Read the MAX30101 datasheet for more information.

The library supports the following functions:

  • .begin(wirePort, i2cSpeed) - If you have a platform with multiple I2C ports, pass the port object when you call begin. You can increase the I2C speed to 400kHz by including I2C_SPEED_FAST when you call .begin() as well.
  • .setup() - Initializes the sensor with various settings. See the Example 2 from the MAX30105 hookup guide for a good explanation of the options.
  • .getRed() - Returns the immediate red value
  • .getIR() - Returns the immediate IR value
  • .getGreen() - Returns the immediate Green value
  • .available() - Returns how many new samples are available
  • .readTemperature() - Returns the temperature of the IC in C
  • .readTemperatureF() - Returns the temperature of the IC in F
  • .softReset() - Resets everything including data and configuration
  • .shutDown() - Powers down the IC but retains all configuration
  • .wakeUp() - Opposite of shutDown
  • .setLEDMode(mode) - Configure the sensor to use 1 (Red only), 2 (Red + IR), or 3 (Red + IR + Green) LEDs
  • .setADCRange(adcRange) - Set ADC to be at 2048, 4096, 8192, or 16384
  • .setSampleRate(sampleRate) - Configure the sample rate: 50, 100, 200, 400, 800, 1000, 1600, 3200
Interrupts
  • .getINT1() - Returns the main interrupt group
  • .getINT2() - Returns the temp ready interrupt
  • Enable/disable individual interrupts. See page 13 and 14 of the datasheet for an explanation of each interrupt:
    • .enableAFULL()
    • .disableAFULL()
    • .enableDATARDY()
    • .disableDATARDY()
    • .enableALCOVF()
    • .disableALCOVF()
    • .enablePROXINT()
    • .disablePROXINT()
    • .enableDIETEMPRDY()
    • .disableDIETEMPRDY()
FIFO

The MAX30101 has a 32 byte FIFO (first-in first-out) buffer. This allows us do other things on our microcontroller while the sensor is taking measurements.

  • .check() - Call regularly to pull data in from sensor
  • .nextSample() - Advances the FIFO
  • .getFIFORed() - Returns the FIFO sample pointed to by tail
  • .getFIFOIR() - Returns the FIFO sample pointed to by tail
  • .getFIFOGreen() - Returns the FIFO sample pointed to by tail

Arduino Examples

☠ Do not rely on our examples for medical diagnosis or any life saving applications

Note: Particle detection, heart rate measurement, and photoplethysmography (for pulse oximetry) are applications of the MAX30101. These applications require a fundamental understanding of the operating principles of the sensor and a conceptual knowledge of the applications. Although, we provide some examples for these applications; they are primarily for demonstration purposes only and are not supported by SparkFun.

Note: Although there is an example, Maxim has since removed the proximity sensing and particle detection as functionalities of this sensor in their datasheet.

Example 1 - Reading Red/IR/Green

Once you've got the library installed, open the Example1 Basic Readings sketch. You can find it under

File > Examples > SparkFun MAX3010x Pulse and Proximity Sensor Library > Examples

Then load it onto your RedBoard or Uno. Open your favorite Serial Terminal to see the printed values.

Screen shot of MAX30101 readings
Data readings for photodetector. (Click to enlarge)

This example outputs the raw values read by the sensor. With the sensor pointing up, use your hand to hover over the sensor. You should see a change in values as your hand reflects different amounts of light. Note that the IR readings will probably change before the Red and Green readings. IR is better at sensing distance changes.

Completely cover the sensor with your finger. Note the very large readings. This is one of the features that sets the MAX30101 from other reflectance sensors. The IC is capable of reading up to 18-bits or values up to 262,144. An extremely small change in light can be detected!

The MAX30101 is easy to use! Calling particleSensor.getGreen() will take a reading and return the reflected amount of green light.

Example 3 - Temperature Sensor

Open the Example3 Temperature Sense sketch, and load it onto your RedBoard or Uno.

Temperature output from MAX30101 sensor
Internal temperature readings. (Click to enlarge)

This example outputs readings from the on-board temperature sensor in both Celsius and Fahrenheit. The temp sensor is accurate to ±1 °C but has an astonishing precision of 0.0625 °C.

The temperature is used internally by the sensor to calibrate its samples but can be useful if you need a sensitive and fast responding temp sensor.

Example 4 - Heart Beat Plotting

Note: The Arduino IDE must be version 1.6.6 or higher. The Serial Plotter is only available in Arduino versions v1.6.6 or later.

For this demo, you'll need a rubber band small enough to go through the mounting holes on the breakout. Make sure to follow the example in the Hardware Assembly section for the best results.

This is where the fun really begins! Hemoglobin reflects IR light really well, and the MAX30101 is capable of detecting such small changes in IR reflectance that it can detect blood flowing through your finger at different rates. Let's graph it! Open the Example4 HeartBeat Plotter sketch, and load it on your Redboard or Uno.

Instructions:

  1. Load code onto Redboard
  2. Attach sensor to your finger with a rubber band
  3. Open Tools->Serial Plotter
  4. Make sure the drop down is set to 115200 baud
  5. Checkout the blips!
  6. Feel the pulse on your neck and watch it mimic the blips
I'll just hold my finger on the sensor instead...

Humans are bad at applying consistent pressure to a thing. Without a rubber band the pressure varies enough to cause the blood in your finger to flow differently which causes the sensor readings to go wonky. It is best to attach the sensor to your finger using a rubber band or other tightening device.

Graph of heart beat
Graph of IR data - That's my pulse!

Now that we have seen the blips, Example 5 will try to calculate the time between blips and show us beats per minute (BPM).

Example 5 - HeartRate

☠ WARNING: Let's have a brief chat about the example code. We're going to try to detect heart-rate optically. This is tricky and prone to give false readings. We really don't want to get anyone hurt, so use this code only as an example of how to process optical data. Build fun stuff with our MAX30101 breakout board, but don't use it for actual medical diagnosis.

Open the Example5 HeartRate sketch, and load it on your Redboard or Uno.

Heart rate output
Heart rate readings. (Click to enlarge)

This example runs a filter called the PBA or Penpheral Beat Amplitude algorithm on the IR data. This algorithm is able to pull out the blips from all the noise and calculate the time between blips to get a heart rate. The output is your instantaneous heart rate and your average heart rate (BPM).

As one might expect the human body isn't as precise as a metronome. The time between pulses can vary quite a bit so this sketch takes a running average of 4 readings to try to smooth out the variance.

Python Package

Note: This tutorial assumes you are using the latest version of Python 3. If this is your first time using Python or I2C hardware on a Raspberry Pi, please checkout our tutorial on Python Programming with the Raspberry Pi and the Raspberry Pi SPI and I2C Tutorial. Jetson Nano users can check out this tutorial on Working with Qwiic on a Jetson Nano through Jupyter Notebooks.

We've written a Python package to easily get setup and take readings from the button controller on the Top pHAT. There are two methods for installing the Python package for the button controller.

  1. Install the all inclusive SparkFun Qwiic Python package.
  2. Independently install the SparkFun MAX3010x Python package.

The all inclusive SparkFun Qwiic Python package, is recommended as is also installs the required I2C driver as well.

Note: Don't forget to double check that the hardware I2C connection is enabled on your single board computer.

SparkFun Qwiic Package

This repository is hosted on PyPi as the sparkfun-qwiic package. On systems that support PyPi installation via pip3 (use pip for Python 2) is simple, using the following commands:

For all users (note: the user must have sudo privileges):

language:bash
sudo pip3 install sparkfun-qwiic

For the current user:

language:bash
pip3 install sparkfun-qwiic

Independent Installation

You can install the sparkfun-qwiic-max3010x Python package independently, which is hosted by PyPi. However, if you prefer to manually download and install the package from the GitHub repository, you can grab them here (*Please be aware of any package dependencies. You can also check out the repository documentation page, hosted on ReadtheDocs.):

PyPi Installation

This repository is hosted on PyPi as the sparkfun-qwiic-max3010x package. On systems that support PyPi installation via pip3 (use pip for Python 2) is simple, using the following commands:

For all users (note: the user must have sudo privileges):

language:bash
sudo pip3 install sparkfun-qwiic-max3010x

For the current user:

language:bash
pip3 install sparkfun-qwiic-max3010x

Local Installation

To install, make sure the setuptools package is installed on the system.

Direct installation at the command line (use python for Python 2):

language:bash
python3 setup.py install

To build a package for use with pip3:

language:bash
python3 setup.py sdist

A package file is built and placed in a subdirectory called dist. This package file can be installed using pip3.

language:bash
cd dist
pip3 install sparkfun_qwic_max3010x-<version>.tar.gz

Python Package Operation

Before we jump into getting readings, let's take a closer look at the available functions in the Python package. Below, is a description of the basic functionality of the Python package. This includes the package organization, built-in methods, and their inputs and/or outputs. For more details on how the Python package works, check out the source code and package documentation.

Dependencies

This Python package has a very few dependencies in the code, listed below:

language:python
from __future__ import print_function
import struct
import qwiic_i2c
import time
from smbus2 import SMBus, i2c_msg
_i2c_msg = i2c_msg

from . import heart_rate
hr = heart_rate.HeartRate()

Default Variables

The default variables, in the code, for this Python package are listed below:

language:python
# Some devices have multiple availabel addresses - this is a list of these addresses.
# NOTE: The first address in this list is considered the default I2C address for the
# device.
_AVAILABLE_I2C_ADDRESS = [0x57] # 7-bit I2C Address
# Note that MAX30102 has the same I2C address and Part ID

# Status Registers
MAX30105_INTSTAT1 =     0x00 
MAX30105_INTSTAT2 =     0x01 
MAX30105_INTENABLE1 =       0x02 
MAX30105_INTENABLE2 =       0x03 

# FIFO Registers
MAX30105_FIFOWRITEPTR =     0x04 
MAX30105_FIFOOVERFLOW =     0x05 
MAX30105_FIFOREADPTR =  0x06 
MAX30105_FIFODATA =     0x07 

# Configuration Registers
MAX30105_FIFOCONFIG =       0x08 
MAX30105_MODECONFIG =       0x09 
MAX30105_PARTICLECONFIG =   0x0A     # Note, sometimes listed as "SPO2" config in datasheet (pg. 11)
MAX30105_LED1_PULSEAMP =    0x0C 
MAX30105_LED2_PULSEAMP =    0x0D 
MAX30105_LED3_PULSEAMP =    0x0E 
MAX30105_LED_PROX_AMP =     0x10 
MAX30105_MULTILEDCONFIG1 = 0x11 
MAX30105_MULTILEDCONFIG2 = 0x12 

# Die Temperature Registers
MAX30105_DIETEMPINT =       0x1F 
MAX30105_DIETEMPFRAC =  0x20 
MAX30105_DIETEMPCONFIG =    0x21 

# Proximity Function Registers
MAX30105_PROXINTTHRESH =    0x30 

# Part ID Registers
MAX30105_REVISIONID =       0xFE 
MAX30105_PARTID =           0xFF     # Should always be 0x15. Identical to MAX30102.

# MAX30105 Commands
# Interrupt configuration (pg 13, 14)
MAX30105_INT_A_FULL_MASK =      (~0b10000000)
MAX30105_INT_A_FULL_ENABLE =    0x80 
MAX30105_INT_A_FULL_DISABLE =   0x00 

MAX30105_INT_DATA_RDY_MASK = (~0b01000000)
MAX30105_INT_DATA_RDY_ENABLE =  0x40 
MAX30105_INT_DATA_RDY_DISABLE = 0x00 

MAX30105_INT_ALC_OVF_MASK = (~0b00100000)
MAX30105_INT_ALC_OVF_ENABLE =   0x20 
MAX30105_INT_ALC_OVF_DISABLE = 0x00 

MAX30105_INT_PROX_INT_MASK = (~0b00010000)
MAX30105_INT_PROX_INT_ENABLE = 0x10 
MAX30105_INT_PROX_INT_DISABLE = 0x00 

MAX30105_INT_DIE_TEMP_RDY_MASK = (~0b00000010)
MAX30105_INT_DIE_TEMP_RDY_ENABLE = 0x02 
MAX30105_INT_DIE_TEMP_RDY_DISABLE = 0x00 

MAX30105_SAMPLEAVG_MASK =   (~0b11100000)
MAX30105_SAMPLEAVG_1 =  0x00 
MAX30105_SAMPLEAVG_2 =  0x20 
MAX30105_SAMPLEAVG_4 =  0x40 
MAX30105_SAMPLEAVG_8 =  0x60 
MAX30105_SAMPLEAVG_16 =     0x80 
MAX30105_SAMPLEAVG_32 =     0xA0 

MAX30105_ROLLOVER_MASK =    0xEF 
MAX30105_ROLLOVER_ENABLE = 0x10 
MAX30105_ROLLOVER_DISABLE = 0x00 

MAX30105_A_FULL_MASK =  0xF0 

# Mode configuration commands (page 19)
MAX30105_SHUTDOWN_MASK =    0x7F 
MAX30105_SHUTDOWN =         0x80 
MAX30105_WAKEUP =           0x00 

MAX30105_RESET_MASK =       0xBF 
MAX30105_RESET =            0x40 

MAX30105_MODE_MASK =        0xF8 
MAX30105_MODE_REDONLY =     0x02 
MAX30105_MODE_REDIRONLY =   0x03 
MAX30105_MODE_MULTILED =    0x07 

# Particle sensing configuration commands (pgs 19-20)
MAX30105_ADCRANGE_MASK =    0x9F 
MAX30105_ADCRANGE_2048 =    0x00 
MAX30105_ADCRANGE_4096 =    0x20 
MAX30105_ADCRANGE_8192 =    0x40 
MAX30105_ADCRANGE_16384 =   0x60 

MAX30105_SAMPLERATE_MASK = 0xE3 
MAX30105_SAMPLERATE_50 =    0x00 
MAX30105_SAMPLERATE_100 =   0x04 
MAX30105_SAMPLERATE_200 =   0x08 
MAX30105_SAMPLERATE_400 =   0x0C 
MAX30105_SAMPLERATE_800 =   0x10 
MAX30105_SAMPLERATE_1000 = 0x14 
MAX30105_SAMPLERATE_1600 = 0x18 
MAX30105_SAMPLERATE_3200 = 0x1C 

MAX30105_PULSEWIDTH_MASK = 0xFC 
MAX30105_PULSEWIDTH_69 =    0x00 
MAX30105_PULSEWIDTH_118 =   0x01 
MAX30105_PULSEWIDTH_215 =   0x02 
MAX30105_PULSEWIDTH_411 =   0x03 

#Multi-LED Mode configuration (pg 22)
MAX30105_SLOT1_MASK =       0xF8 
MAX30105_SLOT2_MASK =       0x8F 
MAX30105_SLOT3_MASK =       0xF8 
MAX30105_SLOT4_MASK =       0x8F 

SLOT_NONE =                 0x00 
SLOT_RED_LED =          0x01 
SLOT_IR_LED =               0x02 
SLOT_GREEN_LED =            0x03 
SLOT_NONE_PILOT =           0x04 
SLOT_RED_PILOT =            0x05 
SLOT_IR_PILOT =             0x06 
SLOT_GREEN_PILOT =      0x07 

MAX_30105_EXPECTEDPARTID = 0x15

Class

QwiicMax3010x() or QwiicMax3010x(address)
This Python package operates as a class object, allowing new instances of that type to be made. An __init__() constructor is used that creates a connection to an I2C device over the I2C bus using the default or specified I2C address.

The Constructor

A constructor is a special kind of method used to initialize (assign values to) the data members needed by the object when it is created.

__init__(address=None, i2c_driver=None):

Input: value
The value of the device address. If not defined, the Python package will use the default I2C address (0x71) stored under _AVAILABLE_I2C_ADDRESS variable.
Input: i2c_driver
Loads the specified I2C driver; by default the Qwiic I2C driver is used: qwiic_i2c.getI2CDriver(). Users should use the default I2C driver and leave this field blank.

Functions

A function is an attribute of the class, which defines a method for instances of that class. In simple terms, they are objects for the operations (or methods) of the class. A list of all the available functions are detailed on the API Reference page of ReadtheDocs for the Qwiic_MAX3010x_Py Python package.

Upgrading the Python Package

In the future, changes to the Python package might be made. Updating the installed packages has to be done individually for each package (i.e. sub-modules and dependencies won't update automatically and must be updated manually). For the sparkfun-qwiic-max3010x Python package, use the following command (use pip for Python 2):

For all users (note: the user must have sudo privileges):

language:bash
sudo pip3 install --upgrade sparkfun-qwiic-max3010x

For the current user:

language:bash
pip3 install --upgrade sparkfun-qwiic-max3010x

Python Examples

☠ Do not rely on our examples for medical diagnosis or any life saving applications

Note: Particle detection, heart rate measurement, and photoplethysmography (for pulse oximetry) are applications of the MAX30101. These applications require a fundamental understanding of the operating principles of the sensor and a conceptual knowledge of the applications. Although, we provide some examples for these applications; they are primarily for demonstration purposes only and are not supported by SparkFun.

Note: Although there is an example, Maxim has since removed the proximity sensing and particle detection as functionalities of this sensor in their datasheet.

There are several examples written for the Qwiic_MAX30101x_Py Python package. They can be found in the Examples folder of the GitHub repository or view on the repository documentation page, hosted on ReadtheDocs. Users can also grab them here, using the link below. (*Please be aware of any package dependencies.):

Example 1 - Basic Readings

Example 1 outputs the raw values read by the sensor.

language:python
#!/usr/bin/env python
#-----------------------------------------------------------------------------
# ex1_Basic_Readings.py
#
# Simple example for the qwiic MAX3010x device
# Outputs all Red/IR/Green values.
#
#------------------------------------------------------------------------
#
# Written by Pete Lewis
# SparkFun Electronics, May 2020
#
# Based on code from the SparkFun MAX3010x Sensor Arduino Library
# https://github.com/sparkfun/SparkFun_MAX3010x_Sensor_Library
# By: Nathan Seidle @ SparkFun Electronics, October 2nd, 2016
# 
# This python library supports the SparkFun Electroncis qwiic 
# qwiic sensor/board ecosystem on a Raspberry Pi (and compatable) single
# board computers. 
#
# More information on qwiic is at https://www.sparkfun.com/qwiic
#
# Do you like this library? Help support SparkFun. Buy a board!
#
#==================================================================================
# Copyright (c) 2019 SparkFun Electronics
#
# Permission is hereby granted, free of charge, to any person obtaining a copy 
# of this software and associated documentation files (the "Software"), to deal 
# in the Software without restriction, including without limitation the rights 
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
# copies of the Software, and to permit persons to whom the Software is 
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all 
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
# SOFTWARE.
#==================================================================================
# Example 1
#

from __future__ import print_function
import qwiic_max3010x
import time
import sys

def runExample():

    print("\nSparkFun MAX3010x Photodetector - Example 1\n")
    sensor = qwiic_max3010x.QwiicMax3010x()

    if sensor.begin() == False:
        print("The Qwiic MAX3010x device isn't connected to the system. Please check your connection", \
            file=sys.stderr)
        return
    else:
        print("The Qwiic MAX3010x is connected.")

    if sensor.setup() == False:
        print("Device setup failure. Please check your connection", \
            file=sys.stderr)
        return
    else:
        print("Setup complete.")        

    while True:
            print(\
             'R[', sensor.getRed() , '] \t'\
                                                             'IR[', sensor.getIR() , '] \t'\
                                                             'G[', sensor.getGreen() , ']'\
            )
            time.sleep(0.1)

if __name__ == '__main__':
    try:
        runExample()
    except (KeyboardInterrupt, SystemExit) as exErr:
        print("\nEnding Example 1")
        sys.exit(0)

Just as in the Arduino example, feel free to wave you hand over the sensor to see the changes in values. Users should see an output similar to the image below:

streaming data
Raw data streaming from the MAX30101.

Example 3 - Temperature Sense

Example 3 outputs readings from the on-board temperature sensor in both Celsius and Fahrenheit. The temp sensor is accurate to ±1 °C but has an astonishing precision of 0.0625 °C.

language:python
#!/usr/bin/env python
#-----------------------------------------------------------------------------
# ex3_Temperature_Sesnse.py
#
# Simple example for the qwiic MAX3010x device
# This demo outputs the onboard temperature sensor. 
# The temp sensor is accurate to +/-1 C but
# has an astonishing precision of 0.0625 C.
#
#------------------------------------------------------------------------
#
# Written by Pete Lewis
# SparkFun Electronics, May 2020
#
# Based on code from the SparkFun MAX3010x Sensor Arduino Library
# https://github.com/sparkfun/SparkFun_MAX3010x_Sensor_Library
# By: Nathan Seidle @ SparkFun Electronics, October 2016
# 
# This python library supports the SparkFun Electroncis qwiic 
# qwiic sensor/board ecosystem on a Raspberry Pi (and compatable) single
# board computers. 
#
# More information on qwiic is at https://www.sparkfun.com/qwiic
#
# Do you like this library? Help support SparkFun. Buy a board!
#
#==================================================================================
# Copyright (c) 2019 SparkFun Electronics
#
# Permission is hereby granted, free of charge, to any person obtaining a copy 
# of this software and associated documentation files (the "Software"), to deal 
# in the Software without restriction, including without limitation the rights 
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
# copies of the Software, and to permit persons to whom the Software is 
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all 
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
# SOFTWARE.
#==================================================================================
# Example 3
#

from __future__ import print_function
import qwiic_max3010x
import time
import sys

def runExample():

    print("\nSparkFun MAX3010x Photodetector - Example 3\n")
    sensor = qwiic_max3010x.QwiicMax3010x()

    if sensor.begin() == False:
        print("The Qwiic MAX3010x device isn't connected to the system. Please check your connection", \
            file=sys.stderr)
        return
    else:
        print("The Qwiic MAX3010x is connected.")

    # Setup Sensor
    # The LEDs are very low power and won't affect the temp reading much but
    # we will call setup() with LEDs off, to avoid any local heating (ledMode = 0)

    if sensor.setup(ledMode = 0) == False:
        print("Device setup failure. Please check your connection", \
            file=sys.stderr)
        return
    else:
        print("Setup complete.")        

    sensor.enableDIETEMPRDY() # Enable the temp ready interrupt. This is required.

    while True:
            temperature = sensor.readTemperature()
            temperatureF = sensor.readTemperatureF()

            temperature = round(temperature, 4)
            temperatureF = round(temperatureF, 4)

            print(\
             'temperatureC[', temperature , '] \t',\
             'temperatureF[', temperatureF , ']',\
            )


if __name__ == '__main__':
    try:
        runExample()
    except (KeyboardInterrupt, SystemExit) as exErr:
        print("\nEnding Example 3")
        sys.exit(0)

Feel free to heat up the sensor with your finger or blowing on it to cool it down.

Temp data streaming
Internal temperature data streaming from the MAX30101.

Example 4 - Heartbeat Plotter

Note: For this demo, you'll need a rubber band small enough to go through the mounting holes on the breakout. Make sure to follow the example in the Hardware Assembly section for the best results. Additionally, this example requires some software for the plotter to be installed.

On the Raspberry Pi, execute the following lines in the terminal:

  • sudo apt-get install libatlas3-base libffi-dev at-spi2-core python3-gi-cairo
  • sudo pip3 install matplotlib
On a Jeston Nano, execute the following line in the terminal:
  • sudo apt-get install python3-matplotlib

Example 4 is where the fun really begins! Hemoglobin reflects IR light really well, and the MAX30101 is capable of detecting such small changes in IR reflectance that it can detect blood flowing through your finger at different rates.

language:python
#!/usr/bin/env python
#-----------------------------------------------------------------------------
# ex4_HeartBeat_Plotter.py
#
# Simple example for the qwiic MAX3010x device
# Shows the user's heart beat on a graphical plotter
# Using Matplotlib
# To learn more about plotting data in python check out this tutorial:
# https://learn.sparkfun.com/tutorials/graph-sensor-data-with-python-and-matplotlib/
# The example code below was built using the code from the previously mentioned tutorial.
# Thanks Shawn Hymel!
#
# Instructions:
#   1) Install MatplotLib (see below)
#   2) Connect sensor to system via qwiic cable
#   3) Attach sensor to your finger with a rubber band (see below)
#   4) Run this python example
#   5) Checkout the blips!
#   6) Feel the pulse on your neck and watch it mimic the blips
#
#   It is best to attach the sensor to your finger using a rubber band or other tightening
#   device. Humans are generally bad at applying constant pressure to a thing. When you
#   press your finger against the sensor it varies enough to cause the blood in your
#   finger to flow differently which causes the sensor readings to go wonky.
#
# MatplotLib install
# Install Dependencies
# Like any good Linux project, we need to install a number of dependencies and libraries 
# in order to get matplotlib to run properly. Make sure you have an Internet connection 
# and in a terminal, enter the following commands. You may need to wait several minutes 
# while the various packages are downloaded and installed.
#
# sudo apt-get update
# sudo apt-get install libatlas3-base libffi-dev at-spi2-core python3-gi-cairo
# sudo pip3 install cairocffi
# sudo pip3 install matplotlib
#
#------------------------------------------------------------------------
#
# Written by Pete Lewis
# SparkFun Electronics, May 2020
#
# Based on code from the SparkFun MAX3010x Sensor Arduino Library
# https://github.com/sparkfun/SparkFun_MAX3010x_Sensor_Library
# By: Nathan Seidle @ SparkFun Electronics, October 2nd, 2016
# 
# This python library supports the SparkFun Electroncis qwiic 
# qwiic sensor/board ecosystem on a Raspberry Pi (and compatable) single
# board computers. 
#
# More information on qwiic is at https://www.sparkfun.com/qwiic
#
# Do you like this library? Help support SparkFun. Buy a board!
#
#==================================================================================
# Copyright (c) 2019 SparkFun Electronics
#
# Permission is hereby granted, free of charge, to any person obtaining a copy 
# of this software and associated documentation files (the "Software"), to deal 
# in the Software without restriction, including without limitation the rights 
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
# copies of the Software, and to permit persons to whom the Software is 
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all 
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
# SOFTWARE.
#==================================================================================
# Example 4
#

from __future__ import print_function
import qwiic_max3010x
import time
import sys

sensor = qwiic_max3010x.QwiicMax3010x()

#Plotter Stuff
import matplotlib.pyplot as plt
import matplotlib.animation as animation

# Create figure for plotting
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
xlen= 100 #sample number, increments and is used for labeling x axis in plot
xs = list(range(0,xlen))
ys = [0]*xlen
line, = ax.plot(xs, ys)
plt.title('Heartbeat over time')
plt.ylabel('IR Value')

# This function is called periodically from FuncAnimation
def animate(i, ys):
    # Read IR from MAX3010x
    ir = sensor.getIR()

    ys.append(ir)
    ys = ys[-xlen:]
    line.set_ydata(ys)
    ax.set_ylim([min(ys),max(ys)])

    return line,


def runExample():

    print("\nSparkFun MAX3010x Photodetector - Example 4\n")

    if sensor.begin() == False:
        print("The Qwiic MAX3010x device isn't connected to the system. Please check your connection", \
            file=sys.stderr)
        return
    else:
        print("The Qwiic MAX3010x is connected.")

    # Setup to sensor
    ledBrightness = 0x1F # Options: 0=Off to 255=50mA
    sampleAverage = 8 # Options: 1, 2, 4, 8, 16, 32
    ledMode = 3 # Options: 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green
    sampleRate = 100 # Options: 50, 100, 200, 400, 800, 1000, 1600, 3200
    pulseWidth = 411 # Options: 69, 118, 215, 411
    adcRange = 4096 # Options: 2048, 4096, 8192, 16384

    if sensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange) == False:
        print("Device setup failure. Please check your connection", \
            file=sys.stderr)
        return
    else:
        print("Setup complete.")
    # Set up plot to call animate() function periodically
    ani = animation.FuncAnimation(fig, animate, fargs=(ys,), interval=10, blit=True)
    plt.show()


if __name__ == '__main__':
    try:
        runExample()
    except (KeyboardInterrupt, SystemExit) as exErr:
        print("\nEnding Example 4")
        sys.exit(0)

Once the code is running, you should begin to see your pulse as the scale of the axis shrinks into the proper range. Again, the sensor can be a little finicky; especially, if it is moving around slightly. It make take several attempts to view your pulse.

I'll just hold my finger on the sensor instead...

Humans are bad at applying consistent pressure to a thing. Without a rubber band the pressure varies enough to cause the blood in your finger to flow differently which causes the sensor readings to go wonky. It is best to attach the sensor to your finger using a rubber band or other tightening device.

Plotting IR data
The last 40 values of IR data streaming onto a graph chart from the MAX30101.

Feel free to compare the plot with your pulse from your carotid artery.

Example 5 - Heartrate

☠ WARNING: Let's have a brief chat about the example code. We're going to try to detect heart-rate optically. This is tricky and prone to give false readings. We really don't want to get anyone hurt, so use this code only as an example of how to process optical data. Build fun stuff with our MAX30101 breakout board, but don't use it for actual medical diagnosis.

Example 5 runs a filter called the PBA or Penpheral Beat Amplitude algorithm on the IR data. This algorithm is able to pull out the blips from all the noise and calculate the time between blips to get a heart rate. The output is your instantaneous heart rate and your average heart rate (BPM).

language:python
#!/usr/bin/env python
#-----------------------------------------------------------------------------
# ex5_HeartRate.py
#
# Simple example for the qwiic MAX3010x device
# This is a demo to show the reading of heart rate or beats per minute (BPM) using
# a Penpheral Beat Amplitude (PBA) algorithm.
#
# It is best to attach the sensor to your finger using a rubber band or other tightening
# device. Humans are generally bad at applying constant pressure to a thing. When you
# press your finger against the sensor it varies enough to cause the blood in your
# finger to flow differently which causes the sensor readings to go wonky.
#
#------------------------------------------------------------------------
#
# Written by Pete Lewis
# SparkFun Electronics, May 2020
#
# Based on code from the SparkFun MAX3010x Sensor Arduino Library
# https://github.com/sparkfun/SparkFun_MAX3010x_Sensor_Library
# By: Nathan Seidle @ SparkFun Electronics, October 2nd, 2016
# 
# This python library supports the SparkFun Electroncis qwiic 
# qwiic sensor/board ecosystem on a Raspberry Pi (and compatable) single
# board computers. 
#
# More information on qwiic is at https://www.sparkfun.com/qwiic
#
# Do you like this library? Help support SparkFun. Buy a board!
#
#==================================================================================
# Copyright (c) 2019 SparkFun Electronics
#
# Permission is hereby granted, free of charge, to any person obtaining a copy 
# of this software and associated documentation files (the "Software"), to deal 
# in the Software without restriction, including without limitation the rights 
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
# copies of the Software, and to permit persons to whom the Software is 
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all 
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
# SOFTWARE.
#==================================================================================
# Example 5
#

from __future__ import print_function
import qwiic_max3010x
import time
import sys

def millis():
    return int(round(time.time() * 1000))

def runExample():

    print("\nSparkFun MAX3010x Photodetector - Example 5\n")
    sensor = qwiic_max3010x.QwiicMax3010x()

    if sensor.begin() == False:
        print("The Qwiic MAX3010x device isn't connected to the system. Please check your connection", \
            file=sys.stderr)
        return
    else:
        print("The Qwiic MAX3010x is connected.")

    print("Place your index finger on the sensor with steady pressure.")

    if sensor.setup() == False:
        print("Device setup failure. Please check your connection", \
            file=sys.stderr)
        return
    else:
        print("Setup complete.")

    sensor.setPulseAmplitudeRed(0x0A) # Turn Red LED to low to indicate sensor is running
    sensor.setPulseAmplitudeGreen(0) # Turn off Green LED

    RATE_SIZE = 4 # Increase this for more averaging. 4 is good.
    rates = list(range(RATE_SIZE)) # list of heart rates
    rateSpot = 0
    lastBeat = 0 # Time at which the last beat occurred
    beatsPerMinute = 0.00
    beatAvg = 0
    samplesTaken = 0 # Counter for calculating the Hz or read rate
    startTime = millis() # Used to calculate measurement rate

    while True:

        irValue = sensor.getIR()
        samplesTaken += 1
        if sensor.checkForBeat(irValue) == True:
            # We sensed a beat!
            print('BEAT')
            delta = ( millis() - lastBeat )
            lastBeat = millis() 

            beatsPerMinute = 60 / (delta / 1000.0)
            beatsPerMinute = round(beatsPerMinute,1)

            if beatsPerMinute < 255 and beatsPerMinute > 20:
                rateSpot += 1
                rateSpot %= RATE_SIZE # Wrap variable
                rates[rateSpot] = beatsPerMinute # Store this reading in the array

                # Take average of readings
                beatAvg = 0
                for x in range(0, RATE_SIZE):
                    beatAvg += rates[x]
                beatAvg /= RATE_SIZE
                beatAvg = round(beatAvg)

        Hz = round(float(samplesTaken) / ( ( millis() - startTime ) / 1000.0 ) , 2)
        if (samplesTaken % 200 ) == 0:

            print(\
                'IR=', irValue , ' \t',\
                            'BPM=', beatsPerMinute , '\t',\
                                                                                #'DCE', getDCE() , '\t',\
                            'Avg=', beatAvg , '\t',\
                'Hz=', Hz, \
                )

if __name__ == '__main__':
    try:
        runExample()
    except (KeyboardInterrupt, SystemExit) as exErr:
        print("\nEnding Example 5")
        sys.exit(0)

As one might expect the human body isn't as precise as a metronome. The time between pulses can vary quite a bit so this code takes a running average of 4 readings to try to smooth out the variance.

data output
Example heart rate calculations. For reference, my resting heart rate was around 68 BPM.

Troubleshooting

Raspberry Pi

For comprehensive information or troubleshooting issues, on the Raspberry Pi, users should check out the Raspberry Pi Foundation website and their forum.

As a general guideline, users should use the following resources when looking for technical information or assistance that is specifically related to the Raspberry Pi itself:

  1. Raspberry Pi FAQ
  2. Raspberry Pi Beginner's Subforum
  3. Raspberry Pi Documentation and Help Guides
  4. Raspberry Pi Forum

Nvidia Jetson Nano

For comprehensive information or troubleshooting issues, on the Nvidia Jetson, users should check out the Nvidia website and their forum.

As a general guideline, users should use the following resources when looking for technical information or assistance that is specifically related to the Jetson Nano itself:

  1. Jetson Support Resources
  2. Jetson Nano Getting Started Guide
  3. Developer Kit User Manual
  4. Jetson Nano Wiki
  5. Nvidia FAQ
  6. Jetson Forum
  7. Jetpack Documentation

For users looking for technical assistance, click on the link. There you will find, basic troubleshooting tips and instructions to get started with posting a topic in our forum. Our technical support team will do their best to assist you.

Resources and Going Further

For more on the SparkFun Photodetector (MAX30101), check out the links below:

Application Notes

Note: Particle detection, heart rate measurement, and photoplethysmography (for pulse oximetry) are applications of the MAX30101. These applications are detailed in the notes below; however, they require an understanding of the operating principles of the sensor and a conceptual knowledge of the application(s). Although, we provided the information below for interested users and may provide some examples of the application in our software; these applications are, unfortunately, not supported by SparkFun and the examples are primarily for demonstration purposes only.

Here are additional resources on how the MAX30101 functions for HR detection and pulse oximetry:

For more information on particulate matter and their detection, check out these resources:

Maxim's Original Firmware for the MAX30102 adapted in our Arduino Library:

For more sensor action, check out these other great SparkFun tutorials.

Photon Remote Water Level Sensor

Learn how to build a remote water level sensor for a water storage tank and how to automate a pump based off the readings!

MyoWare Muscle Sensor Kit

Line of products to work with the MyoWare muscle sensor from Advancer Technologies.

Photocell Hookup Guide

Hook a light-sensing photocell up to an Arduino to create an ambient light monitor.

SparkFun Qwiic MicroPressure Hookup Guide

Get started using your Qwiic MicroPressure breakout board with this hookup guide.

Or check out this blog post for ideas: