Initial commit: ESP32-S3-RLCD-4.2 hardware utility classes and demo
This commit is contained in:
+122
@@ -0,0 +1,122 @@
|
||||
import time
|
||||
from machine import I2C, Pin, RTC
|
||||
|
||||
class PCF85063:
|
||||
"""Utility class for the PCF85063 Real-Time Clock (RTC) chip."""
|
||||
ADDR = 0x51
|
||||
|
||||
# Starting register for timekeeping data
|
||||
TIME_REG_START = 0x04
|
||||
|
||||
def __init__(self, i2c=None):
|
||||
if i2c is None:
|
||||
# Default to ESP32-S3-RLCD-4.2 onboard I2C pins
|
||||
self.i2c = I2C(0, sda=Pin(13), scl=Pin(14))
|
||||
else:
|
||||
self.i2c = i2c
|
||||
|
||||
# Initialize RTC if needed (ensure oscillator is running)
|
||||
self._init_rtc()
|
||||
|
||||
def _init_rtc(self):
|
||||
try:
|
||||
# Control register 1 (0x00) should be 0 to ensure oscillator is not stopped (bit 5 = STOP)
|
||||
ctrl1 = self.i2c.readfrom_mem(self.ADDR, 0x00, 1)[0]
|
||||
if ctrl1 & 0x20: # Oscillator is stopped
|
||||
print("RTC oscillator was stopped. Starting oscillator...")
|
||||
self.i2c.writeto_mem(self.ADDR, 0x00, b'\x00')
|
||||
except Exception as e:
|
||||
print(f"Error initializing PCF85063: {e}")
|
||||
|
||||
def _dec2bcd(self, val):
|
||||
return (val // 10 << 4) | (val % 10)
|
||||
|
||||
def _bcd2dec(self, val):
|
||||
return ((val >> 4) * 10) + (val & 0x0F)
|
||||
|
||||
def get_datetime(self):
|
||||
"""Reads current time from hardware RTC.
|
||||
|
||||
Returns:
|
||||
tuple: (year, month, day, weekday, hour, minute, second) or None on error.
|
||||
Note: year is 4-digit (e.g. 2026).
|
||||
"""
|
||||
try:
|
||||
# Read 7 registers: Seconds, Minutes, Hours, Days, Weekdays, Months, Years
|
||||
data = self.i2c.readfrom_mem(self.ADDR, self.TIME_REG_START, 7)
|
||||
|
||||
second = self._bcd2dec(data[0] & 0x7F) # Bit 7 is integrity flag OS
|
||||
minute = self._bcd2dec(data[1] & 0x7F)
|
||||
hour = self._bcd2dec(data[2] & 0x3F) # 24-hour mode
|
||||
day = self._bcd2dec(data[3] & 0x3F)
|
||||
weekday = data[4] & 0x07 # 0-6
|
||||
month = self._bcd2dec(data[5] & 0x1F)
|
||||
year = 2000 + self._bcd2dec(data[6]) # 0-99 mapping to 2000-2099
|
||||
|
||||
return (year, month, day, weekday, hour, minute, second)
|
||||
except Exception as e:
|
||||
print(f"Error reading PCF85063 RTC: {e}")
|
||||
return None
|
||||
|
||||
def set_datetime(self, dt):
|
||||
"""Sets the hardware RTC time.
|
||||
|
||||
Args:
|
||||
dt (tuple): (year, month, day, weekday, hour, minute, second)
|
||||
Note: year can be 4-digit (e.g. 2026) or 2-digit (e.g. 26).
|
||||
"""
|
||||
try:
|
||||
year, month, day, weekday, hour, minute, second = dt
|
||||
|
||||
# Format to registers
|
||||
reg_year = year % 100
|
||||
|
||||
data = bytearray(7)
|
||||
data[0] = self._dec2bcd(second) & 0x7F # Clear OS bit (re-starts oscillator integrity check)
|
||||
data[1] = self._dec2bcd(minute)
|
||||
data[2] = self._dec2bcd(hour)
|
||||
data[3] = self._dec2bcd(day)
|
||||
data[4] = weekday & 0x07
|
||||
data[5] = self._dec2bcd(month)
|
||||
data[6] = self._dec2bcd(reg_year)
|
||||
|
||||
self.i2c.writeto_mem(self.ADDR, self.TIME_REG_START, data)
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Error setting PCF85063 RTC: {e}")
|
||||
return False
|
||||
|
||||
def sync_to_system(self):
|
||||
"""Synchronizes the ESP32-S3 internal system time from this hardware RTC."""
|
||||
dt = self.get_datetime()
|
||||
if dt:
|
||||
year, month, day, weekday, hour, minute, second = dt
|
||||
# machine.RTC.datetime requires 8-tuple: (year, month, day, weekday, hour, minute, second, subseconds)
|
||||
sys_rtc = RTC()
|
||||
sys_rtc.datetime((year, month, day, weekday, hour, minute, second, 0))
|
||||
print(f"System clock synced to RTC: {year:04d}-{month:02d}-{day:02d} {hour:02d}:{minute:02d}:{second:02d}")
|
||||
return True
|
||||
return False
|
||||
|
||||
def sync_from_system(self):
|
||||
"""Synchronizes the hardware RTC time from the ESP32-S3 system clock."""
|
||||
try:
|
||||
# Get current system time (localtime tuple: year, month, mday, hour, minute, second, weekday, yearday)
|
||||
t = time.localtime()
|
||||
# mapping time.localtime() weekday to PCF85063:
|
||||
# Python weekday (0=Monday...6=Sunday)
|
||||
dt = (t[0], t[1], t[2], t[6], t[3], t[4], t[5])
|
||||
success = self.set_datetime(dt)
|
||||
if success:
|
||||
print(f"RTC synced from System: {t[0]:04d}-{t[1]:02d}-{t[2]:02d} {t[3]:02d}:{t[4]:02d}:{t[5]:02d}")
|
||||
return success
|
||||
except Exception as e:
|
||||
print(f"Error syncing RTC from system: {e}")
|
||||
return False
|
||||
|
||||
def get_time_string(self):
|
||||
"""Returns current time as a formatted string: YYYY-MM-DD HH:MM:SS"""
|
||||
dt = self.get_datetime()
|
||||
if dt:
|
||||
return f"{dt[0]:04d}-{dt[1]:02d}-{dt[2]:02d} {dt[4]:02d}:{dt[5]:02d}:{dt[6]:02d}"
|
||||
return "0000-00-00 00:00:00"
|
||||
Reference in New Issue
Block a user