X1 barometrification

This commit is contained in:
liquidraver
2026-08-14 14:01:18 +02:00
parent 4473b261ee
commit 216012574e
11 changed files with 167 additions and 35 deletions
+46 -21
View File
@@ -50,6 +50,31 @@ static const struct device *temp_humidity_dev = NULL;
static const struct device *pressure_dev = NULL;
static bool temp_dev_has_pressure = false; /* BME280/BME680 also have pressure */
static bool env_available = false;
/* Is this sensor usable — bringing it up first if its node deferred init?
*
* A part behind a switched rail cannot be probed at POST_KERNEL. Regulators
* come up at priority 75 and sensors at 90, typically microseconds later, and a
* regulator-boot-on rail never applies its startup-delay-us (regulator_common_init
* takes the refcount-only branch, so regulator_delay() never runs). Such a node
* is marked zephyr,deferred-init and initialised from here instead, where the
* rail has had the whole boot to settle. See the i2c0 comment in the
* MeshTracker X1 DTS for the failure this prevents.
*
* Safe to call for every candidate on every board: do_device_init() marks a
* device initialized even when its init function failed, so device_init()
* answers -EALREADY for anything that already ran at POST_KERNEL and this
* reduces to a plain device_is_ready() check. */
static bool sensor_ready(const struct device *dev)
{
if (dev == NULL) {
return false;
}
if (!device_is_ready(dev)) {
(void)device_init(dev);
}
return device_is_ready(dev);
}
#endif
int env_sensors_init(void)
@@ -63,7 +88,7 @@ int env_sensors_init(void)
/* SHTC3 (e.g., RAK1901) */
dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(shtc3));
if (dev && device_is_ready(dev)) {
if (sensor_ready(dev)) {
temp_humidity_dev = dev;
LOG_INF("Found temp/humidity sensor: %s (SHTC3)", dev->name);
goto check_pressure;
@@ -71,13 +96,13 @@ int env_sensors_init(void)
/* Aosong AHT20/DHT20/AM2301B — same chip family, three compatible strings */
dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(aht20));
if (!dev || !device_is_ready(dev)) {
if (!sensor_ready(dev)) {
dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(dht20));
}
if (!dev || !device_is_ready(dev)) {
if (!sensor_ready(dev)) {
dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(am2301b));
}
if (dev && device_is_ready(dev)) {
if (sensor_ready(dev)) {
temp_humidity_dev = dev;
LOG_INF("Found temp/humidity sensor: %s (AHT20/DHT20)", dev->name);
goto check_pressure;
@@ -85,7 +110,7 @@ int env_sensors_init(void)
/* SHT4x */
dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(sht4x));
if (dev && device_is_ready(dev)) {
if (sensor_ready(dev)) {
temp_humidity_dev = dev;
LOG_INF("Found temp/humidity sensor: %s (SHT4x)", dev->name);
goto check_pressure;
@@ -93,7 +118,7 @@ int env_sensors_init(void)
/* SHT3xD */
dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(sht3xd));
if (dev && device_is_ready(dev)) {
if (sensor_ready(dev)) {
temp_humidity_dev = dev;
LOG_INF("Found temp/humidity sensor: %s (SHT3xD)", dev->name);
goto check_pressure;
@@ -101,7 +126,7 @@ int env_sensors_init(void)
/* BME280 — temperature + humidity + pressure */
dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(bme280));
if (dev && device_is_ready(dev)) {
if (sensor_ready(dev)) {
temp_humidity_dev = dev;
temp_dev_has_pressure = true;
LOG_INF("Found env sensor: %s (BME280 — temp/humidity/pressure)", dev->name);
@@ -110,7 +135,7 @@ int env_sensors_init(void)
/* BME680 — temperature + humidity + pressure (+ gas) */
dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(bme680));
if (dev && device_is_ready(dev)) {
if (sensor_ready(dev)) {
temp_humidity_dev = dev;
temp_dev_has_pressure = true;
LOG_INF("Found env sensor: %s (BME680 — temp/humidity/pressure)", dev->name);
@@ -123,7 +148,7 @@ check_pressure:
if (!temp_dev_has_pressure) {
/* LPS22HB (e.g., RAK1902) */
dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(lps22hb));
if (dev && device_is_ready(dev)) {
if (sensor_ready(dev)) {
pressure_dev = dev;
LOG_INF("Found pressure sensor: %s (LPS22HB)", dev->name);
goto done;
@@ -131,7 +156,7 @@ check_pressure:
/* BMP280 — pressure + temperature (lower priority as temp source) */
dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(bmp280));
if (dev && device_is_ready(dev)) {
if (sensor_ready(dev)) {
pressure_dev = dev;
LOG_INF("Found pressure sensor: %s (BMP280)", dev->name);
goto done;
@@ -139,7 +164,7 @@ check_pressure:
/* BMP388 */
dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(bmp388));
if (dev && device_is_ready(dev)) {
if (sensor_ready(dev)) {
pressure_dev = dev;
LOG_INF("Found pressure sensor: %s (BMP388)", dev->name);
goto done;
@@ -148,10 +173,10 @@ check_pressure:
/* SPA06 — the two nodes are the same part at its two possible
* addresses; the one that isn't there fails its ID check. */
dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(spa06));
if (!dev || !device_is_ready(dev)) {
if (!sensor_ready(dev)) {
dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(spa06_alt));
}
if (dev && device_is_ready(dev)) {
if (sensor_ready(dev)) {
pressure_dev = dev;
LOG_INF("Found pressure sensor: %s (SPA06)", dev->name);
goto done;
@@ -273,7 +298,7 @@ int power_sensors_init(void)
/* INA3221 — 3-channel power monitor (check first — most channels) */
dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(ina3221));
if (dev && device_is_ready(dev)) {
if (sensor_ready(dev)) {
ina_dev = dev;
ina_found = INA_3221;
ina_num_channels = 3;
@@ -284,7 +309,7 @@ int power_sensors_init(void)
/* INA219 — standalone single-channel */
dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(ina219));
if (dev && device_is_ready(dev)) {
if (sensor_ready(dev)) {
ina_dev = dev;
ina_found = INA_219;
ina_num_channels = 1;
@@ -295,22 +320,22 @@ int power_sensors_init(void)
/* ina2xx unified family — try all supported variants */
dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(ina226));
if (!dev || !device_is_ready(dev)) {
if (!sensor_ready(dev)) {
dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(ina228));
}
if (!dev || !device_is_ready(dev)) {
if (!sensor_ready(dev)) {
dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(ina230));
}
if (!dev || !device_is_ready(dev)) {
if (!sensor_ready(dev)) {
dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(ina232));
}
if (!dev || !device_is_ready(dev)) {
if (!sensor_ready(dev)) {
dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(ina236));
}
if (!dev || !device_is_ready(dev)) {
if (!sensor_ready(dev)) {
dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(ina237));
}
if (dev && device_is_ready(dev)) {
if (sensor_ready(dev)) {
ina_dev = dev;
ina_found = INA_2XX;
ina_num_channels = 1;
+9
View File
@@ -171,11 +171,17 @@ static int spa06_init(const struct device *dev)
int rc;
if (!i2c_is_ready_dt(&cfg->bus)) {
LOG_ERR("I2C bus %s not ready", cfg->bus.bus->name);
return -ENODEV;
}
/* Probe failures stay at debug level: a board may declare the part at both
* of its possible addresses and let the absent one fail here. Everything
* past this point is a part that answered and then went wrong, so those
* are errors. */
rc = i2c_reg_read_byte_dt(&cfg->bus, SPA06_REG_ID, &id);
if (rc < 0) {
LOG_DBG("no answer at 0x%02x (id read: %d)", cfg->bus.addr, rc);
return -ENODEV;
}
if (id != SPA06_CHIP_ID) {
@@ -185,6 +191,7 @@ static int spa06_init(const struct device *dev)
rc = i2c_reg_write_byte_dt(&cfg->bus, SPA06_REG_RESET, SPA06_SOFT_RESET);
if (rc < 0) {
LOG_ERR("SPA06 soft reset failed: %d", rc);
return rc;
}
k_msleep(15);
@@ -204,6 +211,7 @@ static int spa06_init(const struct device *dev)
ready:
rc = spa06_read_coefficients(dev);
if (rc < 0) {
LOG_ERR("SPA06 coefficient read failed: %d", rc);
return rc;
}
@@ -222,6 +230,7 @@ ready:
SPA06_MEAS_CONT_BOTH);
}
if (rc < 0) {
LOG_ERR("SPA06 configuration failed: %d", rc);
return rc;
}
@@ -85,6 +85,14 @@
enable-gpios = <&gpio0 3 GPIO_ACTIVE_HIGH>;
regulator-boot-on;
regulator-always-on;
/* Documents the rail's requirement, but do not rely on it. It is
* inert twice over: regulator-boot-on sends regulator_common_init()
* down the refcount-only branch so regulator_delay() never runs, and
* regulator-always-on makes regulator_enable() return at its first
* line. The real settle time comes from the ST7735R driver's own
* mipi_dbi_reset() + exit-sleep delay at DISPLAY_INIT_PRIORITY 85;
* the GNSS side is safe because gnss-nmea-generic never probes the
* receiver, it just parses whatever the UART delivers. */
startup-delay-us = <10000>;
};
@@ -112,6 +120,9 @@
enable-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>;
regulator-boot-on;
regulator-always-on;
/* Documents the FEM's requirement, but do not rely on it — inert for
* the same two reasons as vext above. Harmless because the FEM is a
* passive gain block with no bus to probe. */
startup-delay-us = <1000>;
};
@@ -87,6 +87,14 @@
regulator-name = "gps-power";
enable-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
regulator-boot-on;
/* Documents the module's requirement, but do not rely on it:
* regulator-boot-on sends regulator_common_init() down the
* refcount-only branch, so regulator_delay() never runs and this
* value is inert. Harmless here because gnss-nmea-generic never
* probes the receiver — it attaches a UART and parses whatever
* arrives, so an unpowered module means no sentences yet, not a
* failed init. ZephyrGPSManager owns the rail at runtime via
* chosen { zephcore,gps-power }. */
startup-delay-us = <10000>;
};
@@ -105,6 +113,11 @@
regulator-name = "vfem-enable";
enable-gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>;
regulator-boot-on;
/* Documents the FEM's requirement, but do not rely on it:
* regulator-boot-on sends regulator_common_init() down the
* refcount-only branch, so regulator_delay() never runs and this
* value is inert. Harmless here because the FEM is a passive
* gain block with no bus to probe — nothing addresses it at init. */
startup-delay-us = <1000>;
};
@@ -124,6 +137,12 @@
regulator-name = "tft-pwr-enable";
enable-gpios = <&gpio0 26 GPIO_ACTIVE_HIGH>;
regulator-boot-on;
/* Documents the panel's requirement, but do not rely on it:
* regulator-boot-on sends regulator_common_init() down the
* refcount-only branch, so regulator_delay() never runs and this
* value is inert. The real settle time comes from the ST7735R
* driver's own mipi_dbi_reset() + exit-sleep delay, at
* DISPLAY_INIT_PRIORITY 85 against this rail's 75. */
startup-delay-us = <10000>;
};
@@ -144,7 +144,17 @@
* 3. tcxo_enable (P0.21) — external TCXO for SX1262
*
* These are all regulator-fixed with regulator-boot-on so Zephyr's
* regulator framework brings them up before the SX1262 driver init. */
* regulator framework brings them up before the SX1262 driver init
* REGULATOR_FIXED_INIT_PRIORITY 75 against LORA_INIT_PRIORITY 90.
*
* Ordering is all that guarantee covers. It does NOT mean a rail has
* settled: regulator-boot-on sends regulator_common_init() down the
* refcount-only branch, so regulator_delay() never runs and the
* startup-delay-us below is inert. The SX1262 is safe because its driver
* resets the part (5 ms NRESET pulse + 5 ms wait + BUSY poll) before any
* SPI traffic. Anything put behind these rails that does NOT
* reset-then-wait needs zephyr,deferred-init instead; see
* meshtracker_x1's i2c0 for what that failure looks like. */
pwr_enable: pwr-enable {
compatible = "regulator-fixed";
@@ -125,6 +125,14 @@
regulator-name = "pwr-enable";
enable-gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>;
regulator-boot-on;
/* Documents the LDO's requirement, but do not rely on it:
* regulator-boot-on sends regulator_common_init() down the
* refcount-only branch, so regulator_delay() never runs and this
* value is inert. What actually gives this rail time to settle is the
* priority-30 pin above — every consumer here (QSPI 41, OLED 85,
* SX1262 90) has real boot work between it and the rail, and the
* SX1262 and SSD1315 both reset-then-wait besides. The GPS, which
* does neither, is zephyr,deferred-init for that reason. */
startup-delay-us = <10000>;
};
@@ -285,24 +285,42 @@
pinctrl-1 = <&i2c0_sleep>;
pinctrl-names = "default", "sleep";
/* Sealed enclosure — only these two parts are ever on this bus */
/* Sealed enclosure — only these two parts are ever on this bus, and both
* sit behind the sensor_power switch. NEITHER can be probed at POST_KERNEL.
*
* sensor_power comes up at CONFIG_REGULATOR_FIXED_INIT_PRIORITY (75) and
* both drivers run at 90 — microseconds later, with nothing scheduled in
* between on this board. The node's startup-delay-us does not save them:
* with regulator-boot-on, regulator_common_init() takes the refcount-only
* branch and regulator_delay() never runs. Same trap as flash_power below.
* (vin-supply + regulator_enable() would not help either — that applies
* off-on-delay-us, and only on the 0->1 refcount transition.)
*
* So both nodes are deferred and the app owns their bring-up, by which
* time the rail has been up for seconds:
* SPA06 -> env_sensors_init() (adapters/sensors/ZephyrEnvSensors.cpp)
* DRV2605 -> haptic_init() (helpers/ui/haptic.c)
*
* Do not "simplify" one of these back to a normal probe. An earlier
* revision deferred only the DRV2605, and the SPA06 — which sorts after it
* within POST_KERNEL priority 90, since equal-priority devices order by DT
* dependency ordinal and drv2605@5a sorts before spa06@77 — silently lost
* the settling time it had been borrowing from the DRV2605's failing probe.
* The barometer had "worked" only by that accident, and went dead the day
* the haptic was fixed. */
spa06: spa06@77 {
compatible = "goertek,spa06";
reg = <0x77>;
zephyr,deferred-init;
};
/* Deferred-init so haptic_init() owns the power-up sequence.
*
* Upstream's drv2605_init() spends DRV2605_POWER_UP_DELAY_US *before*
* drv2605_gpio_config() raises en-gpios, then reads the status register
* over I2C immediately after — so the part gets no settling time at all
* between EN rising and its first transaction, and NACKs. Deferring the
* node is what lets us assert EN and wait first; without it the driver
* has already run (and failed) by the time the app gets a say, and
* device_init() would just answer -EALREADY.
*
* Not a rail problem: the SPA06 shares this bus, this rail and this init
* priority and comes up fine. The enable pin is the only difference. */
/* Deferring this one also lets haptic_init() assert EN and wait before the
* first transaction. Upstream's drv2605_init() spends its
* DRV2605_POWER_UP_DELAY_US *before* drv2605_gpio_config() raises en-gpios,
* then reads the status register over I2C immediately after — so the part
* gets no settling time at all between EN rising and being addressed, and
* NACKs. Without the deferral the driver has already run (and failed) by
* the time the app gets a say, and device_init() would answer -EALREADY. */
haptic: drv2605@5a {
compatible = "ti,drv2605";
reg = <0x5a>;
@@ -62,6 +62,14 @@
regulator-name = "vcc3v3-enable";
enable-gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>;
regulator-boot-on;
/* Documents the module's requirement, but do not rely on it:
* regulator-boot-on sends regulator_common_init() down the
* refcount-only branch, so regulator_delay() never runs and this
* value is inert. The real settle time comes from lr20xx_hal_reset(),
* which the driver runs (with two retries, 10 ms apart) before any
* SPI traffic — and at LORA_INIT_PRIORITY 90 against this rail's 75.
* Anything put behind this rail that does NOT reset-then-wait needs
* zephyr,deferred-init instead; see meshtracker_x1's i2c0. */
startup-delay-us = <5000>;
};
@@ -63,6 +63,14 @@
regulator-name = "vcc3v3-enable";
enable-gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>;
regulator-boot-on;
/* Documents the module's requirement, but do not rely on it:
* regulator-boot-on sends regulator_common_init() down the
* refcount-only branch, so regulator_delay() never runs and this
* value is inert. The real settle time comes from the SX126x driver's
* own reset (5 ms NRESET pulse + 5 ms wait + BUSY poll) before any
* SPI traffic, at LORA_INIT_PRIORITY 90 against this rail's 75.
* Anything put behind this rail that does NOT reset-then-wait needs
* zephyr,deferred-init instead; see meshtracker_x1's i2c0. */
startup-delay-us = <5000>;
};
@@ -93,6 +93,14 @@
regulator-name = "lora-pwr-enable";
enable-gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>;
regulator-boot-on;
/* Documents the FEM's requirement, but do not rely on it:
* regulator-boot-on sends regulator_common_init() down the
* refcount-only branch, so regulator_delay() never runs and this
* value is inert. The real settle time comes from the SX126x driver's
* own reset (5 ms NRESET pulse + 5 ms wait + BUSY poll) before any
* SPI traffic, at LORA_INIT_PRIORITY 90 against this rail's 75.
* Anything put behind this rail that does NOT reset-then-wait needs
* zephyr,deferred-init instead; see meshtracker_x1's i2c0. */
startup-delay-us = <10000>;
};
@@ -120,6 +120,14 @@
regulator-name = "lora-pwr-enable";
enable-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
regulator-boot-on;
/* Documents the module's requirement, but do not rely on it:
* regulator-boot-on sends regulator_common_init() down the
* refcount-only branch, so regulator_delay() never runs and this
* value is inert. The real settle time comes from the SX126x driver's
* own reset (5 ms NRESET pulse + 5 ms wait + BUSY poll) before any
* SPI traffic, at LORA_INIT_PRIORITY 90 against this rail's 75.
* Anything put behind this rail that does NOT reset-then-wait needs
* zephyr,deferred-init instead; see meshtracker_x1's i2c0. */
startup-delay-us = <10000>;
};