Skip to content

Commit 58003b1

Browse files
committed
modules: sensor: add warmup delays to prevent CCS810 early read failures
CCS811 sensor needs 5-second stabilization after init before valid readings. Added configurable per-sensor warmup periods with tracking to skip reads during warmup. - CCS811: 5000ms warmup, BME280/HM3301: 100ms - Individual sensor warmup completion tracking - Partial data handling during warmup The change fixes the regression introduced in PR #15 where removing the global warmup delay caused CCS811 to fail with -EAGAIN during the first few read attempts after system initialization. Refs: #16 Signed-off-by: Natalia Pluta <pluta.natalia.m@gmail.com>
1 parent 8f6404c commit 58003b1

3 files changed

Lines changed: 137 additions & 5 deletions

File tree

app/src/modules/controller/controller_module.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ ZBUS_SUBSCRIBER_DEFINE(controller_sensor_subscriber,
1515
CONFIG_CONTROLLER_MODULE_ZBUS_SUBSCRIBER_QUEUE_SIZE);
1616

1717
/* Controller state machine object initialization macro */
18-
#define CONTROLLER_MODULE_STATE_OBJECT_INIT() \
18+
#define CONTROLLER_STATE_OBJECT_INIT() \
1919
(struct controller_state_object) \
2020
{ \
2121
.sample_interval_ms = CONFIG_CONTROLLER_MODULE_SAMPLE_INTERVAL_MS, \
@@ -91,7 +91,7 @@ int controller_module_init(void)
9191
LOG_INF("Initializing controller module");
9292

9393
/* Initialize state machine object */
94-
controller_state_obj = CONTROLLER_MODULE_STATE_OBJECT_INIT();
94+
controller_state_obj = CONTROLLER_STATE_OBJECT_INIT();
9595

9696
/* Initialize state machine */
9797
smf_set_initial(SMF_CTX(&controller_state_obj),

app/src/modules/sensor/Kconfig.sensor

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,36 @@ config SENSOR_MODULE_MAX_RETRIES
4646
help
4747
Maximum number of recovery attempts before giving up.
4848

49+
# Sensor-specific warmup configurations
50+
config SENSOR_MODULE_WARMUP_ENABLE
51+
bool "Enable sensor warmup periods"
52+
default y
53+
help
54+
Enable warmup delays for sensors that need stabilization time
55+
before providing accurate readings.
56+
57+
config SENSOR_MODULE_CCS811_WARMUP_MS
58+
int "CCS811 warmup period (ms)"
59+
default 5000
60+
depends on SENSOR_MODULE_WARMUP_ENABLE
61+
help
62+
Warmup time required for CCS811 sensor before first valid reading.
63+
CCS811 needs time to stabilize after power-on or reset.
64+
65+
config SENSOR_MODULE_BME280_WARMUP_MS
66+
int "BME280 warmup period (ms)"
67+
default 100
68+
depends on SENSOR_MODULE_WARMUP_ENABLE
69+
help
70+
Warmup time required for BME280 sensor before first valid reading.
71+
72+
config SENSOR_MODULE_HM3301_WARMUP_MS
73+
int "HM3301 warmup period (ms)"
74+
default 100
75+
depends on SENSOR_MODULE_WARMUP_ENABLE
76+
help
77+
Warmup time required for HM3301 sensor before first valid reading.
78+
4979
config CCS811_ENV_COMPENSATION
5080
bool "Enable environmental compensation for CCS811"
5181
default y

app/src/modules/sensor/sensor_module.c

Lines changed: 105 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,14 @@ LOG_MODULE_REGISTER(sensor_module, CONFIG_SENSOR_MODULE_LOG_LEVEL);
1212

1313
/* Macro for type-safe sensor state object initialization */
1414
#define SENSOR_STATE_OBJECT_INIT() \
15+
(struct sensor_state_object) \
1516
{ \
1617
.ctx = {0}, .current_state = SENSOR_MODULE_STATE_INIT, .current_data = {0}, \
17-
.error_count = 0, .max_retries = 0, .last_read_time = 0, .read_timeout_ms = 0 \
18+
.error_count = 0, .max_retries = 0, .last_read_time = 0, \
19+
.read_timeout_ms = \
20+
0 IF_ENABLED(CONFIG_SENSOR_MODULE_WARMUP_ENABLE, \
21+
(,.sensor_init_time = 0, \
22+
.sensor_warmup_complete = {false})) \
1823
}
1924

2025
/* ZBUS subscriber for sensor requests */
@@ -56,6 +61,12 @@ struct sensor_state_object {
5661
/* Timing */
5762
int64_t last_read_time;
5863
int64_t read_timeout_ms;
64+
65+
#ifdef CONFIG_SENSOR_MODULE_WARMUP_ENABLE
66+
/* Sensor warmup tracking */
67+
int64_t sensor_init_time;
68+
bool sensor_warmup_complete[SENSOR_TYPE_COUNT];
69+
#endif
5970
};
6071

6172
/* Forward declarations for state functions */
@@ -115,6 +126,11 @@ static void update_sensor_health(struct sensor_health *health, bool success);
115126
static const char *get_sensor_name(enum sensor_type type);
116127
static void sensor_set_state(struct sensor_state_object *ctx, enum sensor_module_state new_state);
117128

129+
#ifdef CONFIG_SENSOR_MODULE_WARMUP_ENABLE
130+
static bool is_sensor_warmup_complete(enum sensor_type type);
131+
static int64_t get_sensor_warmup_time(enum sensor_type type);
132+
#endif
133+
118134
#ifdef CONFIG_CCS811_ENV_COMPENSATION
119135
static int update_ccs811_env_data(const struct sensor_value *temp, const struct sensor_value *hum);
120136
static void handle_ccs811_env_compensation(const struct sensor_value *temp,
@@ -127,7 +143,7 @@ int sensor_module_init(void)
127143
int ret;
128144

129145
/* Initialize state machine context */
130-
sensor_state_obj = (struct sensor_state_object)SENSOR_STATE_OBJECT_INIT();
146+
sensor_state_obj = SENSOR_STATE_OBJECT_INIT();
131147

132148
sensor_state_obj.max_retries = CONFIG_SENSOR_MODULE_MAX_RETRIES;
133149
sensor_state_obj.read_timeout_ms = CONFIG_SENSOR_MODULE_READ_TIMEOUT_MS;
@@ -246,6 +262,14 @@ static void sensor_state_init_run(void *obj)
246262
return;
247263
}
248264

265+
#ifdef CONFIG_SENSOR_MODULE_WARMUP_ENABLE
266+
/* Initialize warmup timing */
267+
ctx->sensor_init_time = k_uptime_get();
268+
for (int i = 0; i < SENSOR_TYPE_COUNT; i++) {
269+
ctx->sensor_warmup_complete[i] = false;
270+
}
271+
#endif
272+
249273
/* Initialize context with configured values */
250274
ctx->error_count = 0;
251275
ctx->max_retries = sensor_state_obj.max_retries;
@@ -292,6 +316,15 @@ static void sensor_state_reading_run(void *obj)
292316
continue;
293317
}
294318

319+
#ifdef CONFIG_SENSOR_MODULE_WARMUP_ENABLE
320+
/* Check if sensor warmup is complete */
321+
if (!is_sensor_warmup_complete(i)) {
322+
LOG_DBG("Sensor SM: %s warmup not complete, skipping read",
323+
get_sensor_name(i));
324+
continue;
325+
}
326+
#endif
327+
295328
int ret = read_sensor_data(i, &ctx->current_data);
296329
if (ret == 0) {
297330
successful_reads++;
@@ -319,18 +352,43 @@ static void sensor_state_reading_run(void *obj)
319352
}
320353
}
321354

322-
/* Count enabled sensors */
355+
/* Count enabled sensors that have completed warmup */
323356
int enabled_sensor_count = 0;
324357
for (int i = 0; i < SENSOR_TYPE_COUNT; i++) {
325358
if (sensors[i].enabled) {
359+
#ifdef CONFIG_SENSOR_MODULE_WARMUP_ENABLE
360+
if (is_sensor_warmup_complete(i)) {
361+
enabled_sensor_count++;
362+
}
363+
#else
326364
enabled_sensor_count++;
365+
#endif
327366
}
328367
}
329368

330369
/* Only publish data if at least one sensor read successfully */
331370
if (successful_reads == 0) {
371+
#ifdef CONFIG_SENSOR_MODULE_WARMUP_ENABLE
372+
/* Check if any sensors are still warming up */
373+
bool any_warming = false;
374+
for (int i = 0; i < SENSOR_TYPE_COUNT; i++) {
375+
if (sensors[i].enabled && !is_sensor_warmup_complete(i)) {
376+
any_warming = true;
377+
break;
378+
}
379+
}
380+
381+
if (any_warming) {
382+
LOG_DBG("Sensor SM: No readings yet - sensors still warming up");
383+
sensor_set_state(ctx, SENSOR_MODULE_STATE_IDLE);
384+
} else {
385+
LOG_ERR("Sensor SM: All sensors failed, entering error state");
386+
sensor_set_state(ctx, SENSOR_MODULE_STATE_ERROR);
387+
}
388+
#else
332389
LOG_ERR("Sensor SM: All sensors failed, entering error state");
333390
sensor_set_state(ctx, SENSOR_MODULE_STATE_ERROR);
391+
#endif
334392
} else if (successful_reads < enabled_sensor_count) {
335393
LOG_WRN("Sensor SM: Partial sensor failure (%d/%d successful), but publishing "
336394
"available data",
@@ -703,3 +761,47 @@ static void sensor_set_state(struct sensor_state_object *ctx, enum sensor_module
703761
ctx->current_state = new_state;
704762
smf_set_state(SMF_CTX(ctx), &sensor_states[new_state]);
705763
}
764+
765+
#ifdef CONFIG_SENSOR_MODULE_WARMUP_ENABLE
766+
/* Helper function to get warmup time for a sensor type */
767+
static int64_t get_sensor_warmup_time(enum sensor_type type)
768+
{
769+
switch (type) {
770+
case SENSOR_TYPE_BME280:
771+
return CONFIG_SENSOR_MODULE_BME280_WARMUP_MS;
772+
case SENSOR_TYPE_CCS811:
773+
return CONFIG_SENSOR_MODULE_CCS811_WARMUP_MS;
774+
case SENSOR_TYPE_HM3301:
775+
return CONFIG_SENSOR_MODULE_HM3301_WARMUP_MS;
776+
default:
777+
return 0;
778+
}
779+
}
780+
781+
/* Helper function to check if sensor warmup is complete */
782+
static bool is_sensor_warmup_complete(enum sensor_type type)
783+
{
784+
if (type >= SENSOR_TYPE_COUNT) {
785+
return false;
786+
}
787+
788+
/* Check if already marked as complete */
789+
if (sensor_state_obj.sensor_warmup_complete[type]) {
790+
return true;
791+
}
792+
793+
/* Check if warmup time has elapsed */
794+
int64_t elapsed_time = k_uptime_get() - sensor_state_obj.sensor_init_time;
795+
int64_t warmup_time = get_sensor_warmup_time(type);
796+
797+
if (elapsed_time >= warmup_time) {
798+
/* Mark as complete and log */
799+
sensor_state_obj.sensor_warmup_complete[type] = true;
800+
LOG_INF("Sensor SM: %s warmup complete after %lld ms", get_sensor_name(type),
801+
elapsed_time);
802+
return true;
803+
}
804+
805+
return false;
806+
}
807+
#endif /* CONFIG_SENSOR_MODULE_WARMUP_ENABLE */

0 commit comments

Comments
 (0)