ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
ldc1614.h
Go to the documentation of this file.
1// ProtoCore v1.0.16 - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file ldc1614.h
6 * @brief TI LDC1614 inductance-to-digital field-sensing codec (PROTOCORE_ENABLE_LDC1614).
7 *
8 * The LDC1614 measures the resonant frequency of an external LC tank driven by a coil; a nearby
9 * conductor changes the coil's effective inductance (eddy currents), moving that frequency - so the
10 * 28-bit conversion result tracks metal proximity, displacement, and EM-field perturbation without
11 * contact. It shares TI's FDC/LDC register architecture: each channel's result is a DATA MSB register
12 * (top 4 bits error flags, low 12 bits data MSB) plus a DATA LSB register, combining into 28 bits, with
13 * `f_sensor = data / 2^28 * f_ref` and `L = 1 / (C * (2*pi*f)^2)` derived by the app from the tank C.
14 *
15 * This codec is pure and host-tested: ::protocore_ldc1614_data combines the register pair, ::protocore_ldc1614_error
16 * pulls the flags, ::protocore_ldc1614_sensor_freq_hz scales to frequency, and ::protocore_ldc1614_build_config emits a
17 * single-channel bring-up. On an ESP32 the binding replays that config and reads the channel over I2C;
18 * only that touches hardware. Bridge the readings northbound like any sensor.
19 */
20
21#ifndef PROTOCORE_LDC1614_H
22#define PROTOCORE_LDC1614_H
23
24#include "protocore_config.h" // the entry point: protocore_types.h for the widths
25
26#if PROTOCORE_ENABLE_LDC1614
27
29
30// PROTOCORE_I2C_DEVICE_BORROW - the bytes this module runs out of - is stated in protocore_config.h, which sums
31// it into its arena. A caller takes them once and passes the pointer to every call. How they
32// are carved is this module's and is never named here.
33
34#define LDC1614_REG_DATA_CH0_MSB 0x00
35
36#define LDC1614_REG_DATA_CH0_LSB 0x01
37
38#define LDC1614_REG_RCOUNT_CH0 0x08
39
40#define LDC1614_REG_SETTLECOUNT_CH0 0x10
41
42#define LDC1614_REG_CLOCK_DIVIDERS_CH0 0x14
43
44#define LDC1614_REG_STATUS 0x18
45
46#define LDC1614_REG_ERROR_CONFIG 0x19
47
48#define LDC1614_REG_CONFIG 0x1A
49
50#define LDC1614_REG_MUX_CONFIG 0x1B
51
52#define LDC1614_REG_DRIVE_CURRENT_CH0 0x1E
53
54#define LDC1614_REG_MANUFACTURER_ID 0x7E
55
56#define LDC1614_REG_DEVICE_ID 0x7F
57
58#define LDC1614_MANUFACTURER_ID 0x5449 ///< "TI".
59
60#define LDC1614_DEVICE_ID 0x3055 ///< LDC1614 / LDC1612.
61
62#define LDC1614_CONFIG_MAX 21
63
64/** @brief What data takes: msb_reg, lsb_reg. */
65typedef struct
66{
67 uint16_t msb_reg;
68 uint16_t lsb_reg;
69} Ldc1614DataArgs;
70
71/** @brief What error takes: msb_reg. */
72typedef struct
73{
74 uint16_t msb_reg;
75} Ldc1614ErrorArgs;
76
77/** @brief What sensor_freq_hz takes: data28, fref_hz. */
78typedef struct
79{
80 uint32_t data28;
81 uint32_t fref_hz;
82} Ldc1614SensorFreqHzArgs;
83
84/** @brief What build_config takes: buf, cap, rcount, settlecount. */
85typedef struct
86{
87 uint8_t *buf;
88 size_t cap;
89 uint16_t rcount;
90 uint16_t settlecount;
91} Ldc1614BuildConfigArgs;
92
93/** @brief What begin takes: addr, rcount, settlecount. */
94typedef struct
95{
96 uint8_t addr;
97 uint16_t rcount;
98 uint16_t settlecount;
99} Ldc1614BeginArgs;
100
101/** @brief What read_ch0 takes: out. */
102typedef struct
103{
104 uint32_t *out;
105} Ldc1614ReadCh0Args;
106
107/**
108 * @brief TI LDC1614 inductance-to-digital field-sensing codec (PROTOCORE_ENABLE_LDC1614).
109 *
110 * A caller sets the members a call takes, invokes it through ::Ldc1614 with the bytes it runs
111 * out of, and reads the outcome off the same handle.
112 *
113 * Ldc1614.data_args.msb_reg = ...;
114 * Ldc1614.data_args.lsb_reg = ...;
115 * Ldc1614.data(work);
116 * // Ldc1614.value is what the call reports
117 *
118 * @var Ldc1614Ns::data_args what data takes: msb_reg, lsb_reg
119 * @var Ldc1614Ns::error_args what error takes: msb_reg
120 * @var Ldc1614Ns::sensor_freq_hz_args what sensor_freq_hz takes: data28, fref_hz
121 * @var Ldc1614Ns::build_config_args what build_config takes: buf, cap, rcount, settlecount
122 * @var Ldc1614Ns::begin_args what begin takes: addr, rcount, settlecount
123 * @var Ldc1614Ns::read_ch0_args what read_ch0 takes: out
124 * @var Ldc1614Ns::ok a call's true/false outcome
125 * @var Ldc1614Ns::value the value a call reports
126 * @var Ldc1614Ns::flags what a call reports
127 * @var Ldc1614Ns::hz what a call reports
128 * @var Ldc1614Ns::n bytes written (7 * 3 = 21), or 0 if cap < LDC1614_CONFIG_MAX
129 * @var Ldc1614Ns::data combine a DATA MSB register (low 12 bits) and DATA LSB register ...
130 * @var Ldc1614Ns::error the 4 error flags from the top of a DATA MSB register (bits 15:12)
131 * @var Ldc1614Ns::sensor_freq_hz sensor frequency in Hz for a 28-bit result against a reference ...
132 * @var Ldc1614Ns::build_config emit a single-channel (CH0) continuous-conversion bring-up as ...
133 * @var Ldc1614Ns::begin verify the device id and apply the CH0 config at addr. true if ...
134 * @var Ldc1614Ns::read_ch0 read channel 0's 28-bit conversion result into out. false on I2C ...
135 *
136 * @c work is PROTOCORE_I2C_DEVICE_BORROW bytes the CALLER took, at an address it knows. It is not held past the call,
137 * so nothing here aliases it. How those bytes are carved is this module's and is never named here.
138 */
139typedef struct
140{
141 Ldc1614DataArgs data_args;
142 Ldc1614ErrorArgs error_args;
143 Ldc1614SensorFreqHzArgs sensor_freq_hz_args;
144 Ldc1614BuildConfigArgs build_config_args;
145 Ldc1614BeginArgs begin_args;
146 Ldc1614ReadCh0Args read_ch0_args;
147 proto_bool ok;
148 uint32_t value;
149 uint8_t flags;
150 uint64_t hz;
151 size_t n;
152} Ldc1614Vars;
153
154/** @brief The operands and the outcome. */
155extern Ldc1614Vars Ldc1614V;
156
157/** @brief The entries. */
158typedef struct
159{
160 void (*const data)(uint8_t *work);
161 void (*const error)(uint8_t *work);
162 void (*const sensor_freq_hz)(uint8_t *work);
163 void (*const build_config)(uint8_t *work);
164 void (*const begin)(uint8_t *work);
165 void (*const read_ch0)(uint8_t *work);
166} Ldc1614Ns;
167
168// What the table binds, defined once in the .c and taking one parameter each: everything
169// else an entry needs is an operand in Ldc1614V or a region of the borrow at a fixed offset.
170void protocore_ldc1614_data(uint8_t *work);
171void protocore_ldc1614_error(uint8_t *work);
172void protocore_ldc1614_sensor_freq_hz(uint8_t *work);
173void protocore_ldc1614_build_config(uint8_t *work);
174void protocore_ldc1614_begin(uint8_t *work);
175void protocore_ldc1614_read_ch0(uint8_t *work);
176
177// `static const`, initialised HERE rather than `extern` against a definition in the .c: a
178// const object whose initializer every translation unit can see is a COMPILE-TIME FACT, so
179// `Ldc1614.data(work)` resolves to a named function and becomes a DIRECT call. An extern table
180// leaves the call indirect and the symbol live at every level, -O2 -flto included.
181static const Ldc1614Ns Ldc1614 __attribute__((unused)) = {
182 .data = protocore_ldc1614_data,
183 .error = protocore_ldc1614_error,
184 .sensor_freq_hz = protocore_ldc1614_sensor_freq_hz,
185 .build_config = protocore_ldc1614_build_config,
186 .begin = protocore_ldc1614_begin,
187 .read_ch0 = protocore_ldc1614_read_ch0,
188};
189
190/**
191 * @brief The PROTOCORE_I2C_DEVICE_BORROW bytes this module's state lives in.
192 *
193 * Stated beside the namespace rather than on it: an entry takes a borrow, and this is where
194 * that borrow comes from. Taken once from the end of the pool, which no mark and no release
195 * walks, so the state lasts the life of the program.
196 *
197 * @return the span.
198 */
199uint8_t *protocore_ldc1614_span(void);
200
202
203#endif // PROTOCORE_ENABLE_LDC1614
204
205#endif // PROTOCORE_LDC1614_H
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
Definition types.h:96
_Bool proto_bool
The truth value.
Definition types.h:64
#define PROTOCORE_END_DECLS
Definition types.h:97