mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-09-05 11:33:53 +00:00
release note supdate and X1 sensor tuning
This commit is contained in:
@@ -1,198 +1,181 @@
|
||||
# ZephCore 1.17.0-zephcore
|
||||
|
||||
A **hardware release**. A new tracker board lands — the Seeed SenseCAP MeshTracker X1 — and with it the
|
||||
LR2021 radio becomes a real, on-air-validated option instead of bring-up code. Plus GPS diagnostics, an
|
||||
LED master switch, and a batch of receive-path hardening.
|
||||
|
||||
---
|
||||
|
||||
> [!IMPORTANT]
|
||||
> ## Before you upgrade
|
||||
>
|
||||
> **From v1.16.5 – v1.16.8** — clean flash, no re-bond, bonds and data survive.
|
||||
> **From v1.16.5 – v1.16.8** — just flash it. Bonds and data survive, no re-pairing.
|
||||
>
|
||||
> **From v1.16.2 / v1.16.3 / v1.16.4** — clean flash, bonds and data survive. If you are on an
|
||||
> **ESP32-S3 / ESP32-C board** and have *not* yet taken the v1.16.5 update, you still owe the one-time
|
||||
> serial reflash: the app moved to flash offset `0x10000` in v1.16.5, and a board on the old layout
|
||||
> cannot cross that update over WiFi-OTA or the browser flasher — **flash the `-merged.bin` once over
|
||||
> USB/serial.** Affected boards: *Heltec V3 / V4 / V4.3, Station G2, Wireless Tracker / V2, XIAO
|
||||
> ESP32-S3 / C3 / C6, LilyGo T-Lora C6, ThinkNode M9.* Identity, contacts, channels, prefs, and BLE
|
||||
> bonds are preserved. nRF52, classic ESP32 (T-Beam / PICO-D4 / TTGO LoRa32), STM32WL, and native
|
||||
> Linux are unaffected.
|
||||
> **From v1.16.2 – v1.16.4 on an ESP32-S3 / ESP32-C board** — you still owe a one-time **USB/serial
|
||||
> reflash of `-merged.bin`**. The app moved to flash offset `0x10000` in v1.16.5, and a board on the old
|
||||
> layout cannot cross that gap over WiFi-OTA or the browser flasher. Affected: *Heltec V3 / V4 / V4.3,
|
||||
> Station G2, Wireless Tracker / V2, XIAO ESP32-S3 / C3 / C6, LilyGo T-Lora C6, ThinkNode M9.* Your
|
||||
> identity, contacts, channels, prefs and bonds are preserved. Everything else (nRF52, classic ESP32,
|
||||
> STM32WL) upgrades normally.
|
||||
>
|
||||
> **From v1.16.1 or older** — flash it; on first boot it clears BLE bonds automatically (identity,
|
||||
> contacts, channels, prefs preserved). Re-bond your phone/desktop once.
|
||||
> **From v1.16.1 or older** — flash it; BLE bonds are cleared on first boot, so re-pair your phone once.
|
||||
> Identity, contacts, channels and prefs are kept.
|
||||
>
|
||||
> **Coming from Arduino MeshCore** — flash it; auto-formats on first boot (new identity, clean storage).
|
||||
> **Coming from Arduino MeshCore** — flash it; storage auto-formats and you get a new identity.
|
||||
>
|
||||
> **ThinkNode M6 owners: this release stops using the external flash chip, because the board does not
|
||||
> have one.** Contacts, channels and prefs move to internal flash on first boot. See the M6 section.
|
||||
> **ThinkNode M6 owners** — this release stops using the external flash chip, because the board doesn't
|
||||
> actually have one. Contacts, channels and prefs move to internal flash on first boot.
|
||||
>
|
||||
> **Repeater and room-server telemetry no longer hands out your GPS position to non-admins.**
|
||||
> If you were relying on public position reporting from a fixed node, set the location in prefs and
|
||||
> advertise it instead.
|
||||
> **Repeater / room-server telemetry no longer shares GPS position with non-admins.** If you were
|
||||
> relying on that, set the location in prefs and advertise it instead.
|
||||
>
|
||||
> **ESP32 light sleep (new in 1.16.8) is still awaiting hardware validation.** It remains on by default
|
||||
> for Heltec repeaters, and their USB CLI still stops answering 10 minutes after boot as a result —
|
||||
> reconnecting the terminal resets the node and gives you another window. Rebuild with `-DCONFIG_PM=n`
|
||||
> to take it out.
|
||||
> **ESP32 light sleep** stays on by default for Heltec repeaters. It has now been confirmed working on a
|
||||
> Heltec V4 — but only that one board so far. Side effect: the USB CLI stops answering ~10 minutes after
|
||||
> boot; reconnect the terminal to get another window. Rebuild with `-DCONFIG_PM=n` to remove it.
|
||||
|
||||
---
|
||||
|
||||
A **hardware and receive-path release**. A new tracker board lands (Seeed SenseCAP MeshTracker X1, the
|
||||
first LR2021 target with real hardware behind it), the LR2021 gains multi-SF receive, the LR11xx and
|
||||
LR20xx receive gates get the same stuck-state bound the SX126x got in 1.16.x, GPS module configuration
|
||||
grew a diagnostics path and a dynamic-model setting, and the Zephyr pin moves to 4.4.2 final.
|
||||
## New board — Seeed SenseCAP MeshTracker X1
|
||||
|
||||
## Highlights
|
||||
`meshtracker_x1` — nRF52840 + **Semtech LR2021**, 863–928 MHz / 22 dBm, dual-band L1+L5 GNSS,
|
||||
barometer, haptic motor, RGB LED, buzzer, 1100 mAh battery, 8 MB external flash and an on-board RTC.
|
||||
Companion, repeater and room server all build and run.
|
||||
|
||||
### New board — Seeed SenseCAP MeshTracker X1
|
||||
It is essentially a T1000-E with a different radio, so most of the board reuses well-travelled code.
|
||||
What's new:
|
||||
|
||||
`meshtracker_x1` — nRF52840 + **Semtech LR2021**, 863–928 MHz / 22 dBm, dual-band L1+L5 Airoha GNSS,
|
||||
SPA06-003 barometer, DRV2605L haptic motor, RGB LED, buzzer, 1100 mAh high-voltage LiPo, 8 MB QSPI
|
||||
flash and an on-board RTC. Companion, repeater and room-server all build.
|
||||
- **Barometer support** — a from-scratch SPA06-003 driver. Pressure and temperature are meant to show
|
||||
up in normal environment telemetry. **Not yet confirmed on hardware.**
|
||||
- **Haptic notifications.** The buzzer setting became a four-way notification mode:
|
||||
`set buzzer 0|1|2|3` = silent / sound+vibrate / vibrate / sound, and the 3-tap button cycles them.
|
||||
Boards without a motor keep the plain on/off toggle. **The X1's motor and buzzer are not yet
|
||||
confirmed working** — see Known limitations.
|
||||
- **8 MB external flash** for contacts, channels and the blob cache, plus the on-board RTC.
|
||||
|
||||
Hardware-wise it is a T1000-E with the radio swapped, so the LoRa SPI pins, button, buzzer, battery
|
||||
divider and the whole GNSS control pin set map straight onto the existing T1000-E paths. What is new
|
||||
on this board:
|
||||
## The LR2021 radio is now validated on hardware
|
||||
|
||||
- **SPA06-003 barometer driver, written from scratch** (`adapters/sensors/spa06.c` plus its binding) —
|
||||
no upstream Zephyr driver exists. It lives in the app tree rather than the Zephyr tree, so it needs
|
||||
no patch and survives `west update`. Pressure and temperature are reported through the normal
|
||||
environment-telemetry path.
|
||||
- **Haptic notifications.** `helpers/ui/haptic.c` wraps Zephyr's `ti,drv2605`, and the buzzer setting
|
||||
became a four-state notification mode — `set buzzer 0|1|2|3` = silent / sound+vibrate / vibrate /
|
||||
sound, with the 3-tap button cycling through them. Boards with no motor keep a plain on/off toggle.
|
||||
The value rides in the existing `buzzer_quiet` byte, so there is no prefs migration.
|
||||
- **8 MB of QSPI flash as `/ext`** for contacts, channels and the blob cache, and the on-board
|
||||
YSN8900 RTC on its own I²C bus, discovered and BCD-validated at boot.
|
||||
Previously this driver was marked experimental with no board behind it. It has now had a full audit and
|
||||
an on-air validation pass on the X1 — transmit, receive, listen-before-talk and RX duty cycle are all
|
||||
confirmed working. Highlights of what changed to get there:
|
||||
|
||||
> [!NOTE]
|
||||
> The **LR2021 radio path is still bring-up code.** The driver is ZephCore's own, and only one LR2021 board
|
||||
> has been validated on air yet. Treat X1 radio behaviour as untested; the rest of the board (GNSS,
|
||||
> sensors, storage, UI, power) is on well-travelled paths.
|
||||
- **The chip's firmware patch is now loaded at boot** (Semtech "highly recommends" it; without it the
|
||||
chip runs unpatched). The `PRAM loaded:` log line is proof it took.
|
||||
- **Listen-before-talk runs on the chip itself** — it checks the channel and transmits in one shot with
|
||||
no round-trip to the CPU. Longer transmissions automatically fall back to the classic route.
|
||||
- **RX duty cycle (sniff mode) works**, with the sleep/wake timing derived from the datasheet rather
|
||||
than estimated.
|
||||
- **Several datasheet-conformance bugs fixed**, the most user-visible being a receive filter that was
|
||||
not restored after transmitting — a node would silently stop hearing any packet longer than its own
|
||||
last transmission.
|
||||
|
||||
### LR2021 multi-SF receive — `set extra.sf`
|
||||
`promicro_lr2021` still builds but remains untested (the module was destroyed during bring-up).
|
||||
|
||||
The LR2021 can demodulate up to **three extra spreading factors at once**, alongside the configured
|
||||
one, on the same bandwidth. One repeater can therefore serve several SF communities without splitting
|
||||
the site, and which SF a packet arrived on is a chip-side readout rather than an inference.
|
||||
## LR2021 multi-SF receive — `set extra.sf`
|
||||
|
||||
The LR2021 can listen on **up to three extra spreading factors at once**, on the same bandwidth. One
|
||||
repeater can serve several SF communities without splitting the site.
|
||||
|
||||
```
|
||||
set extra.sf 9 10 # receive SF9 and SF10 in addition to the configured SF
|
||||
set extra.sf 9 10 # also receive SF9 and SF10
|
||||
get extra.sf # -> 9,10
|
||||
set extra.sf off # back to single-SF receive
|
||||
set extra.sf off # back to single-SF
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **Receive only, and the bridge it creates is one-way.** Transmission always uses the single
|
||||
> configured `sf`, and every detector shares one bandwidth — multi-SF, not multi-channel.
|
||||
> **Receive only — the bridge it creates is one-way.** Transmission always uses your configured `sf`.
|
||||
> A node on `sf 7` with `extra.sf 8` hears and forwards SF8 traffic, but forwards it at SF7. So traffic
|
||||
> flows **SF8 → SF7 and never back**. Adverts and flood traffic propagate fine; an SF8 node's direct
|
||||
> messages get delivered but its ACKs never arrive, so it retries to its limit every time.
|
||||
>
|
||||
> A node running `sf 7` with `extra.sf 8` hears SF8 traffic and *does* forward it, but the forward goes
|
||||
> out at SF7. Traffic therefore moves **SF8 → SF7 only, and nothing comes back**. Adverts and one-way
|
||||
> flood traffic propagate fine; an SF8 node's direct messages get delivered but its ACKs never arrive,
|
||||
> so it retries to its limit every time. That is worth weighing before deploying it next to a busy
|
||||
> slow-SF island.
|
||||
>
|
||||
> The direction cannot be reversed. Because every extra SF must be *greater* than `sf`, the main SF is
|
||||
> always the lowest in the set, and TX always uses the main SF — so a side-detector node is always
|
||||
> high-SF-in / low-SF-out. Two of them back to back point the same way; **no configuration carries
|
||||
> SF7 → SF8.** Think of this as a collector that pulls slower-SF stragglers into a fast mesh, not as a
|
||||
> link between two SF islands. A genuine bidirectional bridge needs two nodes joined by a non-LoRa
|
||||
> link, or one node time-slicing its radio config — neither of which this feature provides.
|
||||
> There is no configuration that reverses this — extra SFs must always be *higher* than your main SF,
|
||||
> and TX always uses the main SF. Treat it as a collector that pulls slower-SF stragglers into a fast
|
||||
> mesh, not as a link between two SF islands.
|
||||
|
||||
The chip's constraints are enforced in the driver, so an accepted set is a valid one: every extra SF
|
||||
must be **greater** than the configured `sf`, all distinct, highest−lowest ≤ 4, and at BW ≥ 500 kHz at
|
||||
most two (only one when `sf` ≥ 10). The setting is persisted and re-applied on every RX entry; a set
|
||||
that no longer fits after an `sf` or `bw` change is refused at boot and logged rather than silently
|
||||
half-applied. `Error: unsupported` on every non-LR2021 radio.
|
||||
The chip's rules are enforced for you, so anything accepted is valid: extra SFs must be higher than
|
||||
`sf`, distinct, within 4 of each other, and at BW ≥ 500 kHz at most two. A set that no longer fits
|
||||
after you change `sf` or `bw` is refused at boot and logged. `Error: unsupported` on other radios.
|
||||
|
||||
One thing worth knowing about how this interacts with listen-before-talk: the chip's SF constraint for
|
||||
**CAD** is the exact inverse of the one for **receive** — CAD wants the main SF above the side SFs,
|
||||
receive wants it below. Both cannot hold at once, so the driver switches side detectors off for each
|
||||
LBT CAD and restores them when RX re-arms. That costs two extra SPI commands per transmission and
|
||||
needs no configuration. (Arduino MeshCore hit the same wall from the other direction, as a `-706`
|
||||
error on the receive restart after a hardware CAD.)
|
||||
## No more silent mute-until-reboot
|
||||
|
||||
### The LR11xx receive gate can no longer wedge
|
||||
All four radio drivers gate transmission on "am I currently receiving?" — and on the LR11xx and LR2021
|
||||
that answer could get stuck true forever if a packet header arrived but the packet never completed.
|
||||
The node would keep receiving and never transmit again, with nothing in the log pointing at it. Both
|
||||
now bound that state with a generous deadline (max-length packet airtime + margin) and log a warning if
|
||||
it ever fires. The SX126x got the same fix in 1.16.x.
|
||||
|
||||
The driver reports "we are currently receiving" from the chip's latched PREAMBLE_DETECTED and
|
||||
HEADER_VALID bits, and that answer is what gates every transmission. Neither bit is self-clearing:
|
||||
they are dropped only by a terminal interrupt or an RX restart, and in continuous receive there is no
|
||||
symbol timer, so neither is guaranteed to arrive. A header whose packet never completes would pin the
|
||||
gate true **forever** — the node keeps receiving but never transmits again, until reboot, with nothing
|
||||
in the log pointing at it.
|
||||
Related: an error-only interrupt on the LR2021 no longer triggers a receive restart that regenerates
|
||||
the same error, which on the X1 could cost ~88 ms of deafness and a hardware reset.
|
||||
|
||||
This is the same class of fault the SX126x driver was hardened against earlier (`0013`), and it is now
|
||||
closed on the LR11xx:
|
||||
## Adaptive CAD now uses only levels the chip can distinguish
|
||||
|
||||
- **LR11xx (LR1110)** already had the preamble grace; it gains the payload deadline.
|
||||
- **LR20xx (LR2021)** still has an unbounded gate — a bare OR of the two bits. The bound was written
|
||||
for it too, then pulled back out: it landed alongside a duty-cycle rework that regressed receive on
|
||||
the MeshTracker X1, and the whole group was reverted to the last configuration confirmed working on
|
||||
hardware. It will return once the LR2021 receive path is settled.
|
||||
The auto-tuning channel-detection threshold walks a range of levels, but where those levels fell
|
||||
outside the radio's own hardware limits, several of them programmed the *identical* setting — so the
|
||||
tuner was comparing physically identical rungs and reading noise as a trend. The usable window is now
|
||||
derived per-driver, so every level is a distinct configuration and the `pk` value in `get cad` is what
|
||||
the chip actually got. This mattered most on the LR2021.
|
||||
|
||||
The deadline is the airtime of a maximum-length packet at the current SF/BW at coding rate 4/8 with
|
||||
LDRO pinned on, plus 25% and 100 ms — deliberately generous, because this is a stuck-state safety net
|
||||
and releasing early would start a transmission on top of a packet that is still arriving. When it
|
||||
fires it logs a warning, which is the tripwire that would prove the fault happens in the field; it has
|
||||
never been reproduced on a bench.
|
||||
## Virtual-contact fixes (companion)
|
||||
|
||||
### ThinkNode M6 — the external flash is gone, because the chip is not there
|
||||
The built-in admin chat contact got three fixes worth knowing about:
|
||||
|
||||
The M6 routes a QSPI bus and its datasheet lists an MX25R1635F, so ZephCore declared the part, gave it
|
||||
a power-enable regulator, and mounted it as `/ext`. Upstream Arduino MeshCore has since dropped the
|
||||
same assumption after hitting it on real hardware — *"M6 doesn't have flash chip available, so
|
||||
companion roles fail to start"* — which means companion builds most likely never came up on this board
|
||||
here either.
|
||||
- **Deleting it in the app is now temporary.** It comes back on the next app connect. Previously a
|
||||
"purge all contacts" in the app permanently disabled the feature with no way back except the USB CLI.
|
||||
The only durable off switch is `set v.contact off` on the node.
|
||||
- **Favourite star and telemetry permissions stick** across reconnects and reboots.
|
||||
- **"Last seen" no longer grows forever**, and the contact re-syncs to the app properly instead of
|
||||
being sent exactly once ever.
|
||||
|
||||
The flash node, its partition, the enable regulator and the `/ext` mount are removed. Everything now
|
||||
lives on internal flash: identity, prefs, contacts and channels all on `/lfs`. This is the second
|
||||
ThinkNode M6 assumption disproved by upstream bench data in as many releases — the GPS REINIT pin was
|
||||
the first — so the board is worth treating as under-verified generally.
|
||||
## GPS: dynamic model and a diagnostics readout
|
||||
|
||||
### GPS module configuration: dynamic model, and a diagnostics readout
|
||||
- **`CONFIG_ZEPHCORE_GPS_NAV_MODE`** sets the dynamic model on CASIC modules (Quectel L76K / L76KB,
|
||||
Air530Z) — stationary for repeaters and room servers, automotive otherwise. Worth setting: **the
|
||||
model is stored in the module** and survives reflashing the host, so a second-hand module can arrive
|
||||
stuck in an airborne profile and behave oddly on a rooftop.
|
||||
- **`set gps diag on` / `get gps diag`** shows what the last module-configuration attempt actually did:
|
||||
which path ran, bytes sent, and tracked satellites per constellation. Not persisted.
|
||||
|
||||
Two additions on the GNSS side, both aimed at the thing that is hardest to see from outside: whether
|
||||
the module actually accepted what the firmware sent it.
|
||||
|
||||
- **`CONFIG_ZEPHCORE_GPS_NAV_MODE`** sets the dynamic model on CASIC-family modules (Quectel L76K /
|
||||
L76KB, Air530Z) — stationary by default for repeaters and room servers, automotive otherwise. This
|
||||
is worth setting rather than leaving alone, because **the model is stored in the module** and
|
||||
survives reflashing the host: a module pulled from another device can arrive stuck in an airborne
|
||||
profile and behave oddly on a rooftop.
|
||||
- **`set gps diag on` / `get gps diag`** reports what the last module-configuration attempt actually
|
||||
did: which path ran, how many bytes were sent, and tracked satellites per constellation. Not
|
||||
persisted — it clears on reboot.
|
||||
|
||||
### `set leds on|off` — one master switch
|
||||
## `set leds on|off` — one master switch
|
||||
|
||||
A single persisted switch for every LED on the node, applied live: heartbeat, unread-message and LoRa
|
||||
TX-activity LEDs, plus the message and shutdown flashes. It works on every role, including headless
|
||||
repeaters where the TX LED is the only one that ever lights. The display backlight is not covered —
|
||||
that is the separate UI brightness setting.
|
||||
TX-activity LEDs, plus the message and shutdown flashes. Works on every role, including headless
|
||||
repeaters. Display backlight is separate (that's the UI brightness setting).
|
||||
|
||||
### Repeater and room-server GPS position is now admin-only
|
||||
## Repeater / room-server GPS position is admin-only
|
||||
|
||||
Telemetry from a repeater or room server used to include the node's GPS position for any requester
|
||||
holding the location permission. It is now released to **admins only**. A fixed node that should
|
||||
publish its position can still do so through prefs and adverts, which is the deliberate, visible way
|
||||
to share it.
|
||||
Telemetry from a repeater or room server used to hand out its GPS position to anyone holding the
|
||||
location permission. It now goes to **admins only**. A fixed node that should publish its position can
|
||||
still do so through prefs and adverts.
|
||||
|
||||
## ThinkNode M6 — external flash removed
|
||||
|
||||
The M6's datasheet lists a flash chip that the board doesn't have, which almost certainly meant
|
||||
companion builds never came up on it. The flash node, partition, power regulator and `/ext` mount are
|
||||
gone; identity, prefs, contacts and channels now all live on internal flash. This is the second M6
|
||||
datasheet claim disproved by real hardware in as many releases, so treat this board as under-verified
|
||||
generally.
|
||||
|
||||
## Other changes
|
||||
|
||||
- **Zephyr pinned to 4.4.2 final** (was a 4.4.2 pre-release commit).
|
||||
- **ESP32: the user button is now a light-sleep wake source** on boards using the shared PM overlay, so
|
||||
a sleeping node wakes on a button press rather than only on a received packet.
|
||||
- **LR2021 SPI HAL resynced with RadioLib**, and the driver picked up a batch of datasheet-conformance
|
||||
fixes: the TCXO start-up deadline is counted in 32 MHz periods rather than RTC ticks (the previous
|
||||
unit turned a 5 ms allowance into 5 µs and guaranteed a start-up error), front-end calibration is
|
||||
issued in its full three-slot form, the DIO interrupt mask is narrowed to the events the handler
|
||||
actually services, the CAD detection thresholds now come from the datasheet's 4-symbol row to match
|
||||
the 4-symbol window actually used, and the receive payload-length filter is restored after each
|
||||
transmission — without that, a node silently stopped hearing any packet longer than its own last
|
||||
transmission.
|
||||
- **Adaptive-CAD and noise-floor sampling** picked up further fixes in the SX126x patch set.
|
||||
- **Zephyr pinned to 4.4.2 final.**
|
||||
- **ESP32: the user button now wakes the node from light sleep** on boards using the shared PM overlay
|
||||
— previously only an incoming packet would.
|
||||
- **`get freqerr`** (LR2021 only) reports carrier frequency error measured on received packets. Purely
|
||||
diagnostic — nothing acts on it, and small values are the expected answer.
|
||||
- **X1 external flash runs in quad mode**, and the LR2021 SPI layer was resynced with RadioLib.
|
||||
- Further adaptive-CAD and noise-floor sampling fixes in the SX126x driver.
|
||||
|
||||
## Known limitations
|
||||
|
||||
- **LR2021 is not hardware-validated.** No LR2021 board has been confirmed on air. The X1's radio path
|
||||
and everything in the multi-SF feature above are code-complete and build-verified only.
|
||||
- **ESP32 light sleep is not hardware-validated** and remains on by default for Heltec repeaters. The
|
||||
failure mode to rule out is a deaf repeater; check the boot log for `Pin N is not wakeup capable`.
|
||||
- **ThinkNode M3 / M6 GPS fixes are not hardware-confirmed** — both were derived from upstream bench
|
||||
data on their respective boards, not measured here.
|
||||
- **ESP32 light sleep is validated on one board only** — a Heltec V4, where it works. It is on by
|
||||
default for all Heltec repeaters, so the other variants are running it untested. The failure mode to
|
||||
watch for is a deaf repeater; check the boot log for `Pin N is not wakeup capable`.
|
||||
- **ThinkNode M3 / M6 GPS fixes are not confirmed here** — both came from upstream bench data on those
|
||||
boards, not measured on ours.
|
||||
- **`promicro_lr2021` is untested.** The X1 is the only validated LR2021 board.
|
||||
- **The X1's barometer, haptic motor and buzzer are not validated.** The radio, GNSS, storage, UI and
|
||||
power paths are; these three are not. The haptic driver is currently failing to come up at boot
|
||||
(`haptic drv2605@5a not ready`) and is under investigation.
|
||||
- **The X1's on-board RTC does not hold time across a reboot.** Its supply is switched by an MCU pin,
|
||||
which goes high-impedance on reset, so the chip raises its power-loss flag and the clock is re-set
|
||||
from the next GPS/app/CLI sync. Time is still correct in normal operation; it just isn't preserved
|
||||
across a restart.
|
||||
|
||||
@@ -291,11 +291,24 @@
|
||||
reg = <0x77>;
|
||||
};
|
||||
|
||||
/* 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. */
|
||||
haptic: drv2605@5a {
|
||||
compatible = "ti,drv2605";
|
||||
reg = <0x5a>;
|
||||
actuator-mode = "LRA";
|
||||
en-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
|
||||
zephyr,deferred-init;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -14,11 +14,44 @@ LOG_MODULE_REGISTER(zephcore_haptic, CONFIG_ZEPHCORE_SENSORS_LOG_LEVEL);
|
||||
|
||||
#if DT_HAS_COMPAT_STATUS_OKAY(ti_drv2605)
|
||||
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
#include <zephyr/drivers/haptics.h>
|
||||
#include <zephyr/drivers/haptics/drv2605.h>
|
||||
|
||||
#define HAPTIC_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(ti_drv2605)
|
||||
|
||||
#if DT_PROP(HAPTIC_NODE, zephyr_deferred_init)
|
||||
/* Wake a deferred-init DRV2605 and run its init here, where the part's supply
|
||||
* rail has been up since boot instead of microseconds.
|
||||
*
|
||||
* The enable pin is asserted *before* device_init() on purpose. Upstream's
|
||||
* drv2605_init() spends its DRV2605_POWER_UP_DELAY_US before it configures the
|
||||
* GPIOs, so EN rises and the very next thing it does is read the status
|
||||
* register over I2C — no settling time at all between the two. Raising EN
|
||||
* ourselves and waiting turns that race into a plain sequence; the driver's own
|
||||
* gpio_pin_configure_dt() to OUTPUT_ACTIVE afterwards is then a no-op. */
|
||||
static void haptic_deferred_init(const struct device *dev)
|
||||
{
|
||||
static const struct gpio_dt_spec en =
|
||||
GPIO_DT_SPEC_GET_OR(HAPTIC_NODE, en_gpios, {0});
|
||||
int rc;
|
||||
|
||||
if (en.port != NULL && gpio_is_ready_dt(&en)) {
|
||||
if (gpio_pin_configure_dt(&en, GPIO_OUTPUT_ACTIVE) == 0) {
|
||||
/* 250 us is the datasheet figure; 1 ms costs nothing on a
|
||||
* one-shot boot path and covers the rail as well. */
|
||||
k_msleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
rc = device_init(dev);
|
||||
LOG_DBG("haptic deferred init: rc=%d ready=%d", rc,
|
||||
(int)device_is_ready(dev));
|
||||
}
|
||||
#else
|
||||
static inline void haptic_deferred_init(const struct device *dev) { ARG_UNUSED(dev); }
|
||||
#endif
|
||||
|
||||
static const struct device *haptic_dev;
|
||||
static bool haptic_enabled = true;
|
||||
|
||||
@@ -36,6 +69,9 @@ int haptic_init(void)
|
||||
int rc;
|
||||
|
||||
haptic_dev = DEVICE_DT_GET(HAPTIC_NODE);
|
||||
if (!device_is_ready(haptic_dev)) {
|
||||
haptic_deferred_init(haptic_dev);
|
||||
}
|
||||
if (!device_is_ready(haptic_dev)) {
|
||||
/* The DRV2605 driver logs its own reason at debug level, so say
|
||||
* enough here to tell "chip absent" from "bus down". */
|
||||
|
||||
Reference in New Issue
Block a user