I've been reading about RTC crystal drift and calibration. I've also received some good information on the Adafruit forum in this thread:
https://forums.adafruit.com/viewtopic.php?f=57&t=108693
I don't have a truly accurate measurement of drift in ppm as discussed in this thread:
http://forum.micropython.org/viewtopic.php?f=6&t=326
After setting the PCF8523 in my Adalogger by calling an ntp server on my LAN, then comparing the rtc and ntp times after three days running time, my rtc is gaining approximately 2.3 seconds per 24 hour period.
If I understand correctly, 2.3 seconds * 11.6 ppm (from Adafruit thread linked to above) means I should calibrate my rtc by writing -26.68 to it's calibration register to slow it down and reduce the gain. So how to write -26.68 into the calibration register? Is it possible with micropython on the esp8266?
Section 8.8 (page 28) of the PCF8523 datasheet has information about the Register Offset for accuracy tuning:
http://www.nxp.com/documents/data_sheet/PCF8523.pdf
I'd like to better understand the datasheet and know how to write into the correct register but that is outside my knowledge and experience level. I tried some Google searches for a tutorial on the subject but didn't find anything. Some assistance or guidance would be greatly appreciated.
I have some C code in an Arduino sketch that someone wrote to calibrate an MCP79412. If it would be easier for me to connect the Adalogger to an Arduino and write to the register, I might be able to re-use that code, provided I can determine the proper byte to write to for the PCF8523.
Thanks for any suggestions, help, or guidance.
J
[SOLVED] Calibrating the PCF8523 RTC
[SOLVED] Calibrating the PCF8523 RTC
Last edited by jpj on Tue Dec 27, 2016 1:04 pm, edited 2 times in total.
Re: Calibrating the PCF8523 RTC
Update: I need to write positive ppm to slow the rtc down, not negative (-26.68) as I posted previously. The PCF8523 register address is 0x0E, but what bits to actually write into it for my calibration I haven't determined. I don't understand the tables and mode starting on age 28 of the datasheet.
Last edited by jpj on Mon Dec 26, 2016 1:47 pm, edited 1 time in total.
- pythoncoder
- Posts: 5956
- Joined: Fri Jul 18, 2014 8:01 am
- Location: UK
- Contact:
Re: Calibrating the PCF8523 RTC
If you look at the calibration workflow on page 31 of the manual you'll see that you need to write 26.62/4.34 = 6 if you're in mode 0 (low power) or 26.62/4.069 = 7 if you're in mode 1 (their example corresponds to your case where the clock is gaining time). If you're not sure what mode you're in I'd write 6 as the precise result for mode 1 is 6.542 so it's marginal whether 6 or 7 is the optimal value.
The device uses an I2C interface so MicroPython will be able to write to the register. I suggest you read the docs on I2C http://docs.micropython.org/en/latest/e ... e.I2C.html. You'll need to find the pin numbers used to connect the processor to the PCF8523. I'd start by issuing a scan:
you should see the device on address 0x68 (page 46 of the manual). I2C uses 7 bit addressing with the LSB being read/write.
If my reading of the manual is correct the following code fragment should work:
The device uses an I2C interface so MicroPython will be able to write to the register. I suggest you read the docs on I2C http://docs.micropython.org/en/latest/e ... e.I2C.html. You'll need to find the pin numbers used to connect the processor to the PCF8523. I'd start by issuing a scan:
Code: Select all
from machine import Pin, I2C
sda = Pin(id, Pin.OPEN_DRAIN) # replace id with the data pin
scl = Pin(id, Pin.OPEN_DRAIN) # Likewise for the clock pin
i2c = I2C(sda, scl)
i2c.scan()
If my reading of the manual is correct the following code fragment should work:
Code: Select all
from machine import Pin, I2C
sda = Pin(id, Pin.OPEN_DRAIN) # replace id with the data pin
scl = Pin(id, Pin.OPEN_DRAIN) # Likewise for the clock pin
i2c = I2C(sda, scl)
buf = bytearray((6,)) # Your correction value
i2c.writeto_mem(0x68, 0x0e, buf)
Peter Hinch
Index to my micropython libraries.
Index to my micropython libraries.
Re: Calibrating the PCF8523 RTC
Thank you pythoncoder! This was the guidance I needed.
I wrote the calibration to the rtc, reset the time from a call to ntp, and will now monitor for accuracy. My REPL session below, with some white space added to enhance readability.
I need to study the PCF8523 datasheet until it makes sense. I also didn't know about the i2c.writeto_mem() function. I had briefly read about bytearray() but need to review that too. You're filling in the blanks for me is greatly appreciated!
For other beginners who may be reading this, the i2c scan returned two addresses, 104 (0x68) is my rtc and 112 (0x70) is a display I have connected.
I wrote the calibration to the rtc, reset the time from a call to ntp, and will now monitor for accuracy. My REPL session below, with some white space added to enhance readability.
I need to study the PCF8523 datasheet until it makes sense. I also didn't know about the i2c.writeto_mem() function. I had briefly read about bytearray() but need to review that too. You're filling in the blanks for me is greatly appreciated!
For other beginners who may be reading this, the i2c scan returned two addresses, 104 (0x68) is my rtc and 112 (0x70) is a display I have connected.
Code: Select all
>>> from machine import I2C, Pin
>>> i2c = I2C(scl=Pin(5), sda=Pin(4))
>>> i2c.scan()
[104, 112]
>>> buf = bytearray((6,))
>>> buf
bytearray(b'\x06')
>>> i2c.writeto_mem(0x68, 0x0e, buf)
>>> import mytime
>>> mytime.setrtc()
>>> import comparetime
>>> comparetime.runv()
NTP 2016-12-26 13:19:58
RTC 2016-12-26 13:19:58
Re: Calibrating the PCF8523 RTC
If you are using the uRTC library, you can also wite that value to the register with this code:
Where rtc is your PCF8523 object.
Code: Select all
rtc._register(0x0e, '\x06')
Re: Calibrating the PCF8523 RTC
I am using uRTC (thanks to your recent help in a different thread).deshipu wrote:If you are using the uRTC library, you can also wite that value to the register with this code:
Where rtc is your PCF8523 object.Code: Select all
rtc._register(0x0e, '\x06')
Thanks, I'll check it out!