Arduino library for the ProtoCentral TMF8829 breakout — a multi-zone direct time-of-flight (dToF) depth sensor based on the ams-OSRAM TMF8829.
Don't have one? Buy it here
| 🛒 Product page | https://protocentral.com/product/tmf8829-depth-imager/ |
| 🔧 Hardware design files | https://github.com/Protocentral/protocentral_tmf8829_hardware |
| 📄 IC datasheet (ams OSRAM) | https://look.ams-osram.com/m/4215c1ea1a30e283/original/TMF8829-Time-of-flight-sensor.pdf |
The TMF8829 is a single-chip dToF sensor that returns a live depth map — distance and confidence for every zone in its field of view — with up to 48×32 zones, 0.25 mm resolution and a maximum range of 11 m, all over a simple I²C interface. It's suited to gesture sensing, presence and people detection, robotics obstacle mapping, and 3D scanning.
The chip ships with only a bootloader in ROM — the measurement application lives in RAM and must be downloaded by the host on every cold boot. This library bundles the official ams-OSRAM RAM firmware (~14 KB) and handles the whole cold-boot sequence for you: bootloader handshake, firmware streaming, mode configuration, and frame decoding for all four focal-plane modes.
- Live per-zone distance (mm) and confidence depth maps
- All four focal-plane modes: 8×8 / 16×16 / 32×32 / 48×32 zones
(x, y)accessors —distanceMmAt(x, y),confidenceAt(x, y),isValidAt(x, y)— with the row-major coordinate convention baked in- Bundled ams-OSRAM RAM firmware;
loadFirmware()streams it into the chip (no extra files to flash) - Handles the multi-sub-frame stitching for 32×32 / 48×32 internally — one
readFrame()call returns a complete grid - Pixel size decoded dynamically from the frame's
result_formatbyte (peaks / signal / noise / xtalk) - ProtoCentral OpenView streaming example for live heat-map visualisation
- Open the Arduino IDE
- Go to Sketch → Include Library → Manage Libraries
- Search for "ProtoCentral TMF8829"
- Click Install
- Download or clone this repository
- Copy it to your Arduino libraries folder (
~/Documents/Arduino/libraries/) - Restart the Arduino IDE
| TMF8829 pin | Arduino pin (UNO / Nano) | Function |
|---|---|---|
| VIN | 3.3 V | Supply |
| GND | GND | Ground |
| SDA | A4 | I²C data |
| SCL | A5 | I²C clock |
| EN | D7 (optional) | Hard enable |
| INT | (optional) | Result interrupt |
The board uses I²C address 0x41. If EN is hard-wired high on your breakout, skip setEnablePin() (or pass -1) before begin().
Bus speed: 8×8 fits I²C Standard-mode (100 kHz). 16×16 needs Fast-mode (400 kHz); 32×32 and 48×32 need Fast-mode Plus — call
Wire.setClock(1000000)on a core that supports it (most ARM/ESP cores do; AVR caps at 400 kHz).
#include <Wire.h>
#include <Protocentral_TMF8829.h>
TMF8829 tof;
void setup() {
Serial.begin(115200);
Wire.begin();
tof.setEnablePin(7); // omit / pass -1 if EN is tied high
if (!tof.begin()) { // power up + chip-ID check + bootloader latch
Serial.println("TMF8829 not found");
while (1);
}
tof.loadFirmware(); // stream the bundled RAM app into the chip
tof.setMeasurementMode(TMF8829_MODE_8X8);
tof.startMeasurement();
}
void loop() {
if (tof.dataReady()) {
tmf8829_frame_t frame;
if (tof.readFrame(&frame) == TMF8829_OK) {
// distance at the centre of the grid
uint8_t cx = frame.cols / 2, cy = frame.rows / 2;
if (frame.isValidAt(cx, cy)) {
Serial.print("centre: ");
Serial.print(frame.distanceMmAt(cx, cy));
Serial.println(" mm");
}
}
}
}The chip has no measurement code in ROM, so the order of operations matters:
begin()— drivesENhigh, waits for the CPU-ready bit, verifies the chip ID (0x9E), and latches I²C as the host interface (BL_CMD_SPI_OFF). After this the chip is in its ROM bootloader (APP_ID = 0x80).loadFirmware()— streams the bundled ams-OSRAM RAM patch into the chip and starts it. Idempotent (a no-op if the RAM app is already running).APP_IDflips to0x01.setMeasurementMode()→startMeasurement()→readFrame()— app-level commands, now legal.
Pulling
ENlow wipes RAM, soloadFirmware()must run again after any hard power cycle. A host re-flash (Nano 33 BLE, SAMD, ESP32 …) does not power-cycle the sensor — the library handles the "previous session still running" case for you.
| Method | Description |
|---|---|
TMF8829(uint8_t address = 0x41, TwoWire* wire = &Wire) |
Constructor; default I²C address 0x41. |
void setEnablePin(int pin) |
GPIO wired to EN. Pass -1 (or skip) if EN is tied high. |
bool begin() |
Power up, wait for CPU-ready, verify chip ID, latch I²C. Returns true on success. |
bool isConnected() |
Returns whether the chip ACKs at its address. |
void shutdown() |
Drive EN low (wipes RAM). |
| Method | Description |
|---|---|
tmf8829_id_t readIdentification() |
Chip ID, revision, app ID and version in one struct. |
getChipId() / getRevId() / getAppId() |
Individual register reads. |
uint32_t getSerialNumber() |
32-bit unique serial number. |
| Method | Description |
|---|---|
bool inBootloader() |
True while APP_ID == 0x80. |
tmf8829_status_t loadFirmware() |
Stream the bundled RAM app and start it. Idempotent. |
bool isApplicationRunning() |
True once the RAM app (APP_ID == 0x01) is running. |
| Method | Description |
|---|---|
tmf8829_status_t setMeasurementMode(tmf8829_mode_t mode) |
Select grid: TMF8829_MODE_8X8 (+ _LONG_RANGE / _HIGH_ACCURACY), _16X16, _32X32, _48X32. |
tmf8829_status_t startMeasurement() / stopMeasurement() |
Start / stop cyclic measurements. |
bool dataReady() |
Non-destructive check of the result interrupt. |
tmf8829_status_t readFrame(tmf8829_frame_t* frame) |
Read and decode one full frame (stitches 32×32 / 48×32 sub-frames internally). |
| Member / method | Description |
|---|---|
rows, cols, zone_count |
Grid dimensions for this frame (from the header). |
distanceMmAt(x, y) |
Distance in mm at column x (0 = left), row y (0 = top). |
confidenceAt(x, y) |
SNR / confidence (0 = invalid). |
isValidAt(x, y, min_conf = 1) |
Whether the zone has a usable return. |
getInterruptStatus(), clearInterrupts(), and the readRegister* / writeRegister* passthroughs (including the AVR-safe readRegistersChunked()) are exposed for power users.
tmf8829_frame_t sizes its per-zone arrays to TMF8829_MAX_ZONES, which defaults to 1536 (48×32) — about 7 KB of SRAM. That is fine on Nano 33 BLE, SAMD, ESP32 and RP2040, but a 2 KB AVR (Uno / Nano) cannot fit it. To use the library on AVR, scale the grid back at compile time:
-DTMF8829_MAX_ZONES=64 # 8x8
-DTMF8829_MAX_ZONES=256 # 16x16
| # | Sketch | Description |
|---|---|---|
| 01 | DistanceSingle | 8×8 mode: print the nearest zone and the centre distance each frame. The "hello world". |
| 02 | ProximityLED | Simplest demo — light the built-in LED when an object comes within 20 cm. No serial monitor needed. |
| 03 | SerialPlotter | Plot centre and nearest distance in the Arduino IDE Serial Plotter. |
| 04 | GridASCII | 8×8 ASCII heat-map + numeric grid using the (x, y) accessors. |
| 05 | HighResGrid | 16×16 console heat-map — the high-resolution multi-zone mode (switchable to 32×32 / 48×32). |
| 06 | GestureProximity | Detect hand swipes (left / right / up / down) from the moving depth centroid. |
| 07 | OpenViewStream | Stream the depth grid to ProtoCentral OpenView for live heat-map visualisation. |
This library is built against the official ams-OSRAM documentation:
- TMF8829 product page & datasheet (DS001140)
- TMF8829 Host Driver Communication application note (AN001096) — available from ams-OSRAM
- Upstream reference driver: github.com/ams-OSRAM/tmf8829_driver_arduino
- Software (this library) — MIT License
- Hardware (board design files, in the protocentral_tmf8829_hardware repository) — CERN-OHL-P v2
- Documentation — CC BY-SA 4.0
See LICENSE.md for the full text. Copyright (c) 2026 ProtoCentral Electronics.
src/tmf8829_image.c / src/tmf8829_image.h contain the official ams-OSRAM TMF8829 RAM patch (~14 KB), Copyright © 2024–2025 ams-OSRAM AG, MIT-licensed — see LICENSES/AMS-OSRAM-MIT.TXT. The byte content of tmf8829_image[] is unchanged from upstream (github.com/ams-OSRAM/tmf8829_driver_arduino); only trivial cross-platform PROGMEM shims were added so the file builds on both AVR and ARM cores.
