The RV3028 backup switchover (and trickle charger) that AutoDiscoverRTCClock::begin() turns on is lost at the next midnight, and the same write overwrites a factory frequency-calibration bit. Proposed fix: #3545. Confirmed on hardware, before and after; see Evidence.
References used throughout:
- The manual: RV-3028-C7 Application Manual, Micro Crystal, Rev. 1.4, November 2021, from the Documents section of the product page: https://www.microcrystal.com/en/products/real-time-clock-rtc-modules/rv-3028-c7. Every "§" section number and "p." page number below is that document's.
- The code: upstream
dev at 3e3150c8 (AutoDiscoverRTCClock is unchanged since fad0ffb7, where the before-fix tests ran).
- The RTC library: Melopero RV3028 Arduino library, tag
1.2.0, the version MeshCore builds against.
src/helpers/AutoDiscoverRTCClock.cpp L38-L39:
rtc_rv3028.writeToRegister(0x35, 0x00);
rtc_rv3028.writeToRegister(0x37, 0xB4); // Direct Switching Mode (DSM): when VDD < VBACKUP, switchover occurs from VDD to VBACKUP
Melopero's writeToRegister() is a plain I2C register write, so these change only the RAM mirror of two EEPROM-backed configuration registers.
1. The setting reverts at the next midnight
- §3.7, Control 1 (0Fh), bit EERD, p. 23. With EERD = 0, the default: "All data in the Configuration Registers are refreshed by the data stored in the EEPROM each 24 hours, at date increment (at the beginning of the last second before midnight)." §4.6.2 (p. 54) says the same.
- §4.6.9, p. 57. "To perform certain tests, it is sufficient to use only the RAM mirror. But the new, changed configurations are lost as soon as a refresh occurs (POR refresh, Automatic refresh or Refresh by software)."
- §3.15.6, EEPROM Backup (37h), p. 39. BSM = 00 ("Switchover Disabled") and TCE = 0 are the default values on delivery.
- §7.3, p. 105. The vendor's own rechargeable-backup circuit says: "Power Management settings have to be stored in EEPROM for permanent configuration".
On a part whose EEPROM still holds the factory value, the switchover and trickle charging enabled at boot turn off at the first midnight after boot, and stay off until the next reboot. A power cut after that midnight loses the time, and the supercapacitor stops being charged. That covers any repeater that stays up for more than a day.
The choice of mode is right. DSM with the trickle charger is what §7.3 (p. 105) specifies for a capacitor: "DSM Backup Switchover Mode for capacitors (or LSM for rechargeable battery)". What is missing is the EEPROM store.
2. 0xB4 overwrites the factory frequency calibration
Bit 7 of 37h is EEOffset[0], the LSB of the factory-calibrated frequency offset (§3.15.6, p. 39). §7.3 (p. 105) shows that bit as "0/1", meaning leave it as it is. Writing the whole byte forces it to 1. On a part calibrated with 0 there, that shifts the trim by one step until the next refresh: 0.9537 ppm per step (§3.15.5, p. 38). A fix that stored 0xB4 to EEPROM as-is would make that shift permanent.
#3545 stores the configuration in EEPROM. Its body has the full procedure, with permalinks.
- Sequence. It follows §3.15.6 (p. 39), which says BSM must be 00 or 10 for any EEPROM read or write:
- EERD = 1, then wait for EEbusy (§4.6.7, p. 56).
- Hold BSM = 00 in RAM.
- Compare each config byte against the EEPROM with a single-byte read (§4.6.6, p. 55), and write only the bytes that differ with a single-byte write (§4.6.5, p. 55). Only CLKOE in 35h, and TCE, FEDE, BSM and TCR in 37h, are touched.
- A closing Refresh (§4.6.4, p. 54) restores the stored switchover. Read it back, then clear EERD.
- What it never writes. The factory calibration bits, 37h bit 7 and 36h.
- What this issue first suggested instead. A Refresh plus a whole-block Update (§4.6.3, p. 54) with BSM live, as Zephyr's
drivers/mfd/mfd_rv3028.c and Micro Crystal's Linux driver do. §3.15.6 was chosen instead, after testing on two boards found no spurious switchover either way. Only the §3.15.6 sequence stays valid when the backup sits above VDD, and it never rewrites the 36h trim.
Evidence
All power cuts were done by hand, with USB unplugged and no battery fitted. The hardware is RAK4631 + RAK12002 boards.
MeshCore, on a part whose EEPROM still held factory values. A throwaway diagnostic CLI (test/rv3028-diag) stepped the RTC to 23:59:50, so midnight passed in seconds. Full table, with the commit each test ran on: #3545, Testing.
- Before, on
dev fad0ffb7:
- After boot, RAM 37h =
B4, against EEPROM 10, so bit 7 was forced to 1 against the chip's 0.
- After RTC midnight, RAM 37h =
10: BSM = 00, TCE = 0, switchover off.
- A ~60 s power cut then lost the time: the RTC came back at 2000-01-01, with PORF = 1.
- After, with the fix:
- EEPROM 35h/37h =
40/34, written once, with the trim bit kept.
- Nothing is written on reboot.
- It holds past midnight.
- A ~60 s power cut after midnight kept the time to the second, with BSF = 1 and PORF = 0.
- This was tested on both the first and the final sequence.
ZephCore (ptr727/liquidraver-ZephCore#35, same §3.15.6 sequence, second board):
- With the switchover never enabled, a 30 s cut came back with the power-loss flag set.
- With the EEPROM-stored configuration, a 31 s cut came back with the correct time, PORF clear and BSF set.
No spurious switchovers: status 0Eh was polled every 30 s on both boards (31 min on MeshCore, about 55 min on ZephCore). BSF never set outside a deliberate power cut.
Also resolved by #3545: the old RAM writes were issued without waiting for EEbusy, so a POR refresh (§4.6.1, p. 54) within about 66 ms of the RTC's own power-on could overwrite them. #3545 sets EERD and waits for EEbusy before touching the configuration. That race was never observed; the fix removes it by construction.
The RV3028 backup switchover (and trickle charger) that
AutoDiscoverRTCClock::begin()turns on is lost at the next midnight, and the same write overwrites a factory frequency-calibration bit. Proposed fix: #3545. Confirmed on hardware, before and after; see Evidence.References used throughout:
devat3e3150c8(AutoDiscoverRTCClockis unchanged sincefad0ffb7, where the before-fix tests ran).1.2.0, the version MeshCore builds against.src/helpers/AutoDiscoverRTCClock.cppL38-L39:Melopero's
writeToRegister()is a plain I2C register write, so these change only the RAM mirror of two EEPROM-backed configuration registers.1. The setting reverts at the next midnight
On a part whose EEPROM still holds the factory value, the switchover and trickle charging enabled at boot turn off at the first midnight after boot, and stay off until the next reboot. A power cut after that midnight loses the time, and the supercapacitor stops being charged. That covers any repeater that stays up for more than a day.
The choice of mode is right. DSM with the trickle charger is what §7.3 (p. 105) specifies for a capacitor: "DSM Backup Switchover Mode for capacitors (or LSM for rechargeable battery)". What is missing is the EEPROM store.
2.
0xB4overwrites the factory frequency calibrationBit 7 of 37h is EEOffset[0], the LSB of the factory-calibrated frequency offset (§3.15.6, p. 39). §7.3 (p. 105) shows that bit as "0/1", meaning leave it as it is. Writing the whole byte forces it to 1. On a part calibrated with 0 there, that shifts the trim by one step until the next refresh: 0.9537 ppm per step (§3.15.5, p. 38). A fix that stored
0xB4to EEPROM as-is would make that shift permanent.The fix (#3545)
#3545 stores the configuration in EEPROM. Its body has the full procedure, with permalinks.
drivers/mfd/mfd_rv3028.cand Micro Crystal's Linux driver do. §3.15.6 was chosen instead, after testing on two boards found no spurious switchover either way. Only the §3.15.6 sequence stays valid when the backup sits above VDD, and it never rewrites the 36h trim.Evidence
All power cuts were done by hand, with USB unplugged and no battery fitted. The hardware is RAK4631 + RAK12002 boards.
MeshCore, on a part whose EEPROM still held factory values. A throwaway diagnostic CLI (
test/rv3028-diag) stepped the RTC to 23:59:50, so midnight passed in seconds. Full table, with the commit each test ran on: #3545, Testing.devfad0ffb7:B4, against EEPROM10, so bit 7 was forced to 1 against the chip's 0.10: BSM = 00, TCE = 0, switchover off.40/34, written once, with the trim bit kept.ZephCore (ptr727/liquidraver-ZephCore#35, same §3.15.6 sequence, second board):
No spurious switchovers: status 0Eh was polled every 30 s on both boards (31 min on MeshCore, about 55 min on ZephCore). BSF never set outside a deliberate power cut.
Also resolved by #3545: the old RAM writes were issued without waiting for EEbusy, so a POR refresh (§4.6.1, p. 54) within about 66 ms of the RTC's own power-on could overwrite them. #3545 sets EERD and waits for EEbusy before touching the configuration. That race was never observed; the fix removes it by construction.