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
This commit is contained in:
TheHexaMaster 2025-07-12 21:17:43 +02:00 committed by GitHub
parent 6c699e9b95
commit d3e2bb6906
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 140 additions and 1 deletions

View File

@ -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.

View File

@ -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)

View File

@ -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