MAX30102 + Arduino Uno · Progress Report 3, Sections 2.7–2.8

Oximeter Bench Guide

Everything the three of us need on assembly day: what each part is, where every wire goes, the order to switch things on, the code to upload, and what to do when something doesn't work.

The code lives in the pulse_oximeter folder: three Arduino sketches in firmware/ and two MATLAB scripts in matlab/. Figure 5 and Table 10 of the report are the source for the wiring and the test order; this guide adds the practical detail.

Türkçe: Oksimetre Tezgâh Rehberi

The day in one line

Solder headers → build the breadboard with USB unplugged → check for shorts → power up one stage at a time (Table 10) → tune → record 60 s.

Three roles, swap every hour

Builder handles the parts. Checker reads this guide aloud and confirms every wire against the table. Operator runs the laptop: uploads, Serial Monitor, MATLAB.

00The finished setup

What it looks like when everything works: the sensor under one fingertip, the reference oximeter on the next finger, and the data on the laptop.

Side view: fingertip on the sensortableribbon taped down, 10 cm to the breadboardbase blockfingertip pad flat on the glass windowvelcro strap: snug, not tightblack tape around the sidesmodule, window uppins hang over the block's edgered and IR light go in and scatter;part comes back to the detector
Side view. The fingertip pad lies on the glass window. The red and infrared light enter the finger, scatter, and part of it comes back up to the detector next to the LEDs (reflective PPG, Section 1.1). The strap holds the finger with a steady pressure and the black tape keeps room light out.
Top view: the test tablet = 30 s HR 72 SpO2 96.4laptop on battery: Serial Plotter / MATLABArduino Unobreadboard next to the hand96 72our sensor on the index fingerARTIMED reference on the middle finger10 cm ribbon, tapedhand rests still, palm downOOperatorruns MATLAB, starts each stateRRecorderreads the ARTIMED every 10 sLamps and windows behind the volunteer, not above the hand.Next volunteer: swap the two fingers, or use the other hand.Volunteer: seated, quiet, still
Top view of the test table. Both devices are on the same hand (Section 2.6), so they see the same pulse. The breadboard sits right next to the hand because the sensor wires are only 10 cm.

One volunteer, start to finish

  1. Before measuring: explain what is measured and that they can stop any time, get consent, give a code (S01, S02…), note the skin tone on the light/medium/dark scale. No nail polish or artificial nails on the two fingers.
  2. Seat them with the right hand resting palm-down on the table. Sensor on the index finger, ARTIMED on the middle finger. Wait 30 s for both to settle.
  3. Record the four states of Table 6, 150 s each. The Operator sets state in record_session.m and starts it. The Recorder writes the ARTIMED's SpO₂ and pulse each time MATLAB prints a 10 s mark. The first reading of each state is dropped later.
  4. Next volunteer: swap the fingers (or use the left hand), so a difference between fingers does not look like a device error.
state 1 · 150 sRest

Hand flat and still, no talking.

state 2 · 150 sAfter light activity

Short stretching routine, then sit and measure.

state 3 · 150 sFinger movement

Move the finger slowly in a fixed pattern during the measurement.

state 4 · 2 × 150 sAmbient light

Room light on; once with the black tape cover, once without.

Calibration split

The volunteers whose data fit the SpO₂ curve are not the ones used to test its accuracy (Section 2.6). Decide which codes go in which group before the first test.

01Before the day

Do all of this at home, on the laptop you will bring. Each box remembers its tick in your own browser.

02Know your parts

For each part: what it looks like, its job in our circuit, how to use it, and the one mistake to avoid.

Arduino Uno R3

1 · the brain · already owned or the CH340 clone
Looks like
Blue (or black) board, about the size of a credit card, with a square USB-B socket, a round barrel power jack, and two long rows of black sockets (headers) along the edges. The pin names are printed next to the sockets.
Job
Reads the sensor over I²C, runs the filters and beat detection, and sends the numbers to the laptop over USB.
Pins we use
5V, 3.3V, two GND (power header, next to VIN); A4 = SDA and A5 = SCL (analog header); D2 (digital header, labelled just "2").
Avoid
Never connect anything to D0/D1 (they carry the USB data), and never connect 5V to 3.3V. The USB cable powers everything; no battery or barrel jack needed.

MAX30102 module

2 · the sensor · one is a spare
Looks like
Small black board (about 2 × 1.5 cm). On one side, a tiny black rectangle with a glass window: that is the MAX30102 chip with its two LEDs and photodetector. A row of 7 holes along one edge: VIN GND SDA SCL INT IRD RD (the printed order on your board is what counts).
Job
Shines red (660 nm) and infrared (880 nm) light into the fingertip, measures what comes back, and stores the numbers for the Uno to collect.
How to use
Header pins are soldered so the pins stick out the back, away from the glass window. The fingertip rests flat on the window.
Avoid
IRD and RD stay unconnected. Find the 3-pad "pull-up" solder jumper marked 1.8V / 3.3V and confirm the blob joins the 3.3V side (step 3 of section 06 checks it electrically).

Logic level shifter

1 · 4-channel, bidirectional · the translator
Looks like
Small board with 12 holes in two rows of 6. Four tiny 3-legged black parts (BSS138 transistors) and a few resistors. One row is the high side, labelled HV HV1 HV2 HV3 HV4 GND; the other the low side LV LV1 LV2 LV3 LV4 GND.
Job
The Uno only reads an I²C line as "high" above 3.5 V; the sensor's lines only go to 3.3 V. The shifter passes each signal across while the Uno side sees 5 V and the sensor side 3.3 V. Channel 1 = SDA, 2 = SCL, 3 = INT, 4 unused.
How to use
It needs three power connections or it does nothing: HV to 5 V, LV to 3.3 V, GND to ground (either GND pin; we wire both).
Avoid
Swapping the sides. Some boards say VA/VB or A/B: the side whose supply pin you connect to 3.3 V is the low side, and the sensor goes there.

Breadboard, 830 points

1 · the solderless base
Looks like
White plastic block full of holes. A groove runs down the middle. Long red and blue lines run along both edges.
Job
Joins wires and parts without solder. Hidden metal clips connect certain holes together (see section 03).
Avoid
Assuming the edge rails run the full length: on some boards they are cut in the middle. Check with the multimeter's beep mode before using them.

140-piece jumper kit

1 box · rigid, pre-cut, pre-bent
Looks like
Box of short U-shaped wires with bare ends, sorted by length. The colour tells the length, not a function.
Job
Every connection on the breadboard, and from the breadboard to the Uno's sockets (pick the longest ones for the Uno, and keep the Uno right next to the breadboard).
How to use
Pick the length that lies flat between the two holes; push the ends straight down until they stop (about 5 mm).

Female-to-male wires, 10 cm

1 pack of 40 · the sensor cable
Looks like
A flat rainbow ribbon of 40 wires. Each wire has a socket (female) on one end and a pin (male) on the other.
Job
Connect the module (female end onto its header pins) to the breadboard (male end into a hole).
How to use
Peel off a strip of 5 wires that stay stuck together; it is much easier to tape down. Split only the last few cm at the breadboard end. Write down which colour is VIN, GND, SDA, SCL, INT.

10 µF capacitor (C1)

1 · electrolytic, 25 V · polarised
Looks like
Small cylinder (usually black or blue) with two legs. A light stripe with "–" signs runs down one side.
Job
A small energy reserve right where the sensor's power wires land, so the LED pulses don't make the supply voltage dip.
Avoid
It has a direction. The leg under the "–" stripe (also the shorter leg) goes to GND; the other leg to VIN.

100 nF capacitor (C2)

pack of 10 · ceramic · use 1
Looks like
Tiny yellow, blue or orange blob or disc with two legs, printed 104 (10 × 10⁴ pF = 100 nF).
Job
Works alongside C1 and filters fast spikes C1 is too slow for.
How to use
No direction: either way round, across the same two strips as C1.

4.7 kΩ resistors (R1, R2)

pack of 10 · backup only
Looks like
Tiny beige or blue tube with coloured bands: yellow, violet, red, gold (4 bands) or yellow, violet, black, brown, brown (5 bands).
Job
Extra pull-ups on SDA and SCL, sensor side. Only used if step 3 or 4 in section 06 shows the module's own pull-ups are missing. Normally they stay in the bag.
How to use
No direction. One leg in the SDA strip (sensor side), the other on the 3.3 V rail; same for SCL.

Multimeter

1 · already owned · our eyes for electricity
Job
Checks voltages before anything delicate is connected, and finds shorts and broken wires.
How to use
See section 03. Black probe in COM, red probe in the socket marked V (often VΩmA). Never the 10A socket.

Tape, velcro, batteries

finger holder + reference
Black electrical tape
Blocks room light around the fingertip and holds the module and its wires still.
Velcro strap, 10 mm
Hook on one side, loop on the other, so it sticks to itself. Cut about 15 cm. Holds the finger on the sensor with steady, gentle pressure.
AAA batteries
For the ARTIMED reference oximeter, if its own are flat.

03Basic skills

How a breadboard connects things

Using the multimeter

Measuring a voltage (circuit powered)

  1. Turn the dial to V⎓ (DC volts; the V with a straight line). If it has ranges, pick 20 V.
  2. Black probe on any GND point, red probe on the point you want.
  3. Read the number. A minus sign means the probes are swapped; nothing breaks.

Checking a connection (circuit unplugged)

  1. Turn the dial to the beep mode (a speaker or ))) symbol, often shared with the diode symbol).
  2. Touch the two probes together: it beeps. That's "connected".
  3. Touch two points. Beep = connected. Silence = not connected.
Never

Use beep or resistance mode on a powered circuit, and never put the red probe in the 10A or mA socket for these checks: that turns the meter into a short circuit.

Soldering the header pins (at school)

  1. Break off a 7-pin strip for the module (if it didn't come with one) and two 6-pin strips for the shifter. Snap with pliers or bend at the notch.
  2. Use the breadboard as a jig. Push the long ends of the pins into the breadboard, then lay the board on top so the short ends poke up through its holes.
    • Module: glass window facing up, so after soldering the long pins come out the back, away from the finger.
    • Level shifter: components facing up. Its two pin rows go into the breadboard across the groove so it sits level.
  3. Heat the iron (about 330–350 °C). Wipe the tip on the wet sponge or brass wool and touch a little solder to the tip.
  4. Solder one corner pin first: hold the tip against the pin and the copper ring for 1–2 seconds, feed solder into the joint (not onto the iron), remove the solder, then the iron. Check the board is flat; if not, re-melt that one joint and straighten it.
  5. Do the opposite corner, then the rest. Each joint should be a small shiny cone hugging the pin. A ball sitting on top, or a dull grey blob, needs re-heating.
  6. Look for bridges, solder joining two neighbouring pins. Check every neighbouring pair with beep mode; none should beep. Remove a bridge by dragging a clean hot tip between the pins.
Pull-up pad

While the module is at the station, check the 3-pad jumper. If the blob joins the middle pad to the 1.8V side, melt it off and bridge the middle pad to 3.3V instead. Even on 1.8 V the circuit usually still works through the shifter, but 3.3 V is what the report describes.

04Wiring plan

This is Figure 5 laid out hole by hole. The diagram shows where things go; the table is the checklist. Build everything with the USB cable unplugged.

Breadboard wiring plan +5V GND +3V3 GND a b c d e f g h i j 1 1 5 5 10 10 15 15 20 20 Arduino Uno (pins drawn by function, not by position) 5V GND 3.3V GND A4 / SDA A5 / SCL D2 USB to laptop level shifter HV top · LV bottom HV1 LV1 HV2 LV2 HV LV GND GND HV3 LV3 HV4 LV4 C1 10 µF, + leg in 20 C2 100 nF finger holder sensor MAX30102 VIN GND SDA SCL INT IRD RD IRD, RD: leave empty dashed: 10 cm female-to-male wires (female end on the module)
Strip numbers and letters as printed on most 830-point boards. Exact holes don't matter as long as each wire lands in the right strip and the right half. The level shifter pin order is the common one; follow the labels on your board.

Connection table

#FromToWhat it does
1Uno 5Vtop + rail (5V)5 V supply line
2Uno GNDtop – railground, top
3Uno 3.3Vbottom + rail (3V3)3.3 V supply line
4Uno second GNDbottom – railground, bottom (joins both ground rails at the Uno)
5Level shifteracross the groove, strips 6–11HV row in the top half, LV row in the bottom half
6strip 8 top (HV)top + rail (5V)powers the Uno side
7strip 9 top (GND)top – rail
8strip 8 bottom (LV)bottom + rail (3V3)powers the sensor side
9strip 9 bottom (GND)bottom – rail
10Uno A4strip 6 top (HV1)SDA, Uno side
11Uno A5strip 7 top (HV2)SCL, Uno side
12Uno D2strip 10 top (HV3)INT, Uno side
13strip 20 bottombottom + rail (3V3)sensor power landing (VIN). For the 5 V test, move this wire's rail end to the top + rail.
14strip 21 bottombottom – railsensor ground landing
15C1 10 µF+ leg strip 20, – leg (stripe) strip 21decoupling
16C2 100 nFstrip 20 and strip 21decoupling
17module VIN (F-M)strip 20 bottom
18module GND (F-M)strip 21 bottom
19module SDA (F-M)strip 6 bottom (LV1)SDA, sensor side
20module SCL (F-M)strip 7 bottom (LV2)SCL, sensor side
21module INT (F-M)strip 10 bottom (LV3)INT, sensor side
–module IRD, RDnothingleave empty
opt.R1 4.7 kΩ / R2 4.7 kΩstrip 6 bottom → 3V3 rail / strip 7 bottom → 3V3 railonly if section 06 says so

Build order

  1. Rails and Uno power (rows 1–4). Stop and do the short check below.
  2. Level shifter and its power (5–9).
  3. Sensor power landing with C1 and C2 (13–16). Check C1's stripe is on strip 21.
  4. Signal wires on the Uno side (10–12).
  5. Module power wires only (17–18). SDA, SCL and INT stay off the breadboard for now: section 06 connects them one stage at a time.
Short check before the first power-on

USB unplugged, meter on beep: touch top + rail and top – rail; then bottom + and bottom –; then top + and bottom +. None of these may beep. A beep means a wire is in the wrong place. Find it before plugging in.

05Finger holder

Its two jobs (Section 2.8): keep the finger still with a steady pressure, and keep room light out.

  1. Place the module on the base block, glass window up, with the edge that has the pins hanging just over the edge of the block. The wire sockets then hang down beside the block and the module lies flat.
  2. Tape the module to the block along its two sides. Keep tape off the glass window; tape glue on the window ruins the signal.
  3. Tape the 5-wire ribbon down to the block and to the table, so pulling the finger away does not tug the wires.
  4. Put the block right next to the breadboard (the wires are only 10 cm).
  5. Velcro: stick one end to the underside of the block with tape, so the strap can wrap over the fingertip and close on itself.
  6. Finger on: pad of the fingertip centred on the window, strap snug but not tight. Then wrap a short piece of black tape loosely around fingertip and block to cover the sides from light.
Pressure

Too tight squeezes the blood out of the fingertip and the pulse almost disappears. Too loose and every movement shows up. Tighten until the finger can't slide, then back off a little. Keep the same strap tension for every volunteer.

06First power-on, one stage at a time

This is Table 10 of the report with exact actions. Do the stages in order; if one fails, fix it before going on (section 09). Unplug USB every time you move a wire.

Uno and railsTable 10 · 1

Plug in the USB cable. The Uno's green ON LED lights. Meter on V⎓, black probe on a GND rail:

ExpectTop + rail about 5.0 V (4.7–5.2), bottom + rail about 3.3 V (3.2–3.4). Shifter HV strip 5 V, LV strip 3.3 V. Strip 20 bottom (VIN landing) 3.3 V.

Sensor powered, signals not connectedTable 10 · 2

Unplug USB. Plug in only the module's VIN and GND wires (17–18). Plug in USB. Measure on the module's own SDA and SCL pins (touch the red probe to the pin or the socket of its loose wire).

ExpectAbout 3.3 V on SDA and SCL: the pull-up pad is on 3.3 V. 1.8 V means the pad is on the 1.8 V side (fix at school, or carry on; it usually still works). 0 V means the module has no pull-ups: you will need R1 and R2.

I²C scannerTable 10 · 3

Unplug USB. Connect the module's SDA, SCL and INT wires (19–21). Plug in USB. Open step1_i2c_scanner, Upload, open Serial Monitor (magnifier icon top right), set the speed to 115200 baud.

I2C scanner - looking for the MAX30102 at 0x57
  device at 0x57  <- MAX30102
Done, 1 device(s) found.
ExpectOne device at 0x57, repeated every 3 s. Wiggle the sensor wires gently while it runs: the result must not change.

Sensor checkTable 10 · 4

Upload step2_sensor_check. Serial Monitor at 115200.

Part ID: 0x15  OK (MAX30102)
Revision ID: 0x03
Die temperature: 27.31 C
INT on D2: idle HIGH, data waiting LOW  -> INT wire OK
ExpectPart ID 0x15, a temperature near room temperature (the chip runs a few degrees warm; holding a finger on it raises it), and "INT wire OK". The revision number can differ.

Raw signal with a fingerTable 10 · 5

Upload oximeter_main. The sensor's red LED should now glow faintly (the IR LED is invisible; a phone's front camera sometimes shows it as purple). Close Serial Monitor, open Tools → Serial Plotter, set 115200, type w in its message box and press Enter. Put a finger on the sensor, strap it, keep still.

ExpectWithout a finger both lines are low. With a finger both jump up and settle, then show a small regular ripple: your pulse. Type p to see only the ripple (AC), which is much easier to read. Neither line may sit flat at 262143 (saturation).

Tune LED current and ADC rangeTable 10 · 6

In Serial Monitor (or the Plotter's message box) type s to see the settings and the current DC levels. Then adjust:

  • I / i: IR LED current up / down by 1 mA. R / r: same for red. Each change restarts the filters.
  • a: next ADC range (2048 → 4096 → 8192 → 16384 nA). A larger range takes more light before saturating.
ExpectAim for both DC values between about 50,000 and 200,000 (around the middle of 0–262,143), roughly equal for red and IR, with a clear ripple in plot mode. Write the final currents down; to keep them, put them in redCurrent, irCurrent and adcRange at the top of the sketch and upload again. The Uno's reset button brings back the values in the code.

Red/IR check (once): type r until the red current reads 0.0 mA. The red column must drop to almost nothing. If ir drops instead, set SWAP_RED_IR = true in the sketch.

Finger threshold (once): note the IR DC with no finger and with a finger (s). Set FINGER_DC_MIN to about halfway between them (the code's 30,000 is only a starting guess).

60 s rest recording, then 5 VTable 10 · 7

Type c to go back to CSV. Close the Arduino Serial Monitor and Plotter. Run record_session.m in MATLAB with durationS = 60, then analyze_recording.m on the file (section 08).

Then unplug USB, move wire 13's rail end from the 3V3 rail to the 5V rail (VIN = 5 V), plug in, check VIN strip reads 5 V, re-tune, record again and compare the SNR.

ExpectA clear peak at your heart rate in the analysis, an SNR value for each supply, and the spectrum heart rate within a few bpm of the firmware's.

07Using the firmware

The three sketches

SketchWhenWhat it tells you
step1_i2c_scannerFirst time the sensor is wiredWhether anything answers on the I²C wires, and at which address
step2_sensor_checkAfter the scanner finds 0x57Right chip (ID 0x15), temperature, INT wire working
oximeter_mainEverything after thatThe real program from Section 2.7.3: streams data, heart rate, SpO₂ and quality flags

Uploading any sketch

  1. File → Open → the .ino file (the folder name must match the file name; keep them as they are).
  2. Tools → Board → Arduino AVR Boards → Arduino Uno. Tools → Port → your COM port.
  3. Click Upload (→). The Uno's TX/RX LEDs flicker; the IDE says "Done uploading".
  4. Open Serial Monitor or Serial Plotter at 115200 baud. Opening either one restarts the Uno, which is normal.

What oximeter_main sends

One line per sample, 100 lines per second. Lines starting with # are messages.

t_ms,red,ir,red_ac,ir_ac,hr,spo2,flags
24130,88412,119634,-41,-312,72,95.8,0
ColumnMeaning
t_msTime from the sensor's own clock: sample number × 10 ms. A jump bigger than 10 means samples were lost.
red, irRaw 18-bit readings, 0–262,143. More light reaching the detector = bigger number.
red_ac, ir_acThe pulsing part after the two filters (about 0.5–4.6 Hz). Swings around 0.
hrHeart rate in bpm, from the last 4 beat intervals. 0 = not enough clean beats yet.
spo2104 − 17·R, median of the last 4 beats. 0 = no value yet. Uncalibrated until Section 2.6 is done; a few % off is expected.
flagsSum of: 1 no finger, 2 saturation, 4 low perfusion, 8 ambient light. 0 = clean. Example: 9 = no finger + ambient light.

Commands

Type one letter into the Serial Monitor's input box (or the Plotter's message box) and press Enter.

KeyEffect
cCSV output (default; for MATLAB)
pPlot mode: only red and IR AC, labelled, for the Serial Plotter
wPlot mode: raw red and IR
R r · I iRed · IR LED current up / down by 1 mA (0–51 mA)
aNext ADC range
tDie temperature
sSettings, finger yes/no, DC levels, lost samples, I²C errors
?Short help line

Normal things that look wrong

Settings at the top of the sketch

redCurrent, irCurrent, adcRange (start values), FINGER_DC_MIN and PI_MIN (the two thresholds the report leaves "to be determined from the initial recordings"), CAL_A and CAL_B (the calibration line), and SWAP_RED_IR. Change, upload, done.

08Recording with MATLAB

  1. Upload oximeter_main, tune, then close the Serial Monitor and Plotter. Only one program can hold the COM port.
  2. In record_session.m, set port (e.g. "COM5"), durationS, subject (a code like S01, never a name) and state. Run it.
  3. Every 10 s it prints a line with the Uno time. The second person reads the ARTIMED screen at that moment and writes SpO₂ and pulse next to that time on paper.
  4. It saves e.g. S01_rest_20261112_101500.csv in MATLAB's current folder.
  5. Put that name in analyze_recording.m and run it: it prints lost samples, the share of each quality flag, the SNR, the spectrum heart rate vs the firmware's, and R for each 10 s window to put next to the paper readings.
If MATLAB stops with an error

Type clear s in the Command Window to release the COM port before running again or reopening the Arduino Serial Monitor.

09Troubleshooting

Find the symptom, try the causes in order. When stuck: unplug, re-check the connection table line by line with the Checker reading it aloud, then try again. Most problems on a first build are one wire in the wrong strip.

Something gets hot, smells, or the Uno's ON LED goes out when the circuit is connectedpower · stop

Unplug the USB cable immediately. This is a short circuit: a supply connected straight to ground.

  1. Re-do the short check from section 04 (beep mode, USB unplugged).
  2. Usual causes: a rail jumper in the wrong rail, VIN and GND swapped on the module, C1 in backwards, a wire landed one strip off so 5V and GND share a strip.
  3. Feel which part was warm; the fault is around it. If the module got hot, use the spare after fixing the wiring.
No COM port appears when the Uno is plugged inlaptop
  1. Try another USB cable. Many cables only charge and carry no data.
  2. Try another USB port, directly on the laptop (no hub).
  3. Clone with CH340: Windows 10/11 usually installs the driver by itself within a minute. If not, install the CH340 driver (CH341SER) from the chip maker WCH's site, then re-plug.
  4. Device Manager → Ports (COM & LPT): a yellow warning sign means the driver is missing.
Upload fails: "programmer is not responding", "not in sync" or a timeoutlaptop
  1. Wrong port selected: Tools → Port, unplug and re-plug to see which one disappears.
  2. Wrong board: must be Arduino Uno.
  3. MATLAB or another program has the port open: close it (clear s in MATLAB).
  4. Something is plugged into D0 or D1: remove it.
  5. Press the Uno's reset button just as "Uploading..." appears, then try again.
"Access denied" or "port busy"laptop

Another window holds the port: close Serial Monitor, Serial Plotter, MATLAB's serialport (clear s), or a second Arduino IDE window.

Serial Monitor shows gibberish characterslaptop

Set the speed menu at the bottom right of Serial Monitor to 115200 baud.

Verify/compile error in the IDElaptop
  1. Board must be Arduino Uno (the sketches use the Uno's Wire library).
  2. The sketch folder name must match the .ino name.
  3. If you edited a setting, check you kept the ; at the end of the line.
  4. Copy the first red error line and send it to us / look it up.
3.3 V or 5 V rail reads 0 V or a wrong valuepower
  1. Is the Uno's ON LED lit? If not, the USB cable/port gives no power.
  2. Measure directly on the Uno's 3.3V and 5V sockets. Right there but wrong on the rail: the rail jumper is loose, in the wrong rail, or the rail is split in the middle (beep along its length).
  3. A few tenths of a volt low under load is fine (5 V from USB is often 4.7–5.0 V).
Scanner finds no devicessensor link
  1. Is the module powered? Measure VIN–GND on the module's pins: 3.3 V (or 5 V).
  2. Is the shifter powered on both sides? HV strip 5 V, LV strip 3.3 V, GND connected. Without HV or LV it passes nothing.
  3. HV and LV sides swapped? The Uno's wires must be on the HV row.
  4. SDA and SCL swapped somewhere? Follow A4 → HV1 → LV1 → module SDA, A5 → HV2 → LV2 → module SCL.
  5. Bad solder joint on the header: with USB unplugged, beep from the module's copper pad side of each pin to the breadboard strip it should reach.
  6. No pull-ups: section 06 step 2 measured 0 V on SDA/SCL? Add R1 and R2.
  7. Still nothing: swap in the spare module.
Scanner says "Bus timeout: SDA or SCL is held low"sensor link
  1. A signal wire is touching ground: check strips 6 and 7 for a stray GND wire or a leg of C1/C2.
  2. The module or the shifter's LV side has no power, so it holds the line down.
  3. Unplug the module's SDA/SCL wires: if the timeout stops, the problem is on the sensor side.
Scanner finds a device, but not at 0x57sensor link

Something else is on the bus or the chip is not a MAX30102. Run step2_sensor_check only if 0x57 is listed. A different address alone means a different chip: use the spare and tell the seller.

Part ID is 0x11 instead of 0x15sensor link

The board carries a MAX30100, the older chip (the same mix-up we avoided at Robotistan). Its registers are different and our settings won't work. Check the spare; if both read 0x11, contact the seller.

"INT wire" check failssensor link

Only matters for the interrupt method; our firmware polls every 40 ms and works without INT. Still worth fixing: check module INT → LV3 → HV3 → D2. "Stuck LOW" means INT touches ground or the shifter's HV side has no power.

"# I2C error" messages while running, or the scanner result comes and goessensor link
  1. A loose wire: press each F-M socket fully onto its pin and each male end fully into the breadboard.
  2. Tape the ribbon down so finger movements don't pull it.
  3. Breadboard holes that are worn: move the wire to another hole in the same strip.
  4. Cracked solder joint on the module: re-heat it at school.
oximeter_main keeps printing "sensor not ready ... retrying"sensor link

The Uno can't read the part ID. Go back to step1_i2c_scanner and fix the link first.

Red LED on the sensor doesn't glowsignal
  1. It only glows while oximeter_main runs (or 50 ms per cycle in step2). Check the program is running: Serial Monitor shows data?
  2. Red current turned to 0 with r? Press the Uno's reset button.
  3. VIN voltage too low (below 3.1 V on the LED side): try VIN at 5 V.
Readings stay low even with a fingersignal
  1. The finger is on the wrong side: the glass window must face the finger.
  2. Raise the LED currents with I and R.
  3. Lower the ADC range: a until 2048 nA (more counts per unit of light).
  4. Tape over the window? Remove it; clean the window with a dry tissue.
A line sits flat at 262143 (flag 2, saturation)signal
  1. Too much light: lower that LED's current (i or r).
  2. Or raise the ADC range with a.
  3. Cover the finger against room light; strong light can also saturate.
DC is fine but there is no visible pulsesignal
  1. Use plot mode p; the pulse is tiny next to the DC in raw mode.
  2. Strap too tight: loosen it. Too loose: tighten a little.
  3. Cold hands give a weak pulse: warm the hands, try another finger (index or middle).
  4. Keep completely still and stop talking for 10 s.
  5. Raise the LED current a few mA.
Big jumps and spikes, flag 8 (ambient light)signal

Room light reaches the detector. Wrap the black tape around fingertip and block, turn away from windows and lamps. Fluorescent and LED room lights flicker at 100 Hz, which can leak into the signal.

Signal is noisy only while the laptop charger is plugged insignal

Run the laptop on battery during recordings (Section 2.8 plans to compare both). Keep the sensor wires away from the USB cable.

Heart rate stays 0numbers
  1. Wait 7–10 s after placing the finger and keep still.
  2. flags not 0? A flag blocks beats: 1 = finger not detected (lower FINGER_DC_MIN), 2 = saturation, 4 = pulse too weak, 8 = room light.
  3. No visible pulse in plot mode? See "no visible pulse".
Heart rate about double (or half) the referencenumbers

Double: the detector counts a second bump in each beat (the dicrotic wave) or noise. Half: it misses every other beat. Both come from a weak or noisy pulse. Improve contact and light shielding first; check the AC plot shows one clean bump per beat. If it persists, save a recording: the threshold (60 %) and refractory time (300 ms) can be tuned against it.

Flag 1 (no finger) although the finger is onnumbers

The IR DC is below FINGER_DC_MIN. Type s to see the IR DC with the finger on, and set FINGER_DC_MIN to about half of it. Or raise the IR current.

Flag 4 (low perfusion) most of the timenumbers

The pulse is below 0.1 % of the DC. Fix the contact first (pressure, warm finger). If the pulse is clearly visible in plot mode and the flag still shows, lower PI_MIN based on the first recordings.

SpO₂ above 100, or far from the referencenumbers
  1. Expected before calibration: 104 − 17·R is a borrowed starting line.
  2. Do the red/IR check from section 06; swapped channels give nonsense R.
  3. Very different red and IR DC levels: balance the currents (step 6).
  4. For calibration, collect R per 10 s window (analyze_recording.m) next to the reference readings.
"lost samples" is not 0 (type s)numbers

The Uno fell behind. Make sure only one window reads the port, and avoid typing many commands quickly. A few after an upload or reset are harmless.

A part wobbles or keeps popping out of the breadboardbuild

Header pins too short or bent: straighten with pliers. Push straight down. Tape the module's ribbon so its weight doesn't pull the male ends out.

Solder joint looks like a ball, or two pins are joinedbuild

Ball: re-heat the pin and pad together for 2 s, add a touch of solder. Bridge: drag a clean, hot tip between the pins; check with beep mode afterwards.

Not sure a wire is really connectedbuild

USB unplugged, beep mode: one probe on the start pin, the other on the end pin (not the breadboard hole). Beep = good. Do this for every wire when nothing makes sense.

10Safety rules

11Words you will hear

GND (ground)The 0 V reference. Every part must share it, or signals mean nothing.
VINThe module's power input. Its own regulators make the 1.8 V and LED voltages from it.
I²C, SDA, SCLThe two-wire link between Uno and sensor. SDA carries data, SCL the clock. Each chip has an address; the MAX30102's is 0x57.
Pull-up resistorI²C chips can only pull a line down to 0 V; a resistor to the supply pulls it back up. The module and the shifter already have them.
Level shifterLets a 5 V side and a 3.3 V side talk without either seeing the wrong voltage.
Decoupling capacitorA small local energy store near a part's power pins that smooths quick dips.
RegisterA numbered memory cell inside the sensor. Writing values to registers sets it up (Table 7).
FIFOThe sensor's 32-sample waiting line. The Uno empties it every 40 ms.
SaturationSo much light that the reading hits its maximum (262,143) and stops showing changes.
AC, DC, perfusion indexDC: the steady light level. AC: the small pulsing part. Perfusion index: AC divided by DC.
BaudSpeed of the USB serial link. Ours is 115200 on both ends.
Sketch, upload, COM portAn Arduino program; copying it to the Uno; the name Windows gives the Uno's USB connection.