Drive.H
LRA/ERM haptic driver for the Drive.H tile (rev a).
Embeds the TI DRV2605 (DEVICE_ID 3 — the non-L part), a haptic driver for LRA (Linear Resonant Actuator) and ERM actuators with a built-in waveform library of 123 effects. The actuator is external, connected via the tile's OUT+ / OUT- pads; V_MOTOR accepts 2.5-5.5 V.
The chip regulates output amplitude itself: the supply rail only sets headroom. Full-scale drive level comes from RATED_VOLTAGE / OD_CLAMP (see tile_drive_h_set_actuator_voltage()), NOT from the voltage applied to V_MOTOR.
Examples
Quick start
#include "core_tiles.h"
tile_t haptic;
tile_drive_h_init(core_tiles_pal(&core_i2c1), 0, &haptic, NULL);
if (tile_is_ready(&haptic)) {
tile_drive_h_play(&haptic, 1, 1); // play effect #1 once
}API reference
Initialization
tile_drive_h_find
uint8_t tile_drive_h_find(tiles_pal_t* hal, uint8_t instance)Check whether a DRV2605L is present on the I2C bus.
- hal
- Platform HAL handle
- instance
- Instance index (0 = default, see mapping table)
Returns 1 if device ACKs, 0 otherwise
tile_drive_h_init
void tile_drive_h_init(tiles_pal_t* hal, uint8_t instance, tile_t* tile, const drive_h_cfg_t *cfg)Verifies the device ID, exits standby, and configures the actuator drive mode. Pass cfg=NULL for defaults (LRA closed-loop, library 6, 1.8 Vrms drive levels).
- hal
- Platform HAL handle
- instance
- Instance index (0 = default, see mapping table)
- tile
- Pointer to tile handle (populated by this function)
- cfg
- Optional config, or NULL for defaults
- Blocks for ~500 ms during init. Call once at startup.
Runtime
tile_drive_h_play
Studiovoid tile_drive_h_play(tile_t* tile, uint8_t index, uint8_t repeats)Loads the effect index into sequence slot 0, terminates the sequence, and triggers playback. For repeats > 1, re-triggers with a 200ms gap between plays.
- index
- [1..123] Library effect index (see datasheet).
- repeats
- [1..20] Number of times to play (1 = once).
tile_drive_h_play_sequence
Studiovoid tile_drive_h_play_sequence(tile_t* tile, const uint8_t *effects, uint8_t count)Loads effects into the waveform sequencer registers (0x04-0x0B), terminates the sequence, and triggers playback. Returns immediately — use tile_drive_h_is_playing() to poll for completion. DSL pads short sequences with 0 (DRV2605 effect 0 is "stop"), so a 3-effect sequence written as `[5, 10, 15, 0, 0, 0, 0, 0]` plays effects 5/10/15 then halts.
- tile
- Pointer to tile handle
- effects
- Array of effect indices (1-123, 0 = stop)
- count
- Number of effects (1-8)
tile_drive_h_load_sequence
Studiovoid tile_drive_h_load_sequence(tile_t* tile, const uint8_t *effects, uint8_t count)Identical to tile_drive_h_play_sequence() but does NOT assert the GO bit. Use this to pre-load effects before switching to external trigger mode (edge or level).
- tile
- Pointer to tile handle
- effects
- Array of effect indices (1-123, 0 = stop)
- count
- Number of effects (1-8)
tile_drive_h_set_trigger
Studiovoid tile_drive_h_set_trigger(tile_t* tile, uint8_t mode)Selects how the waveform sequencer is triggered: - DRIVE_H_TRIG_INTERNAL (default): I2C GO bit, used by play() and play_sequence(). - DRIVE_H_TRIG_EDGE: a rising edge on the IN/TRIG pin sets GO. A second rising edge while playing cancels. Pre-load effects with tile_drive_h_load_sequence() before entering this mode. - DRIVE_H_TRIG_LEVEL: GO follows the IN/TRIG pin level. High = playing, low = idle. Falling edge cancels. DRIVE_H_TRIG_LEVEL
- tile
- Pointer to tile handle
- mode
- One of DRIVE_H_TRIG_INTERNAL, DRIVE_H_TRIG_EDGE,
tile_drive_h_is_playing
Studiouint8_t tile_drive_h_is_playing(tile_t* tile)Reads the GO bit in register 0x0C. The GO bit remains high until playback completes.
Returns 1 if playing, 0 if idle
tile_drive_h_stop
Studiovoid tile_drive_h_stop(tile_t* tile)Stop any currently playing effect.
tile_drive_h_rtp_start
Studiovoid tile_drive_h_rtp_start(tile_t* tile)Sets DRV2605L MODE register to 0x05 (RTP). The chip drives the LRA at its resonant frequency with amplitude controlled by tile_drive_h_rtp_write(). Call tile_drive_h_rtp_stop() to return to internal trigger mode.
tile_drive_h_rtp_write
Studiovoid tile_drive_h_rtp_write(tile_t* tile, uint8_t amplitude)Write an amplitude value in RTP mode.
- amplitude
- [0..127] Amplitude (0 = off, 127 = max).
tile_drive_h_rtp_stop
Studiovoid tile_drive_h_rtp_stop(tile_t* tile)Exit RTP mode and return to internal trigger mode.
tile_drive_h_get_status
Studiouint8_t tile_drive_h_get_status(tile_t* tile)Contains DEVICE_ID[7:5], DIAG_RESULT[3], FB_STS[2], OVER_TEMP[1], OC_DETECT[0]. Status bits clear on read.
- tile
- Pointer to tile handle
Returns Raw status byte
tile_drive_h_diagnose
Studiouint8_t tile_drive_h_diagnose(tile_t* tile)Enters diagnostic mode (MODE=6), triggers GO, and polls for completion. The DRV2605L checks whether the actuator is present, open, or shorted.
Returns 1 if actuator passed diagnostics, 0 if fault detected
tile_drive_h_calibrate
Studiouint8_t tile_drive_h_calibrate(tile_t* tile)Enters calibration mode (MODE=7) with datasheet-recommended parameters, triggers GO, and polls for completion. On success, the DRV2605L stores optimized A_CAL_COMP and A_CAL_BEMF values that improve playback fidelity.
Returns 1 if calibration passed, 0 if it failed to converge
tile_drive_h_get_vbat_mv
Studiouint16_t tile_drive_h_get_vbat_mv(tile_t* tile)Reads the VBAT register (0x21). The reading is only valid while the device is actively driving a waveform (RTP, library playback, etc.).
Returns Battery voltage in mV (e.g. 3300 = 3.3 V), 0 if idle
tile_drive_h_get_resonance_hz
Studiouint16_t tile_drive_h_get_resonance_hz(tile_t* tile)Reads the LRA_PERIOD register (0x22). The reading is only valid while the device is actively driving a waveform and must not be polled during braking.
Returns Resonant frequency in Hz (e.g. 235), 0 if unavailable
tile_drive_h_standby
Studiovoid tile_drive_h_standby(tile_t* tile)Sets the STANDBY bit in the MODE register. The device retains register values and can be woken quickly with tile_drive_h_wake().
tile_drive_h_wake
Studiovoid tile_drive_h_wake(tile_t* tile)Clears the STANDBY bit in the MODE register. The device returns to the active state, ready for playback.
tile_drive_h_play_click
Studiovoid tile_drive_h_play_click(tile_t* tile)Plays ROM library effect 1 ("Strong Click — 100%") once. Returns immediately; the chip drives the click after the call returns. Use @ref tile_drive_h_is_playing to poll for completion.
- tile
- Initialised tile handle
tile_drive_h_play_double_tap
Studiovoid tile_drive_h_play_double_tap(tile_t* tile)Loads the sequencer with two strong-click effects (ROM library effect 10 — "Double Click — 100%") and triggers playback. The chip handles the inter-tap timing internally. Returns immediately; use @ref tile_drive_h_is_playing to poll.
- tile
- Initialised tile handle
tile_drive_h_play_alert
Studiovoid tile_drive_h_play_alert(tile_t* tile)Sequences three ROM-library effects to produce a sharp-buzz-sharp notification: effect 14 ("Strong Buzz — 100%" tick) → effect 56 ("Long Buzz for Programmatic Stopping — 100%") → effect 14. Returns immediately; use @ref tile_drive_h_is_playing to poll.
- tile
- Initialised tile handle
tile_drive_h_play_buzz
Studiovoid tile_drive_h_play_buzz(tile_t* tile, uint16_t ms)Switches into RTP (Real-Time Playback) mode, drives a constant full-amplitude signal for `ms` milliseconds, then stops the RTP stream and returns to internal-trigger mode. / @ref tile_drive_h_rtp_stop.
- tile
- Initialised tile handle
- ms
- Duration in milliseconds
- Blocking call — does not return until the buzz completes. For longer non-blocking patterns, drive RTP directly via
tile_drive_h_is_calibrated
Studiouint8_t tile_drive_h_is_calibrated(tile_t* tile)Reads the STATUS register's DIAG_RESULT bit, which the auto- calibration engine populates on completion: 0 = converged (calibration produced valid A_CAL_COMP / A_CAL_BEMF values), 1 = failed. Only meaningful after a prior call to @ref tile_drive_h_calibrate.
- tile
- Initialised tile handle
Returns 1 if calibration converged, 0 otherwise
- STATUS bits clear on read, so the result reflects the most recent calibration / diagnostic run.
Config
tile_drive_h_set_sequence_wait
Studiovoid tile_drive_h_set_sequence_wait(tile_t* tile, uint8_t slot, uint8_t delay_steps)The 8 sequencer slots can each be marked as either an effect (MSB=0, low 7 bits = waveform 1..123) or a wait time (MSB=1, low 7 bits × 10 ms = pause). This call rewrites slot @p slot with a wait of @p delay_steps × 10 ms (max 1270 ms). Use it after tile_drive_h_load_sequence() to insert pauses between effects, e.g. play 1, wait 200 ms, play 47. Slot is silently ignored if >= 8; delay_steps is clipped to 0x7F.
- tile
- Pointer to tile handle
- slot
- Slot index 0..7
- delay_steps
- Wait length in 10 ms steps (0 = no wait, 0x7F = 1.27 s)
tile_drive_h_set_library
Studiovoid tile_drive_h_set_library(tile_t* tile, uint8_t library)The DRV2605L ships with 6 ROM libraries: 1–5 are TS2200 ERM libraries (A–E), 6 is the LRA library. Library 0 is empty (silence). This call also updates the FEEDBACK_CTRL N_ERM_LRA bit so the chip drives the correct actuator type.
- tile
- Pointer to tile handle
- library
- Library index 0..6 (use DRIVE_H_LIB_* constants)
tile_drive_h_set_actuator_params
Studiovoid tile_drive_h_set_actuator_params(tile_t* tile, uint8_t rated_voltage, uint8_t od_clamp, uint8_t fb_brake, uint8_t loop_gain)Writes the four registers that the auto-calibration engine and smart-loop architecture consume: - rated_voltage (0x16): full-scale RMS drive level (closed-loop ref). - od_clamp (0x17): peak overdrive ceiling (also open-loop ref). - fb_brake (0x1A bits 6:4): feedback brake factor (0=1× .. 6=16×, 7=off). - loop_gain (0x1A bits 3:2): closed-loop gain (0=Low .. 3=Very high). Pass 0 for rated_voltage / od_clamp to leave that register untouched. Pass 0xFF for fb_brake / loop_gain to leave them untouched. Run tile_drive_h_calibrate() afterwards to update A_CAL_COMP / A_CAL_BEMF.
- tile
- Pointer to tile handle
- rated_voltage
- RATED_VOLTAGE byte (0 = no change)
- od_clamp
- OD_CLAMP byte (0 = no change)
- fb_brake
- Feedback brake factor 0..7 (0xFF = no change)
- loop_gain
- Loop gain 0..3 (0xFF = no change)
tile_drive_h_set_loop_mode
Studiovoid tile_drive_h_set_loop_mode(tile_t* tile, uint8_t closed)Closed loop (recommended for LRAs) enables smart-loop back-EMF feedback: automatic resonance tracking, overdrive, and braking, with full-scale amplitude referenced to RATED_VOLTAGE. Open loop drives blind: amplitude is referenced to OD_CLAMP, RATED_VOLTAGE is ignored, and LRA playback does NOT resonance-track on this part — the commutation frequency comes from DRIVE_TIME (see tile_drive_h_set_resonance_hz()). Applies to whichever actuator type is currently selected (set_library() / FEEDBACK_CTRL N_ERM_LRA).
- tile
- Pointer to tile handle
- closed
- 1 = closed-loop (smart-loop), 0 = open-loop
tile_drive_h_set_actuator_voltage
Studiovoid tile_drive_h_set_actuator_voltage(tile_t* tile, uint16_t rated_mv, uint16_t overdrive_mv)The friendly-units version of tile_drive_h_set_actuator_params(): converts voltages to the RATED_VOLTAGE (0x16) and OD_CLAMP (0x17) register values using the DRV2605 datasheet equations (section 7.5.2, Eq. 2-5), honouring the currently selected actuator type (ERM vs LRA) and, for LRAs, the drive frequency currently programmed via tile_drive_h_set_resonance_hz(). - rated_mv: steady-state full-scale level (RMS for LRA, average for ERM). Closed-loop reference. - overdrive_mv: peak ceiling for overdrive/braking; also the full-scale reference in open-loop mode. Must be >= rated_mv; typically 1.3-1.5x for LRAs. Run tile_drive_h_calibrate() afterwards — the datasheet requires recalibration whenever these references change.
- tile
- Pointer to tile handle
- rated_mv
- [300..3600] Rated drive level in mV
- overdrive_mv
- [300..5000] Overdrive clamp in mV
tile_drive_h_set_resonance_hz
Studiovoid tile_drive_h_set_resonance_hz(tile_t* tile, uint16_t hz)Programs CONTROL1 DRIVE_TIME to half the LRA period — the datasheet-optimal value. In closed-loop mode this seeds the auto-resonance tracker (which then follows the real resonance); in open-loop mode it directly sets the commutation frequency. Read the actuator's actual resonance with tile_drive_h_get_resonance_hz() while driving in closed loop.
- tile
- Pointer to tile handle
- hz
- [125..300] LRA resonant frequency in Hz
tile_drive_h_set_resonance_params
Studiovoid tile_drive_h_set_resonance_params(tile_t* tile, uint8_t sample_time, uint8_t blanking_time, uint8_t idiss_time)Writes Control2 (0x1C) bits for sample / blanking / current- dissipation timing. Default values (3 / 1 / 1) work for most coin-type LRAs at 175–235 Hz. Tune only if calibration fails to converge or the actuator runs at the edges of the 125–300 Hz window. Pass 0xFF for any field to leave that register slice untouched.
- tile
- Pointer to tile handle
- sample_time
- Sample time 0..3 (0=150µs, 3=300µs; 0xFF = no change)
- blanking_time
- Blanking time 0..3 (0xFF = no change)
- idiss_time
- Current-dissipation time 0..3 (0xFF = no change)
tile_drive_h_set_waveform_timing
Studiovoid tile_drive_h_set_waveform_timing(tile_t* tile, int8_t overdrive, int8_t sustain_pos, int8_t sustain_neg, int8_t brake)Adds signed offsets (in 5 ms steps) to the overdrive, sustain, and brake portions of every library effect. Offsets are 8-bit two's complement, so range is -640..+635 ms per knob. These offsets are only honoured in open-loop mode — closed-loop mode generates them automatically from back-EMF feedback.
- tile
- Pointer to tile handle
- overdrive
- Overdrive Time Offset (0x0D, signed × 5 ms)
- sustain_pos
- Sustain-Time Positive Offset (0x0E, signed × 5 ms)
- sustain_neg
- Sustain-Time Negative Offset (0x0F, signed × 5 ms)
- brake
- Brake Time Offset (0x10, signed × 5 ms)
tile_drive_h_set_rtp_format
Studiovoid tile_drive_h_set_rtp_format(tile_t* tile, uint8_t unsigned_, uint8_t bidir)Selects how RTP_INPUT bytes are interpreted: - signed (default for closed-loop bidirectional): 0x80 = full reverse, 0x00 = mid-scale (no drive), 0x7F = full forward. - unsigned (recommended for closed-loop unidirectional and open-loop): 0x00 = no drive, 0xFF = full drive. Also exposes the BIDIR_INPUT bit (CONTROL2[7]) which selects unidirectional vs bidirectional input interpretation; tie this to the same convention as the format flag.
- tile
- Pointer to tile handle
- unsigned_
- 1 = unsigned data format, 0 = signed (default)
- bidir
- 1 = bidirectional input (default), 0 = unidirectional
tile_drive_h_set_audio_params
Studiovoid tile_drive_h_set_audio_params(tile_t* tile, uint8_t peak_time, uint8_t filter, uint8_t min_input, uint8_t max_input, uint8_t min_drive, uint8_t max_drive)Configures the four ATV control registers: - ATV_CTRL (0x11): peak-detect time (0=10ms..3=40ms) and low-pass filter cutoff (0=100Hz..3=200Hz). - ATV_MIN_INPUT (0x12): minimum input level below which the envelope is gated (output silent). raw × 1.8/255 V. - ATV_MAX_INPUT (0x13): full-scale input level. raw × 1.8/255 V. - ATV_MIN_DRIVE (0x14): minimum output drive once unmuted. raw / 255 × 100 %. - ATV_MAX_DRIVE (0x15): maximum output drive at full input. raw / 255 × 100 %. Pass 0xFF for any field to leave it untouched.
- tile
- Pointer to tile handle
- peak_time
- ATH_PEAK_TIME 0..3 (10/20/30/40 ms; 0xFF = no change)
- filter
- ATH_FILTER 0..3 (100/125/150/200 Hz; 0xFF = no change)
- min_input
- Minimum input gate (0xFF = no change)
- max_input
- Full-scale input level (0xFF = no change)
- min_drive
- Minimum output drive once active (0xFF = no change)
- max_drive
- Full-scale output drive (0xFF = no change)
Other
tile_drive_h_pwm_input_start
Studiovoid tile_drive_h_pwm_input_start(tile_t* tile)Sets MODE=3 with N_PWM_ANALOG=0. The chip accepts a 10–250 kHz PWM signal: duty cycle directly modulates output amplitude (50 % = no drive in bidirectional mode; 0 % = no drive in unidirectional mode). Useful for offloading waveform generation to a hardware timer or audio rendering pipeline. Call tile_drive_h_set_rtp_format() first if you need to change the unidirectional / bidirectional interpretation.
tile_drive_h_analog_input_start
Studiovoid tile_drive_h_analog_input_start(tile_t* tile)Sets MODE=3 with N_PWM_ANALOG=1. Reference voltage is 1.8 V: 0 V → 0 % drive, 0.9 V → 50 %, 1.8 V → 100 %. Useful for waveform synthesis from a DAC or analog signal source.
- Pad 2 (TRIG) is a digital pad on the tile. The chip pin itself accepts 0–1.8 V analog, but the driving Core must output a clean analog level — Drive.H has no input filter or AC-coupling cap on TRIG.
tile_drive_h_pwm_input_stop
Studiovoid tile_drive_h_pwm_input_stop(tile_t* tile)Returns to internal-trigger mode (MODE=0). Same effect as tile_drive_h_audio_stop(); both modes share the IN/TRIG pin.
tile_drive_h_audio_start
Studiovoid tile_drive_h_audio_start(tile_t* tile)Sets MODE=4 (audio-to-vibe), N_PWM_ANALOG=1 (analog), and AC_COUPLE=1 (0.9 V common-mode bias on IN/TRIG). The chip envelope-detects the audio and drives haptic vibration at matching intensity.
- The DRV2605L expects an AC-coupled line-level audio source (1.8 Vpp full-scale). Drive.H rev a does not include a series capacitor on pad 2 — users wanting audio-to-vibe must add their own external 1 µF AC-coupling cap between the audio source and pad 2.
tile_drive_h_audio_stop
Studiovoid tile_drive_h_audio_stop(tile_t* tile)Returns to internal-trigger mode (MODE=0) and clears the AC_COUPLE bit. Same physical effect as tile_drive_h_pwm_input_stop().
tile_drive_h_program_otp
uint8_t tile_drive_h_program_otp(tile_t* tile)Writes the current contents of registers 0x16–0x1A (RATED_VOLTAGE, OD_CLAMP, A_CAL_COMP, A_CAL_BEMF, FEEDBACK_CTRL) to the DRV2605L's nonvolatile OTP cells. After this, those values become the power-on defaults — the chip skips run-time calibration on subsequent boots. once per device. A bad programming run permanently mistunes the chip. NOT exposed to Studio by design. Pre-conditions: - Run tile_drive_h_calibrate() first and confirm pass. - VDD must be 4.0–4.4 V at the moment of programming (datasheet section 7.5.7). Lower VDD silently corrupts the cells. Returns 1 if the OTP_STATUS bit reads 1 after programming, 0 if the burn failed or OTP was already programmed.
- tile
- Pointer to tile handle
Returns 1 on success, 0 on failure / already-programmed
tile_drive_h_get_otp_status
Studiouint8_t tile_drive_h_get_otp_status(tile_t* tile)Returns 1 if the chip's OTP cells have already been programmed (registers 0x16–0x1A boot from OTP rather than chip defaults).
Returns 1 if OTP is programmed, 0 if unprogrammed
Driver gaps · 1
Chip capabilities this driver doesn’t expose yet.
Constants
| TILE_DRIVE_H_VERSION_MAJOR | 4 | |
| TILE_DRIVE_H_VERSION_MINOR | 2 | |
| TILE_DRIVE_H_VERSION_PATCH | 0 | |
| DRV2605L_I2C_ADDR_DEFAULT | 0x5A | |
| DRV2605L_STATUS_DEFAULT | 0x60 | Expected default STATUS register value (DEVICE_ID = 3). |
| DRV2605L_STATUS_DEVICE_ID | 0xE0 | Bits 7:5 — device ID |
| DRV2605L_STATUS_DIAG_RESULT | 0x08 | Bit 3 — diagnostic result |
| DRV2605L_STATUS_OVER_TEMP | 0x02 | Bit 1 — over-temperature |
| DRV2605L_STATUS_OC_DETECT | 0x01 | Bit 0 — overcurrent detect |
| DRV2605L_MODE_INTERNAL_TRIG | 0x00 | Internal trigger (I2C GO) |
| DRV2605L_MODE_EXT_EDGE | 0x01 | External trigger, edge mode |
| DRV2605L_MODE_EXT_LEVEL | 0x02 | External trigger, level mode |
| DRV2605L_MODE_PWM_ANALOG | 0x03 | PWM or analog input on TRIG |
| DRV2605L_MODE_AUDIO | 0x04 | Audio-to-vibe on TRIG |
| DRV2605L_MODE_RTP | 0x05 | Real-time playback |
| DRV2605L_MODE_DIAGNOSTICS | 0x06 | Actuator diagnostics |
| DRV2605L_MODE_CALIBRATION | 0x07 | Auto-calibration |
| DRV2605L_MODE_STANDBY | 0x40 | STANDBY bit (bit 6) |
| DRIVE_H_TRIG_INTERNAL | 0 | |
| DRIVE_H_TRIG_EDGE | 1 | |
| DRIVE_H_TRIG_LEVEL | 2 | |
| DRV2605L_SEQ_MAX | 8 | |
| DRIVE_H_LIB_EMPTY | 0 | Empty library (silence). |
| DRIVE_H_LIB_ERM_A | 1 | TS2200 Library A (ERM, fixed open-loop overdrive). |
| DRIVE_H_LIB_ERM_B | 2 | TS2200 Library B (ERM, no overdrive). |
| DRIVE_H_LIB_ERM_C | 3 | TS2200 Library C (ERM, no overdrive). |
| DRIVE_H_LIB_ERM_D | 4 | TS2200 Library D (ERM, no overdrive). |
| DRIVE_H_LIB_ERM_E | 5 | TS2200 Library E (ERM, no overdrive). |
| DRIVE_H_LIB_LRA | 6 | LRA Library (auto-resonance). |

