Arduino library for TI FDC1004, FDC1004-Q1 and FDC2x1x capacitive sensing ICs.
Calibration-first • Clean-room • Family-aware • Arduino-friendly
FDC1004 direct capacitance sensing + FDC2x1x frequency-first resonant sensing
FDCxCapSense is a clean-room Arduino library for TI FDC capacitive sensing ICs, designed for research, prototyping, and reference-style embedded sensing workflows.
It supports:
- FDC1004 / FDC1004-Q1 direct capacitance sensing
- FDC2112 / FDC2114 / FDC2212 / FDC2214 frequency-first resonant sensing
- CAPDAC calibration
- baseline tracking
- diagnostics
- temperature compensation helpers
- metadata-aware samples
- experimental profile helpers for liquid level, proximity, material response, powder/granular proxy sensing, and surface-state candidates
The library is designed to keep FDC1004 direct CDC physics separate from FDC2x1x resonant LC physics.
Not just a breakout driver — a calibration-first, family-aware Arduino reference library for TI FDC capacitive sensing ICs.
This project started as part of Proio research work around capacitive sensing for icing and surface-state sensor experiments.
Website: proio.ir
While developing sensor research tools for our own work, we decided to publish this library freely as a more complete reference-style Arduino library for the developer, embedded systems, and sensing community.
We welcome feedback, bug reports, test results, documentation improvements, and better workflow suggestions. If you find an issue, an unclear API, a datasheet mismatch, or hardware behavior that needs better handling, please open an issue so we can improve the project together.
Maintainer: Parvaz Jamei
LinkedIn: linkedin.com/in/parvaz-jamei
| Area | What FDCxCapSense provides |
|---|---|
| FDC1004 support | Direct capacitance readout, CAPDAC handling, baseline tracking, and diagnostics |
| FDC2x1x support | Frequency-first foundation for resonant LC sensing with model-dependent derived capacitance |
| Family-aware design | FDC1004 and FDC2x1x are not treated as the same physical measurement model |
| Calibration-first workflow | Designed around baseline, drift, temperature, reference compensation, and profile metadata |
| Arduino-friendly structure | Lightweight per-family headers and standard Arduino Library layout |
| Claim-safe profiles | Experimental helpers with confidence, reason, and raw metrics; no hardcoded magic detection |
| Clean-room policy | Built independently with strict third-party code reuse rules |
| Research-ready | Useful for liquid level, proximity, material response, surface-state experiments, and industrial IoT prototypes |
| Chip family | Status | Measurement model |
|---|---|---|
| FDC1004 | Supported | Direct capacitance-to-digital conversion |
| FDC1004-Q1 | Supported at API/docs level | Direct capacitance-to-digital conversion |
| FDC2212 | Frequency-first foundation | Resonant LC / frequency-based sensing |
| FDC2214 | Frequency-first foundation | Resonant LC / frequency-based sensing |
| FDC2112 | Raw/foundation support | 12-bit raw foundation; precise conversion is not implemented in v0.6.x |
| FDC2114 | Raw/foundation support | 12-bit raw foundation; precise conversion is not implemented in v0.6.x |
FDC2x1x capacitance values are derived/model-dependent and require valid LC parameters. They are not the same as FDC1004 direct pF readings.
- Open Arduino IDE.
- Go to Sketch → Include Library → Manage Libraries.
- Search for:
FDCxCapSense
Arduino Library Manager submission is in progress. After approval, install from Arduino IDE via Sketch → Include Library → Manage Libraries and search for FDCxCapSense.
Download the release ZIP and place it in your Arduino libraries folder.
Use the lightweight family-specific headers when possible:
#include <FDCxCapSense_FDC1004.h>#include <FDCxCapSense_FDC2x1x.h>Use the full header only when you need all features and experimental profile helpers:
#include <FDCxCapSense.h>library.properties intentionally controls the Arduino IDE Include Library suggestions with:
includes=FDCxCapSense.h,FDCxCapSense_FDC1004.h,FDCxCapSense_FDC2x1x.h
#include <Wire.h>
#include <FDCxCapSense_FDC1004.h>
FDC1004 fdc;
void setup() {
Serial.begin(115200);
Wire.begin();
FDCxStatus status = fdc.begin(Wire);
if (status != FDCxStatus::Ok) {
Serial.println("FDC1004 not detected");
return;
}
fdc.setSampleRate(FDC1004Rate::SPS_100);
fdc.configureSingleEnded(FDC1004Measurement::M1, FDC1004Channel::CIN1);
}
void loop() {
fdc.triggerSingleMeasurement(FDC1004Measurement::M1);
if (fdc.waitForMeasurement(FDC1004Measurement::M1, 100) == FDCxStatus::Ok) {
float pf = 0.0f;
if (fdc.readLastCapacitancePf(FDC1004Measurement::M1, pf) == FDCxStatus::Ok) {
Serial.print("Capacitance: ");
Serial.print(pf, 6);
Serial.println(" pF");
}
}
delay(250);
}#include <Wire.h>
#include <FDCxCapSense_FDC2x1x.h>
FDC2x1x fdc;
void setup() {
Serial.begin(115200);
Wire.begin();
FDCxStatus status = fdc.begin(Wire, FDC2x1xVariant::FDC2214, 0x2A);
if (status != FDCxStatus::Ok) {
Serial.println("FDC2x1x device not detected");
return;
}
// These are example configuration values. Real hardware values must be selected
// from the datasheet based on the LC tank, reference clock and sensor topology.
fdc.setSleepMode(true);
fdc.setRCount(FDC2x1xChannel::CH0, 0x0100);
fdc.setSettleCount(FDC2x1xChannel::CH0, 0x0100);
fdc.configureClockDividers(FDC2x1xChannel::CH0, 2, 1);
fdc.setDriveCurrentCode(FDC2x1xChannel::CH0, 15);
fdc.setDeglitch(FDC2x1xDeglitch::MHz_10);
fdc.startContinuous(FDC2x1xChannel::CH0);
}
void loop() {
FDC2x1xFrequency reading;
if (fdc.waitDataReady(FDC2x1xChannel::CH0, 100) == FDCxStatus::Ok &&
fdc.readFrequencyHzFromRegisters(FDC2x1xChannel::CH0, 40000000.0f, reading) == FDCxStatus::Ok) {
Serial.print("Sensor frequency: ");
Serial.print(reading.frequencyHz, 2);
Serial.println(" Hz");
}
delay(250);
}configureChannel() is retained as a validation-only compatibility alias in v0.6.x. It does not fully configure the resonator or start conversion. Real FDC2x1x hardware setup requires datasheet-based setRCount(), setSettleCount(), configureClockDividers() / writeRawClockDividers(), setDriveCurrentCode(), setDeglitch(), and then startContinuous() to clear CONFIG.SLEEP_MODE_EN. Prefer readFrequencyHzFromRegisters() for real hardware because it decodes CLOCK_DIVIDERS_CHx from the device registers.
| Feature | FDC1004 | FDC2x1x |
|---|---|---|
| Physical model | Direct capacitance-to-digital converter | Resonant LC / frequency-based sensing |
| Primary output | Capacitance-like direct measurement | Frequency/raw code |
| Capacitance | Direct pF path | Derived from frequency and LC parameters |
| Calibration | CAPDAC, baseline, temperature/reference compensation | LC parameters, baseline frequency, reference clock |
| Profile use | Direct capacitance sample | Frequency or derived sample with metadata |
FDCxCapSense uses metadata-aware samples to avoid mixing these two measurement models.
For FDC2x1x derived capacitance, FDC2x1xLCParams.traceReferenceClockHz is trace metadata only. The derivation helper uses already-converted frequencyHz, inductanceUH, and parasiticCapacitancePf. The effective reference clock belongs to the readFrequencyHzFromRegisters() or explicit readFrequencyHz(..., frefHz, finSelMultiplier, ...) step.
The library includes experimental helpers for:
- liquid level
- proximity
- surface-state candidates
- material feature extraction
- powder/granular proxy sensing
- automotive proximity demo
These profiles provide:
- state
- confidence
- reason
- raw metrics
- diagnostic flags
They do not provide certified, guaranteed, or safety-critical decisions.
Official profile examples use metadata-aware inputs through FDCxSample and FDCxFeatureVector. Raw-float profile helpers are compatibility-only; define FDCX_DISABLE_LEGACY_PROFILE_HELPERS before including the library if you want to hide those overloads from your build.
FDCxCapSense does not provide:
- certified safety decisions
- not automotive-grade validation
- field validation by the Developer
- guaranteed black ice detection
- guaranteed liquid/material classification
- hardware validation by the Developer
Application profiles are experimental and calibration-dependent. Real-world deployment requires electrode design, shielding, grounding, cable length review, environment testing, and owner-side hardware validation.
Allowed wording:
- experimental
- calibration-aware
- research-first
- hardware validation required
- owner-side validation required
- derived capacitance is model-dependent
FDCxCapSense is intended as a reference-style Arduino library for developers working on:
- capacitive sensing
- industrial IoT sensing
- embedded sensor research
- liquid level sensing
- proximity sensing
- material/surface response experiments
- sensor calibration workflows
- edge/field prototype development
This project also reflects the engineering approach behind Proio: building practical embedded and industrial IoT systems from low-level sensor behavior to calibration, diagnostics, and application-level interpretation.
Suggested repository description:
Arduino library for TI FDC1004, FDC1004-Q1 and FDC2x1x/FDC2214 capacitive sensing with calibration, CAPDAC, diagnostics, liquid level, proximity and surface-state profiles.
Suggested GitHub topics:
arduino arduino-library capacitive-sensing fdc1004 fdc2214 fdc2x1x i2c esp32 liquid-level-sensing proximity-sensing fdc1004-q1 fdc2212 fdc2114 fdc2112 sensor-calibration industrial-iot embedded
Optional additional topics:
capacitance-sensor capacitance-to-digital touch-sensing surface-sensing sensor-fusion embedded-systems edge-ai
This library is free for the community.
If you test it with real hardware, improve documentation, find a bug, notice a datasheet mismatch, or want to suggest a better workflow, please open an issue.
We are especially interested in feedback from:
- Arduino users
- embedded developers
- industrial IoT engineers
- sensor researchers
- FDC1004/FDC2214 users
- teams building capacitive sensing products or prototypes
Maintainer: Parvaz Jamei
LinkedIn: linkedin.com/in/parvaz-jamei
Website: proio.ir
Bundled checks:
tools/clean_package_check.sh
tools/claim_safety_scan.sh
scripts/architecture_contract_scan.sh
tools/host_smoke_compile.sh
scripts/compile_examples_arduino_cli.sh arduino:avr:uno
scripts/compile_examples_arduino_cli.sh arduino:samd:mkrzero
scripts/compile_examples_arduino_cli.sh esp32:esp32:esp32If Arduino CLI is not installed, Arduino compile is reported as NOT RUN instead of a false PASS. GitHub Actions workflows are included for owner-side CI execution, including compile examples, unit-test smoke checks, and Arduino Lint.
Hardware validation was not performed by the Developer. Hardware testing is owner-side and must be recorded in docs/hardware_validation_matrix.md before any field or product interpretation.
MIT License.
This project follows a strict clean-room policy. Existing libraries may be inspected for research, risk discovery, learning, and conceptual comparison. Third-party code, examples, tests, documentation text, API shape, file layout, naming pattern, or recognizable implementation structure must not be copied or closely derived without explicit license review, compatibility check, approval, and attribution.
Official implementation source of truth:
- TI official datasheets/application notes
- Arduino official documentation
- independently written project code
Current status:
Public Release Candidate
Code/package-level accepted for owner-side handoff
Hardware validation: owner-side / not performed by Developer
Arduino Library Manager submission: pending public repo URL, CI, lint and tag
Owner-side release blockers before public submission:
- Repository URL is set to
https://github.com/Parvaz-Jamei/FDCxCapSense; owner must confirm the public repository exists before tagging/submission. - Run GitHub Actions compile matrix and Arduino Lint on the public repository.
- Record owner-side hardware evidence in
docs/hardware_validation_matrix.md. - Check Arduino Library Manager name uniqueness for
FDCxCapSense. - Create a SemVer tag only after metadata, CI, and documentation are final.
See:
docs/library_manager_checklist.mddocs/release_process.mddocs/maintenance_plan.mddocs/release_candidate_checklist.md
- FDC2x1x
setDeglitch()now preserves the datasheet/defaultMUX_CONFIGreserved pattern0x0208while updating only deglitch bits and preserving autoscan/sequence bits. - Added safe startup APIs:
setSleepMode(),setActiveChannel(),startContinuous(),stopConversions(), andconfigureSingleChannel(). - Public FDC2x1x examples now explicitly configure channel timing/current/deglitch, then start continuous conversion before waiting for data.
- Safe
setRCount()rejects reserved low public values below0x0100;writeRawRCount()remains an explicit raw path. readFrequencyHzFromRegisters()remains the recommended hardware path because it decodes the clock divider register instead of relying on a stale caller-side assumption.
This package tightens the FDC2x1x publish path: waitDataReady() is channel-aware, DATA MSB error flags are rejected before raw masking, FDC221x frequency conversion can decode CHx_FIN_SEL and CHx_FREF_DIVIDER from CLOCK_DIVIDERS_CHx, and FDC1004 readings now report the configured CIN channel. Arduino CLI compile remains owner-side if the tool is unavailable in the Developer environment.
CONFIGraw writes now validate the writable reserved-bit pattern0x1401instead of treating real option bits as fixed reserved bits.- Safe helpers preserve
SENSOR_ACTIVATE_SEL,REF_CLK_SRC,INTB_DIS, andHIGH_CURRENT_DRVwhile changing sleep/active-channel state. setReferenceClockSource()makes external-clock sketches explicit; public examples set external clock before using40000000.0f.configureSingleChannel()now clearsAUTOSCAN_EN/RR_SEQUENCEand writes a single-channelMUX_CONFIGvalue.- Two-channel variants reject raw
CONFIGactive channels andMUX_CONFIGautoscan sequences that include unavailable CH2/CH3. - Single-ended topology helpers force the documented
FIN_SELpath used by examples.
FDC211x remains raw/foundation-only for v0.6.x precise frequency conversion; FDC221x remains the supported frequency-conversion path. Hardware validation is still owner-side and not claimed by this package.
ERROR_CONFIGraw writes now reject reserved bits and accept only documented alert/interrupt routing bits.- High-level FDC2x1x configuration setters require Sleep Mode, matching the datasheet-oriented
sleep -> configure -> startContinuous()flow. Raw register writers remain explicit advanced APIs. FDC2x1xDerivedCapacitance::toSample()clamps NaN confidence to0.0fand still clamps negative/above-one values to[0, 1].- The legacy
readFrequencyHz(channel, frefHz, output)overload is strongly marked as a compatibility helper and now readsCHx_FIN_SELbefore calculating instead of silently assumingFIN_SEL=1. Real hardware examples still preferreadFrequencyHzFromRegisters(). - FDC2112/FDC2114 remain raw/foundation-only for v0.6.x; precise FDC221x frequency conversion is the supported public conversion path.
- FDC1004
readCapacitancePf()/readLastCapacitancePf()are latest-register reads; usereadSingleMeasurement()for fresh single-shot conversion.
- Two-channel FDC2112/FDC2212 autoscan validation now accepts
RR_SEQUENCE=b00andb11for CH0/CH1, and still rejects sequences that include CH2/CH3. RESET_DEVraw writes reject reserved bits; FDC221x rejects FDC211x-onlyOUTPUT_GAINbits.CONFIG.HIGH_CURRENT_DRVis guarded as CH0 single-channel only and cannot coexist withMUX_CONFIG.AUTOSCAN_EN.- Differential clock-divider setup now has
configureClockDividersForDifferential(channel, finSelMultiplier, frefDivider)soFIN_SEL=1orFIN_SEL=2is explicit. - Official FDC2x1x examples keep using
readFrequencyHzFromRegisters(); the simplerreadFrequencyHz(channel, frefHz, output)overload is legacy compatibility only. - FDC1004
readCapacitancePf()is documented as latest-register read; usereadSingleMeasurement()for a fresh single-shot conversion.