Repository navigation
Conversation
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
No unresolved blocking issues were identified.
Review effort: Lite
Findings: None
What changed in this PR
Updates RV3028 persistence to use an A0h unset marker and restrict writes to years 2000–2099.
Changes:
- Uses a marker followed by one seven-byte time burst.
- Rejects out-of-range years and handles unset markers.
- Updates RTC API and devicetree documentation.
| File | Description |
|---|---|
zephcore/dts/bindings/rtc/zephcore,rtc-i2c.yaml |
Documents RV3028 marker and year limits. |
zephcore/adapters/clock/ZephyrRTCDiscover.h |
Updates the RTC contract documentation. |
zephcore/adapters/clock/ZephyrRTCDiscover.c |
Implements marker writes, detection, retries, and year validation. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
The RV3028 time write set year 00h, burst-wrote 00h-05h, then wrote the real year, so a write cut short left year 2000 and the next boot took no time from it. That split the write into separate accesses against the manual's one-access rule (Application Manual Rev 1.4, 4.5), relying on the Seconds write restarting the prescaler, and used a real date as the "not set" mark. The write now sets 06h to A0h, which is not BCD, then writes all seven registers 00h-06h in one burst, year last, inside the existing BSF bracket. The chip keeps each byte as it is acknowledged, so a write cut between the mark and the year byte leaves the mark. On read at an rv3028-eeprom-config descriptor, a year of A0h-FEh gives no time: a New Year counts a left mark on (A0h to A1h, A9h to B0h). FFh stays a failed read, since a read cut short returns 1s and the year is the last byte. The save also refuses a year outside 2000-2099, for every chip, because ZephCore writes the year as two BCD digits and no century bit (the DS3231 and PCF8563 century bits are written as 0 and masked off on read). It encoded y % 100, so a time before 2000, accepted by a node whose clock had no time yet, was stored as a year near the end of the century: `time 900000000` (1998) was restored at the next boot as 2098, past the 2025 floor. At an rv3028-eeprom-config descriptor a refused year is marked A0h instead, so the next boot takes no time rather than the older time the chip still holds; the mark gets the BSF bracket and the same 5 s repeat as a time write, sharing its 13-attempt cap, and a repeat whose run-on time leaves 2000-2099 marks instead. Other chips keep their older time. The header contract and the binding describe both; the Kconfig help and ARCHITECTURE.md describe the 2000-2099 range, and ARCHITECTURE.md the refused-year mark. The same write order, year handling and 2000-2099 range are used by Zephyr and MeshCore for the RV3028; the three are kept consistent in behaviour. Link: zephyrproject-rtos/zephyr#121389 Link: meshcore-dev/MeshCore#3421 Link: liquidraver#98 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6e7f4ff to
535a37c
Compare
|
Thanks for the work on these. I've gone through #103 and #104 and I'd like to take much less of both, to keep this file as small as it can be. #103: keep only the year-range check
This is the real bug: a pre-2000 time is stored as #103: drop
#104: replace with a much smaller version I'd take what MeshCore does: clear the RV3028's 12_24 bit once at boot, before the time is read, and let the chip convert its own hours.
Could you cut #103 down to the above and rework #104 this way (or close it and open a fresh one)? |
|
Thanks. Done as two new PRs, so this one stays as the record of the version coordinated with Zephyr and MeshCore, whose PRs link here:
Closing. |
A follow-up to #98. The Zephyr and MeshCore counterparts are zephyrproject-rtos/zephyr#121389 and meshcore-dev/MeshCore#3421.
Code links are permalinks:
devata2e8d5f, this PR's commit535a37c.Cross-project consistency. This change is part of a coordinated update to RV3028 time handling across three codebases, kept consistent in behaviour: Zephyr (zephyrproject-rtos/zephyr#121389), MeshCore (meshcore-dev/MeshCore#3421) and ZephCore (#103, a follow-up to #98). It replaces the rule all three adopted on 2026-10-05: zero the year, write 00h-05h, then write the year. That rule split the time write into separate accesses against the manual's one-access rule (RV-3028-C7 Application Manual Rev 1.4, §4.5), with the argument that the Seconds write restarts the prescaler, so no tick lands before the year write. It also used year 00 as the "not set" marker, which made 2000-01-01 unusable as a date. Hardware tests on an RV-3028-C7 then showed three things: a write cut short by an interface reset keeps the bytes already acknowledged and leaves the rest unchanged (tested with the 950 ms bus timeout, §4.5.1); the year register keeps a non-BCD value while the clock counts; and a New Year rollover counts a left mark up like a BCD value (A0h to A1h, A9h to B0h), so it stays a non-BCD year. The shared rule is now: write 06h := A0h, then one 7-byte burst 00h-06h, and read a year of A0h-FEh as not set and FFh as a failed read. Retry policy and never-set detection (PORF) are left to each project.
All three projects also take only years 2000-2099 on a write, refusing any other year before touching the chip, since a BCD-encoded year outside that range either aliases into it or, for 2100, equals the A0h mark.
The change
At a descriptor with
rv3028-eeprom-config(the RAK4631's RAK12002):rv3028_write_time()writes 06h :=A0hon its own, then one 7-byte burst to 00h-06h, year last. It replaces year00h, a 6-byte burst, then the year. The BSF bracket around it and the retry (every 5 s, 13 attempts) are unchanged.rtc_probe(), a year ofA0h-FEhlogstime not yet set (year A0h)and takes no time. The chip stays the write-back target.FFhstill falls to "time unreadable". Before this change, any non-BCD year logged "time unreadable", so behaviour is the same and only the log line differs.For every chip:
rtc_time_block()now fails outside 2000-2099, andzephcore_rtc_save()writes nothing then. ZephCore writes the year as two BCD digits and no century bit, and it encodedy % 100. So a time before 2000, accepted by a node whose clock had no time yet, was stored as a year near the end of the century:time 900000000(1998) was restored at the next boot as 2098, past the 2025 floor. Other chips keep their older time on a refusal.rv3028-eeprom-configdescriptor,rv3028_mark_year()writes the A0h mark instead, so the next boot takes no time rather than the chip's older one. The mark gets the BSF bracket and the same 5 s repeat as a time write, sharing its 13-attempt cap, and a repeat whose run-on time leaves 2000-2099 marks instead. Marking on a refusal is ZephCore's own choice: Zephyr returns-EINVALwith no side effects, and MeshCore keeps the old time.Unchanged: the 2025 floor, so a power-on-reset chip (2000-01-01) still gives no time, and PORF: no time is taken while it is set, and only a confirmed time write clears it.
The header contract and the
zephcore,rtc-i2cbinding describe both, kept to the length of the RTC comments after9d6b21a(comment diet vol.2). The Kconfig help anddocs/ARCHITECTURE.mdnow say the RTC is written only for a time within 2000-2099, andARCHITECTURE.mdthat an RV3028 withrv3028-eeprom-configmarks its year unset instead.Testing
RAK4631 + RAK12002, repeater debug builds on
dev9bb7ccf(Zephyr74b7173), with this PR's code; rebased ontoa2e8d5fsince, with comment-only changes and a clean build:RTC rtc-rv3028@52: restored 2026-10-06 15:53:27 UTC.time <now>thenrebootrestored the set time.time <now>gavetime write not confirmed, repeating every 5 s, thennot confirmed after 13 tries. Afterreboot:rtc-rv3028@52 present, time not yet set (year A0h).time not yet set (year A0h)at boot. Thentime <now>andreboot:restored 2026-10-06 15:59:40 UTC, so the one-burst write clears the mark.time outside 2000-2099 not written, year marked unset. This PR then booted withtime not yet set (year A0h), and a realtime <now>plusrebootrestored16:43:03 UTC.Known wording point: the read-side comment says "A0h-FEh holds the A0h mark". Only A0h is the mark as written; A1h-F9h are it counted on by a New Year, and the code rejects the whole range either way.
Iteration history and review: ptr727#50.
🤖 Generated with Claude Code