ProtoCore v0.0.2
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
fdc2214.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file fdc2214.cpp
6 * @brief FDC2114/2214 capacitance-to-digital codec + ESP32 binding (see fdc2214.h).
7 */
8
10#include "protocore_config.h"
11
12#if PC_ENABLE_FDC2214
13
14#if defined(ARDUINO)
16#include <Arduino.h>
17#include <Wire.h>
18#endif
19uint32_t pc_fdc2214_data(uint16_t msb_reg, uint16_t lsb_reg)
20{
21 return ((uint32_t)(msb_reg & 0x0FFF) << 16) | lsb_reg;
22}
23
24uint8_t pc_fdc2214_error(uint16_t msb_reg)
25{
26 return (uint8_t)((msb_reg >> 12) & 0x0F);
27}
28
29uint64_t pc_fdc2214_sensor_freq_hz(uint32_t data28, uint32_t fref_hz)
30{
31 return ((uint64_t)data28 * fref_hz) >> 28;
32}
33
34size_t pc_fdc2214_build_config(uint8_t *buf, size_t cap, uint16_t rcount, uint16_t settlecount)
35{
36 if (!buf || cap < FDC2214_CONFIG_MAX)
37 {
38 return 0;
39 }
40 // (register, value) writes; CONFIG is written last because it starts the conversion.
41 const uint16_t seq[][2] = {
42 {FDC2214_REG_RCOUNT_CH0, rcount},
43 {FDC2214_REG_SETTLECOUNT_CH0, settlecount},
44 {FDC2214_REG_CLOCK_DIVIDERS_CH0, 0x1001}, // FIN_SEL=1, FREF_DIVIDER=1
45 {FDC2214_REG_DRIVE_CURRENT_CH0, 0x8C40}, // mid drive current
46 {FDC2214_REG_ERROR_CONFIG, 0x0000}, // no error reporting on INTB
47 {FDC2214_REG_MUX_CONFIG, 0x020D}, // single channel CH0, 10 MHz deglitch
48 {FDC2214_REG_CONFIG, 0x1E01}, // active CH0, internal ref, full current, start
49 };
50 size_t o = 0;
51 for (size_t i = 0; i < sizeof(seq) / sizeof(seq[0]); i++)
52 {
53 buf[o++] = (uint8_t)seq[i][0];
54 buf[o++] = (uint8_t)(seq[i][1] >> 8);
55 buf[o++] = (uint8_t)seq[i][1];
56 }
57 return o;
58}
59
60#if defined(ARDUINO)
61
62namespace
63{
64// All FDC2214 I2C-binding state, owned by one instance (internal linkage): the device address,
65// so it is one named owner, unreachable from any other translation unit.
66struct Fdc2214Ctx
67{
68 uint8_t addr = 0x2A;
69};
70Fdc2214Ctx s_fdc;
71
72bool read16(uint8_t reg, uint16_t *out)
73{
74 Wire.beginTransmission(s_fdc.addr);
75 Wire.write(reg);
76 if (Wire.endTransmission(false) != 0)
77 {
78 return false;
79 }
80 if (Wire.requestFrom((int)s_fdc.addr, 2) != 2)
81 {
82 return false;
83 }
84 uint16_t hi = Wire.read();
85 uint16_t lo = Wire.read();
86 *out = (uint16_t)((hi << 8) | lo);
87 return true;
88}
89
90bool write16(uint8_t reg, uint16_t val)
91{
92 Wire.beginTransmission(s_fdc.addr);
93 Wire.write(reg);
94 Wire.write((uint8_t)(val >> 8));
95 Wire.write((uint8_t)val);
96 return Wire.endTransmission() == 0;
97}
98} // namespace
99
100bool pc_fdc2214_begin(uint8_t addr, uint16_t rcount, uint16_t settlecount)
101{
102 pc_i2c_begin();
103 s_fdc.addr = addr;
104 uint16_t id = 0;
105 if (!read16(FDC2214_REG_DEVICE_ID, &id))
106 {
107 return false;
108 }
109 if (id != FDC2214_DEVICE_ID && id != 0x3054) // 0x3054 = FDC2114 (12-bit sibling)
110 {
111 return false;
112 }
113 uint8_t seq[FDC2214_CONFIG_MAX];
114 size_t n = pc_fdc2214_build_config(seq, sizeof(seq), rcount, settlecount);
115 for (size_t i = 0; i + 3 <= n; i += 3)
116 {
117 if (!write16(seq[i], (uint16_t)((seq[i + 1] << 8) | seq[i + 2])))
118 {
119 return false;
120 }
121 }
122 return true;
123}
124
125bool pc_fdc2214_read_ch0(uint32_t *out)
126{
127 if (!out)
128 {
129 return false;
130 }
131 uint16_t msb = 0;
132 uint16_t lsb = 0;
133 if (!read16(FDC2214_REG_DATA_CH0_MSB, &msb) || !read16(FDC2214_REG_DATA_CH0_LSB, &lsb))
134 {
135 return false;
136 }
137 *out = pc_fdc2214_data(msb, lsb);
138 return true;
139}
140
141#endif // ARDUINO
142
143#endif // PC_ENABLE_FDC2214
TI FDC2114/2214 capacitance-to-digital field-sensing codec (PC_ENABLE_FDC2214).
#define FDC2214_DEVICE_ID
FDC2214 (the 12-bit FDC2114 reads 0x3054).
Definition fdc2214.h:43
bool pc_fdc2214_begin(uint8_t addr, uint16_t rcount, uint16_t settlecount)
Verify the device id and apply the CH0 config at addr.
#define FDC2214_REG_MUX_CONFIG
Definition fdc2214.h:37
#define FDC2214_REG_DEVICE_ID
Definition fdc2214.h:40
uint64_t pc_fdc2214_sensor_freq_hz(uint32_t data28, uint32_t fref_hz)
Sensor frequency in Hz for a 28-bit result against a reference clock: data / 2^28 * fref.
#define FDC2214_REG_DATA_CH0_LSB
Definition fdc2214.h:30
uint8_t pc_fdc2214_error(uint16_t msb_reg)
The 4 error flags from the top of a DATA MSB register (bits 15:12).
#define FDC2214_REG_RCOUNT_CH0
Definition fdc2214.h:31
#define FDC2214_REG_DATA_CH0_MSB
Definition fdc2214.h:29
#define FDC2214_REG_CLOCK_DIVIDERS_CH0
Definition fdc2214.h:33
#define FDC2214_CONFIG_MAX
Largest config sequence in bytes: 7 register writes * 3 bytes (reg, msb, lsb).
Definition fdc2214.h:46
size_t pc_fdc2214_build_config(uint8_t *buf, size_t cap, uint16_t rcount, uint16_t settlecount)
Emit a single-channel (CH0) continuous-conversion bring-up as (reg, val_msb, val_lsb) triples.
#define FDC2214_REG_DRIVE_CURRENT_CH0
Definition fdc2214.h:38
#define FDC2214_REG_SETTLECOUNT_CH0
Definition fdc2214.h:32
bool pc_fdc2214_read_ch0(uint32_t *out)
Read channel 0's 28-bit conversion result into out.
uint32_t pc_fdc2214_data(uint16_t msb_reg, uint16_t lsb_reg)
Combine a DATA MSB register (low 12 bits) and DATA LSB register into the 28-bit result.
#define FDC2214_REG_CONFIG
Definition fdc2214.h:36
#define FDC2214_REG_ERROR_CONFIG
Definition fdc2214.h:35
The one owner of the shared I2C bus bring-up for the peripheral drivers.
void pc_i2c_begin()
Bring up the shared I2C bus on PC_I2C_SDA_PIN / PC_I2C_SCL_PIN (-1 = default).
Definition i2c.h:33
User-facing configuration for ProtoCore.