diff --git a/lib/ds3231.py b/lib/ds3231.py deleted file mode 100644 index 5ec777f..0000000 --- a/lib/ds3231.py +++ /dev/null @@ -1,142 +0,0 @@ -# Driver for ds3231 clock. -#Uses I2C communication. - -import pyb, utime - -def bcd2dec(bcd): - return (((bcd & 0xF0) >> 4) * 10 + (bcd & 0x0F)) - -def dec2bcd(dec): - tens, units = divmod(dec, 10) - return (tens << 4) + units - -class ds3231(object): - _ADDRESS = 0x68 - _SECONDS = const(0) - _MINUTES = const(1) - _HOURS = const(2) - _WEEKDAY = const(3) - _DAY = const(4) - _MONTH = const(5) - _YEAR = const(6) - - def __init__( self, aLoc ) : - """aLoc I2C pin location is either 1 for 'X' or 2 for 'Y'.""" - self.rtc = pyb.RTC() #Real time clock. - self.i2c = pyb.I2C(aLoc, pyb.I2C.MASTER) - self._buffer = bytearray(7) - self.time(True) - - def time( self, Set = False ) : - if Set: - data = self.wait() - else: - data = self.i2c.mem_read(self._buffer, self._ADDRESS, 0) - s = bcd2dec(data[_SECONDS]) - m = bcd2dec(data[_MINUTES]) - if data[_HOURS] & 0x40 : - h = bcd2dec(data[_HOURS] & 0x1F) - if data[_HOURS] & 0x20: - h += 12 - else: - h = bcd2dec(data[_HOURS]) - wd = data[_WEEKDAY] - day = bcd2dec(data[_DAY]) - month = bcd2dec(data[_MONTH] & 0x1F) - year = bcd2dec(data[_YEAR]) - #Month value MSB indicates century. - if data[_MONTH] & 0x80: - year += 2000 - else: - year += 1900 - - if Set: - self.rtc.datetime((year, month, day, wd, h, m, s, 0)) - - return (year, month, day, h, m, s, wd - 1, 0) # Time from DS3231 in time.time() format (less yday) - - def _set( self, data ) : - (year, month, day, wday, h, m, s, subsecs) = data - self.i2c.mem_write(dec2bcd(s), self._ADDRESS, _SECONDS) - self.i2c.mem_write(dec2bcd(m), self._ADDRESS, _MINUTES) - self.i2c.mem_write(dec2bcd(h), self._ADDRESS, _HOURS) # Sets to 24hr mode - self.i2c.mem_write(dec2bcd(wday), self._ADDRESS, _WEEKDAY) # 1 == Monday, 7 == Sunday - self.i2c.mem_write(dec2bcd(day), self._ADDRESS, _DAY) - if year >= 2000: - self.i2c.mem_write(dec2bcd(month) | 0b10000000, self._ADDRESS, _MONTH) - self.i2c.mem_write(dec2bcd(year - 2000), self._ADDRESS, _YEAR) - else: - self.i2c.mem_write(dec2bcd(month), self._ADDRESS, _MONTH) - self.i2c.mem_write(dec2bcd(year - 1900), self._ADDRESS, _YEAR) - - def save( self ) : - '''Save rtc time to the device.''' - self._set(self.rtc.datetime()) - - def delta( self ) : - self.wait() - ms = self.now() - ut = utime.mktime(self.time()) - return ms - 1000 * ut - - def wait( self ) : - '''Wait for a 1 second change in time.''' - data = self.i2c.mem_read(self._buffer, self._ADDRESS, 0) - s = data[_SECONDS] - while s == data[_SECONDS]: - data = self.i2c.mem_read(self._buffer, self._ADDRESS, 0) - return data - -# Get calibration factor for Pyboard RTC. Note that the DS3231 doesn't have millisecond resolution so we -# wait for a seconds transition to emulate it. -# This function returns the required calibration factor for the RTC (approximately the no. of ppm the -# RTC lags the DS3231). -# Delay(min) Outcome (successive runs). Note 1min/yr ~= 2ppm -# 5 173 169 173 173 173 -# 10 171 173 171 -# 20 172 172 174 -# 40 173 172 173 Mean: 172.3 -# Note calibration factor is not saved on power down unless an RTC backup battery is used. An option is -# to store the calibration factor on disk and issue rtc.calibration(factor) on boot. - - def getcal( self, minutes = 5 ) : - self.rtc.calibration(0) # Clear existing cal - self.save() # Set DS3231 from RTC - self.wait() # Wait for DS3231 to change: on a 1 second boundary - tus = pyb.micros() - st = self.rtc.datetime()[7] - while self.rtc.datetime()[7] == st: # Wait for RTC to change - pass - t1 = pyb.elapsed_micros(tus) # t1 is duration (uS) between DS and RTC change (start) - rtcstart = self.nownr() # RTC start time in mS - dsstart = utime.mktime(self.time()) # DS start time in secs - pyb.delay(minutes * 60000) - self.wait() # DS second boundary - tus = pyb.micros() - st = self.rtc.datetime()[7] - while self.rtc.datetime()[7] == st: - pass - t2 = pyb.elapsed_micros(tus) # t2 is duration (uS) between DS and RTC change (end) - rtcend = self.nownr() - dsend = time.mktime(self.time()) - dsdelta = (dsend - dsstart) * 1000000 # Duration (uS) between DS edges as measured by DS3231 - rtcdelta = (rtcend - rtcstart) * 1000 + t1 -t2 # Duration (uS) between DS edges as measured by RTC and corrected - ppm = (1000000* (rtcdelta - dsdelta)) / dsdelta - return int(-ppm / 0.954) - - def calibrate( self, minutes = 5 ) : - print('Waiting {} minutes to acquire calibration factor...'.format(minutes)) - cal = self.getcal(minutes) - self.rtc.calibration(cal) - print('Pyboard RTC is calibrated. Factor is {}.'.format(cal)) - return cal - - def now( self ): # Return the current time from the RTC in millisecs from year 2000 - secs = utime.time() - ms = 1000 * (255 - self.rtc.datetime()[7]) >> 8 - if ms < 50: # Might have just rolled over - secs = utime.time() - return 1000 * secs + ms - - def nownr( self ): # Return the current time from the RTC: caller ensures transition has occurred - return 1000 * utime.time() + (1000 * (255 - self.rtc.datetime()[7]) >> 8) diff --git a/lib/ds3231_pb.py b/lib/ds3231_pb.py deleted file mode 100644 index 1be6aa2..0000000 --- a/lib/ds3231_pb.py +++ /dev/null @@ -1,143 +0,0 @@ -# Pyboard driver for DS3231 precison real time clock. -# Adapted from WiPy driver at https://github.com/scudderfish/uDS3231 -# Includes routine to calibrate the Pyboard's RTC from the DS3231 -# delta method now operates to 1mS precision -# precison of calibration further improved by timing Pyboard RTC transition -# Adapted by Peter Hinch, Jan 2016 - -import utime, pyb -DS3231_I2C_ADDR = 104 - -class DS3231Exception(OSError): - pass - -rtc = pyb.RTC() - -def now(): # Return the current time from the RTC in millisecs from year 2000 - secs = utime.time() - ms = 1000 * (255 -rtc.datetime()[7]) >> 8 - if ms < 50: # Might have just rolled over - secs = utime.time() - return 1000 * secs + ms - -def nownr(): # Return the current time from the RTC: caller ensures transition has occurred - return 1000 * utime.time() + (1000 * (255 -rtc.datetime()[7]) >> 8) - -# Driver for DS3231 accurate RTC module (+- 1 min/yr) needs adapting for Pyboard -# source https://github.com/scudderfish/uDS3231 -def bcd2dec(bcd): - return (((bcd & 0xf0) >> 4) * 10 + (bcd & 0x0f)) - -def dec2bcd(dec): - tens, units = divmod(dec, 10) - return (tens << 4) + units - -class DS3231: - def __init__(self, side = 'X'): - side = side.lower() - if side == 'x': - bus = 1 - elif side == 'y': - bus = 2 - else: - raise ValueError('Side must be "X" or "Y"') - self.ds3231 = pyb.I2C(bus, mode=pyb.I2C.MASTER, baudrate=400000) - self.timebuf = bytearray(7) - if DS3231_I2C_ADDR not in self.ds3231.scan(): - raise DS3231Exception("DS3231 not found on I2C bus at %d" % DS3231_I2C_ADDR) - - def get_time(self, set_rtc = False): - if set_rtc: - data = self.await_transition() # For accuracy set RTC immediately after a seconds transition - else: - data = self.ds3231.mem_read(self.timebuf, DS3231_I2C_ADDR, 0) # don't wait - ss = bcd2dec(data[0]) - mm = bcd2dec(data[1]) - if data[2] & 0x40: - hh = bcd2dec(data[2] & 0x1f) - if data[2] & 0x20: - hh += 12 - else: - hh = bcd2dec(data[2]) - wday = data[3] - DD = bcd2dec(data[4]) - MM = bcd2dec(data[5] & 0x1f) - YY = bcd2dec(data[6]) - if data[5] & 0x80: - YY += 2000 - else: - YY += 1900 - if set_rtc: - rtc.datetime((YY, MM, DD, wday, hh, mm, ss, 0)) - return (YY, MM, DD, hh, mm, ss, wday -1, 0) # Time from DS3231 in time.time() format (less yday) - - def save_time(self): - (YY, MM, DD, wday, hh, mm, ss, subsecs) = rtc.datetime() - self.ds3231.mem_write(dec2bcd(ss), DS3231_I2C_ADDR, 0) - self.ds3231.mem_write(dec2bcd(mm), DS3231_I2C_ADDR, 1) - self.ds3231.mem_write(dec2bcd(hh), DS3231_I2C_ADDR, 2) # Sets to 24hr mode - self.ds3231.mem_write(dec2bcd(wday), DS3231_I2C_ADDR, 3) # 1 == Monday, 7 == Sunday - self.ds3231.mem_write(dec2bcd(DD), DS3231_I2C_ADDR, 4) - if YY >= 2000: - self.ds3231.mem_write(dec2bcd(MM) | 0b10000000, DS3231_I2C_ADDR, 5) - self.ds3231.mem_write(dec2bcd(YY-2000), DS3231_I2C_ADDR, 6) - else: - self.ds3231.mem_write(dec2bcd(MM), DS3231_I2C_ADDR, 5) - self.ds3231.mem_write(dec2bcd(YY-1900), DS3231_I2C_ADDR, 6) - - def delta(self): # Return no. of mS RTC leads DS3231 - self.await_transition() - rtc_ms = now() - t_ds3231 = utime.mktime(self.get_time()) # To second precision, still in same sec as transition - return rtc_ms - 1000 * t_ds3231 - - def await_transition(self): # Wait until DS3231 seconds value changes - data = self.ds3231.mem_read(self.timebuf, DS3231_I2C_ADDR, 0) - ss = data[0] - while ss == data[0]: - data = self.ds3231.mem_read(self.timebuf, DS3231_I2C_ADDR, 0) - return data - -# Get calibration factor for Pyboard RTC. Note that the DS3231 doesn't have millisecond resolution so we -# wait for a seconds transition to emulate it. -# This function returns the required calibration factor for the RTC (approximately the no. of ppm the -# RTC lags the DS3231). -# Delay(min) Outcome (successive runs). Note 1min/yr ~= 2ppm -# 5 173 169 173 173 173 -# 10 171 173 171 -# 20 172 172 174 -# 40 173 172 173 Mean: 172.3 -# Note calibration factor is not saved on power down unless an RTC backup battery is used. An option is -# to store the calibration factor on disk and issue rtc.calibration(factor) on boot. - - def getcal(self, minutes=5): - rtc.calibration(0) # Clear existing cal - self.save_time() # Set DS3231 from RTC - self.await_transition() # Wait for DS3231 to change: on a 1 second boundary - tus = pyb.micros() - st = rtc.datetime()[7] - while rtc.datetime()[7] == st: # Wait for RTC to change - pass - t1 = pyb.elapsed_micros(tus) # t1 is duration (uS) between DS and RTC change (start) - rtcstart = nownr() # RTC start time in mS - dsstart = utime.mktime(self.get_time()) # DS start time in secs - pyb.delay(minutes * 60000) - self.await_transition() # DS second boundary - tus = pyb.micros() - st = rtc.datetime()[7] - while rtc.datetime()[7] == st: - pass - t2 = pyb.elapsed_micros(tus) # t2 is duration (uS) between DS and RTC change (end) - rtcend = nownr() - dsend = utime.mktime(self.get_time()) - dsdelta = (dsend - dsstart) * 1000000 # Duration (uS) between DS edges as measured by DS3231 - rtcdelta = (rtcend - rtcstart) * 1000 + t1 -t2 # Duration (uS) between DS edges as measured by RTC and corrected - ppm = (1000000* (rtcdelta - dsdelta))/dsdelta - return int(-ppm/0.954) - - def calibrate(self, minutes=5): - print('Waiting {} minutes to acquire calibration factor...'.format(minutes)) - cal = self.getcal(minutes) - rtc.calibration(cal) - print('Pyboard RTC is calibrated. Factor is {}.'.format(cal)) - return cal