BERGSONNE

Drive.P

Piezoelectric haptic driver for the Drive.P tile (rev a).

Embeds the Boréas Technologies BOS1921, a piezoelectric driver with integrated high-voltage boost (190 Vpp differential), waveform synthesizer, 1024-sample FIFO, and piezo sensing.

Datasheet

Examples

Quick start

  #include "core_tiles.h"

  tile_t piezo;
  tile_drive_p_init(core_tiles_pal(&core_i2c1), 0, &piezo, NULL);
  if (tile_is_ready(&piezo)) {
      tile_drive_p_set_mode(&piezo, DRIVE_P_MODE_PLAY_FIFO);
      tile_drive_p_write_fifo(&piezo, 0x7FFF);
  }

API reference

Initialization

tile_drive_p_find

uint8_t tile_drive_p_find(tiles_pal_t* hal, uint8_t instance)

Check whether a BOS1921 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_p_init

void tile_drive_p_init(tiles_pal_t* hal, uint8_t instance, tile_t* tile, const drive_p_cfg_t *cfg)

Wakes the device, performs a software reset, verifies the chip ID, and configures parasitic capacitance and supply parameters for a 260nF piezo on a 3.7V LiPo supply. The SUP_RISE I2C_ADDR nibble is derived from the instance's address, so a reassigned chip (0x45/0x46) keeps its address — a soft reset doesn't revert it, so init may reset such a chip normally. Pass cfg=NULL for defaults.

hal
Platform HAL handle
instance
Instance index (0=0x44, 1=0x45, 2=0x46; see mapping table)
tile
Pointer to tile handle (populated by this function)
cfg
Optional config, or NULL for defaults

Lifecycle

tile_drive_p_reset

void tile_drive_p_reset(tile_t* tile)

Perform a software reset.

tile
Pointer to tile handle

tile_drive_p_sleep

Studio
void tile_drive_p_sleep(tile_t* tile)

Enter low-power sleep mode.

tile
Pointer to tile handle

Runtime

tile_drive_p_set_mode

Studio
void tile_drive_p_set_mode(tile_t* tile, drive_p_mode_t mode)

Set the operating mode.

tile
Pointer to tile handle
mode
One of the drive_p_mode_t values

tile_drive_p_read

Studio
uint16_t tile_drive_p_read(tile_t* tile)

Read the current return register value.

tile
Pointer to tile handle

Returns 16-bit value from the currently selected return register

tile_drive_p_read_sense

Studio
int16_t tile_drive_p_read_sense(tile_t* tile)

Must be in SENSE_FINE or SENSE_COARSE mode.

tile
Pointer to tile handle

Returns Signed 16-bit sense value (−2048 to +2047)

tile_drive_p_read_status

Studio
uint16_t tile_drive_p_read_status(tile_t* tile)

Read the IC status register.

tile
Pointer to tile handle

Returns 16-bit IC_STATUS value

tile_drive_p_play_click

Studio
void tile_drive_p_play_click(tile_t* tile, uint8_t intensity_pct)

Streams a half-sine pulse through the FIFO at 8 ksps. Intensity scales the peak output amplitude in the configured voltage range (default ±95 V; see @ref tile_drive_p_set_output_range to switch to ±13.25 V for low-voltage piezos). Returns when the FIFO has been written; the chip continues playing the click after the call returns.

tile
Initialised tile handle
intensity_pct
0–100 percent of full-scale output

tile_drive_p_play_sine

Studio
void tile_drive_p_play_sine(tile_t* tile, uint16_t freq_hz, uint8_t intensity_pct, uint16_t ms)

Generates and streams sine samples at 8 ksps. Frequency is software-quantised to the sample rate (max useful ~3 kHz). The call blocks until the FIFO is filled; for streams longer than the 1024-sample FIFO depth (~128 ms at 8 ksps) the call refills as the chip drains.

tile
Initialised tile handle
freq_hz
Sine frequency in Hz (50–3000 useful range)
intensity_pct
0–100 percent of full-scale output
ms
Duration in milliseconds

tile_drive_p_play_buzz

Studio
void tile_drive_p_play_buzz(tile_t* tile, uint8_t intensity_pct, uint16_t ms)

Convenience wrapper for @ref tile_drive_p_play_sine at 150 Hz — a frequency typical small-form-factor piezo actuators feel strongly at. Use `play_sine` directly if you need a specific frequency.

tile
Initialised tile handle
intensity_pct
0–100 percent of full-scale output
ms
Duration in milliseconds

tile_drive_p_play_pulse_train

Studio
void tile_drive_p_play_pulse_train(tile_t* tile, uint8_t intensity_pct, uint8_t count, uint16_t gap_ms)

The classic "tick-tick-tick" pattern. Composes @ref tile_drive_p_play_click with `core_delay_ms` between clicks.

tile
Initialised tile handle
intensity_pct
0–100 percent of full-scale output
count
Number of clicks (1–255)
gap_ms
Milliseconds between successive clicks

tile_drive_p_is_touched

Studio
uint8_t tile_drive_p_is_touched(tile_t* tile, uint16_t threshold_mv)

Switches into sense mode (fine resolution), reads one sense sample, compares the absolute value against `threshold_mv`, and returns the boolean result. Leaves the chip in sense mode after the call — call `tile_drive_p_set_mode(tile, DRIVE_P_MODE_IDLE)` (or any play mode) to return to driving the actuator.

tile
Initialised tile handle
threshold_mv
Absolute sense voltage threshold in mV

Returns 1 if sense > threshold (touched), 0 otherwise

tile_drive_p_play_on_touch

Studio
uint8_t tile_drive_p_play_on_touch(tile_t* tile, uint8_t intensity_pct, uint16_t threshold_mv, uint32_t timeout_ms)

Polls the sense channel until `threshold_mv` is exceeded, then switches into FIFO mode and plays a click via @ref tile_drive_p_play_click. The classic closed-loop tactile-feedback idiom — press the piezo, feel the click. Polling polls every ~1 ms; returns 0 if `timeout_ms` elapses without detection.

tile
Initialised tile handle
intensity_pct
0–100 percent of full-scale output
threshold_mv
Touch threshold in mV
timeout_ms
Maximum time to wait

Returns 1 if a touch fired the click, 0 on timeout

tile_drive_p_play_samples

Studio
void tile_drive_p_play_samples(tile_t* tile, const int16_t* samples, uint16_t count)

Switches into FIFO play mode (if not already there) and writes `count` samples. Samples are signed 12-bit (range −2048..+2047) left-justified into the chip's 16-bit FIFO words; values outside that range are clamped. Use this for arbitrary waveforms that don't fit the click / sine / buzz / pulse-train idioms — e.g., recorded waveforms or DSP-generated patterns.

tile
Initialised tile handle
samples
Pointer to buffer of int16_t samples
count
Number of samples to write

tile_drive_p_read_sense_samples

Studio
void tile_drive_p_read_sense_samples(tile_t* tile, int16_t* buf, uint16_t count)

Switches into fine-resolution sense mode (if not already there) and reads `count` consecutive samples into the caller's buffer. Each sample takes ~125 µs to acquire (8 ksps native). Use for impedance characterisation, multi-touch pattern detection, or piezo-as-mic experiments beyond the simple `is_touched` API.

tile
Initialised tile handle
buf
Output buffer for int16_t sense samples
count
Number of samples to read

Config

tile_drive_p_set_output_range

Studio
void tile_drive_p_set_output_range(tile_t* tile, drive_p_output_range_t range)

High-V (±95 V) is the BOS1921 default and suits most piezo actuators. Low-V (±13.28 V) is for low-voltage piezos where the full ±95 V swing would be wasteful or destructive. Use this from IDLE before setting a play mode — the change takes effect on the next OE-enable.

tile
Pointer to tile handle
range
DRIVE_P_OUTPUT_HIGH_V or DRIVE_P_OUTPUT_LOW_V
  • Changing range invalidates the PARCAP / TI_RISE tuning set at init. If accurate output behaviour matters, recompute and rewrite those registers for the new FBratio (see datasheet §7.5).

tile_drive_p_set_sense_gain

Studio
void tile_drive_p_set_sense_gain(tile_t* tile, drive_p_sense_gain_t gain)

Fine gain (7.6 mV LSB) is the BOS1921 default and gives the highest sensing resolution. Coarse gain (54.5 mV LSB) widens the input range — useful when sensing high-amplitude press events that would otherwise saturate at fine gain. Use from IDLE before entering a sense mode.

tile
Pointer to tile handle
gain
DRIVE_P_SENSE_FINE_GAIN or DRIVE_P_SENSE_COARSE_GAIN

tile_drive_p_set_sleep_retention

Studio
void tile_drive_p_set_sleep_retention(tile_t* tile, uint8_t retain)

Default is retain (~2.4 µA quiescent) so that RAM contents and register configuration survive a sleep cycle. Disabling retention (~0.6 µA) is useful for ultra-low-power applications that re-init on every wake anyway. Set this before calling sleep().

tile
Pointer to tile handle
retain
1 = retain (default), 0 = clear on sleep

tile_drive_p_set_auto_sleep

Studio
void tile_drive_p_set_auto_sleep(tile_t* tile, uint8_t enabled)

When enabled, the device drops into SLEEP after 4 ms of bus inactivity during Direct or FIFO playback. Useful for unattended one-shot waveforms; harmful for long streaming playback where a host gap would unexpectedly stop the output.

tile
Pointer to tile handle
enabled
1 = auto-sleep on idle, 0 = stay awake
  • After a timeout-triggered sleep, PLAY_SRATE is reset to 0x7 (8 ksps) — re-set the sample rate before the next playback if you were using a faster rate.

tile_drive_p_set_upi

Studio
void tile_drive_p_set_upi(tile_t* tile, uint8_t enabled)

UPI forces the BOS1921 into sink-only operation: energy recovered from piezo discharge is dumped instead of pushed back into the supply. Useful for battery-powered designs where the supply rail can't safely absorb returned energy.

tile
Pointer to tile handle
enabled
1 = sink-only (UPI on), 0 = energy recovery (default)

Advanced

tile_drive_p_write_fifo

Studio
void tile_drive_p_write_fifo(tile_t* tile, int16_t sample)

Write a sample to the FIFO.

tile
Pointer to tile handle
sample
Signed 16-bit waveform sample

tile_drive_p_write_reg

void tile_drive_p_write_reg(tile_t* tile, uint8_t reg, uint16_t value)

Write a raw 16-bit value to any BOS1921 register.

tile
Pointer to tile handle
reg
8-bit register address
value
16-bit value (sent big-endian on the wire)

tile_drive_p_wfs_write

Studio
void tile_drive_p_wfs_write(tile_t* tile, const uint16_t* words, uint16_t count)

Write a multi-word WFS command to the BOS1921.

tile
Pointer to tile handle
words
Array of 16-bit words (big-endian on wire)
count
Number of words (max 8)

tile_drive_p_check_and_recover

Studio
uint8_t tile_drive_p_check_and_recover(tile_t* tile, drive_p_mode_t restore_mode)

Check status and recover from error/fault states.

tile
Pointer to tile handle
restore_mode
Mode to re-enter after recovery

Returns 1 if recovery was performed, 0 if device was healthy

gapMulti-device SYNC pinSYNC pin coordinates phase between cascaded BOS1921s (< 2 µs delay). The Drive.P tile has 10 pads (I2C/I3C, OUT±, GPIO, V+, V_DRIVE, GND); the SYNC pin on the IC is not routed to a pad, so multi-tile cascading is hardware-gated to a future tile rev.

Other

tile_drive_p_init_at

void tile_drive_p_init_at(tiles_pal_t* hal, uint8_t addr, tile_t* tile, const drive_p_cfg_t *cfg)

The address-explicit sibling of tile_drive_p_init(): identical bring-up, but you name the operating address directly instead of an instance index. This decouples a chip from the fixed instance→address table, which a topology- driven bringup needs — e.g. the v1 Ring runs two Drive.P on separate buses, BOTH at 0x44 (no readdress), which the instance map can't express. Shadow state is keyed per-tile, so two chips at the same address on different buses don't collide. Pass cfg=NULL for defaults.

hal
Platform HAL handle (the bus this chip lives on)
addr
Operating I2C address (e.g. 0x44 / 0x45 / 0x46)
tile
Pointer to tile handle (populated by this function)
cfg
Optional config, or NULL for defaults

tile_drive_p_reassign_address

uint8_t tile_drive_p_reassign_address(tiles_pal_t* hal, uint8_t cur_addr, uint8_t new_addr)

For two BOS1921 sharing a bus (both at 0x44), move each to a unique address. The call wakes the chip(s) still at cur_addr, sets COMM.GPIODIR=1 (GPIO becomes a write-gate), writes the new address into SUP_RISE.I2C_ADDR, and verifies CHIP_ID at new_addr. Only the chip whose GPIO the caller holds low latches the change; the others are untouched. The driver performs the I2C register sequence only; the **caller owns the GPIO** (a board-specific Core pad, not reachable through the tile PAL). Move BOTH chips of a pair off 0x44 (→ 0x45 and 0x46); each call gates a different chip: // chip A → 0x45 : hold A's GPIO low, B's high core_pad_write(GPIO_A, 0); core_pad_write(GPIO_B, 1); tile_drive_p_reassign_address(hal, 0x44, 0x45); // chip B → 0x46 : hold B's GPIO low, A's high (A has left 0x44) core_pad_write(GPIO_A, 1); core_pad_write(GPIO_B, 0); tile_drive_p_reassign_address(hal, 0x44, 0x46); core_pad_input(GPIO_A); core_pad_input(GPIO_B); // release // then init instance 1 (0x45) and 2 (0x46) so it must be in 0x40..0x4F (BOS1921_I2C_ADDR_SECOND/THIRD)

hal
Platform HAL handle
cur_addr
the chip's current 7-bit address (0x44 at power-up)
new_addr
desired 7-bit address; only the low nibble is settable,

Returns 1 if the chip answers at new_addr with the correct CHIP_ID, else 0

  • The new address persists until power-on reset; a soft reset will not revert it. Re-running this from 0x44 after a reflash (no power cycle) is a no-op — the chips already left 0x44.

Driver gaps · 1

Chip capabilities this driver doesn’t expose yet.

advancedI3C alternate bus modePads 4/5 are bus-shared between I²C (default) and I3C SDR (≤12.5 Mbps with in-band interrupts). The cores tile-driver framework only ships an I²C PAL; I3C support is an ecosystem-wide gap, not BOS1921-specific.

Enums

drive_p_mode_t

Drive.P operating mode.

DRIVE_P_MODE_IDLE
Output disabled, status readback
DRIVE_P_MODE_SENSE_FINE
Piezo sensing, 7.6 mV/LSB resolution
DRIVE_P_MODE_SENSE_COARSE
Piezo sensing, 54.5 mV/LSB resolution
DRIVE_P_MODE_PLAY_DIRECT
Direct waveform output
DRIVE_P_MODE_PLAY_FIFO
FIFO-buffered playback, 8 ksps
DRIVE_P_MODE_PLAY_RAM_SYNTH
RAM Synthesis waveform playback

drive_p_output_range_t

Output voltage range (CONFIG.GAIND).

DRIVE_P_OUTPUT_HIGH_V
±95 V range, FBratio 31 (default)
DRIVE_P_OUTPUT_LOW_V
±13.28 V range, FBratio 4.33

drive_p_sense_gain_t

Sense-channel resolution (CONFIG.GAINS).

DRIVE_P_SENSE_COARSE_GAIN
54.5 mV LSB, FBratio 31
DRIVE_P_SENSE_FINE_GAIN
7.6 mV LSB, FBratio 4.33 (default)

Constants

TILE_DRIVE_P_VERSION_MAJOR3
TILE_DRIVE_P_VERSION_MINOR3
TILE_DRIVE_P_VERSION_PATCH0
BOS1921_I2C_ADDR_DEFAULT0x44
BOS1921_I2C_ADDR_SECOND0x45Instance 1 — first of a pair
BOS1921_I2C_ADDR_THIRD0x46Instance 2 — second of a pair
BOS1921_CHIP_ID_DEFAULT0x0781Expected lower 12 bits of CHIP_ID register.
BOS_STATUS_STATE_MASK0x0300STATE field in IC_STATUS (bits 9:8).
BOS_STATUS_STATE_IDLE0x0000
BOS_STATUS_STATE_CALIB0x0100
BOS_STATUS_STATE_RUNNING0x0200
BOS_STATUS_STATE_ERROR0x0300
BOS_STATUS_FAULT_MASK0x00FCFault bits in IC_STATUS (bits 7:2, excluding FULL and PLAYST).
BOS_SUP_RISE_I2C_ADDR_POS12
BOS_SUP_RISE_TIMING_DEFAULT0x0967default with I2C_ADDR nibble cleared