Wearable Health Patch
Table
| Function | nRF52840 Pin | Net | Connected To |
|---|---|---|---|
| I2C SCL | P0.11 | I2C_SCL | MAX30102, MPRLS, KX022, MAX17048 |
| I2C SDA | P0.12 | I2C_SDA | MAX30102, MPRLS, KX022, MAX17048 |
| SPI SCLK | P0.13 | SPI_SCLK | ADS1292R, AD5940 |
| SPI MOSI | P0.14 | SPI_MOSI | ADS1292R DIN, AD5940 MOSI |
| SPI MISO | P0.15 | SPI_MISO | ADS1292R DOUT, AD5940 MISO |
| ECG CS | P0.16 | CS_ECG_N | ADS1292R CS |
| Electrochemical CS | P0.17 | CS_ECHEM_N | AD5940 CS |
| MCU reset | P0.18 | MCU_RESET_N | Reset switch and SWD reset |
| ECG data ready | P0.19 | ECG_DRDY_N | ADS1292R DRDY |
| ECG reset | P0.20 | ECG_RESET_N | ADS1292R PWDN/RESET |
| ECG start | P0.21 | ECG_START | ADS1292R START |
| Accelerometer CS | P0.22 | ACCEL_CS_N | KX022 CS, held high for I2C mode |
| AD5940 reset | P0.23 | ECHEM_RESET_N | AD5940 RESET |
| AD5940 interrupt | P0.24 | ECHEM_INT | AD5940 GPIO0 |
| PPG interrupt | P0.25 | PPG_INT_N | MAX30102 INT |
| Pressure EOC | P0.26 | PRESS_EOC | MPRLS EOC |
| Accelerometer INT1 | P0.27 | ACCEL_INT1 | KX022 INT1 |
| Fuel gauge alert | P0.28 | FUEL_ALRT_N | MAX17048 ALRT |
| Charger PGOOD | P0.30 | CHG_PGOOD_N | BQ24074 PGOOD |
| Charger status | P0.31 | CHG_STAT_N | BQ24074 CHG |
| User/DFU button | P1.00 | USER_DFU_BTN | SW2 |
| Patient switch control | P1.01 | PATIENT_SW_CTRL | ADG824 IN pins |
| USB | D+/D−/VBUS | USB_D_P/N, USB_VBUS | USB-C connector |
| SWD | SWDIO/SWDCLK | SWDIO/SWDCLK | J5 |
Ini
[env:nrf52840_dk] platform = nordicnrf52 board = nrf52840_dk framework = arduino monitor_speed = 115200 lib_deps = adafruit/Adafruit MAX3010x Sensor Library adafruit/Adafruit BusIO
Cpp
#include <Arduino.h> #include <Wire.h> #include <SPI.h> #include <bluefruit.h> #define PIN_I2C_SCL 11 #define PIN_I2C_SDA 12 #define PIN_SPI_SCLK 13 #define PIN_SPI_MOSI 14 #define PIN_SPI_MISO 15 #define PIN_CS_ECG 16 #define PIN_CS_ECHEM 17 #define PIN_ECG_DRDY 19 #define PIN_ECG_RESET 20 #define PIN_ECG_START 21 #define PIN_ACCEL_CS 22 #define PIN_ECHEM_RESET 23 #define PIN_ECHEM_INT 24 #define PIN_PPG_INT 25 #define PIN_PRESS_EOC 26 #define PIN_ACCEL_INT1 27 #define PIN_FUEL_ALRT 28 #define PIN_CHG_PGOOD 30 #define PIN_CHG_STAT 31 #define PIN_USER_DFU 32 // P1.00 in schematic; map to Arduino variant as needed #define PIN_PATIENT_SW_CTRL 33 // P1.01 in schematic; map to Arduino variant as needed #define I2C_ADDR_MAX30102 0x57 #define I2C_ADDR_MPRLS 0x18 #define I2C_ADDR_MAX17048 0x36 #define I2C_ADDR_KX022_ALT0 0x1E static BLEService vitalService = BLEService(0x181C); static BLECharacteristic dataChar = BLECharacteristic(0x2A58); uint8_t i2cRead8(uint8_t addr, uint8_t reg) { Wire.beginTransmission(addr); Wire.write(reg); if (Wire.endTransmission(false) != 0) return 0xFF; Wire.requestFrom(addr, (uint8_t)1); return Wire.available() ? Wire.read() : 0xFF; } bool i2cWrite8(uint8_t addr, uint8_t reg, uint8_t value) { Wire.beginTransmission(addr); Wire.write(reg); Wire.write(value); return Wire.endTransmission() == 0; } uint16_t max17048ReadReg(uint8_t reg) { Wire.beginTransmission(I2C_ADDR_MAX17048); Wire.write(reg); if (Wire.endTransmission(false) != 0) return 0xFFFF; Wire.requestFrom(I2C_ADDR_MAX17048, (uint8_t)2); if (Wire.available() < 2) return 0xFFFF; return ((uint16_t)Wire.read() << 8) | Wire.read(); } void ecgWriteReg(uint8_t reg, uint8_t value) { digitalWrite(PIN_CS_ECG, LOW); SPI.transfer(0x40 | reg); // WREG command base for ADS129x SPI.transfer(0x00); // one register SPI.transfer(value); digitalWrite(PIN_CS_ECG, HIGH); } uint8_t ecgReadReg(uint8_t reg) { digitalWrite(PIN_CS_ECG, LOW); SPI.transfer(0x20 | reg); // RREG command base SPI.transfer(0x00); uint8_t v = SPI.transfer(0x00); digitalWrite(PIN_CS_ECG, HIGH); return v; } uint16_t ad5940Read16(uint16_t addr) { digitalWrite(PIN_CS_ECHEM, LOW); SPI.transfer(0x6D); // AD5940 read-register command placeholder; verify with ADI driver SPI.transfer((addr >> 8) & 0xFF); SPI.transfer(addr & 0xFF); uint16_t v = ((uint16_t)SPI.transfer(0x00) << 8) | SPI.transfer(0x00); digitalWrite(PIN_CS_ECHEM, HIGH); return v; } void initBle() { Bluefruit.begin(); Bluefruit.setName("NeuraVitalPatch"); vitalService.begin(); dataChar.setProperties(CHR_PROPS_NOTIFY | CHR_PROPS_READ); dataChar.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); dataChar.setFixedLen(20); dataChar.begin(); Bluefruit.Advertising.addService(vitalService); Bluefruit.Advertising.addName(); Bluefruit.Advertising.start(0); } void setPatientSensingEnabled(bool enabled) { // Fail-safe policy: keep disabled whenever USB/charge is present. bool usbPresent = digitalRead(PIN_CHG_PGOOD) == LOW; digitalWrite(PIN_PATIENT_SW_CTRL, (enabled && !usbPresent) ? HIGH : LOW); } void setup() { pinMode(PIN_CS_ECG, OUTPUT); digitalWrite(PIN_CS_ECG, HIGH); pinMode(PIN_CS_ECHEM, OUTPUT); digitalWrite(PIN_CS_ECHEM, HIGH); pinMode(PIN_ACCEL_CS, OUTPUT); digitalWrite(PIN_ACCEL_CS, HIGH); pinMode(PIN_ECG_RESET, OUTPUT); digitalWrite(PIN_ECG_RESET, HIGH); pinMode(PIN_ECG_START, OUTPUT); digitalWrite(PIN_ECG_START, LOW); pinMode(PIN_ECHEM_RESET, OUTPUT); digitalWrite(PIN_ECHEM_RESET, HIGH); pinMode(PIN_PATIENT_SW_CTRL, OUTPUT); digitalWrite(PIN_PATIENT_SW_CTRL, LOW); pinMode(PIN_ECG_DRDY, INPUT_PULLUP); pinMode(PIN_PPG_INT, INPUT_PULLUP); pinMode(PIN_PRESS_EOC, INPUT); pinMode(PIN_ACCEL_INT1, INPUT); pinMode(PIN_FUEL_ALRT, INPUT_PULLUP); pinMode(PIN_CHG_PGOOD, INPUT_PULLUP); pinMode(PIN_CHG_STAT, INPUT_PULLUP); pinMode(PIN_USER_DFU, INPUT_PULLUP); Serial.begin(115200); Wire.setPins(PIN_I2C_SDA, PIN_I2C_SCL); Wire.begin(); SPI.begin(); initBle(); setPatientSensingEnabled(false); // Minimal sensor presence reads. Serial.printf("MAX30102 PART_ID: 0x%02X\n", i2cRead8(I2C_ADDR_MAX30102, 0xFF)); Serial.printf("MAX17048 VCELL: 0x%04X\n", max17048ReadReg(0x02)); Serial.printf("ADS1292 ID: 0x%02X\n", ecgReadReg(0x00)); } void loop() { static uint32_t last = 0; if (millis() - last >= 1000) { last = millis(); setPatientSensingEnabled(true); uint16_t vcell = max17048ReadReg(0x02); uint8_t ppgPart = i2cRead8(I2C_ADDR_MAX30102, 0xFF); char payload[20]; snprintf(payload, sizeof(payload), "B%04X P%02X", vcell, ppgPart); dataChar.notify((uint8_t*)payload, strlen(payload)); Serial.println(payload); } }
Bash
pio run pio run -t upload pio device monitor
Platform & Toolchain
Pin Mapping
platformio.ini
Complete Starter Source
Build & Flash
Production Firmware Notes