BERGSONNE

Sense.T.C

Capacitive touch/proximity driver for the Sense.T.C tile (IQS323).

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
Touch thresholdbasic1 to 25540set_touch_threshold(threshold)
Proximity thresholdadvanced1 to 25520set_prox_threshold(threshold)
Power modeadvancedNormal power mode, Low power mode, Ultra-low power mode, Halt (lowest power), Auto power mode switching, Auto mode, skip ultra-low powerAuto power mode switchingset_power_mode(mode)
I2C reportingadvancedContinuous reporting at the configured power-mode rate (the chip's reset default), RDY pulses only on enabled events (what init() selects)RDY pulses only on enabled events (what init() selects)set_comm_mode(mode)
Idle time before low poweradvanced0 to 650002000set_power_timeout(ms)

Examples

Simple polling example (Cores SDK)

  tile_t touch;
  tile_sense_t_c_init(core_tiles_pal(&core_i2c3), 0, &touch, NULL);
  while (1) {
      tile_sense_t_c_process(&touch);
      if (tile_sense_t_c_is_touched(&touch, SENSE_T_C_CH_SURFACE))
          led_on();
      else
          led_off();
      core_delay_ms(30);
  }

Callback example (polled)

  void on_touch(tile_t *t, uint16_t status, void *ctx) {
      if (status & SENSE_T_C_SURFACE_TOUCH)
          led_green();
      else
          led_off();
  }

  sense_t_c_cfg_t cfg = { .on_event = on_touch };
  tile_sense_t_c_init(core_tiles_pal(&core_i2c3), 0, &touch, &cfg);
  while (1) {
      tile_sense_t_c_process(&touch);
      core_delay_ms(30);
  }

Callback example (RDY interrupt)

  sense_t_c_cfg_t cfg = {
      .rdy_pin = 3,
      .on_event = on_touch,
  };
  tile_sense_t_c_init(core_tiles_pal(&core_i2c3), 0, &touch, &cfg);
  while (1) {
      tile_sense_t_c_process(&touch);
      // ... other work — process() returns fast if no RDY event ...
  }

API reference

Initialization

tile_sense_t_c_find

uint8_t tile_sense_t_c_find(tiles_pal_t *hal, uint8_t instance)

Instance 0 is 0x44 (order code IQS323-001, this tile); instance 1 is 0x58 (IQS323-002). The address is fixed by the order code, not a strap.

hal
Tiles HAL handle (I2C bus)
instance
Device instance (0 or 1, selects I2C address)

Returns 1 if found, 0 if not

tile_sense_t_c_init

void tile_sense_t_c_init(tiles_pal_t *hal, uint8_t instance, tile_t *tile, const sense_t_c_cfg_t *cfg)

Soft resets, then configures the chip (see the file header): channels, thresholds, filters, report rates, AUTO power, ATI, event mode. Takes roughly 0.5-2 s, most of it ATI and the forced communication windows.

hal
Tiles HAL handle (I2C bus)
instance
Device instance (0 or 1, selects I2C address)
tile
Tile handle to initialize
cfg
Optional config (thresholds, RDY pin, callback). NULL for defaults.

Lifecycle

tile_sense_t_c_sleep

Studio
void tile_sense_t_c_sleep(tile_t *tile)

The chip stops sensing; process() does nothing until wake().

tile_sense_t_c_wake

Studio
void tile_sense_t_c_wake(tile_t *tile)

Restores the power mode last chosen with set_power_mode() (init: AUTO).

tile_sense_t_c_reset

void tile_sense_t_c_reset(tile_t *tile)

All registers return to their reset values (thresholds, report rates and filters 0, every channel on CRx0) and the tile leaves the READY state. Call init() again afterwards.

Runtime

tile_sense_t_c_get_status

Studio
uint16_t tile_sense_t_c_get_status(tile_t *tile)

Read the cached System Status word from the last process() call.

tile_sense_t_c_get_gestures

Studio
uint16_t tile_sense_t_c_get_gestures(tile_t *tile)

Read the Gesture Status word (a live read, not cached).

tile_sense_t_c_is_touched

Studio
uint8_t tile_sense_t_c_is_touched(tile_t *tile, uint8_t channel)

Reads the cached System Status from the last process() call.

channel
[0..2] 0 = pad 8 electrode, 1 = tile surface, 2 = not routed

Returns 1 if touched, 0 otherwise

tile_sense_t_c_is_prox

Studio
uint8_t tile_sense_t_c_is_prox(tile_t *tile, uint8_t channel)

Reads the cached System Status from the last process() call.

channel
[0..2] 0 = pad 8 electrode, 1 = tile surface, 2 = not routed

Returns 1 if in proximity, 0 otherwise

tile_sense_t_c_get_counts

Studio
uint16_t tile_sense_t_c_get_counts(tile_t *tile, uint8_t channel)

Self-capacitance counts DROP when a finger approaches.

channel
[0..2] Channel

Returns Filtered counts, or 0 for a bad channel

tile_sense_t_c_get_lta

Studio
uint16_t tile_sense_t_c_get_lta(tile_t *tile, uint8_t channel)

Read the long-term average (LTA) for a channel.

channel
[0..2] Channel

Returns LTA baseline in counts

tile_sense_t_c_get_delta

Studio
int16_t tile_sense_t_c_get_delta(tile_t *tile, uint8_t channel)

Read the delta (counts - LTA) for a channel.

channel
[0..2] Channel

Returns counts - LTA; negative when a finger is near a self-cap channel

tile_sense_t_c_get_slider

Studio
uint16_t tile_sense_t_c_get_slider(tile_t *tile)

Raw Slider Position register (0x12): 0..Slider Resolution (0x93). Stays 0 until a slider is configured (see the slider note above).

Returns Slider position

tile_sense_t_c_set_thresholds

Studio
void tile_sense_t_c_set_thresholds(tile_t *tile, uint8_t channel, uint8_t prox_thresh, uint8_t touch_thresh)

Prox is an absolute delta in counts (A.16, written with 4/4 debounce); touch is relative, threshold/256 of the LTA (A.17). A 0 leaves that register unchanged. Azoteq's EV-kit uses prox 20, touch 40. These per-channel values are lost if the chip resets (process() re-applies the all-channel thresholds from init / set_touch_threshold / set_prox_threshold).

channel
[0..2] Channel
prox_thresh
[0..255] Prox threshold, delta counts (0 = unchanged)
touch_thresh
[0..255] Touch threshold, x/256 of LTA (0 = unchanged)

tile_sense_t_c_is_touched_any

Studio
uint8_t tile_sense_t_c_is_touched_any(tile_t *tile)

Reflects the cached System Status from the most recent process() call — it does not perform an I²C read itself, so it's safe to call from any rate. Returns 1 if any of CH0/CH1/CH2 currently reports touch, 0 otherwise. Pair with @ref tile_sense_t_c_process in your main loop.

Returns 1 if any channel is touched, 0 otherwise

tile_sense_t_c_wait_for_touch

Studio
uint8_t tile_sense_t_c_wait_for_touch(tile_t *tile, uint32_t timeout_ms)

Polls process() at ~5 ms cadence and returns as soon as any channel reports touch. If RDY-mode is configured, process() is a no-op until RDY fires, so the poll is effectively interrupt-paced. In polled mode the cadence determines latency. Returns 0 if `timeout_ms` elapses without a touch event.

timeout_ms
Maximum time to wait, in milliseconds

Returns 1 if a touch was detected, 0 on timeout

tile_sense_t_c_wait_for_gesture

Studio
uint16_t tile_sense_t_c_wait_for_gesture(tile_t *tile, uint32_t timeout_ms)

Polls the Gesture Status register at ~5 ms cadence. Returns the raw 16-bit gesture word as soon as any gesture bit is set (IQS323_GESTURE_TAP / SWIPE_POS / SWIPE_NEG / FLICK_POS / FLICK_NEG / HOLD). Returns 0 on timeout. Gestures require the slider/wheel UI to be configured — a single tile surface alone does not produce gesture events. See the datasheet §7.4 for the slider-config requirements.

timeout_ms
Maximum time to wait, in milliseconds

Returns Raw Gesture Status word (non-zero) on detection, 0 on timeout

tile_sense_t_c_read_slider_pct

Studio
uint8_t tile_sense_t_c_read_slider_pct(tile_t *tile, uint8_t *out_pct)

The IQS323 slider position runs 0..Slider Resolution (register 0x93, datasheet §7.4). This helper reads both and integer-scales the position to 0–100 through `out_pct`. Returns 0 if either read returned an invalid (out-of-window) response, or if the resolution is 0 (no slider configured): `out_pct` is untouched in that case so callers can keep the previous value. Like @ref tile_sense_t_c_get_slider, this requires a valid slider configuration on this chip (the surface plus an electrode on pad 8). A single tile surface alone cannot produce a slider output.

out_pct
Pointer to receive the percentage (0–100)

Returns 1 on success, 0 on read failure (out_pct unmodified)

tile_sense_t_c_reseed

Studio
void tile_sense_t_c_reseed(tile_t *tile)

Sets SYSTEM_CONTROL.RESEED (self-clearing). Use after a known environmental change (object placed/removed, cover added) to discard the slow baseline and re-zero the channels immediately, instead of waiting for the LTA filter to drift there.

Events

tile_sense_t_c_process

Studio
void tile_sense_t_c_process(tile_t *tile)

Call from your main loop. In polled mode: reads status register, fires callback if events present. In RDY mode: returns immediately if no RDY interrupt; reads + fires callback only when the device has new data.

tile_sense_t_c_on_event

Studio
void tile_sense_t_c_on_event(tile_t *tile, sense_t_c_event_cb_t cb, void *ctx)

Register or change the event callback for touch/proximity events.

cb
Callback function (NULL to disable)
ctx
User context passed to callback

Config

tile_sense_t_c_set_touch_threshold

Studio
void tile_sense_t_c_set_touch_threshold(tile_t *tile, uint8_t threshold)

The touch threshold is relative: a touch registers when the counts drop by threshold/256 of the channel's baseline (A.17). Lower is more sensitive (a touch through thicker covers); higher rejects near misses. Kept by the driver, so it survives a chip reset. 0 is ignored.

threshold
[1..255] x/256 of the LTA (default 40, about 16 %)

tile_sense_t_c_set_prox_threshold

Studio
void tile_sense_t_c_set_prox_threshold(tile_t *tile, uint8_t threshold)

Proximity is an absolute drop in counts (A.16), written with Azoteq's 4/4 debounce. Lower detects a hand from further away. Kept by the driver, so it survives a chip reset. 0 is ignored.

threshold
[1..255] delta counts (default 20)

tile_sense_t_c_set_power_mode

Studio
void tile_sense_t_c_set_power_mode(tile_t *tile, sense_t_c_power_mode_t mode)

AUTO steps from normal to low and ultra-low power after the power timeout without activity, and back on a touch (datasheet §5.3). Typical draw (3 self-cap channels, EV-kit rates): normal 125 µA, low 37.5 µA, ultra-low 4 µA, halt 2 µA. Values above 5 are ignored.

mode
Power mode (System Control bits 6-4); init selects AUTO

tile_sense_t_c_enable_events

Studio
void tile_sense_t_c_enable_events(tile_t *tile, uint16_t mask)

Set the events-enable mask (which events drive RDY pulses).

mask
Event bits (IQS323_STATUS_*_EVENT); init enables touch + prox

tile_sense_t_c_ati

Studio
void tile_sense_t_c_ati(tile_t *tile)

Trigger an ATI (auto-tuning) cycle and wait for completion.

tile_sense_t_c_set_ati_setup

Studio
void tile_sense_t_c_set_ati_setup(tile_t *tile, uint8_t channel, uint16_t value)

Writes the raw 16-bit ATI Setup register (0x36 + ch·0x10) for the channel. Bit layout (datasheet §A.12): - Bits 15-4: ATI Target / Resolution Factor - Bit 3: ATI Band (0 = 1/16, 1 = 1/8) - Bits 2-0: ATI Mode (0 disabled, 1 comp-only, 2 from-comp-divider, 3 partial, 4 full) (The coarse/fine multipliers and dividers live in the separate ATI Multipliers/Dividers register at 0x38 — see IQS323_REG_ATI_MULTI; the compensation divider lives at 0x39 — see set_compensation.) After changing ATI parameters, call @ref tile_sense_t_c_ati to re-run the auto-tuning sequence with the new values. Useful when ambient capacitance shifts (cover-glass thickness, mounting substrate) push the working point off the chip's defaults.

channel
0–2
value
Raw 16-bit ATI Setup register value

tile_sense_t_c_set_counts_filter

Studio
void tile_sense_t_c_set_counts_filter(tile_t *tile, uint16_t beta)

Datasheet §A.26. Higher beta = more aggressive smoothing on the raw counts (lower noise, slower response). Default is tuned for typical electrode geometries; tune up for noisy environments, tune down for fast-response applications.

beta
Raw 16-bit Counts Filter Betas register value

tile_sense_t_c_set_conversion_freq

Studio
void tile_sense_t_c_set_conversion_freq(tile_t *tile, uint8_t channel, uint16_t value)

Datasheet §A.4. Controls charge-transfer frequency and dead time. Tune for unusual electrode geometries, large capacitance loads, or when self-capacitance interactions push beyond the chip's default Conversion Frequency Fraction.

channel
0–2
value
Raw 16-bit Conversion Frequency register value

tile_sense_t_c_set_channel_mode

Studio
void tile_sense_t_c_set_channel_mode(tile_t *tile, uint8_t channel, sense_t_c_channel_mode_t mode, uint8_t reference_id)

Reference channels measure ambient capacitance (e.g., temperature / humidity drift on the substrate). Follower channels subtract the reference's LTA delta from their own, eliminating common-mode drift. Datasheet §7.3 describes the design pattern. For follower channels, `reference_id` selects which channel to follow (encoded in Channel Setup bits [7:4]). For independent / reference channels, `reference_id` is unused — pass 0. Apply to all participating channels (set the reference channel to REFERENCE first, then set followers). Re-run @ref tile_sense_t_c_ati after changing channel modes.

channel
0–2
mode
Channel role
reference_id
Which channel to follow (only used for FOLLOWER)

tile_sense_t_c_set_comm_mode

Studio
void tile_sense_t_c_set_comm_mode(tile_t *tile, sense_t_c_comm_mode_t mode)

Event mode opens a communication window (RDY low) only for an enabled event (touch or prox change, a reset); lowest power, lowest CPU overhead. init() selects event mode. Streaming mode opens one every report cycle; the chip then waits up to the I2C timeout (200 ms) for the host each time, so use it only with the RDY pin and a host that services every window (continuous logging of counts).

mode
Event or streaming

tile_sense_t_c_set_report_rate

Studio
void tile_sense_t_c_set_report_rate(tile_t *tile, sense_t_c_power_mode_t mode, uint16_t ms)

Writes the per-mode report-rate register (NP 0xC1 / LP 0xC2 / ULP 0xC3 / HALT 0xC4) in plain milliseconds (clamped 0-3000). This is the tile's headline power/latency knob — faster rate = lower latency, higher current. Only the four reporting modes have a rate; AUTO/AUTO_NO_ULP are ignored. init() writes Azoteq's EV-kit values, NP 16 ms, LP 60 ms, ULP 160 ms, Halt 3000 ms (the chip's reset value is 0 for all four). These are lost if the chip resets; process() restores the defaults.

mode
Which power mode's rate to set (NORMAL/LOW/ULTRA_LOW/HALT).
ms
Report interval in milliseconds (0-3000).

tile_sense_t_c_set_power_timeout

Studio
void tile_sense_t_c_set_power_timeout(tile_t *tile, uint16_t ms)

Writes POWER_TIMEOUT (0xC5) in milliseconds. In AUTO / AUTO_NO_ULP the chip steps down a power mode after this much inactivity; 0 disables auto step-down. init() writes Azoteq's EV-kit 2000 ms (the chip's reset value is 0).

ms
[0..65000] Inactivity timeout in milliseconds (0 = off).
gapPer-gesture threshold tuningIQS323 gesture timing (tap touch/release time, hold duration, swipe distance, flick velocity) is packed across several GESTURE_* registers with chip-specific encodings. The driver reports gesture events but doesn't surface a typed API for timing / threshold tuning — closing this properly needs a dedicated pass with Azoteq's gesture-config guide. Raw write_reg works for advanced users in the interim.

Advanced

tile_sense_t_c_read_reg

Studio
uint16_t tile_sense_t_c_read_reg(tile_t *tile, uint8_t reg)

Read a raw 16-bit IQS323 register.

reg
[0..255] Register address (datasheet §9 memory map)

Returns Register value, 0xEEEE if no comms window opened

tile_sense_t_c_write_reg

Studio
void tile_sense_t_c_write_reg(tile_t *tile, uint8_t reg, uint16_t value)

Write a raw 16-bit IQS323 register.

reg
[0..255] Register address (datasheet §9 memory map)
value
16-bit value

tile_sense_t_c_get_compensation

Studio
uint16_t tile_sense_t_c_get_compensation(tile_t *tile, uint8_t channel)

Returns the raw Compensation register (0x39 + ch·0x10). The low 10 bits are the compensation value; bits 15-11 are the divider. Normally set by ATI — read it to capture a tuned working point.

channel
0-2.

Returns Raw 16-bit compensation register, or 0 on a bad channel.

tile_sense_t_c_set_compensation

Studio
void tile_sense_t_c_set_compensation(tile_t *tile, uint8_t channel, uint16_t value, uint8_t divider)

Writes the Compensation register (0x39 + ch·0x10): value (0-1023) in bits 9-0, divider (0-31) in bits 15-11. NOTE: a subsequent full ATI overwrites this — to hold a fixed offset, set the channel's ATI Mode (set_ati_setup) to a non-full mode first.

channel
0-2.
value
Compensation value (0-1023).
divider
Compensation divider (0-31).
gapPer-channel timeout / OutA event-indicatorChannel-timeout disable bits (auto-reseed on timeout) and the OutA pin's event-indicator output mode aren't exposed. Most applications don't need them; raw write_reg covers the niche cases that do. OutA is also not routed on this tile (HW-gated).
gapMutual-capacitance / inductive sensingThe chip can run mutual-capacitance (Tx/Rx pairs) and inductive channels. HW-gated: the tile routes one self-cap electrode per channel (surface on CRx1, pad 8 on CRx0) and no TxA; CRx2 is not routed. The driver configures self-capacitance only.
gapHardware reset (MCLR)Pad 3 is RDY/MCLR: pulling it low outside a window hard-resets the chip. Driver-deferred: the driver uses the soft reset and the pad only as the RDY input. The on-tile 100 nF on the pin slows any host-driven pulse.
gapRelease UI (long-touch release)The tile's IQS323-001 includes the Release UI: an activation LTA that lets a long-held touch or prox release cleanly (registers 0x20-0x25, 0xD4, Sensor Setup bit 6). Driver-deferred; write_reg reaches it. The Movement UI is a different build (IQS323-A01), not on this tile.

Enums

sense_t_c_channel_mode_t

Channel Mode for the Reference UI (datasheet §A.15 bits [3:0]).

SENSE_T_C_CHANNEL_INDEPENDENT
Stand-alone sensing channel
SENSE_T_C_CHANNEL_FOLLOWER
Subtracts a reference channel's LTA
SENSE_T_C_CHANNEL_REFERENCE
Acts as ambient reference for followers

sense_t_c_comm_mode_t

I²C communication mode (System Control register §A.30 bit 7).

SENSE_T_C_COMM_STREAM
Continuous reporting at the configured power-mode rate (the chip's reset default)
SENSE_T_C_COMM_EVENT
RDY pulses only on enabled events (what init() selects)

Constants

TILE_SENSE_T_C_VERSION_MAJOR1
TILE_SENSE_T_C_VERSION_MINOR4
TILE_SENSE_T_C_VERSION_PATCH0
IQS323_I2C_ADDR_0010x44
IQS323_I2C_ADDR_0020x58
SENSE_T_C_CH00CRx0/CTx0 -- pad 8 (external)
SENSE_T_C_CH11CRx1/CTx1 -- tile top surface
SENSE_T_C_CH22CRx2/CTx2 -- not routed on this tile; always disabled
SENSE_T_C_NUM_CHANNELS3
IQS323_STATUS_POWER_SHIFT14
IQS323_EVENTS_DEFINED0x005F
IQS323_INVALID_RESPONSE0xEEEE
IQS323_CTRL_POWER_SHIFT4
IQS323_HW_ID_3DD0xF003
IQS323_HW_ID_3ED0xF004