Overview Documentation Partners

Home / Documentation / Firmware Reference

Firmware Reference

ESP32 firmware architecture, sensor drivers, alert state machine, FreeRTOS task structure, and MQTT/BLE telemetry pipeline for the Apex Security jacket.

DocumentDOC-02
MCUESP32-WROOM-32
FrameworkArduino / FreeRTOS
ProtocolMQTT · BLE GATT
StatusAvailable

Firmware Overview

The Apex Security firmware runs on the ESP32-WROOM-32 using the Arduino framework on top of FreeRTOS. Two cores are used deliberately: Core 0 handles time-critical sensor sampling and the alert finite state machine, while Core 1 manages WiFi, MQTT publishing, and BLE GATT notifications. This separation ensures that a slow network operation never delays a fall or E-field alert.

Core Assignment

Core 0 — Sensor polling (MPU6050 @ 100 Hz, MAX30102 @ 25 Hz, MLX90614 @ 10 Hz, LDR/IR @ 20 Hz), fall detection algorithm, alert FSM, haptic + buzzer output.

Core 1

Core 1 — WiFi stack, MQTT client (PubSubClient), BLE GATT server, OTA update handler, heartbeat watchdog.

// Main task pinning
xTaskCreatePinnedToCore(sensorTask, "Sensors", 8192, NULL, 2, &sensorHandle, 0);
xTaskCreatePinnedToCore(alertTask, "Alert", 4096, NULL, 3, &alertHandle, 0);
xTaskCreatePinnedToCore(commTask, "Comms", 8192, NULL, 1, &commHandle, 1);

Inter-task Communication

FreeRTOS queues pass sensor readings from sensorTask to alertTask. A shared event group (xEventGroupCreate) signals alert conditions to commTask for immediate wireless transmission.

FreeRTOS Task Breakdown

All tasks are statically allocated. Priority levels are assigned to ensure sensor acquisition is never pre-empted by communication tasks during a safety-critical window.

Task NameCorePriorityStackResponsibility
sensorTaskCore 028 KBI2C polling, ADC reads, circular buffer fill
alertTaskCore 034 KBFall FSM, threshold checks, GPIO alert outputs
commTaskCore 118 KBMQTT publish, BLE notify, WiFi reconnect
otaTaskCore 114 KBOTA update listener (idle loop)
watchdogTaskCore 122 KBHardware watchdog reset every 30 s

Queues & Semaphores

xSensorQueue (depth 10) passes SensorPacket structs from sensorTask → alertTask. xI2CSemaphore (binary) guards shared I2C bus access. xAlertEventGroup notifies commTask of urgent events using bit flags (BIT0 = fall, BIT1 = EField, BIT2 = vitals).

Sensor Drivers

Each sensor has a dedicated driver module. All I2C drivers share the Wire instance guarded by xI2CSemaphore to prevent bus collisions during concurrent reads.

MPU6050 — Motion & Fall

Library: Adafruit_MPU6050. Configured at ±8g / ±500°/s range. Interrupt pin (GPIO 23) wakes the ESP32 from light sleep on sudden movement. Raw accelerometer XYZ values are fed into the SVM computation at 100 Hz.

MAX30102 — Heart Rate & SpO₂

Library: SparkFun MAX3010x. Runs in HR+SpO₂ multi-LED mode. A 25-sample circular buffer feeds a peak-detection algorithm. Readings are averaged over 4 s windows to reduce motion artifact noise.

MLX90614 — Infrared Temperature

Library: Adafruit_MLX90614. Polled at 10 Hz. Both object temperature (skin) and ambient temperature are read each cycle. The delta (T_skin − T_ambient) is used for heat-stress scoring alongside absolute skin temperature.

IR Proximity & LDR

IR module (FC-51) on GPIO 34 — digital read, active LOW when object detected. LDR on GPIO 35 — 12-bit ADC reading, averaged over 8 samples per cycle. Both are read in the same 20 Hz polling loop.

Fall Detection FSM

The multi-stage fall detection algorithm uses a finite state machine with five states. Each transition requires specific sensor conditions to be met within defined time windows, preventing false positives from ordinary industrial movements.

// Signal Vector Magnitude
float calcSVM(float ax, float ay, float az) {
  return sqrt(ax*ax + ay*ay + az*az);
}

// FSM states
enum FallState { IDLE, FREE_FALL, IMPACT, ORIENTATION, INACTIVITY, ALERT };
StateConditionThresholdTimeout
IDLE → FREE_FALLSVM drops below threshold< 0.5 g
FREE_FALL → IMPACTSVM spike after free fall> 3.0 g1.5 s window
IMPACT → ORIENTATIONCheck orientation vector angle> 60° from vertical500 ms
ORIENTATION → INACTIVITYLow gyroscope angular velocity< 15°/s10 s hold
INACTIVITY → ALERTNo recovery motion detected15 s total

False Positive Suppression

A running-average filter on SVM rejects short transients. If the IMPACT phase is not followed by orientation shift within 500 ms, the FSM resets to IDLE. Sitting-down and tool-drop events rarely produce SVM > 3 g sustained for the required window.

Vital Sign Alert Logic

Physiological thresholds are based on industrial health guidelines. Alerts only fire if the anomalous reading persists beyond a confirmation window to avoid single-sample noise triggering false alarms.

ParameterAlert ConditionThresholdConfirmation WindowPriority
SpO₂Possible respiratory distress< 90 %10 sHIGH
Heart RateOverexertion / shock response> 120 BPM15 sMED
Heart RateBradycardia / unconsciousness< 45 BPM10 sHIGH
Skin TempHeat stress warning> 39 °C20 sMED
Skin TempHeat stroke risk> 41 °C5 sHIGH

Multi-Modal Alert Output

HIGH priority: buzzer (continuous 2 kHz), haptic motor (continuous), LED (red rapid flash), MQTT alert published immediately. MED priority: buzzer (3 short pulses), haptic (2 pulses), LED (amber slow flash), MQTT published on next 5 s tick.

MQTT Telemetry

The ESP32 connects to a WiFi network and publishes sensor data to an MQTT broker (Mosquitto or cloud-hosted). Two topic hierarchies are used: periodic health data (every 10 s) and immediate alert events (on detection).

// MQTT topics
"apex/<device_id>/health" // periodic: HR, SpO2, temp, lux
"apex/<device_id>/alert" // immediate: fall, efield, vitals
"apex/<device_id>/status" // heartbeat: battery %, uptime

Payload Format (JSON)

All payloads are compact JSON strings. Health payload includes: {"hr":72,"spo2":98,"temp":36.8,"lux":412,"ts":1709123456}. Alert payload includes: {"type":"fall","svm_peak":4.2,"ts":1709123490}.

Reconnect Strategy

If WiFi or MQTT connection drops, commTask enters an exponential back-off retry loop (2 s → 4 s → 8 s → max 30 s). During disconnection, alerts are stored in a 10-entry RAM queue and flushed on reconnection. Local alerts (buzzer/haptic) always fire regardless of connectivity.

BLE GATT Profile

The ESP32's built-in BLE stack exposes a custom GATT service for wrist-cuff pairing and real-time data streaming to a companion mobile application. BLE operates concurrently with WiFi on the ESP32's shared radio using time-division multiplexing.

Service & Characteristic UUIDs

Service: 0x1800 (Apex Safety Service). Characteristics: Heart Rate Measurement 0x2A37, SpO₂ Level 0x2A5F, Temperature 0x2A1C, Alert Level 0x2A06.

Notifications

Health characteristics notify every 2 s when a client is subscribed. Alert Level characteristic notifies immediately on any alert event. The wrist cuff (a secondary ESP32 BLE peripheral) subscribes to Alert Level and mirrors buzzer/haptic output locally on the wrist.

Power Management

Firmware power management balances continuous sensor vigilance against battery longevity using ESP32's light sleep and deep sleep modes alongside sensor-level power gating.

Light Sleep (Idle)

When no motion is detected for 30 s and no active alert exists, the ESP32 enters light sleep (~0.8 mA). The MPU6050 interrupt (GPIO 23) acts as a wake source. I2C and UART remain capable of wake-up. Resume latency is < 1 ms.

Deep Sleep (Long Idle)

After 5 minutes of inactivity with no active WiFi connection, the ESP32 enters deep sleep (~10 µA). A ULP co-processor continues basic motion monitoring. Wake sources: ULP threshold trigger, or external RTC timer every 60 s for a MQTT heartbeat ping.

ModeCurrentWake Source
Active (WiFi TX)~180 mA
Active (Sensor idle)~50 mA
Light Sleep~0.8 mAGPIO interrupt (MPU6050)
Deep Sleep~10 µAULP motion / RTC timer