Sense.CAP
Capacitive trackpad driver for the Sense.CAP tile (IQS7211A).
Examples
Polling example (Cores SDK)
tile_t pad;
tile_sense_cap_init(core_tiles_pal(&core_i2c1), 0, &pad, NULL);
while (1) {
tile_sense_cap_process(&pad);
if (tile_sense_cap_get_num_fingers(&pad) > 0)
printf("x=%u y=%u\n", tile_sense_cap_get_finger_x(&pad, 0),
tile_sense_cap_get_finger_y(&pad, 0));
core_delay_ms(20);
}Gesture callback example
void on_pad(tile_t *t, uint16_t info, void *ctx) {
uint16_t g = tile_sense_cap_get_gestures(t);
if (g & SENSE_CAP_GESTURE_SINGLE_TAP) tap();
if (g & SENSE_CAP_GESTURE_SWIPE_X_POS) next();
}
sense_cap_cfg_t cfg = {
.gestures = SENSE_CAP_GESTURE_SINGLE_TAP | SENSE_CAP_GESTURE_SWIPE_X_POS,
.on_event = on_pad,
};
tile_sense_cap_init(core_tiles_pal(&core_i2c1), 0, &pad, &cfg);API reference
Initialization
tile_sense_cap_find
uint8_t tile_sense_cap_find(tiles_pal_t *hal, uint8_t instance)Probe the bus for an IQS7211A trackpad controller.
- hal
- Tiles HAL handle (I2C bus)
- instance
- Device instance (only 0 exists — the address is fixed)
Returns 1 if a device ACKs at 0x56, 0 if not
tile_sense_cap_init
void tile_sense_cap_init(tiles_pal_t *hal, uint8_t instance, tile_t *tile, const sense_cap_cfg_t *cfg)Probes the bus, verifies the product number (763), caches the firmware version, and acknowledges the power-on reset flag. Applies only the optional settings supplied in @p cfg — the chip's own configuration is otherwise left untouched. Follow with configure_surface() (or setup_2x3()) to program the electrode geometry.
- hal
- Tiles HAL handle (I2C bus)
- instance
- Device instance (only 0 exists)
- tile
- Tile handle to initialize
- cfg
- Optional config. NULL for defaults.
Lifecycle
tile_sense_cap_setup_2x3
Studiouint8_t tile_sense_cap_setup_2x3(tile_t *tile)One-call form of configure_surface() with sense_cap_surface_2x3 — the surface shipped with the r0 tile (2 Rx strips x 3 Tx blocks).
- tile
- Initialised tile handle
Returns 1 if configuration verified and re-ATI completed, 0 otherwise.
tile_sense_cap_get_version_major
Studiouint16_t tile_sense_cap_get_version_major(tile_t *tile)Read the device's firmware major version (cached at init).
- tile
- Tile handle
Returns Major version from register 0x01
tile_sense_cap_get_version_minor
Studiouint16_t tile_sense_cap_get_version_minor(tile_t *tile)Read the device's firmware minor version (cached at init).
- tile
- Tile handle
Returns Minor version from register 0x02
tile_sense_cap_get_settings_version
Studiouint16_t tile_sense_cap_get_settings_version(tile_t *tile)Register 0x74: high byte is the settings major version, low byte the minor. A designer stamps this when exporting a configured firmware from the Azoteq GUI, so the host can confirm the part carries the intended surface configuration (datasheet §10.1.1).
- tile
- Tile handle
Returns Raw 16-bit settings version, or 0 if the tile is not ready
tile_sense_cap_reset
Studiovoid tile_sense_cap_reset(tile_t *tile)The reset takes effect once the communication window closes (datasheet §9.3.2). Blocks for the device's boot time, then clears the reset indication. The tile returns to TILE_STATE_READY.
- tile
- Tile handle
tile_sense_cap_ack_reset
Studiovoid tile_sense_cap_ack_reset(tile_t *tile)The device sets Show Reset on every boot. Acknowledging it means a later Show Reset tells the host the part rebooted unexpectedly — a brown-out or a device-watchdog reset.
- tile
- Tile handle
tile_sense_cap_sleep
Studiovoid tile_sense_cap_sleep(tile_t *tile)Takes manual control of mode switching. The trackpad keeps sensing at the LP2 report rate; call wake() to hand control back to the device's automatic mode machine. Sets TILE_STATE_SLEEPING.
- tile
- Tile handle
tile_sense_cap_wake
Studiovoid tile_sense_cap_wake(tile_t *tile)Return to automatic mode switching, starting in Active mode.
- tile
- Tile handle
Runtime
tile_sense_cap_get_touch_events
Studiouint16_t tile_sense_cap_get_touch_events(tile_t *tile)Every recognizer result since the previous call, as SENSE_CAP_EV_* bits — the polling counterpart to the callbacks, latched so nothing is missed between reads.
- tile
- Tile handle
Returns Latched SENSE_CAP_EV_* bits; reading clears them.
tile_sense_cap_was_tapped
Studiouint8_t tile_sense_cap_was_tapped(tile_t *tile)Consumes the tap bits from the same latch as get_touch_events().
- tile
- Tile handle
Returns 1 if a tap completed, 0 otherwise.
tile_sense_cap_get_zone
Studioint8_t tile_sense_cap_get_zone(tile_t *tile)Zones are channel numbers (§5.1.1): for the 2x3 surface, column c / row r is zone c*2 + r — top row 0/2/4 left to right, bottom row 1/3/5. Computed from the tracked finger position.
- tile
- Tile handle
Returns Zone number, or -1 when nothing is touched.
tile_sense_cap_zone_at
Studioint8_t tile_sense_cap_zone_at(tile_t *tile, uint16_t x, uint16_t y)Pure geometry over the configured surface — use it inside tap/touch callbacks, where the finger has already lifted and get_zone() would report none ("which button was tapped?").
- tile
- Tile handle
- x
- X position in the configured resolution
- y
- Y position in the configured resolution
Returns Zone (channel) number, or -1 before configure_surface().
tile_sense_cap_is_zone_touched
Studiouint8_t tile_sense_cap_is_zone_touched(tile_t *tile, uint8_t zone)Is a specific zone's channel reporting touch?
- tile
- Tile handle
- zone
- Zone (channel) number, 0-31
Returns 1 if that channel's touch bit is set (live read).
tile_sense_cap_get_position_pct
Studiovoid tile_sense_cap_get_position_pct(tile_t *tile, int32_t *x_pct, int32_t *y_pct)Finger position as percentages, resolution-independent.
- tile
- Tile handle
- x_pct
- 0-100 across X (or -1 with no finger); NULL ok
- y_pct
- 0-100 across Y (or -1 with no finger); NULL ok
tile_sense_cap_wait_for_touch
Studiouint8_t tile_sense_cap_wait_for_touch(tile_t *tile, uint32_t timeout_ms)Runs process() internally while waiting.
- tile
- Tile handle
- timeout_ms
- Maximum wait
Returns 1 on touch, 0 on timeout.
tile_sense_cap_process
Studiovoid tile_sense_cap_process(tile_t *tile)Call from your main loop. Reads info flags, gestures, relative XY and both finger slots in one burst, then fires the event callback. In RDY mode returns immediately unless the RDY line has fired.
- tile
- Tile handle
tile_sense_cap_on_event
Studiovoid tile_sense_cap_on_event(tile_t *tile, sense_cap_event_cb_t cb, void *ctx)Register or change the event callback.
- tile
- Tile handle
- cb
- Callback function (NULL to disable)
- ctx
- User context passed to the callback
tile_sense_cap_get_info_flags
Studiouint16_t tile_sense_cap_get_info_flags(tile_t *tile)Read the cached Info Flags word.
- tile
- Tile handle
Returns Info Flags (IQS7211A_INFO_* masks)
tile_sense_cap_get_gestures
Studiouint16_t tile_sense_cap_get_gestures(tile_t *tile)Gesture bits are latched by the device for one report cycle, so read them every process() call or they are missed.
- tile
- Tile handle
Returns Gesture bits (SENSE_CAP_GESTURE_* masks)
tile_sense_cap_get_num_fingers
Studiouint8_t tile_sense_cap_get_num_fingers(tile_t *tile)Number of fingers currently on the trackpad (0, 1 or 2).
- tile
- Tile handle
Returns Finger count from the cached Info Flags
tile_sense_cap_get_finger_x
Studiouint16_t tile_sense_cap_get_finger_x(tile_t *tile, uint8_t finger)Only meaningful while that slot holds a tracked finger — gate on cycle to the next (datasheet §7.2.6), so slot 0 stays slot 0 while it is down. The raw register contents are returned as-is. An empty slot reads 0xFFFF in practice (observed on hardware, 2026-08-04) but the datasheet does not document that sentinel, so gate on the finger count rather than testing for it.
- tile
- Tile handle
- finger
- 0 or 1 (SENSE_CAP_FINGER_1 / _2)
Returns X in trackpad units (0..X resolution)
tile_sense_cap_get_finger_y
Studiouint16_t tile_sense_cap_get_finger_y(tile_t *tile, uint8_t finger)Same slot caveat as @ref tile_sense_cap_get_finger_x.
- tile
- Tile handle
- finger
- 0 or 1 (SENSE_CAP_FINGER_1 / _2)
Returns Y in trackpad units (0..Y resolution)
tile_sense_cap_get_finger_strength
Studiouint16_t tile_sense_cap_get_finger_strength(tile_t *tile, uint8_t finger)Scales with the sensitivity setup, so it is a relative measure, not a force reading. Same slot caveat as @ref tile_sense_cap_get_finger_x.
- tile
- Tile handle
- finger
- 0 or 1
Returns Touch strength in device units
tile_sense_cap_get_finger_area
Studiouint16_t tile_sense_cap_get_finger_area(tile_t *tile, uint8_t finger)Same slot caveat as @ref tile_sense_cap_get_finger_x.
- tile
- Tile handle
- finger
- 0 or 1
Returns Number of channels associated with the finger
tile_sense_cap_get_relative_x
Studioint16_t tile_sense_cap_get_relative_x(tile_t *tile)Relative X movement since the previous report.
- tile
- Tile handle
Returns Signed X delta in trackpad units
tile_sense_cap_get_relative_y
Studioint16_t tile_sense_cap_get_relative_y(tile_t *tile)Relative Y movement since the previous report.
- tile
- Tile handle
Returns Signed Y delta in trackpad units
tile_sense_cap_get_touch_status
Studiouint32_t tile_sense_cap_get_touch_status(tile_t *tile)Live read, not cached — the touch-status words sit outside the data block that process() burst-reads. Useful when unused trackpad channels are repurposed as discrete buttons (datasheet §10.4).
- tile
- Tile handle
Returns Bit n set = channel n touched
tile_sense_cap_is_touched
Studiouint8_t tile_sense_cap_is_touched(tile_t *tile, uint8_t channel)Check whether a single trackpad channel reports touch.
- tile
- Tile handle
- channel
- Channel number, 0..31
Returns 1 if touched, 0 if not
tile_sense_cap_get_num_channels
Studiouint8_t tile_sense_cap_get_num_channels(tile_t *tile)Number of trackpad channels in the configured surface.
- tile
- Tile handle
Returns total_rx * total_tx, or 0 before configure_surface().
tile_sense_cap_get_channel_count
Studiouint16_t tile_sense_cap_get_channel_count(tile_t *tile, uint8_t channel)Live read. Channel numbers follow the datasheet rule: along the Rxs first, then to the next Tx (for the 2x3 surface: Tx column n has channels 2n and 2n+1, top and bottom row).
- tile
- Tile handle
- channel
- Channel number, 0-31
Returns Count value, or 0 for an out-of-range channel.
tile_sense_cap_get_channel_delta
Studiouint16_t tile_sense_cap_get_channel_delta(tile_t *tile, uint8_t channel)Live read from the extended memory map. The delta is what the touch threshold acts on — the primary signal for surface bring-up.
- tile
- Tile handle
- channel
- Channel number, 0-31
Returns Delta value, or 0 for an out-of-range channel.
tile_sense_cap_is_alp_active
Studiouint8_t tile_sense_cap_is_alp_active(tile_t *tile)Check whether the ALP channel detects presence.
- tile
- Tile handle
Returns 1 if the ALP channel reports prox/touch in the cached info flags
tile_sense_cap_get_alp_count
Studiouint16_t tile_sense_cap_get_alp_count(tile_t *tile)Read the raw ALP channel count.
- tile
- Tile handle
Returns ALP count value (live read)
tile_sense_cap_get_alp_lta
Studiouint16_t tile_sense_cap_get_alp_lta(tile_t *tile)Read the ALP channel long-term average.
- tile
- Tile handle
Returns ALP LTA value (live read)
tile_sense_cap_get_mode
Studiouint8_t tile_sense_cap_get_mode(tile_t *tile)Current charging (power) mode of the device.
- tile
- Tile handle
Returns sense_cap_mode_t value from the cached info flags
tile_sense_cap_has_ati_error
Studiouint8_t tile_sense_cap_has_ati_error(tile_t *tile)An ATI error means the auto-tuning could not reach its target — with no sensor surface attached, this is the expected state.
- tile
- Tile handle
Returns 1 if either the trackpad or the ALP ATI error flag is set
Config
tile_sense_cap_set_sensitivity
Studiovoid tile_sense_cap_set_sensitivity(tile_t *tile, uint8_t level)Maps 1 (least sensitive, firm touches only) to 5 (most sensitive, light touches) onto the touch set/clear multiplier pairs.
- tile
- Tile handle
- level
- 1-5; values outside the range are clamped.
tile_sense_cap_enable_gestures
Studiovoid tile_sense_cap_enable_gestures(tile_t *tile, uint16_t mask)Set which gestures the device detects.
- tile
- Tile handle
- mask
- OR of SENSE_CAP_GESTURE_* bits (0 disables all gestures)
tile_sense_cap_set_tap_timing
Studiovoid tile_sense_cap_set_tap_timing(tile_t *tile, uint16_t tap_ms, uint16_t hold_ms)A tap must lift within @p tap_ms and move less than the tap distance; a press that stays down past @p hold_ms raises press-and-hold (datasheet §8.1).
- tile
- Tile handle
- tap_ms
- Maximum tap duration in ms
- hold_ms
- Press-and-hold duration in ms
tile_sense_cap_set_swipe_timing
Studiovoid tile_sense_cap_set_swipe_timing(tile_t *tile, uint16_t swipe_ms, uint16_t x_dist, uint16_t y_dist)A swipe must cover @p x_dist or @p y_dist trackpad units within
- tile
- Tile handle
- swipe_ms
- Maximum swipe duration in ms
- x_dist
- X distance threshold in trackpad units
- y_dist
- Y distance threshold in trackpad units
tile_sense_cap_set_report_rate
Studiovoid tile_sense_cap_set_report_rate(tile_t *tile, uint8_t mode, uint16_t ms)Set the report rate for one charging mode.
- tile
- Tile handle
- mode
- Which mode's rate to set (sense_cap_mode_t)
- ms
- Report period in milliseconds
tile_sense_cap_set_mode_timeout
Studiovoid tile_sense_cap_set_mode_timeout(tile_t *tile, uint8_t mode, uint16_t seconds)Set the inactivity timeout that drops the device to the next mode.
- tile
- Tile handle
- mode
- Mode to set the timeout for (Active, Idle-Touch, Idle or LP1)
- seconds
- Timeout in seconds (0 = never time out of that mode)
tile_sense_cap_set_max_touches
Studiovoid tile_sense_cap_set_max_touches(tile_t *tile, uint8_t fingers)Set the maximum number of simultaneous fingers tracked (1 or 2).
- tile
- Tile handle
- fingers
- 1 or 2
tile_sense_cap_set_resolution
Studiovoid tile_sense_cap_set_resolution(tile_t *tile, uint16_t x_res, uint16_t y_res)Absolute finger coordinates are scaled to 0..x_res and 0..y_res (datasheet §7.4). Meaningful only once a real surface exists.
- tile
- Tile handle
- x_res
- X resolution in units
- y_res
- Y resolution in units
tile_sense_cap_set_touch_multipliers
Studiovoid tile_sense_cap_set_touch_multipliers(tile_t *tile, uint8_t set_mult, uint8_t clear_mult)A channel reports touch when its count rises above Reference x (1 + multiplier/128) — §5.5.1. Smaller multiplier = more sensitive. Distinct set and clear values give hysteresis.
- tile
- Tile handle
- set_mult
- Touch-set multiplier, 0-255
- clear_mult
- Touch-clear multiplier, 0-255
tile_sense_cap_set_alp_threshold
Studiovoid tile_sense_cap_set_alp_threshold(tile_t *tile, uint16_t threshold)The ALP output asserts when the ALP count deviates from its LTA by more than this delta (§5.5.2). Lower = wakes on lighter proximity.
- tile
- Tile handle
- threshold
- Count-delta threshold
tile_sense_cap_set_event_mode
Studiovoid tile_sense_cap_set_event_mode(tile_t *tile, uint8_t enable, uint16_t events)In event mode the device only opens a communication window when an enabled event occurs, instead of every cycle. Pair it with a RDY pin for interrupt-driven operation; in polled mode the driver reads through the device's clock stretching either way. Pass 0 to leave the current event sources alone.
- tile
- Tile handle
- enable
- 1 to enable event mode, 0 for streaming
- events
- Event sources to enable (IQS7211A_CFG_*_EVENT bits).
tile_sense_cap_set_watchdog
Studiovoid tile_sense_cap_set_watchdog(tile_t *tile, uint8_t enable)The device watchdog triggers a full cold boot if its main loop stalls (datasheet §10.2). Independent of the Core's own watchdog.
- tile
- Tile handle
- enable
- 1 to enable, 0 to disable
tile_sense_cap_re_ati
Studiouint8_t tile_sense_cap_re_ati(tile_t *tile)Re-runs auto-tuning on both the trackpad and the ALP channel against whatever settings the device currently holds, then reports whether it converged. Run this after the sensing environment changes.
- tile
- Tile handle
Returns 1 if ATI completed without an error flag, 0 on error or timeout
tile_sense_cap_reseed
Studiovoid tile_sense_cap_reseed(tile_t *tile)Snaps the references to the present counts, discarding any drift the long-term average has accumulated (datasheet §5.4.3).
- tile
- Tile handle
Advanced
tile_sense_cap_read_reg
Studiouint16_t tile_sense_cap_read_reg(tile_t *tile, uint8_t reg)The escape hatch for everything in the `@studio unsupported` list — notably the geometry and ATI registers that a surface bring-up needs before this driver grows a typed API for them.
- tile
- Tile handle
- reg
- Register address (0x00..0xFF)
Returns Register value, little-endian, 0 if the tile is not ready
tile_sense_cap_write_reg
Studiovoid tile_sense_cap_write_reg(tile_t *tile, uint8_t reg, uint16_t value)Write a raw 16-bit register.
- tile
- Tile handle
- reg
- Register address (0x00..0xFF)
- value
- Value to write, little-endian on the wire
Other
tile_sense_cap_configure_surface
uint8_t tile_sense_cap_configure_surface(tile_t *tile, const sense_cap_surface_t *surf)Writes the Rx/Tx totals and pin mapping, packs and writes the sensing- cycle allocation table (unused cycles cleared), sets XY resolution, axis orientation and the recommended XY filters, sets the ATI target, and finishes with a re-ATI against the new geometry. Every write is window-managed and verified. Call after init, before trusting any XY or touch output. The verified geometry survives in the device until reset, so calling once per boot is sufficient.
- tile
- Initialised tile handle
- surf
- Surface description (see sense_cap_surface_2x3)
Returns 1 if every register verified and re-ATI completed, 0 otherwise.
tile_sense_cap_on_touch
void tile_sense_cap_on_touch(tile_t *tile, sense_cap_touch_cb_t cb, void *ctx)Fires from process() for every DOWN / MOVED / UP transition, in main-loop context. Pass NULL to disable.
- tile
- Tile handle
- cb
- Callback (NULL to disable)
- ctx
- User context passed to the callback
tile_sense_cap_next_touch_event
uint8_t tile_sense_cap_next_touch_event(tile_t *tile, sense_cap_touch_t *ev)Events queue in an 8-deep ring so a polling loop cannot miss the transitions that happened between process() calls. Oldest events are dropped first on overflow.
- tile
- Tile handle
- ev
- Filled with the event when one was available
Returns 1 if an event was returned, 0 if the queue is empty.
tile_sense_cap_on_tap
void tile_sense_cap_on_tap(tile_t *tile, sense_cap_tap_cb_t cb, void *ctx)Register the tap recognizer (single and double).
- tile
- Tile handle
- cb
- Callback (NULL to disable)
- ctx
- User context
tile_sense_cap_on_long_press
void tile_sense_cap_on_long_press(tile_t *tile, sense_cap_hold_cb_t cb, void *ctx)Register the long-press recognizer.
- tile
- Tile handle
- cb
- Callback (NULL to disable)
- ctx
- User context
tile_sense_cap_on_swipe
void tile_sense_cap_on_swipe(tile_t *tile, sense_cap_swipe_cb_t cb, void *ctx)Uses the chip's four-way swipe engine (enable the swipe gestures in the init config), enriched with the tracked velocity.
- tile
- Tile handle
- cb
- Callback (NULL to disable)
- ctx
- User context
tile_sense_cap_on_drag
void tile_sense_cap_on_drag(tile_t *tile, sense_cap_drag_cb_t cb, void *ctx)Fires on every movement once the finger travels beyond the tap radius, with per-event deltas — the Android onScroll / iOS pan.
- tile
- Tile handle
- cb
- Callback (NULL to disable)
- ctx
- User context
tile_sense_cap_on_pinch
void tile_sense_cap_on_pinch(tile_t *tile, sense_cap_pinch_cb_t cb, void *ctx)Register the two-finger pinch recognizer.
- tile
- Tile handle
- cb
- Callback (NULL to disable)
- ctx
- User context
Events
- touch_down
- touch_up
- tap
- double_tap
- long_press
- swipe
- drag
Enums
sense_cap_mode_t
Charging (power) mode — reported in Info Flags, selectable in manual control.
- SENSE_CAP_MODE_ACTIVE
- Full report rate
- SENSE_CAP_MODE_IDLE_TOUCH
- Touch held, reduced rate
- SENSE_CAP_MODE_IDLE
- No touch, reduced rate
- SENSE_CAP_MODE_LP1
- Low power 1
- SENSE_CAP_MODE_LP2
- Low power 2 (lowest)
sense_cap_finger_t
Finger slot for the absolute-XY getters.
- SENSE_CAP_FINGER_1
- SENSE_CAP_FINGER_2
sense_cap_phase_t
Phase of a touch event, iOS/Android style.
- SENSE_CAP_TOUCH_DOWN
- Finger arrived
- SENSE_CAP_TOUCH_MOVED
- Position changed while down
- SENSE_CAP_TOUCH_UP
- Finger left
Constants
| TILE_SENSE_CAP_VERSION_MAJOR | 0 | |
| TILE_SENSE_CAP_VERSION_MINOR | 3 | |
| TILE_SENSE_CAP_VERSION_PATCH | 1 | |
| IQS7211A_I2C_ADDR | 0x56 | |
| IQS7211A_PRODUCT_NUMBER | 763 | |
| IQS7211A_INVALID_RESPONSE | 0xEEEE | |
| IQS7211A_CYCLE_PROX_BYTE | 0x05 | Fixed first byte of every cycle record |
| IQS7211A_CHANNEL_NONE | 0xFF | "No channel allocated" in a cycle slot |
| IQS7211A_INFO_MODE_SHIFT | 0 | |
| IQS7211A_INFO_NUM_FINGERS_SHIFT | 8 | |
| SENSE_CAP_GESTURE_ALL | 0x3F | |
| SENSE_CAP_DIR_LEFT | 0 | Toward -X |
| SENSE_CAP_DIR_RIGHT | 1 | Toward +X |
| SENSE_CAP_DIR_UP | 2 | Toward -Y |
| SENSE_CAP_DIR_DOWN | 3 | Toward +Y |
| IQS7211A_CTRL_MODE_SHIFT | 0 | |
| SENSE_CAP_NUM_FINGERS | 2 | |
| SENSE_CAP_MAX_RX | 8 | |
| SENSE_CAP_MAX_TX | 12 | |
| SENSE_CAP_MAX_MAP | 12 |

