BERGSONNE

Sense.TOF

TMF8806 time-of-flight distance sensor.

Platform-agnostic driver for the AMS/Sciosense TMF8806 direct time-of-flight (dToF) sensor with integrated VCSEL emitter and SPAD detector array.

Datasheet

Vibe Settings

What Studio’s Vibe interface lets you change on this tile, in plain language or from the tile inspector. Each one is an argument of a driver function below, so the same setting is available from Blocks, the DSL and C. Basic settings are shown by default; advanced ones sit behind the inspector’s Advanced toggle.

SettingTierValuesDefaultFunction
Distance rangebasicShort range, ~200 mm max, lowest power, Medium range up to 2500 mm (default), Long range up to 5000 mmMedium range up to 2500 mm (default)set_distance_mode(mode)
Measurement ratebasicEvery 30 ms, ~33 per second (default), Every 50 ms, 20 per second, Every 100 ms, 10 per second, Every 250 ms, 4 per second, Every second, Every 2 secondsEvery 30 ms, ~33 per second (default)set_period(period)
Iterations (thousands)advanced10 to 4000900set_kilo_iters(kilo_iters)
Detection thresholdadvanced0 to 636set_threshold(threshold)

Examples

Quick start

  #include "core.h"
  #include "core_tiles.h"
  #include "tile_sense_tof.h"

  tile_t tof;
  sense_tof_cfg_t cfg = { .mode = SENSE_TOF_RANGE_2500MM };
  tile_sense_tof_init(core_tiles_pal(&core_i2c1), 0, &tof, &cfg);

  tile_sense_tof_start(&tof);
  // ... poll or wait for interrupt ...
  uint16_t dist = tile_sense_tof_get_distance_mm(&tof);

  // Single-shot convenience:
  sense_tof_result_t res;
  tile_sense_tof_measure_single(&tof, &res, 500);

API reference

Initialization

tile_sense_tof_find

uint8_t tile_sense_tof_find(tiles_pal_t *hal, uint8_t instance)

Probes the I2C address and reads the ID register. The TMF8806 has a single fixed address (0x41), so only instance 0 is valid.

hal
Platform HAL handle.
instance
Must be 0 (single-address device).

Returns 1 if device ACKs and ID matches (0x09), 0 otherwise.

tile_sense_tof_init

void tile_sense_tof_init(tiles_pal_t *hal, uint8_t instance, tile_t *tile, const sense_tof_cfg_t *cfg)

Performs the full TMF8806 boot sequence: 1. Waits for bootloader to enter sleep (ENABLE == 0x00) 2. Wakes the bootloader (PON = 1) 3. Waits for CPU ready (ENABLE == 0x41) 4. Requests App0 measurement application 5. Waits for App0 to start (APPID == 0xC0) 6. Enables result interrupt Does NOT start measurements — call tile_sense_tof_start() after init. Does NOT software-reset to preserve any existing calibration data.

hal
Platform HAL handle.
instance
Must be 0 (single-address device).
tile
Tile handle to initialise.
cfg
Configuration (NULL for defaults: 2.5 m, 30 ms, 900k iters).

Lifecycle

tile_sense_tof_sleep

Studio
void tile_sense_tof_sleep(tile_t *tile)

Stops any active measurement and powers down the sensor. Use tile_sense_tof_wake() to resume without full re-initialisation.

tile_sense_tof_wake

Studio
void tile_sense_tof_wake(tile_t *tile)

Re-executes the bootloader wake and App0 request sequence. Does not restart measurements — call tile_sense_tof_start() after waking.

tile_sense_tof_reset

Studio
void tile_sense_tof_reset(tile_t *tile)

Performs a full CPU reset and re-runs the boot sequence, so the tile is ready again afterwards. Calibration and saved algorithm state are dropped; the measurement configuration (mode, period, iterations, threshold) is kept. Ranging is stopped: call start() to resume.

Runtime

tile_sense_tof_start

Studio
void tile_sense_tof_start(tile_t *tile)

Writes the factory calibration data (if loaded), configures the measurement command payload from the current cfg, and issues the measurement command. Results are signaled via the result interrupt. If period_ms == 0x00 in the config, a single measurement is taken. Otherwise measurements repeat at the configured period.

tile_sense_tof_stop

Studio
void tile_sense_tof_stop(tile_t *tile)

Sends the stop command and waits for the sensor to acknowledge. No-op if no measurement is active.

tile_sense_tof_get_distance_mm

Studio
uint16_t tile_sense_tof_get_distance_mm(tile_t *tile)

Returns the peak distance in millimeters. Does not check whether new data is available — call tile_sense_tof_result_ready() first or use tile_sense_tof_get_result() for full status. When nothing is in range the sensor reports 0; this SATURATES that to tile_sense_tof_max_range_mm() rather than returning 0, so `if (distance < threshold)` behaves correctly with no special case — "out of range" reads as "very far away", which is what it physically means. Use tile_sense_tof_get_result() when you need to tell "no target" from "target at max range"; that reports the raw value.

Returns Distance in millimeters, saturating at the configured max range.

tile_sense_tof_max_range_mm

Studio
uint16_t tile_sense_tof_max_range_mm(tile_t *tile)

200 mm (short range), 2500 mm, or 5000 mm. This is the value tile_sense_tof_get_distance_mm() saturates to when no object is detected, so `distance >= max_range_mm()` is the explicit "nothing in range" test.

Returns Maximum range in millimeters.

tile_sense_tof_get_result_flat

Studio
void tile_sense_tof_get_result_flat(tile_t *tile, int32_t *out)

Drops the struct in favor of a positional int[5] array — the DSL doesn't have a struct ABI yet, so the per-field outputs come back indexed. Layout: out[0]=distance_mm, out[1]=status, out[2]=reliability, out[3]=temperature_c, out[4]=result_number. The temperature is widened from int8_t to int32_t so negative values sign-extend correctly.

out
Output buffer (5 int32_t slots).

tile_sense_tof_measure_single_flat

Studio
uint8_t tile_sense_tof_measure_single_flat(tile_t *tile, int32_t *mm, int32_t *status, int32_t *reliability, int32_t *temp_c, int32_t *seq, uint32_t timeout_ms)

Combines a single-shot measurement with positional int outputs. Same layout convention as get_result_flat — the per-field values land in five out-scalar slots. Returns the chip's success flag.

mm
Output: distance in millimetres.
status
Output: result status code.
reliability
Output: 0–63 reliability score.
temp_c
Output: die temperature in degrees Celsius.
seq
Output: monotonic result counter.
timeout_ms
Maximum wait for the measurement to complete.

Returns 1 on a valid result, 0 on timeout / bus error.

tile_sense_tof_result_ready

Studio
uint8_t tile_sense_tof_result_ready(tile_t *tile)

Reads the INT_STATUS register and checks the result interrupt bit. Does not clear the interrupt — that is done by get_result() or get_distance_mm().

Returns 1 if a new result is pending, 0 otherwise.

tile_sense_tof_set_distance_mode

Studio
void tile_sense_tof_set_distance_mode(tile_t *tile, sense_tof_distance_mode_t mode)

Stops any active measurement, updates the cached mode, and restarts. If no measurement was running, only updates the config for the next start().

mode
New distance mode.

tile_sense_tof_set_period

Studio
void tile_sense_tof_set_period(tile_t *tile, sense_tof_period_t period)

Slower rates save most of the power: the laser only fires for the ranging time (~24 ms at the default 900k iterations), and the chip idles at ~140 uA for the rest of each period. Stops any active measurement, updates the cached period, and restarts. If no measurement was running, only updates the config for the next start().

period
New repetition period (sense_tof_period_t, or 1-253 ms).

tile_sense_tof_set_kilo_iters

Studio
void tile_sense_tof_set_kilo_iters(tile_t *tile, uint16_t kilo_iters)

Iterations (in thousands) trade power for SNR/range: more iterations give a stronger return and longer reach at higher current draw. Typical range 10-4000 (10k-4M); the ranging default is 900. Stops any active measurement, updates the cached value, and restarts.

kilo_iters
[10..4000] Iterations in thousands (e.g. 900 = 900k).

tile_sense_tof_set_threshold

Studio
void tile_sense_tof_set_threshold(tile_t *tile, uint8_t threshold)

Sets cmd_data3[5:0] — the minimum confidence for a reported target. Higher values reject weak/spurious returns. 0 is not "everything": the chip uses 6 instead (datasheet §6.9.3). Stops any active measurement, updates the cached value, and restarts.

threshold
[0..63] Detection threshold, 0-63.

tile_sense_tof_get_signal_quality_flat

Studio
void tile_sense_tof_get_signal_quality_flat(tile_t *tile, int32_t *reference_hits, int32_t *object_hits, int32_t *crosstalk)

Reads the most recent result block (one 10-byte burst). Reference and object hits are zero when no object was detected (datasheet §7.3.11 to §7.3.18). Crosstalk is only meaningful with low ambient light and no target within 40 cm (§7.3.19). Call after a result is ready.

reference_hits
Output: reference-channel SPAD hit sum (or NULL).
object_hits
Output: object-channel SPAD hit sum (or NULL).
crosstalk
Output: crosstalk peak value, 0-65535 (or NULL).

tile_sense_tof_get_sys_clock_ticks

Studio
uint32_t tile_sense_tof_get_sys_clock_ticks(tile_t *tile)

The TMF8806's internal oscillator can drift ±4 % over temperature, which biases distance readings if the host's measurement period doesn't compensate. Reading this register set after each measurement lets the host compute the actual elapsed chip-time vs. its own elapsed wall-time and apply a software correction (HostDriverCommunication §10). Reads SYS_CLOCK_0..3 (0x24–0x27) as a single 4-byte burst. measurement yet).

Returns 32-bit system-clock tick count (0 if not in App0 / no

tile_sense_tof_is_object_within

Studio
uint8_t tile_sense_tof_is_object_within(tile_t *tile, uint16_t mm)

Performs one blocking single-shot measurement (up to 300 ms) and returns 1 iff the reported distance is non-zero, less than or equal to `mm`, and the result counts as a detection: a short-range result (reliability 1 or 10, which is what short-range mode and any object within ~200 mm give) or a long-range result with reliability of at least @ref SENSE_TOF_PRESENCE_RELIABILITY_MIN. If continuous ranging was running it is paused for the shot and resumed afterwards. 0 otherwise (no target, low reliability, or bus timeout).

mm
Distance threshold in millimetres (inclusive).

Returns 1 if an object is within range with adequate confidence,

tile_sense_tof_wait_for_object

Studio
uint8_t tile_sense_tof_wait_for_object(tile_t *tile, uint16_t mm, uint32_t timeout_ms)

Polls single-shot measurements until one matches the `is_object_within` predicate or `timeout_ms` elapses. Polls every single-shot measurement adds ~30 ms of its own.

mm
Distance threshold in millimetres (inclusive).
timeout_ms
Maximum wait time in milliseconds.

Returns 1 if an object entered range before timeout, 0 otherwise.

  • v1 implementation polls — keeps the helper self-contained and avoids the need to wire the chip's INT pin into the tile pad map. A future revision could swap to the chip's threshold-INT (see @ref tile_sense_tof_set_threshold_interrupt) to let a sleeping host stay asleep until proximity wakes it.

tile_sense_tof_read_distance_with_confidence

Studio
uint8_t tile_sense_tof_read_distance_with_confidence(tile_t *tile, uint16_t *mm, uint8_t *confidence_pct)

Performs a single-shot measurement and writes the distance (mm) and a 0–100 percent confidence. A long-range result maps its 0–63 reliability as `(reliability * 100) / 63`; the short-range codes are not a scale, so 10 (calibrated) reads as 100 and 1 (uncalibrated) as 50. Integer math, no floats.

mm
Output: distance in millimetres (NULL allowed).
confidence_pct
Output: 0–100 confidence (NULL allowed).

Returns 1 on a successful measurement, 0 on timeout / bus error.

Config

tile_sense_tof_set_threshold_interrupt

Studio
uint8_t tile_sense_tof_set_threshold_interrupt(tile_t *tile, uint8_t persistence, uint16_t low_mm, uint16_t high_mm)

Without this configured, the chip fires INT on every measurement completion. With it: INT only fires when an object is detected in the [low_mm, high_mm] range for `persistence` consecutive measurements. Lets a sleeping host stay asleep until something gets close. Per HostDriverCommunication §8.12 (cmd 0x08 = WR_ADD_CONFIG): - persistence = 0 → interrupt every measurement (default) - persistence = N → require N consecutive in-range hits - low_mm > high_mm → no interrupts (no valid range)

persistence
0–255; 0 = disabled (every-measurement INT).
low_mm
Lower bound (inclusive), millimetres.
high_mm
Upper bound (inclusive), millimetres.

Returns 1 on success, 0 on bus / command-execution timeout.

Advanced

tile_sense_tof_factory_calibrate

Studio
uint8_t tile_sense_tof_factory_calibrate(tile_t *tile, uint32_t timeout_ms)

Performs a calibration measurement using the current mode settings. The sensor must be positioned with a known target or open field per the TMF8806 calibration guidelines. Results are stored internally and can be retrieved with tile_sense_tof_get_calibration(). This is a blocking call that waits for the calibration to complete: about 1.1 s in 2.5 m mode and 2.2 s in 5 m mode (40.96 M iterations), so a timeout below 3000 ms is raised to 3000. Continuous ranging is paused and resumed. The calibration belongs to the current mode's family: short range and 2.5 m share one, 5 m needs its own (datasheet §6.4), and switching across that line drops it.

timeout_ms
Maximum wait time in milliseconds.

Returns 1 if calibration completed successfully, 0 on timeout or error.

tile_sense_tof_set_calibration

Studio
void tile_sense_tof_set_calibration(tile_t *tile, const uint8_t *data)

Stores a 14-byte calibration dataset that will be written to the sensor before each measurement start. Call this after init() to restore calibration from non-volatile storage.

data
Pointer to 14-byte calibration data array.

tile_sense_tof_get_calibration

Studio
void tile_sense_tof_get_calibration(tile_t *tile, uint8_t *data)

Reads 14 bytes of calibration data from the sensor's calibration registers. Typically called after tile_sense_tof_factory_calibrate() to save the data for later reloading via set_calibration().

data
Output buffer for 14 bytes of calibration data.

tile_sense_tof_get_app_version_flat

Studio
void tile_sense_tof_get_app_version_flat(tile_t *tile, int32_t *major, int32_t *minor, int32_t *patch)

Drops the struct in favor of three positional out-scalars.

major
Output: major version number.
minor
Output: minor version number.
patch
Output: patch version number.

tile_sense_tof_get_serial_number_flat

Studio
void tile_sense_tof_get_serial_number_flat(tile_t *tile, int32_t *out)

Drops the success bool — on bus error, the buffer comes back as all-zeros, which is invalid as a real serial number so callers can detect failure by checking for a zero serial. Bytes widen to int32 for DSL int compatibility.

out
Output buffer (4 int32_t slots).

tile_sense_tof_save_state

Studio
void tile_sense_tof_save_state(tile_t *tile, uint8_t *data)

Reads 11 bytes of algorithm state data from the sensor (registers 0x28-0x32). This state should be saved before entering sleep in ultra-low-power mode, and restored after wake via restore_state(). Preserving algorithm state across power cycles avoids the ~8 ms re-initialisation penalty and maintains measurement accuracy.

data
Output buffer for 11 bytes of state data.

tile_sense_tof_restore_state

Studio
void tile_sense_tof_restore_state(tile_t *tile, const uint8_t *data)

Writes 11 bytes of previously saved algorithm state to the sensor (registers 0x2E-0x38). Call this after wake() and before start() to resume from the saved algorithm state. The calibration data bitmask in the measurement command (cmd_data7) is automatically updated to include algState when state data has been restored.

data
Pointer to 11 bytes of previously saved state data.

tile_sense_tof_get_threshold_interrupt

Studio
uint8_t tile_sense_tof_get_threshold_interrupt(tile_t *tile, uint8_t *persistence, uint16_t *low_mm, uint16_t *high_mm)

Per HostDriverCommunication §8.12.2 (cmd 0x09 = RD_ADD_CONFIG).

persistence
Output (may be NULL).
low_mm
Output (may be NULL).
high_mm
Output (may be NULL).

Returns 1 on success, 0 on timeout.

tile_sense_tof_read_histogram_flat

Studio
void tile_sense_tof_read_histogram_flat(tile_t *tile, uint8_t hist_type, uint32_t timeout_ms, int32_t *out)

Drops the success bool — on timeout / bus error the buffer comes back zero-filled. Bytes widen to int32 for DSL int compatibility. Caller passes hist_type and timeout_ms as scalar args; the buffer is the function's output (collapsed into the int[128] return).

hist_type
Histogram-type byte (see read_histogram() docs).
timeout_ms
Maximum wait for the histogram-ready interrupt.
out
Output buffer (128 int32_t slots).
gap10 m extended-range modeDeferred to a dedicated session. TMF8806 App0 firmware supports up to 5 m range out of ROM; 10 m mode requires downloading a binary RAM patch from AMS via the bootloader's W_RAM + RAMREMAP_RESET protocol — non-trivial firmware-loading flow not in scope for this driver-coverage pass.

Driver gaps · 6

Chip capabilities this driver doesn’t expose yet.

nicheGPIO0 / GPIO1 runtime controlGPIO0 is routed to tile pad 3 but is consumed as a hardware strap: a 100 k on-board pull-up (R2) to V+ holds GPIO0 high at startup, selecting the 1.8-3.3 V digital-I/O level required by this tile's 2.7-3.5 V rail (TMF8806 datasheet §6.7, Table 4). The chip's EN pin is tied to V+ on the board and is not on a pad, so the sensor cannot be power-cycled from the Core. It is NOT an I2C-address strap (the address is fixed at 0x41, changed only via command 0x49). Driver-deferred: after startup GPIO0 is a normal GPIO (§6.7), and its open-drain object-detect modes (cmd 0x02 cmd_data5 gpio0 = 8 / 9) would work with the on-board pull-up as a second "object present" line on pad 3; push-pull modes would fight R2 and are best avoided. Not exposed yet. GPIO1 is not routed to a pad (held low by a 100 k pull-down, R3).
nicheI2C address change / several sensors on one busHardware-gated in part. Command 0x49 can move the sensor off 0x41, but giving several sensors their own addresses means releasing them one at a time through EN, and EN is tied to V+ on the tile. A GPIO0-conditioned change through pad 3 is possible but not exposed (driver-deferred).
advancedOptical stack / cover glass tuningDriver-deferred. spadSelect (cmd_data7[7:6]) and the SPAD dead time (cmd_data7[5:3], fixed at the datasheet default of 4) tune the sensor for a cover glass or strong sunlight (datasheet §6.5).
nicheSpread spectrum, algKeepReady, immediate interruptDriver-deferred. The VCSEL / SPAD charge-pump spread spectrum (cmd_data9/8), algKeepReady and algImmediateInterrupt are left off.
nicheUltra-low-power shutdownHardware-gated. With EN tied to V+ the chip can't be put in its 0.04 µA shutdown; sleep() (PON off) is the floor, about 85 µA standby.
nicheOscillator drift correction, calibration per modeDriver-deferred. get_sys_clock_ticks() gives the raw clock, but the host-side drift correction and re-trim (host-driver note §10 / §11) are not done, and the driver keeps one calibration at a time (switching into or out of 5 m drops it) rather than a set per mode.

Enums

sense_tof_distance_mode_t

Distance mode selection.

SENSE_TOF_SHORT_RANGE
Short range, ~200 mm max, lowest power
SENSE_TOF_RANGE_2500MM
Medium range up to 2500 mm (default)
SENSE_TOF_RANGE_5000MM
Long range up to 5000 mm

sense_tof_period_t

Measurement repetition period (cmd_data2, `repetitionPeriodMs`).

SENSE_TOF_PERIOD_30MS
Every 30 ms, ~33 per second (default) @studio value=33.3
SENSE_TOF_PERIOD_50MS
Every 50 ms, 20 per second @studio value=20
SENSE_TOF_PERIOD_100MS
Every 100 ms, 10 per second @studio value=10
SENSE_TOF_PERIOD_250MS
Every 250 ms, 4 per second @studio value=4
SENSE_TOF_PERIOD_1S
Every second @studio value=1
SENSE_TOF_PERIOD_2S
Every 2 seconds @studio value=0.5

Constants

TILE_SENSE_TOF_VERSION_MAJOR1
TILE_SENSE_TOF_VERSION_MINOR6
TILE_SENSE_TOF_VERSION_PATCH0
TMF8806_I2C_ADDR0x41Fixed 7-bit I2C address
TMF8806_DEVICE_ID0x09Expected ID value (bits 5:0 only)
TMF8806_ID_MASK0x3FMask for valid ID bits
TMF8806_ENABLE_PON0x01Power-on bit
TMF8806_ENABLE_CPU_READY0x41CPU ready + PON
TMF8806_ENABLE_CPU_RESET0x80CPU reset bit
TMF8806_APPID_BOOTLOADER0x80Bootloader is running
TMF8806_APPID_APP00xC0Measurement application running
TMF8806_CMD_MEASURE0x02Start measurement
TMF8806_CMD_FACTORY_CAL0x0ARun factory calibration
TMF8806_CMD_STOP0xFFStop measurement
TMF8806_CMD_SERIAL0x47Read serial number
TMF8806_FACTORY_CAL_KITERS0xA000
TMF8806_INT_RESULT0x01Result interrupt flag
TMF8806_INT_HISTOGRAM0x02Histogram interrupt flag
TMF8806_CONTENTS_RESULT0x55Result data available
TMF8806_CONTENTS_CALIB0x0ACalibration data available
TMF8806_CONTENTS_SERIAL0x47Serial number available
TMF8806_CALIB_DATA_LEN14Factory calibration data length
TMF8806_STATE_DATA_LEN11Algorithm state data length
TMF8806_BOOT_TIMEOUT_MS500Maximum boot sequence wait
TMF8806_CMD_TIMEOUT_MS1000Maximum command completion wait
TMF8806_POLL_INTERVAL_MS2Polling interval during boot
SENSE_TOF_PRESENCE_RELIABILITY_MIN32
SENSE_TOF_WAIT_POLL_INTERVAL_MS10