Skip to content

Full TMF8828 library: BusIO wrapper, 6 examples, 12 hw_tests, CI#3

Open
ladyada-piclaw wants to merge 46 commits intoadafruit:mainfrom
ladyada-piclaw:main
Open

Full TMF8828 library: BusIO wrapper, 6 examples, 12 hw_tests, CI#3
ladyada-piclaw wants to merge 46 commits intoadafruit:mainfrom
ladyada-piclaw:main

Conversation

@ladyada-piclaw
Copy link
Copy Markdown

Summary

Complete Adafruit Arduino library for the ams-OSRAM TMF8828 8x8 multizone dToF sensor.

Architecture

  • BusIO I2C shim wrapping the ams-OSRAM C driver (from tmf8820_21_28_driver_arduino)
  • Adafruit_TMF8828 C++ wrapper with clean Arduino-style API
  • Firmware blob (7KB) downloaded at begin()

Features

  • 8x8 mode (setMode8x8()) and legacy 3x3/4x4 (setModeLegacy())
  • readFrame() assembles 4 subcaptures into 8×8 grid using official ams remap table
  • getRangingData() for raw subcapture access
  • Active range (short/long), thresholds, GPIO control, I2C address change
  • Factory calibration save/restore
  • Power modes (standby/wakeup/enable/disable)
  • Clock correction, interrupt management, status readback

Examples (6)

  1. simpletest — basic 8x8 ranging
  2. legacy_3x3 — 3x3 mode demo
  3. ascii_art — distance heatmap in terminal
  4. set_address — I2C address change
  5. power_modes — standby/wakeup cycle
  6. webserial — browser-based 8x8 visualizer

Hardware Tests (12/12 passing on Metro Mini)

01 init_alive, 02 mode_switch, 03 ranging_8x8, 04 ranging_legacy,
05 configure, 06 thresholds, 07 power_modes, 08 calibration,
09 interrupts, 10 i2c_address, 11 clock_correction, 12 gpio

CI

  • GitHub Actions workflow for Arduino compile checks
  • clang-format config (with ams driver files excluded)
  • Doxygen deploy to gh-pages

Co-authored-by: ladyada limor@ladyada.net

clawpi and others added 30 commits April 6, 2026 20:35
Co-authored-by: ladyada <limor@ladyada.net>
Co-authored-by: ladyada <limor@ladyada.net>
Co-authored-by: ladyada <limor@ladyada.net>
INT pin is not used internally - users manage it directly. EN pin is optional (breakouts have pullup).

Co-authored-by: ladyada <limor@ladyada.net>
Co-authored-by: ladyada <limor@ladyada.net>
Co-authored-by: ladyada <limor@ladyada.net>
- EN pin defaults to -1 (not needed if hardwired HIGH on breakout)
- begin() now accepts i2cSpeed parameter (default 400kHz)
- Simple examples use plain Adafruit_TMF8828 tmf; constructor
- Only power_modes and set_address examples pass EN_PIN

Co-authored-by: ladyada <limor@ladyada.net>
Co-authored-by: ladyada <limor@ladyada.net>
Co-authored-by: ladyada <limor@ladyada.net>
Doxygen 1.8.13 chokes on markdown badge img-in-a tags. Exclude README.md from Doxyfile instead of hacking the markdown.

Co-authored-by: ladyada <limor@ladyada.net>
Replace verbose fail/while(1) blocks with halt(F(msg)) calls.

Co-authored-by: ladyada <limor@ladyada.net>
Co-authored-by: ladyada <limor@ladyada.net>
Add forceReset() that writes cpu_reset bit in ENABLE register to force the sensor back to ROM bootloader before firmware download. Test 01 now verifies re-init works by calling begin() twice.

Co-authored-by: ladyada <limor@ladyada.net>
- Remove waitForResult(), use non-blocking dataReady() poll in loop()

- Replace printCell() with snprintf-based printGrid()

- Move helper functions after loop()

- Add tmf8828_spad_map_t enum for all 14 SPAD map IDs

- Add inline comments for configure() args

Co-authored-by: ladyada <limor@ladyada.net>
Co-authored-by: ladyada <limor@ladyada.net>
New tmf8828_frame_t struct and readFrame() method collect all 4

subcaptures internally, returning true only when a complete frame

is ready. Simplifies 01_simpletest to use readFrame() instead of

manual accumulation. Also adds tmf8828_spad_map_t enum.

Co-authored-by: ladyada <limor@ladyada.net>
Each subcapture has 36 results but every 9th is a reference channel.

Stripping those gives 32 zones (16 per object). 4 subcaptures x 16 = 64

zones = true 8x8 grid. Credit: shabaz123/TMF8828 for the mapping.

Co-authored-by: ladyada <limor@ladyada.net>
Subcaptures don't always arrive in order. Map sub N to rows N*2..(N*2+1)

instead of using arrival order.

Co-authored-by: ladyada <limor@ladyada.net>
Zone mapping from shabaz123/TMF8828 viewer (confirmed against ams EVM).

Each subcapture's 16 zones map to specific interleaved 8x8 positions,

not sequential rows.

Co-authored-by: ladyada <limor@ladyada.net>
Two bugs in readFrame() zone mapping:

1. Reference channel is the LAST entry in each group of 9 (indices 8,
   17, 26, 35), not the FIRST. Changed skip from (i%9)==0 to (i%9)==8.

2. Zone map order was wrong - had the correct SET of grid positions per
   sub-capture but wrong ORDER within each. Updated to the official
   ams-OSRAM remap table from the tmf882x descattering filter example.

These bugs caused 8 zones (columns 5+7, rows 2-3 and 6-7) to always
read zero because reference channel data was being mapped to real grid
positions, and real zone data was being placed in wrong cells.

Co-authored-by: ladyada <limor@ladyada.net>
Co-authored-by: ladyada <limor@ladyada.net>
Co-authored-by: ladyada <limor@ladyada.net>
Two bugs in readFrame() zone mapping:

1. Reference channel is the LAST entry in each group of 9 (indices 8,
   17, 26, 35), not the FIRST. Changed skip from (i%9)==0 to (i%9)==8.

2. Zone map order was wrong - had the correct SET of grid positions per
   sub-capture but wrong ORDER within each. Updated to the official
   ams-OSRAM remap table from the tmf882x descattering filter example.

These bugs caused 8 zones (columns 5+7, rows 2-3 and 6-7) to always
read zero because reference channel data was being mapped to real grid
positions, and real zone data was being placed in wrong cells.

Co-authored-by: ladyada <limor@ladyada.net>
Co-authored-by: ladyada <limor@ladyada.net>
Co-authored-by: ladyada <limor@ladyada.net>
Co-authored-by: ladyada <limor@ladyada.net>
clawpi and others added 16 commits April 8, 2026 20:29
Test 03: removed captures[4] array (508 bytes on stack) that caused stack overflow on AVR with only 681 bytes free. Now prints subcaptures inline.

Test 09: clear pending IRQs before disableInterrupts test; allow <=1 spurious edge (I2C crosstalk).

Co-authored-by: ladyada <limor@ladyada.net>
Co-authored-by: ladyada <limor@ladyada.net>
begin() resets the CPU which reverts the volatile address. Use readDeviceInfo() to verify instead.

Co-authored-by: ladyada <limor@ladyada.net>
begin() resets the CPU which reverts volatile address changes. Now uses

readDeviceInfo() to verify, and toggles EN if sensor isn't found at

default address on startup.

Co-authored-by: ladyada <limor@ladyada.net>
Loop: wake, capture full 8x8 frame, print grid, standby, sleep.

More useful pattern for battery-powered designs.

Co-authored-by: ladyada <limor@ladyada.net>
The old code used naive row/col offsets leaving bottom rows empty.

Now matches the C++ readFrame() zone mapping exactly.

Co-authored-by: ladyada <limor@ladyada.net>
Eliminates JS-side zone remapping. Arduino sends R0-R7 rows with

distances and confidences. JS just displays them directly.

Also flushes serial RX on startup to avoid error cascade.

Co-authored-by: ladyada <limor@ladyada.net>
Co-authored-by: ladyada <limor@ladyada.net>
Co-authored-by: ladyada <limor@ladyada.net>
Co-authored-by: ladyada <limor@ladyada.net>
Co-authored-by: ladyada <limor@ladyada.net>
…pletest

Co-authored-by: ladyada <limor@ladyada.net>
Co-authored-by: ladyada <limor@ladyada.net>
Co-authored-by: ladyada <limor@ladyada.net>
Co-authored-by: ladyada <limor@ladyada.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant