mirror of
https://github.com/arendst/Tasmota.git
synced 2026-02-20 00:32:32 +01:00
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:
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user