Add support for RX8025T Real Time Clock (#24450)

* Add RX8025 RTC device to I2C devices list

* Add support for RX8025T Real Time Clock

* Define USE_RX8025 for RX8025 RTC chip support

Added support for RX8025 RTC chip.

* Comment out USE_RX8025 definition in user config

* Uncomment USE_RX8025 RTC support in user config
This commit is contained in:
TheHexaMaster
2026-02-14 11:28:06 +01:00
committed by GitHub
parent 314c2c460a
commit ab7814bd60
3 changed files with 243 additions and 1 deletions

View File

@@ -136,5 +136,6 @@ Index | Define | Driver | Device | Address(es) | Bus2 | Descrip
93 | USE_AS33772S | xdrv_119 | AS33772S | 0x52 | Yes | AS33772S USB PD Sink Controller
94 | USE_RV3028 | xdrv_56 | RV3028 | 0x52 | Yes | RV-3028-C7 RTC Controller
95 | USE_AGS02MA | xsns_118 | AGS02MA | 0x1A | | TVOC Gas sensor
96 | USE_RX8025 | xdrv_56 | RX8025 | 0x32 | Yes | RX8025 RTC
NOTE: Bus2 supported on ESP32 only.

View File

@@ -805,6 +805,7 @@
// #define USE_BM8563 // [I2cDriver59] Enable BM8563 RTC - used by M5Stack - support both I2C buses on ESP32 (I2C address 0x51) (+2.5k code)
// #define USE_PCF85363 // [I2cDriver66] Enable PCF85363 RTC - used by Shelly 3EM (I2C address 0x51) (+0k7 code)
// #define USE_RX8010 // [I2cDriver90] Enable RX8010 RTC - used by IOTTIMER - support both I2C buses on ESP32 (I2C address 0x32) (+0k7 code)
// #define USE_RX8025 // [I2cDriver90] Enable RX8025 RTC support both I2C buses on ESP32 (I2C address 0x32)
// #define USE_RX8030 // [I2cDriver90] Enable RX8030 RTC - used by #23855 - support both I2C buses on ESP32 (I2C address 0x32) (+0k7 code)
// #define USE_PCF85063 // [I2cDriver92] Enable PCF85063 RTC support (I2C address 0x51)

View File

@@ -31,7 +31,10 @@
* Used by IOTTIMER (v1 and v2)
* #define USE_RX8030
* RX8010 at I2C address 0x32
* Used by #23855
* Used by #23855
* #define USE_RX8025
* RX8025 at I2C address 0x32
* Used by MSB Master G2
\*********************************************************************************************/
#define XDRV_56 56
@@ -727,6 +730,239 @@ void Rx8010Detected(void) {
}
}
#endif // USE_RX8010
/*********************************************************************************************\
* RX8025T - Real Time Clock
*
* I2C Address: 0x32
\*********************************************************************************************/
#if defined(USE_RX8025)
#define XI2C_96 96 // See I2CDEVICES.md
#define RX8025_ADDRESS 0x32
// RX8025T Register Addresses (per datasheet table 0..F)
#define RX8025_REG_SEC 0x00
#define RX8025_REG_MIN 0x01
#define RX8025_REG_HOUR 0x02
#define RX8025_REG_WEEK 0x03 // bitfield 6..0 (Sun..Sat)
#define RX8025_REG_MDAY 0x04
#define RX8025_REG_MONTH 0x05 // 01..12
#define RX8025_REG_YEAR 0x06 // 00..99 (2000..2099)
#define RX8025_REG_EXT 0x0D
#define RX8025_REG_FLAG 0x0E
#define RX8025_REG_CTRL 0x0F
// FLAG bits (per table: ... VLF VDET)
#define RX8025_FLAG_VLF 1
#define RX8025_FLAG_VDET 0
// CTRL RESET bit0 = stop status (datasheet)
#define RX8025_BIT_CTRL_RESET 0
// WEEK bitfield <-> Tasmota day_of_week (1..7, Sunday=1)
static uint8_t Rx8025WeekToWday(uint8_t week) {
week &= 0x7F; // ignore bit7
for (uint8_t i = 0; i < 7; i++) {
if (week & (1U << i)) { return (uint8_t)(i + 1); } // Sun=1
}
return 1;
}
static uint8_t Rx8025WdayToWeek(uint8_t wday) {
if (wday < 1 || wday > 7) { wday = 1; }
return (uint8_t)(1U << (wday - 1)); // one-hot bits 0..6
}
static void Rx8025LogRaw(const char *tag, uint8_t bus, uint8_t addr,
const uint8_t data[7], uint8_t ctrl, uint8_t flag, uint8_t ext) {
AddLog(LOG_LEVEL_DEBUG,
PSTR("RTC: RX8025T %s bus=%d addr=0x%02X RAW[00..06]=%02X %02X %02X %02X %02X %02X %02X CTRL=%02X FLAG=%02X EXT=%02X"),
tag, bus, addr,
data[0], data[1], data[2], data[3], data[4], data[5], data[6],
ctrl, flag, ext);
}
static void Rx8025PreInitIfNeeded(void) {
uint8_t ctrl = I2cRead8(RtcChip.address, RX8025_REG_CTRL, RtcChip.bus);
uint8_t flag = I2cRead8(RtcChip.address, RX8025_REG_FLAG, RtcChip.bus);
uint8_t ext = I2cRead8(RtcChip.address, RX8025_REG_EXT, RtcChip.bus);
AddLog(LOG_LEVEL_DEBUG, PSTR("RTC: RX8025T PRE-INIT CTRL=%02X FLAG=%02X EXT=%02X"), ctrl, flag, ext);
// If VLF or VDET is set, datasheet says initialize registers before use.
if (flag & (_BV(RX8025_FLAG_VLF) | _BV(RX8025_FLAG_VDET))) {
AddLog(LOG_LEVEL_DEBUG, PSTR("RTC: RX8025T VLF/VDET set -> clearing EXT/FLAG (arduino-style)"));
// Keep CTRL upper bits, force reserved bits 2..1 = 0
uint8_t ctrl_base = ctrl & 0xF8;
// Enter stop status (RESET=1)
I2cWrite8(RtcChip.address, RX8025_REG_CTRL, ctrl_base | _BV(RX8025_BIT_CTRL_RESET), RtcChip.bus);
// Clear EXT and FLAG (common minimal init used by reference libs)
I2cWrite8(RtcChip.address, RX8025_REG_EXT, 0x00, RtcChip.bus);
I2cWrite8(RtcChip.address, RX8025_REG_FLAG, 0x00, RtcChip.bus);
// Exit stop status (RESET=0)
I2cWrite8(RtcChip.address, RX8025_REG_CTRL, ctrl_base, RtcChip.bus);
ctrl = I2cRead8(RtcChip.address, RX8025_REG_CTRL, RtcChip.bus);
flag = I2cRead8(RtcChip.address, RX8025_REG_FLAG, RtcChip.bus);
ext = I2cRead8(RtcChip.address, RX8025_REG_EXT, RtcChip.bus);
AddLog(LOG_LEVEL_DEBUG, PSTR("RTC: RX8025T POST-INIT CTRL=%02X FLAG=%02X EXT=%02X"), ctrl, flag, ext);
}
}
/*-------------------------------------------------------------------------------------------*\
* Read time from RX8025T and return epoch time
\*-------------------------------------------------------------------------------------------*/
uint32_t Rx8025ReadTime(void) {
TIME_T tm;
uint8_t data[7];
I2cReadBuffer(RtcChip.address, RX8025_REG_SEC, data, 7, RtcChip.bus);
uint8_t ctrl = I2cRead8(RtcChip.address, RX8025_REG_CTRL, RtcChip.bus);
uint8_t flag = I2cRead8(RtcChip.address, RX8025_REG_FLAG, RtcChip.bus);
uint8_t ext = I2cRead8(RtcChip.address, RX8025_REG_EXT, RtcChip.bus);
Rx8025LogRaw("READ", RtcChip.bus, RtcChip.address, data, ctrl, flag, ext);
tm.second = Bcd2Dec(data[0] & 0x7F);
tm.minute = Bcd2Dec(data[1] & 0x7F);
tm.hour = Bcd2Dec(data[2] & 0x3F);
tm.day_of_week = Rx8025WeekToWday(data[3]);
tm.day_of_month = Bcd2Dec(data[4] & 0x3F);
// RX8025: MONTH is 01..12 (no -1)
tm.month = Bcd2Dec(data[5] & 0x1F);
// RX8025: YEAR is 00..99 for 2000..2099 => yOff = (2000-1970)+y2k = 30+y2k
uint8_t y2k = Bcd2Dec(data[6]);
tm.year = (uint8_t)(30 + y2k);
uint32_t epoch = MakeTime(tm);
AddLog(LOG_LEVEL_DEBUG,
PSTR("RTC: RX8025T DECODE y2k=%u -> yOff=%u (abs=%u) m=%u d=%u w=%u %02u:%02u:%02u -> epoch=%u"),
y2k, tm.year, (uint16_t)(1970 + tm.year),
tm.month, tm.day_of_month, tm.day_of_week,
tm.hour, tm.minute, tm.second,
epoch);
return epoch;
}
/*-------------------------------------------------------------------------------------------*\
* Set RX8025T time from epoch
\*-------------------------------------------------------------------------------------------*/
void Rx8025SetTime(uint32_t epoch_time) {
TIME_T tm;
BreakTime(epoch_time, tm);
uint16_t abs_year = (uint16_t)(1970 + tm.year);
uint8_t y2k = 0;
if (abs_year < 2000) { y2k = 0; }
else if (abs_year > 2099) { y2k = 99; }
else { y2k = (uint8_t)(abs_year - 2000); }
AddLog(LOG_LEVEL_DEBUG,
PSTR("RTC: RX8025T SET epoch=%u -> yOff=%u (abs=%u) m=%u d=%u w=%u %02u:%02u:%02u"),
epoch_time, tm.year, abs_year,
tm.month, tm.day_of_month, tm.day_of_week,
tm.hour, tm.minute, tm.second);
// CTRL: clear reserved bits 2..1, preserve others
uint8_t ctrl0 = I2cRead8(RtcChip.address, RX8025_REG_CTRL, RtcChip.bus);
uint8_t ctrl_base = ctrl0 & 0xF8;
AddLog(LOG_LEVEL_DEBUG, PSTR("RTC: RX8025T CTRL before=%02X masked=%02X (set RESET bit0=stop)"), ctrl0, ctrl_base);
// Enter stop status (RESET=1)
I2cWrite8(RtcChip.address, RX8025_REG_CTRL, ctrl_base | _BV(RX8025_BIT_CTRL_RESET), RtcChip.bus);
uint8_t ctrl1 = I2cRead8(RtcChip.address, RX8025_REG_CTRL, RtcChip.bus);
AddLog(LOG_LEVEL_DEBUG, PSTR("RTC: RX8025T CTRL after STOP(read)=%02X"), ctrl1);
uint8_t data[7];
data[0] = Dec2Bcd(tm.second);
data[1] = Dec2Bcd(tm.minute);
data[2] = Dec2Bcd(tm.hour);
data[3] = Rx8025WdayToWeek(tm.day_of_week);
data[4] = Dec2Bcd(tm.day_of_month);
// RX8025: MONTH is 01..12 (no +1)
data[5] = Dec2Bcd(tm.month);
data[6] = Dec2Bcd(y2k);
AddLog(LOG_LEVEL_DEBUG,
PSTR("RTC: RX8025T WRITE y2k=%u RAW=%02X %02X %02X %02X %02X %02X %02X"),
y2k, data[0], data[1], data[2], data[3], data[4], data[5], data[6]);
I2cWriteBuffer(RtcChip.address, RX8025_REG_SEC, data, 7, RtcChip.bus);
// Optional readback for verification
uint8_t rb[7];
I2cReadBuffer(RtcChip.address, RX8025_REG_SEC, rb, 7, RtcChip.bus);
uint8_t ctrl_rb = I2cRead8(RtcChip.address, RX8025_REG_CTRL, RtcChip.bus);
uint8_t flag_rb = I2cRead8(RtcChip.address, RX8025_REG_FLAG, RtcChip.bus);
uint8_t ext_rb = I2cRead8(RtcChip.address, RX8025_REG_EXT, RtcChip.bus);
Rx8025LogRaw("READBACK", RtcChip.bus, RtcChip.address, rb, ctrl_rb, flag_rb, ext_rb);
// Exit stop status (RESET=0)
I2cWrite8(RtcChip.address, RX8025_REG_CTRL, ctrl_base, RtcChip.bus);
uint8_t ctrl2 = I2cRead8(RtcChip.address, RX8025_REG_CTRL, RtcChip.bus);
AddLog(LOG_LEVEL_DEBUG, PSTR("RTC: RX8025T CTRL after CLEAR(read)=%02X"), ctrl2);
AddLog(LOG_LEVEL_DEBUG, PSTR("RTC: %s re-synced (" D_UTC_TIME ") %s"), RtcChip.name, GetDateAndTime(DT_UTC).c_str());
}
/*-------------------------------------------------------------------------------------------*\
* Detection
\*-------------------------------------------------------------------------------------------*/
void Rx8025Detected(void) {
if (!RtcChip.detected && I2cEnabled(XI2C_96)) {
RtcChip.address = RX8025_ADDRESS;
for (RtcChip.bus = 0; RtcChip.bus < 2; RtcChip.bus++) {
AddLog(LOG_LEVEL_DEBUG, PSTR("RTC: RX8025T DETECT try bus=%d addr=0x%02X"), RtcChip.bus, RtcChip.address);
if (!I2cSetDevice(RtcChip.address, RtcChip.bus)) {
AddLog(LOG_LEVEL_DEBUG, PSTR("RTC: RX8025T DETECT bus=%d -> I2cSetDevice FAIL"), RtcChip.bus);
continue;
}
// Basic presence check: CTRL must be readable
if (!I2cValidRead(RtcChip.address, RX8025_REG_CTRL, 1, RtcChip.bus)) {
AddLog(LOG_LEVEL_DEBUG, PSTR("RTC: RX8025T DETECT bus=%d -> I2cValidRead(CTRL) FAIL"), RtcChip.bus);
continue;
}
// If VLF/VDET set, clear them before using registers (datasheet requirement)
Rx8025PreInitIfNeeded();
// Debug snapshot of time regs at detect
uint8_t data[7];
I2cReadBuffer(RtcChip.address, RX8025_REG_SEC, data, 7, RtcChip.bus);
uint8_t ctrl = I2cRead8(RtcChip.address, RX8025_REG_CTRL, RtcChip.bus);
uint8_t flag = I2cRead8(RtcChip.address, RX8025_REG_FLAG, RtcChip.bus);
uint8_t ext = I2cRead8(RtcChip.address, RX8025_REG_EXT, RtcChip.bus);
Rx8025LogRaw("DETECTED", RtcChip.bus, RtcChip.address, data, ctrl, flag, ext);
RtcChip.detected = 1;
strcpy_P(RtcChip.name, PSTR("RX8025T"));
RtcChip.ReadTime = &Rx8025ReadTime;
RtcChip.SetTime = &Rx8025SetTime;
RtcChip.mem_size = -1;
break;
}
}
}
#endif // USE_RX8025
/*********************************************************************************************\
* RTC Detect and time set
@@ -754,6 +990,10 @@ void RtcChipDetect(void) {
#ifdef USE_PCF85063
Pcf85063Detected();
#endif // USE_PCF85063
#ifdef USE_RX8025
Rx8025Detected();
#endif // USE_RX8025
if (!RtcChip.detected) { return; }