From d3e2bb690653377eaf8e92c874111fd4c03b5cc2 Mon Sep 17 00:00:00 2001 From: TheHexaMaster <129121144+TheHexaMaster@users.noreply.github.com> Date: Sat, 12 Jul 2025 21:17:43 +0200 Subject: [PATCH] RV3028 RTC Chip support (#23672) * Update xdrv_56_rtc_chips.ino Added support for RV3028 RTC * Update I2CDEVICES.md RV3028 RTC Support * Update my_user_config.h --- I2CDEVICES.md | 1 + tasmota/my_user_config.h | 1 + .../tasmota_xdrv_driver/xdrv_56_rtc_chips.ino | 139 +++++++++++++++++- 3 files changed, 140 insertions(+), 1 deletion(-) diff --git a/I2CDEVICES.md b/I2CDEVICES.md index 822415a7d..af25dfca0 100644 --- a/I2CDEVICES.md +++ b/I2CDEVICES.md @@ -131,5 +131,6 @@ Index | Define | Driver | Device | Address(es) | Bus2 | Descrip 91 | USE_MS5837 | xsns_116 | MS5837 | 0x76 | | Pressure and temperature sensor 92 | USE_PCF85063 | xdrv_56 | PCF85063 | 0x51 | | PCF85063 Real time clock 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 NOTE: Bus2 supported on ESP32 only. diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index d14635336..ffafc48f0 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -791,6 +791,7 @@ // #define USE_AP33772S // [I2cDriver93] Enable AP33772S USB PD Sink Controller (I2C addresses 0x52) (+3k1 code) // #define USE_RTC_CHIPS // Enable RTC chip support and NTP server - Select only one +// #define USE_RV3028 // [I2cDriver94] Enable RV3028 RTC chip support (I2C address 0x52) // #define USE_DS3231 // [I2cDriver26] Enable DS3231 RTC - used by Ulanzi TC001 (I2C address 0x68) (+1k2 code) // #define DS3231_ENABLE_TEMP // In DS3231 driver, enable the internal temperature sensor // #define USE_BM8563 // [I2cDriver59] Enable BM8563 RTC - used by M5Stack - support both I2C buses on ESP32 (I2C address 0x51) (+2.5k code) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_56_rtc_chips.ino b/tasmota/tasmota_xdrv_driver/xdrv_56_rtc_chips.ino index d3927c5a8..14fd53e9e 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_56_rtc_chips.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_56_rtc_chips.ino @@ -11,6 +11,9 @@ /*********************************************************************************************\ * RTC chip support * + * #define USE_RV3028 + * RV-3028-C7 at I2C address 0x52 + * Used in MSB Master G1 * #define USE_DS3231 * DS1307 and DS3231 at I2C address 0x68 * Used by Ulanzi TC001 @@ -44,6 +47,137 @@ struct { char name[10]; } RtcChip; + +/*********************************************************************************************\ + * RV-3028-C7 RTC Controller + * + * I2C Address: 0x52 +\*********************************************************************************************/ + +#ifdef USE_RV3028 + +#define XI2C_94 94 // See I2CDEVICES.md + +#define RV3028_ADDR 0x52 // I2C address of RV-3028-C7 + +// RV-3028-C7 Register Addresses +#define RV3028_SECONDS 0x00 +#define RV3028_MINUTES 0x01 +#define RV3028_HOURS 0x02 +#define RV3028_WEEKDAY 0x03 +#define RV3028_DATE 0x04 +#define RV3028_MONTH 0x05 +#define RV3028_YEAR 0x06 +#define RV3028_STATUS 0x0E +#define RV3028_CONTROL1 0x0F +#define RV3028_CONTROL2 0x10 + +// Status register bits +#define RV3028_PORF 0 // Power-on Reset flag (bit 0 in STATUS register) + + +/*-------------------------------------------------------------------------------------------*\ + * Init register to activate BSM from VBACKUP (Direct Switching Mode) +\*-------------------------------------------------------------------------------------------*/ + +void RV3028_EnableDSM(void) { + uint8_t current_eeprom; + + I2cWrite8(RtcChip.address, 0x25, 0x37, RtcChip.bus); // EEADDR = 0x37 + I2cWrite8(RtcChip.address, 0x27, 0x22, RtcChip.bus); // EECMD = 0x22 (EEPROM Read) + delay(3); + + current_eeprom = I2cRead8(RtcChip.address, 0x26, RtcChip.bus); // EEDATA actual data + + if (current_eeprom != 0x14) { + I2cWrite8(RtcChip.address, 0x25, 0x37, RtcChip.bus); // EEADDR = 0x37 + I2cWrite8(RtcChip.address, 0x26, 0x14, RtcChip.bus); // EEDATA = 0x14 (FEDE=1, BSM=01 DSM mode) + I2cWrite8(RtcChip.address, 0x27, 0x21, RtcChip.bus); // EECMD = 0x21 (EEPROM Write) + delay(25); + AddLog(LOG_LEVEL_INFO, PSTR("RV3028: EEPROM 0x37 updated to DSM mode.")); + } else { + AddLog(LOG_LEVEL_DEBUG, PSTR("RV3028: EEPROM 0x37 already set to DSM mode.")); + } +} + +/*-------------------------------------------------------------------------------------------*\ + * Read time from RV-3028-C7 and return the epoch time (seconds since 1-1-1970 00:00) +\*-------------------------------------------------------------------------------------------*/ +uint32_t RV3028ReadTime(void) { + + uint8_t status = I2cRead8(RtcChip.address, RV3028_STATUS, RtcChip.bus); + + // Skontroluj PORF bit (bit 0 registra STATUS) + if (status & _BV(RV3028_PORF)) { + AddLog(LOG_LEVEL_DEBUG, PSTR("RV3028: PORF detected, RTC time invalid")); + return 0; // Invalid RTC time data + } + + + TIME_T tm; + tm.second = Bcd2Dec(I2cRead8(RtcChip.address, RV3028_SECONDS, RtcChip.bus) & 0x7F); + tm.minute = Bcd2Dec(I2cRead8(RtcChip.address, RV3028_MINUTES, RtcChip.bus) & 0x7F); + tm.hour = Bcd2Dec(I2cRead8(RtcChip.address, RV3028_HOURS, RtcChip.bus) & 0x3F); // 24h mode (12_24 bit = 0) + tm.day_of_week = I2cRead8(RtcChip.address, RV3028_WEEKDAY, RtcChip.bus) & 0x07; // 0..6 (3-bit weekday counter) + tm.day_of_month = Bcd2Dec(I2cRead8(RtcChip.address, RV3028_DATE, RtcChip.bus) & 0x3F); + tm.month = Bcd2Dec(I2cRead8(RtcChip.address, RV3028_MONTH, RtcChip.bus) & 0x1F); + uint8_t year = Bcd2Dec(I2cRead8(RtcChip.address, RV3028_YEAR, RtcChip.bus)); + // RV-3028-C7 holds year 00-99 (representing 2000-2099). + // MakeTime requires tm.year as years since 1970. + tm.year = year + 30; // (e.g., 23 -> 53 for year 2023) + return MakeTime(tm); +} + +/*-------------------------------------------------------------------------------------------*\ + * Set RV-3028-C7 time using the given epoch time (seconds since 1-1-1970 00:00) +\*-------------------------------------------------------------------------------------------*/ +void RV3028SetTime(uint32_t epoch_time) { + TIME_T tm; + BreakTime(epoch_time, tm); + I2cWrite8(RtcChip.address, RV3028_SECONDS, Dec2Bcd(tm.second), RtcChip.bus); + I2cWrite8(RtcChip.address, RV3028_MINUTES, Dec2Bcd(tm.minute), RtcChip.bus); + I2cWrite8(RtcChip.address, RV3028_HOURS, Dec2Bcd(tm.hour), RtcChip.bus); + I2cWrite8(RtcChip.address, RV3028_WEEKDAY, tm.day_of_week, RtcChip.bus); + I2cWrite8(RtcChip.address, RV3028_DATE, Dec2Bcd(tm.day_of_month), RtcChip.bus); + I2cWrite8(RtcChip.address, RV3028_MONTH, Dec2Bcd(tm.month), RtcChip.bus); + // Convert years since 1970 to RTC register value (00..99) + uint8_t true_year = (tm.year < 30) ? (tm.year + 70) : (tm.year - 30); + I2cWrite8(RtcChip.address, RV3028_YEAR, Dec2Bcd(true_year), RtcChip.bus); + // Clear the power-on reset flag (PORF) in the status register + uint8_t status = I2cRead8(RtcChip.address, RV3028_STATUS, RtcChip.bus); + I2cWrite8(RtcChip.address, RV3028_STATUS, status & ~_BV(RV3028_PORF), RtcChip.bus); + + // Enable LSM mode (VBACKUP) + RV3028_EnableDSM(); + +} + + +/*-------------------------------------------------------------------------------------------*\ + * Detection +\*-------------------------------------------------------------------------------------------*/ +void RV3028Detected(void) { + if (!RtcChip.detected && I2cEnabled(XI2C_94)) { + RtcChip.address = RV3028_ADDR; + for (RtcChip.bus = 0; RtcChip.bus < 2; RtcChip.bus++) { + if (!I2cSetDevice(RtcChip.address, RtcChip.bus)) continue; + if (I2cValidRead(RtcChip.address, RV3028_STATUS, 1, RtcChip.bus)) { + uint8_t status = I2cRead8(RtcChip.address, RV3028_STATUS, RtcChip.bus); + if (status & _BV(RV3028_PORF)) { + AddLog(LOG_LEVEL_DEBUG, PSTR("RV3028: PORF detected at init, RTC time invalid")); + } + RtcChip.detected = 1; + strcpy_P(RtcChip.name, PSTR("RV3028")); + RtcChip.ReadTime = &RV3028ReadTime; + RtcChip.SetTime = &RV3028SetTime; + RtcChip.mem_size = 2; // RAM 2 byte + break; + } + } + } +} +#endif // USE_RV3028 + /*********************************************************************************************\ * DS1307 and DS3231 * @@ -188,7 +322,7 @@ void DS3231Detected(void) { #endif // USE_DS3231 - + /*********************************************************************************************\ * PCF85063 support * @@ -596,6 +730,9 @@ void RtcChipDetect(void) { RtcChip.detected = 0; RtcChip.bus = 0; +#ifdef USE_RV3028 + RV3028Detected(); +#endif // USE_RV3028 #ifdef USE_DS3231 DS3231Detected(); #endif // USE_DS3231