MAX30001G 1.3.0 Arduino library for MAX30001G ECG and BIOZ AFE

Interrupt Handling

The driver keeps default behavior in `serviceAllInterrupts()` (updates global flags), and also supports user callbacks. For most sketches, prefer `update()` in `loop()`. It services pending IRQs, drains enabled FIFOs, reads RTOR when configured, and falls back to `serviceAllInterrupts()` when needed. Use `servicePendingInterrupts()` directly only in lower-level custom loops where you want interrupt servicing without the rest of the normal `update()` data-path work.

# Interrupt Usage

Wire MAX30001G `INTB` (and optional `INT2B`) to interrupt-capable GPIO pins and pass those pins to the constructor.

const uint8_t AFE_CS_PIN = 10;
const int AFE_INT1_PIN = 2; // INTB
const int AFE_INT2_PIN = -1; // INT2B optional, -1 if unused
MAX30001G afe(AFE_CS_PIN, AFE_INT1_PIN, AFE_INT2_PIN);
void setup() {
// Constructor attaches ISR handlers for valid interrupt pins.
// Choose which status events drive INT1/INT2:
afe.setInterrupt1(true, true, true, false, false); // ECG + BIOZ + RTOR on INT1
afe.setInterrupt2(false, false, false, false, false); // INT2 disabled
}
void loop() {
if (afe.update()) {
// Interrupts were serviced and configured data paths were drained.
// Read ECG_data / BIOZ_data / RTOR_data here as needed.
}
}
MAX30001G
MAX30001G device driver class used by Arduino sketches.
Definition: max30001g.h:34

`servicePendingInterrupts()` uses Arduino core APIs `noInterrupts()` and `interrupts()` to atomically read/clear the software pending flags. These APIs are available on AVR, SAMD, ESP8266, and ESP32 Arduino cores, so no API change is needed for ESP-type boards.

If your board does not wire interrupt pins, `update()` falls back to `serviceAllInterrupts()`. If you are not using `update()`, call `serviceAllInterrupts()` periodically instead. If you provide your own ISR, set library globals `afe_irq_pending` and `afe_irq1_pending`/`afe_irq2_pending` (do not use a separate local pending flag). If you use latched event/fault globals, clear them explicitly with `clearLatchedStatusFlags()` after handling.

# Configure which events drive INT1/INT2

`setInterrupt1(...)` and `setInterrupt2(...)` program MAX30001G `EN_INT1` and `EN_INT2`.

Example:

// INT1: ECG + BIOZ FIFO related interrupts
afe.setInterrupt1(true, true, false, false, false);
// INT2: R-to-R interrupt
afe.setInterrupt2(false, false, true, false, false);

# Available per-event callbacks (<tt>InterruptEvent</tt>)

- `MAX30001G::IRQ_ECG_FIFO` -> `MAX30001_STATUS_EINT`
- `MAX30001G::IRQ_ECG_OVF` -> `MAX30001_STATUS_EOVF`
- `MAX30001G::IRQ_ECG_FAST` -> `MAX30001_STATUS_FSTINT`
- `MAX30001G::IRQ_ECG_LEADOFF` -> `MAX30001_STATUS_DCLOFFINT`
- `MAX30001G::IRQ_BIOZ_FIFO` -> `MAX30001_STATUS_BINT`
- `MAX30001G::IRQ_BIOZ_OVF` -> `MAX30001_STATUS_BOVF`
- `MAX30001G::IRQ_BIOZ_OVER` -> `MAX30001_STATUS_BOVER`
- `MAX30001G::IRQ_BIOZ_UNDER` -> `MAX30001_STATUS_BUNDR`
- `MAX30001G::IRQ_BIOZ_CGMON` -> `MAX30001_STATUS_BCGMON`
- `MAX30001G::IRQ_LEADS_ON` -> `MAX30001_STATUS_LONINT`
- `MAX30001G::IRQ_RTOR` -> `MAX30001_STATUS_RRINT`
- `MAX30001G::IRQ_PLL_UNLOCK` -> `MAX30001_STATUS_PLLINT`

# Example: Individual ECG and BIOZ FIFO callbacks

void onEcgFifo(MAX30001G* dev, uint32_t status, void* ctx) {
(void)status;
(void)ctx;
dev->handleECGFifoInterrupt(false); // pushes samples into global ECG_data
}
void onBiozFifo(MAX30001G* dev, uint32_t status, void* ctx) {
(void)status;
(void)ctx;
dev->handleBIOZFifoInterrupt(false); // pushes samples into global BIOZ_data
}
void setup() {
afe.setInterruptEventCallback(MAX30001G::IRQ_ECG_FIFO, onEcgFifo);
afe.setInterruptEventCallback(MAX30001G::IRQ_BIOZ_FIFO, onBiozFifo);
}
MAX30001G::handleECGFifoInterrupt
void handleECGFifoInterrupt(bool reportRaw=false)
Convenience callback handler: read ECG FIFO.
Definition: max30001g_interrupt.cpp:338
MAX30001G::handleBIOZFifoInterrupt
void handleBIOZFifoInterrupt(bool reportRaw=false)
Convenience callback handler: read BIOZ FIFO.
Definition: max30001g_interrupt.cpp:342
MAX30001G::IRQ_ECG_FIFO
@ IRQ_ECG_FIFO
Definition: max30001g.h:51
MAX30001G::IRQ_BIOZ_FIFO
@ IRQ_BIOZ_FIFO
Definition: max30001g.h:55
status
max30001_status_reg_t status
Definition: max30001g_globals.cpp:80

# Example: One aggregate callback

void onAfeAggregate(MAX30001G* dev, uint32_t status, void* ctx) {
(void)ctx;
if (status & MAX30001_STATUS_EINT) { dev->handleECGFifoInterrupt(false); }
if (status & MAX30001_STATUS_BINT) { dev->handleBIOZFifoInterrupt(false); }
if (status & MAX30001_STATUS_RRINT) { dev->handleRtoRInterrupt(); }
}
void setup() {
const uint32_t mask = MAX30001_STATUS_EINT | MAX30001_STATUS_BINT | MAX30001_STATUS_RRINT;
afe.setInterruptAggregateCallback(onAfeAggregate, nullptr, mask);
}
MAX30001G::handleRtoRInterrupt
void handleRtoRInterrupt(void)
Convenience callback handler: read RTOR data.
Definition: max30001g_interrupt.cpp:346
MAX30001_STATUS_RRINT
#define MAX30001_STATUS_RRINT
Definition: max30001g_defs.h:73
MAX30001_STATUS_BINT
#define MAX30001_STATUS_BINT
Definition: max30001g_defs.h:67
MAX30001_STATUS_EINT
#define MAX30001_STATUS_EINT
Definition: max30001g_defs.h:63

If aggregate and individual callbacks are both registered, aggregate runs first.

# Interrupt Callback API summary

- `setInterruptEventCallback(event, cb, context)`
- `clearInterruptEventCallback(event)`
- `setInterruptAggregateCallback(cb, context, statusMask)`
- `clearInterruptAggregateCallback()`
- `clearAllInterruptCallbacks()`
- `clearLatchedStatusFlags()`