Skip to content

Commit 6d7b2a4

Browse files
authored
fix(sensors): mitigate cap sensor configuration issues (#703)
* Fixes for FDC1004 - Check the Ready flag for each channel before reading data - Only set the sample rate ONE time ever - Add some delays during capsense initialization to avoid all of the I2C bus traffic - Take out the filtering stuff * Cleaned up tests
1 parent bb7ac57 commit 6d7b2a4

File tree

7 files changed

+320
-234
lines changed

7 files changed

+320
-234
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ if (${CMAKE_CROSSCOMPILING})
6969

7070
add_compile_definitions(ENABLE_CCMRAM)
7171

72+
add_compile_definitions(ENABLE_CROSS_ONLY_HEADERS)
73+
7274
configure_file(common/firmware/platform_specific_hal_conf.h.in ${CMAKE_BINARY_DIR}/generated/platform_specific_hal_conf.h)
7375
configure_file(common/firmware/platform_specific_hal.h.in ${CMAKE_BINARY_DIR}/generated/platform_specific_hal.h)
7476

include/sensors/core/fdc1004.hpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ template <typename Reg>
129129
// This is used to mask the value before writing it to the sensor.
130130
concept FDC1004Register =
131131
std::same_as<std::remove_cvref_t<decltype(Reg::address)>,
132-
std::remove_cvref_t<Registers&>> &&
132+
std::remove_cvref_t<Registers &>> &&
133133
std::integral<decltype(Reg::value_mask)>;
134134

135135
template <typename Reg>
@@ -559,5 +559,21 @@ inline auto update_offset(float capacitance_pf, float current_offset_pf)
559559

560560
return static_cast<float>(capdac) * CAPDAC_PF_PER_LSB;
561561
}
562+
563+
inline auto measurement_ready(fdc1004::FDCConf &fdc,
564+
fdc1004::MeasureConfigMode mode) -> bool {
565+
switch (mode) {
566+
case fdc1004::MeasureConfigMode::ONE:
567+
return fdc.measure_mode_1_status;
568+
case fdc1004::MeasureConfigMode::TWO:
569+
return fdc.measure_mode_2_status;
570+
case fdc1004::MeasureConfigMode::THREE:
571+
return fdc.measure_mode_3_status;
572+
case fdc1004::MeasureConfigMode::FOUR:
573+
return fdc.measure_mode_4_status;
574+
}
575+
return false;
576+
}
577+
562578
} // namespace fdc1004_utils
563579
}; // namespace sensors

include/sensors/core/tasks/capacitive_driver.hpp

Lines changed: 114 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,21 @@
11
#pragma once
22

33
#include <array>
4-
#include <bitset>
4+
5+
#ifdef ENABLE_CROSS_ONLY_HEADERS
6+
// TODO(fps 7/12/2023): This is super hacky and I hate throwing #ifdefs
7+
// in our nicely host-independent code but for now we really just need
8+
// the vTaskDelay function and hopefully sometime in the near future I
9+
// can refactor this file with a nice templated sleep function.
10+
#include "FreeRTOS.h"
11+
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
12+
#define HACKY_TASK_SLEEP(___timeout___) vTaskDelay(___timeout___)
13+
14+
#else
15+
16+
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
17+
#define HACKY_TASK_SLEEP(___timeout___) (void)(___timeout___)
18+
#endif
519

620
#include "can/core/can_writer_task.hpp"
721
#include "can/core/ids.hpp"
@@ -10,7 +24,6 @@
1024
#include "common/core/logging.h"
1125
#include "common/core/message_queue.hpp"
1226
#include "i2c/core/messages.hpp"
13-
#include "ot_utils/core/filters/sma.hpp"
1427
#include "sensors/core/fdc1004.hpp"
1528
#include "sensors/core/sensor_hardware_interface.hpp"
1629
#include "sensors/core/utils.hpp"
@@ -38,19 +51,23 @@ class FDC1004 {
3851
[[nodiscard]] auto initialized() const -> bool { return _initialized; }
3952

4053
auto initialize() -> void {
41-
// FIXME we should grab device id and compare it to the static
42-
// device id in code.
43-
44-
// We should send a message that the sensor is in a ready state,
45-
// not sure if we should have a separate can message to do that
46-
// holding off for this PR.
47-
if (shared_sensor) {
48-
measure_mode = fdc1004::MeasureConfigMode::TWO;
54+
if (!_initialized) {
55+
// FIXME we should grab device id and compare it to the static
56+
// device id in code.
57+
58+
// We should send a message that the sensor is in a ready state,
59+
// not sure if we should have a separate can message to do that
60+
// holding off for this PR.
61+
62+
// Initial delay to avoid I2C bus traffic.
63+
HACKY_TASK_SLEEP(100);
4964
update_capacitance_configuration();
65+
// Second delay to ensure IC is ready to start
66+
// readings (and also to avoid I2C bus traffic).
67+
HACKY_TASK_SLEEP(100);
68+
set_sample_rate();
69+
_initialized = true;
5070
}
51-
measure_mode = fdc1004::MeasureConfigMode::ONE;
52-
update_capacitance_configuration();
53-
_initialized = true;
5471
}
5572

5673
auto register_map() -> fdc1004::FDC1004RegisterMap & { return _registers; }
@@ -70,7 +87,6 @@ class FDC1004 {
7087
}
7188
sensor_id = _id;
7289
update_capacitance_configuration();
73-
filter.reset_filter();
7490
}
7591
}
7692

@@ -100,7 +116,6 @@ class FDC1004 {
100116
// mode.
101117
current_offset_pf = -1;
102118
set_offset(0);
103-
set_sample_rate();
104119
}
105120

106121
void reset_limited() {
@@ -116,13 +131,10 @@ class FDC1004 {
116131
_registers.fdc_conf.measurement_rate =
117132
static_cast<uint8_t>(measurement_rate);
118133
_registers.fdc_conf.repeating_measurements = 1;
119-
if (measure_mode == fdc1004::MeasureConfigMode::TWO) {
120-
_registers.fdc_conf.measure_mode_1 = 0;
121-
_registers.fdc_conf.measure_mode_2 = 1;
122-
} else {
123-
_registers.fdc_conf.measure_mode_1 = 1;
124-
_registers.fdc_conf.measure_mode_2 = 0;
125-
}
134+
// Enable both measurements no matter what. We check the Ready
135+
// bits anyways and the data doesn't overwrite, so there's no danger.
136+
_registers.fdc_conf.measure_mode_1 = 1;
137+
_registers.fdc_conf.measure_mode_2 = 1;
126138
_registers.fdc_conf.padding_0 = 0;
127139
_registers.fdc_conf.padding_1 = 0;
128140
set_register(_registers.fdc_conf);
@@ -164,66 +176,51 @@ class FDC1004 {
164176
auto poll_limited_capacitance(uint16_t number_reads, can::ids::SensorId _id,
165177
uint8_t tags) -> void {
166178
set_sensor_id(_id);
167-
auto converted_msb_addr =
168-
static_cast<uint8_t>(fdc1004::Registers::MEAS1_MSB);
169-
auto converted_lsb_addr =
170-
static_cast<uint8_t>(fdc1004::Registers::MEAS1_LSB);
171-
if (measure_mode == fdc1004::MeasureConfigMode::TWO) {
172-
converted_msb_addr =
173-
static_cast<uint8_t>(fdc1004::Registers::MEAS2_MSB);
174-
converted_lsb_addr =
175-
static_cast<uint8_t>(fdc1004::Registers::MEAS2_LSB);
176-
poller.multi_register_poll(
177-
fdc1004::ADDRESS, converted_msb_addr, 2, converted_lsb_addr, 2,
178-
number_reads, DELAY, own_queue,
179-
utils::build_id(fdc1004::ADDRESS, converted_msb_addr, tags));
180-
} else {
181-
poller.multi_register_poll(
182-
fdc1004::ADDRESS, converted_msb_addr, 2, converted_lsb_addr, 2,
183-
number_reads, DELAY, own_queue,
184-
utils::build_id(fdc1004::ADDRESS, converted_msb_addr, tags));
185-
}
179+
poller.single_register_poll(
180+
fdc1004::ADDRESS,
181+
static_cast<uint8_t>(fdc1004::Registers::FDC_CONF), 2, number_reads,
182+
DELAY, own_queue,
183+
utils::build_id(fdc1004::ADDRESS,
184+
static_cast<uint8_t>(fdc1004::Registers::FDC_CONF),
185+
tags));
186186
}
187187

188188
auto poll_continuous_capacitance(can::ids::SensorId _id, uint8_t tags,
189189
uint8_t binding) -> void {
190190
set_sensor_id(_id);
191191
auto delay = delay_or_disable(binding);
192-
auto converted_msb_addr =
193-
static_cast<uint8_t>(fdc1004::Registers::MEAS1_MSB);
194-
auto converted_lsb_addr =
195-
static_cast<uint8_t>(fdc1004::Registers::MEAS1_LSB);
196-
if (measure_mode == fdc1004::MeasureConfigMode::TWO) {
197-
converted_msb_addr =
198-
static_cast<uint8_t>(fdc1004::Registers::MEAS2_MSB);
199-
converted_lsb_addr =
200-
static_cast<uint8_t>(fdc1004::Registers::MEAS2_LSB);
201-
poller.continuous_multi_register_poll(
202-
fdc1004::ADDRESS, converted_msb_addr, 2, converted_lsb_addr, 2,
203-
delay, own_queue,
204-
utils::build_id(fdc1004::ADDRESS, converted_msb_addr, tags));
205-
} else {
206-
poller.continuous_multi_register_poll(
207-
fdc1004::ADDRESS, converted_msb_addr, 2, converted_lsb_addr, 2,
208-
delay, own_queue,
209-
utils::build_id(fdc1004::ADDRESS, converted_msb_addr, tags));
210-
}
192+
poller.continuous_single_register_poll(
193+
fdc1004::ADDRESS,
194+
static_cast<uint8_t>(fdc1004::Registers::FDC_CONF), 2, delay,
195+
own_queue,
196+
utils::build_id(fdc1004::ADDRESS,
197+
static_cast<uint8_t>(fdc1004::Registers::FDC_CONF),
198+
tags));
211199
}
212200

213201
auto stop_continuous_polling(uint32_t transaction_id) -> void {
214-
auto converted_msb_addr =
215-
static_cast<uint8_t>(fdc1004::Registers::MEAS1_MSB);
216-
auto converted_lsb_addr =
217-
static_cast<uint8_t>(fdc1004::Registers::MEAS1_LSB);
218-
if (measure_mode == fdc1004::MeasureConfigMode::TWO) {
219-
converted_msb_addr =
220-
static_cast<uint8_t>(fdc1004::Registers::MEAS2_MSB);
221-
converted_lsb_addr =
222-
static_cast<uint8_t>(fdc1004::Registers::MEAS2_LSB);
202+
poller.continuous_single_register_poll(
203+
fdc1004::ADDRESS,
204+
static_cast<uint8_t>(fdc1004::Registers::FDC_CONF), 2, STOP_DELAY,
205+
own_queue, transaction_id);
206+
}
207+
208+
void handle_fdc_response(i2c::messages::TransactionResponse &m) {
209+
uint16_t reg_int = 0;
210+
static_cast<void>(bit_utils::bytes_to_int(
211+
m.read_buffer.cbegin(), m.read_buffer.cend(), reg_int));
212+
auto fdc = read_register<fdc1004::FDCConf>(reg_int).value();
213+
auto measurement_done =
214+
fdc1004_utils::measurement_ready(fdc, measure_mode);
215+
if (measurement_done) {
216+
// Start a single-shot, two-register transaction for the data.
217+
send_followup(m);
218+
} else {
219+
i2c::messages::MaxMessageBuffer buffer = {
220+
static_cast<uint8_t>(fdc1004::Registers::FDC_CONF)};
221+
// Retrigger the same exact reading
222+
writer.transact(fdc1004::ADDRESS, 1, buffer, 2, m.id, own_queue);
223223
}
224-
poller.continuous_multi_register_poll(
225-
fdc1004::ADDRESS, converted_msb_addr, 2, converted_lsb_addr, 2,
226-
STOP_DELAY, own_queue, transaction_id);
227224
}
228225

229226
void handle_ongoing_response(i2c::messages::TransactionResponse &m) {
@@ -233,6 +230,7 @@ class FDC1004 {
233230
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
234231
polling_results[m.id.transaction_index]));
235232
if (m.id.transaction_index == 0) {
233+
send_followup(m);
236234
return;
237235
}
238236

@@ -244,19 +242,12 @@ class FDC1004 {
244242
auto raw_capacitance = fdc1004_utils::convert_reads(polling_results[0],
245243
polling_results[1]);
246244

247-
if (!data_stable[int(sensor_id)]) {
248-
raw_capacitance = filter.compute(raw_capacitance);
249-
data_stable.set(int(sensor_id), filter.stop_filter());
250-
}
251-
252245
auto capacitance = fdc1004_utils::convert_capacitance(
253246
raw_capacitance, 1, current_offset_pf);
254247

255-
if (data_stable[int(sensor_id)]) {
256-
auto new_offset =
257-
fdc1004_utils::update_offset(capacitance, current_offset_pf);
258-
set_offset(new_offset);
259-
}
248+
auto new_offset =
249+
fdc1004_utils::update_offset(capacitance, current_offset_pf);
250+
set_offset(new_offset);
260251

261252
if (max_capacitance_sync) {
262253
if (capacitance > fdc1004::MAX_CAPACITANCE_READING) {
@@ -291,6 +282,7 @@ class FDC1004 {
291282
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
292283
baseline_results[m.id.transaction_index]));
293284
if (m.id.transaction_index == 0) {
285+
send_followup(m);
294286
return;
295287
}
296288
measurement += fdc1004_utils::convert_reads(baseline_results[0],
@@ -350,7 +342,6 @@ class FDC1004 {
350342
OwnQueue &own_queue;
351343
hardware::SensorHardwareBase &hardware;
352344

353-
ot_utils::filters::SimpleMovingAverage<int32_t> filter{};
354345
uint8_t sensor_binding{2};
355346
fdc1004::FDC1004RegisterMap _registers{};
356347
bool _initialized = false;
@@ -371,10 +362,49 @@ class FDC1004 {
371362
bool echoing = false;
372363
bool bind_sync = false;
373364
bool max_capacitance_sync = false;
374-
std::bitset<2> data_stable{"00"};
375365
std::array<uint16_t, 2> baseline_results{};
376366
std::array<uint16_t, 2> polling_results{};
377367

368+
auto send_followup(i2c::messages::TransactionResponse &m) -> void {
369+
auto address = utils::reg_from_id<uint8_t>(m.id.token);
370+
uint8_t followup_address = 0;
371+
auto tags = utils::tags_from_token(m.id.token);
372+
i2c::messages::TransactionIdentifier id = m.id;
373+
switch (address) {
374+
case static_cast<uint8_t>(fdc1004::Registers::FDC_CONF):
375+
// After CONF, read MSB for transaction index 0
376+
followup_address =
377+
(measure_mode == fdc1004::MeasureConfigMode::ONE)
378+
? static_cast<uint8_t>(fdc1004::Registers::MEAS1_MSB)
379+
: static_cast<uint8_t>(fdc1004::Registers::MEAS2_MSB);
380+
id.transaction_index = 0;
381+
break;
382+
case static_cast<uint8_t>(fdc1004::Registers::MEAS1_MSB):
383+
// After MSB, read LSB for index 1
384+
followup_address =
385+
static_cast<uint8_t>(fdc1004::Registers::MEAS1_LSB);
386+
id.transaction_index = 1;
387+
break;
388+
case static_cast<uint8_t>(fdc1004::Registers::MEAS2_MSB):
389+
// After MSB, read LSB for index 1
390+
followup_address =
391+
static_cast<uint8_t>(fdc1004::Registers::MEAS2_LSB);
392+
id.transaction_index = 1;
393+
break;
394+
default:
395+
// If this isn't one of the hardcoded regs, do nothing
396+
return;
397+
}
398+
399+
i2c::messages::MaxMessageBuffer buffer;
400+
buffer[0] = followup_address;
401+
402+
// Overwrite the token to get the updated address
403+
id.token = utils::build_id(fdc1004::ADDRESS, followup_address, tags);
404+
// This maintains the entire transaction ID of the original request.
405+
writer.transact(fdc1004::ADDRESS, 1, buffer, 2, id, own_queue);
406+
}
407+
378408
auto build_mode_1_configuration_register() -> fdc1004::ConfMeasure1 {
379409
_registers.config_measure_1.CHA =
380410
static_cast<uint8_t>(fdc1004::CHA::CIN1);

include/sensors/core/tasks/capacitive_sensor_task.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,14 @@ class CapacitiveMessageHandler {
4444

4545
void visit(i2c::messages::TransactionResponse &m) {
4646
auto reg_id = utils::reg_from_id<uint8_t>(m.id.token);
47+
if (reg_id == static_cast<uint8_t>(fdc1004::Registers::FDC_CONF)) {
48+
driver.handle_fdc_response(m);
49+
return;
50+
}
4751
if ((reg_id != static_cast<uint8_t>(fdc1004::Registers::MEAS1_MSB)) &&
48-
(reg_id != static_cast<uint8_t>(fdc1004::Registers::MEAS2_MSB))) {
52+
(reg_id != static_cast<uint8_t>(fdc1004::Registers::MEAS2_MSB)) &&
53+
(reg_id != static_cast<uint8_t>(fdc1004::Registers::MEAS1_LSB)) &&
54+
(reg_id != static_cast<uint8_t>(fdc1004::Registers::MEAS2_LSB))) {
4955
return;
5056
}
5157

include/sensors/core/utils.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ template <std::ranges::range Tags>
7070
return bool(token & (1 << static_cast<size_t>(tag)));
7171
}
7272

73+
[[nodiscard]] inline constexpr auto tags_from_token(uint32_t token) -> uint8_t {
74+
return static_cast<uint8_t>(token & 0xff);
75+
}
76+
7377
[[nodiscard]] inline constexpr auto build_id(uint16_t address, uint8_t reg,
7478
uint8_t tags = 0) -> uint32_t {
7579
return (static_cast<uint32_t>(address) << 16) |

include/sensors/simulation/fdc1004.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@ class FDC1004 : public I2CRegisterMap<uint8_t, uint16_t> {
1313
: I2CRegisterMap(
1414
fdc1004::ADDRESS,
1515
{{static_cast<uint8_t>(fdc1004::Registers::CONF_MEAS1), 0},
16-
{static_cast<uint8_t>(fdc1004::Registers::FDC_CONF), 0},
16+
// Mock out the Read Ready bits as set
17+
{static_cast<uint8_t>(fdc1004::Registers::FDC_CONF), 0x000F},
1718
{static_cast<uint8_t>(fdc1004::Registers::MEAS1_MSB), 100},
1819
{static_cast<uint8_t>(fdc1004::Registers::MEAS1_LSB), 0},
20+
{static_cast<uint8_t>(fdc1004::Registers::MEAS2_MSB), 100},
21+
{static_cast<uint8_t>(fdc1004::Registers::MEAS2_LSB), 0},
1922
{static_cast<uint8_t>(fdc1004::Registers::DEVICE_ID),
2023
fdc1004_utils::DEVICE_ID}}) {}
2124
};

0 commit comments

Comments
 (0)