Uncategorized

DS3231 discussion notes

Is there a package or library for controlling the DS3231 on the Raspberry Pi

Ask QuestionAsked 11 days agoActive todayViewed 64 times21

I’ve just obtained a DS3231 real time clock (RTC), and added it to my RPi 3b. It seems to work as far as keeping time, but I wanted more.

I’d like to be able to set alarms to trigger the INT/SQW pin on the chip (while retaining the basic timekeeping function I currently have), but I’ve been unable to find any way to do that with the toolset in RPi. I’ve installed python-smbus and i2c-tools as part of the RTC configuration. Have I overlooked something? – how should I go about reading & writing the DS3231’s internal registers to set up the alarm function on my RPi 3b?packagesrtctimekeepingshared-librariesds3231ShareEditFollowCloseFlagedited Apr 8 at 8:07asked Apr 6 at 21:41Seamus12.1k22 gold badges1616 silver badges3535 bronze badges

  • I played with DS3231 some three years ago. I found the drivers around then had too limited, (and only minimal functions like many other drivers). So I DIYed my own python library. Fast forward 3 years, now I am playing with Pico and plan to port my old package such as MCP23017, ADS1115 etc to Pico. In case you and other newbie readers are interested to know me the hobbyist developer learned how to do the job, I am writing an answer below. Comments and counter suggestions welcome. Cheers. – tlfong01 Apr 7 at 1:43   
  • I remember 3 years ago the DT3231 libraries then were written in C/C++, me python guy found it hard to append more functions. But if you can now find any python package and wish to add more functions, my little DIY functions and design notes might help you modify any existing python or C/C++ packages. – tlfong01 Apr 7 at 1:58   
  • 2@tlfong01: I appreciate the effort you put into your answer, but it doesn’t actually address my question… with no offense intended, it strikes me as a stream of consciousness rather than an answer. My research suggests all of the code written to configure the ds3231 is written for the Arduino – which is baffling to me. However, I’ve found one resource that seems useful, and may help you in formulating a useful answer. – Seamus Apr 8 at 5:35 
  • 1After reading through the resource I mentioned above, I think I understand more clearly what needs to be done in terms of setting the registers in the ds3231, but I remain at a loss in terms of how to do this from the RPi. – Seamus Apr 8 at 5:40
  • Ha, I like your “literary criticism” on my “answer” which I always think is of a style of “stream of consciousness” or “interior monologue”. I must first point out the misunderstanding that my answer in its current form of not an answer at all. I think it is about one tenth of my final answer which I hope to include a complete “instructable” with Pico python program in Stack Overflow’s recommended style of MCVE (Minimal, Comprehensive, Verifiable, Example). / to continue, … – tlfong01 Apr 8 at 7:09   
  • 1OK, so a work in progress – I’ll leave you to it. However, I’m trying to move forward on this myself. I don’t think now that I need an extraordinarily lengthy answer. It could be as simple as install pkg-Xwrite code in Pythonimport smbus, read register, write register, etc. Nothing I’ve tried so far is working. – Seamus Apr 8 at 7:18
  • So I think you can for now, just sit back, and watch my “technical presentation” of a smart home project using a (1) MCU (Rpi Pico) with microPython, (2) Real time clock (DS3231) and (3) 8 bit/pin GPIO expanders (PCF8574). Internal monologue: My educational object is to introduce the newbies the idea of (a) System integration, (b) Thonny microPython functional programming style for developing scalable, complex systems, using ideas from software engineering languages such as LUA and Scala. / to continue, … – tlfong01 Apr 8 at 7:18   
  • I’m not familiar with ‘micro Python’. I know it’s used on the Pico… BUT this is not for a Pico – it’s for a Raspberry Pi. – Seamus Apr 8 at 7:25
  • Ha, your suggestion is good: You move forward for a quick solution, me a TL:DR answer. Actually my 50+ old posts in rpi.org.forum include the following fully debugged demo programs on (1) How to setup i2cdetect/ping the DS3231, (2) How to read and write DS3231 registers, (3) How to read DS3231 temperature, (4) How to program alarm with interrupts. I am not surprised to hear you saying that “nothing tried so far is working”. One reason is that you might have not understood or have a solid knowledge and troubleshooting skills in basic I2C hardware/software development. / to continue, … – tlfong01 Apr 8 at 7:29   
  • Let us continue this discussion in chat. – tlfong01 Apr 8 at 7:30   

Add a commentStart a bounty

1 Answer

ActiveOldestVotes1

Question

How to write a Rpi4B/Pico Thonny Python program to talk to the DS3231 RTC (Real Time Clock) to do things such as the following:

  1. Detect interrupts,
  2. Trigger on chip square wave signals.

Short Answer

  1. I have searched my 3 year old posts (over 50) in rpi.org.forum to refresh my memory on how I messed around with DS3231, listening to its interrupts, and program/trigger the on chip 32kHz square signals etc.
  2. My old posts are messily scattered in a couple of forums and intermingled with other I2C devices such as MCP23017 IOX and ADS1115 ADC. Porting to Pico is a good opportunity for me to tidy them up.
  3. The OP would like to be able to set alarms to trigger the INT/SQW pin, so I am jumping start to this part. I would first paste the design parameters in Appendix A below, then show a python function on how to program this pin. This double function pin is a bit tricky to handle, you might need to choose SQW mode, program the square wave frequencies, then go back to enable INT, and when INT comes, you need to switch to SQW mode to trigger it. In short, it is a bit tedious and easy to go wrong, so I gave up and tried other workarounds, … 🙂
  4. DS3231 has two alarms, Alarm 1 and Alarm 2, as summarized in Appendix B. I am going to show how to set Alarm 1 for day, hour, min, sec.
  5. There are a couple of DS3231N moudles around in the market. For prototyping and evaluation, I would recommend to buy the most expensive, deluxe version, with a lot of pins to play with, address pins for multiple RTCs, and daisy chain I2C pins for easy extending signals. See Appendix C for more details

ds3231 RTC 1

  1. Now I have written a little python program to detect the addresses of the devices on the two I2C buses of Rpi Pico. DS3231 and 24C32 EEPROM occupy addresses 0x68 and 0x57.
ds3231 addresses

/ to continue, …


Long Answer (TL;DR)

/ to continue, …


References

(1) Search query: DS3231 tlfong01 Record – found 54 matches

(2) Python Program to Ping DS3231 and MCP23017

(3) DS3231 Python Programming Code

(4) DS3231 python Write Register Example

(5) DS3231 Old Posts Reference Links

(6) DS3231 i2cdetect record

(7) DS3231 driver vs dit programming

(8) DS3231 read register functions

(9) DS3231 Set alarm etc

(10) DS3231 python programming design notes

(11) DS3231 python programming design notes

(12) DS3231 python programming design notes

(13) DS3232 Square Wave Setup

(14) DS3231SN Realtime Clock with AT24C32 EEPROM Module – AliExpress US$1.28

(15) Using a $1 DS3231 Real-time Clock Module with Arduino (and which components to remove) – Underwater Arduino Data Loggers

(16) MicroPython class I2C

(17) MicroPython Class RTC

(18) Build Programmable Time-based Switches Using a Real Time Clock (Arduino) – Raymond Genovese, All About Circuits, 2016apr07


/ to continue, …


Appendices

Appendix A – DS3231 INT/SQ pin programming design notes

int/sq pin

Appendix B – DS3231 Alarm programming design notes

alarm 1

Appendix C – Real Time Clock Module

(14) DS3231SN Realtime Clock with AT24C32 EEPROM Module – AliExpress US$1.28

rtc module

Appendix D – Schematic and Pullups to remove to reduce capacitance to < 400pF

Notes

  1. I2C bus uasually has a capacitance limit of 400pF, exceeding which might cause I/O transmission errors.
  2. R4B I2C pins already have strong pullups of 1k8, so it is a good idea to remove the DS3231 and other devices’ on board pullups of usually 4k7, sometimes 10k
  3. It is also a good idea of keeping the I2C wiring short, less than 30cm if possible.
  4. It is also a good idea, especially during prototyping or troubleshooting, to use low frequencies for I2C, say 100kHz or even down to 50kHz, so that resulting impedance is less than 400pF.

ds3231 schematic

Appendix E – Summary of MicroPython I2C I2C and RTC class and methods used to control DS3231

MicroPython class I2C

1. Example usage:

from machine import I2C i2c = I2C(freq=400000)
i2c.scan()
i2c.writeto(42, b’123′) i2c.readfrom(42, 4)

2. Constructors

class machine.I2C(id, *, scl, sda, freq=400000)

3. General Methods

I2C.init(scl, sda, *, freq=400000) I2C.scan()

4. Standard bus operations

I2C.readfrom(addr, nbytes, stop=True, /) Read nbytes from the slave specified by addr. If stop is true then a STOP condition is generated at the end of the transfer. Returns a bytes object with the data read.

I2C.readfrom_into(addr, buf, stop=True, /) Read into buf from the slave specified by addr. The number of bytes read will be the length of buf. If stop is true then a STOP condition is generated at the end of the transfer. The method returns None.

I2C.writeto(addr, buf, stop=True, /) Write the bytes from buf to the slave specified by addr. If a NACK is received following the write of a byte from buf then the remaining bytes are not sent.

I2C.writevto(addr, vector, stop=True, /) Write the bytes contained in vector to the slave specified by addr. vector should be a tuple or list of objects with the buffer protocol. The addr is sent once and then the bytes from each object in vector are written out sequentially. The objects in vector may be zero bytes in length in which case they don’t contribute to the output.


MicroPython Class RTC

class machine.RTC(id=0, …) Create an RTC object. See init for parameters of initialization

RTC.init(datetime) Initialise the RTC. Datetime is a tuple of the form: (year, month, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]])

RTC.now() Get get the current datetime tuple.


Appendix F – Old Rpi python program for DS3231

*** Start clock01 ***

#!/usr/bin/python3

tlfong01.com RpiIotSdkApi v01 clockds3231m01.856 – 2017dec15hkt2131

rpi3B raspian jessie v.2017jun21, python 3.5.1, pySerial 3.3

import buzzer01 as buzzer import timer01 as timer import menu01 as menu import digiout01 as digiout import fprint01 as fprint import sys01 as sys import i2c01 as i2c import demux01 as demux

import lcdm01 as lcdm

*** Config ***

initMdNum = 0 # Module Num initDvNum = 0 # Device Num initMnNum = 0 # Menu Num

initPortNum = 0 initI2cSpeedName = ‘100KHz’ initDemuxChNum = 3 initDvSubAddr = 0b000

testMdNum = initMdNum testDvNum = initDvNum

demuxChPinList = demux.i2cDemuxChPinList

mdCnfg0= { ‘0’: { ‘Title’ : ‘clock device #0’, ‘DvId’ : ‘Hong Kong’, ‘DvNum’: 0, ‘DtNum’: 0, ‘DemuxChNum’ : 3, ‘DtDict’: { ‘Year’ : 17, ‘Month’ : 8, ‘Date’ : 11, ‘Day’ : 5, ‘Hour’ : 20, ‘Minute’: 35, ‘Second’: 0 } }, ‘1’: { ‘Title’ : ‘clock device #1’, ‘DvId’ : ‘New York’, ‘DvNum’: 1, ‘DtNum’: 1, ‘DemuxChNum’ : 1, ‘DtDict’: { ‘Year’ : 17, ‘Month’ : 8, ‘Date’ : 11, ‘Day’ : 5, ‘Hour’ : 20, ‘Minute’: 35, ‘Second’: 0 } }, ‘2’: { ‘Title’ : ‘clock device #2’, ‘DvId’ : ‘London’, ‘DvNum’: 2, ‘DtNum’: 2, ‘DemuxChNum’ : 2, ‘DtDict’: { ‘Year’ : 17, ‘Month’ : 8, ‘Date’ : 11, ‘Day’ : 5, ‘Hour’ : 20, ‘Minute’: 35, ‘Second’: 0 } }, ‘3’: { ‘Title’ : ‘clock device #3’, ‘DvId’ : ‘Tokyo’, ‘DvNum’: 3, ‘DtNum’: 3, ‘DemuxChNum’ : 3, ‘DtDict’: { ‘Year’ : 17, ‘Month’ : 8, ‘Date’ : 11, ‘Day’ : 5, ‘Hour’ : 20, ‘Minute’: 35, ‘Second’: 0 } } }

mdCnfgList = [mdCnfg0, mdCnfg0, mdCnfg0, mdCnfg0]

“”” old mdConfig ‘Title’ : ‘i2c01’, ‘MdNum’: 0, ‘PortType’: ‘i2c’, ‘DemuxChPinList’: demuxChPinList, ‘Init’: { ‘MnNum’ : initMnNum, ‘PortNum’ : initPortNum, ‘Speed’ : initI2cSpeedName, ‘DvNum’ : initDvNum, ‘DemuxChNum’ : initDemuxChNum, ‘DvSubAddr’ : initDvSubAddr }, ‘Now’: { ‘PortNum’ : 0, ‘Speed’ : ‘100KHz’,
‘DvNum’ : 0, ‘DemuxChNum’ : 0, ‘DvSubAddr’ : initDvSubAddr }, “””

*** Test config ***

initClockDvNum = 0 initClockDvNumList = [0, 1, 2, 3] initLcdmDvNumList = [0, 1, 2, 3]

ds3231Addr = 0x68 # DS3231 at24c32Addr = 0x57 # AT24C32

i2cPortNum0 = 0

i2cClockAddr = ds3231Addr i2cEepromAddr = at24c32Addr

dvNumList = [0, 1, 2, 3]

regAddr = { ‘Second’ : 0x00, ‘Minute’ : 0x01, ‘Hour’ : 0x02, ‘Day’ : 0x03, ‘Date’ : 0x04, ‘Month’ : 0x05, ‘Year’ : 0x06, ‘Alarm1Second’ : 0x07, ‘Alarm1Minute’ : 0x08, ‘Alarm1Hour’ : 0x09, ‘Alarm1DayDate’ : 0x0a, ‘Alarm2Minute’ : 0x0b, ‘Alarm2Hour’ : 0x0c, ‘Alarm2DayDate’ : 0x0d, ‘Control’ : 0x0e, ‘StatusControl’ : 0x0f, ‘AgingOffset’ : 0x10, ‘TempMsb’ : 0x11, ‘TempLsb’ : 0x12}

controlByte = { ‘BaseControl’: 0b00000000, ‘StartOscillator’: 0b00000000, ‘StopOscillator’: 0b10000000, ‘EnableBatteryBackedSquareWaveEnable’: 0b01000000, ‘DisableBatteryBackedSquareWaveEnable’: 0b00000000, ‘EnableTemperatureConversion’: 0b00100000, ‘DisableTemperatureConversion’: 0b00000000, ‘SelectFrequencyMask’: 0b11100111, ‘SelectFrequency1Hz’: 0b00000000, ‘SelectFrequency1kHz’: 0b00001000, ‘SelectFrequency4kHz’: 0b00010000, ‘SelectFrequency8kHz’: 0b00011000, ‘SelectInterruptSquareWaveMask’: 0b11111011, ‘EnableInterruptOutput’: 0b00000100, ‘EnableSquareWaveOutput’: 0b00000000, ‘EnableAlarm12Mask’: 0b11111100, ‘EnableAlarm2InterruptStatusFlag’: 0b00000010, ‘EnalbeAlarm1InterruptStatusFlag’: 0b00000001, ‘DataByte0x55’: 0x55, ‘DataByte0x66’: 0x66, ‘EnableSquareWaveOutputMask’ : 0b00000100, ‘SquareWaveFreqClearMask’ : 0b00011000, ‘SquareWaveFreq1HzMask’ : 0b00000000, ‘SquareWaveFreq1024HzMask’ : 0b00001000, ‘SquareWaveFreq4096HzMask’ : 0b00010000, ‘SquareWaveFreq8192HzMask’ : 0b00011000, ‘EnableOsf32Khz’ : 0b10001000, }

clockStatusByte = { ‘AlarmOncePerSecond’: 0x80, ‘AlarmOncePerMinute’: 0x80, ‘ClearAlarm1Flag’: 0b00000001, ‘ClearAlarm2Flag’: 0b00000010}

dayOfWeek = {1: ‘Mon’, 2: ‘Tue’, 3: ‘Wed’, 4: ‘Thu’, 5: ‘Fri’, 6: ‘Sat’, 7: ‘Sun’}

monthOfYear = {1: ‘Jan’, 2: ‘Feb’, 3: ‘Mar’, 4: ‘Apr’, 5: ‘May’, 6: ‘Jun’, 7: ‘Jul’, 8: ‘Aug’, 9: ‘Sep’, 10: ‘Oct’, 11: ‘Nov’, 12: ‘Dec’}

*** Functions ***

*** Demux ***

def selectDemuxChannel(demuxChNum):

i2c.resetDemuxChAllHighActive
i2c.selectDemuxChHighActive(demuxChNum)

return

*** Hex/BCD conversion, str padding *

def decIntToBcdByte(dec): bcd = (int((dec // 10)) << 4) + (dec % 10) return bcd

def bcdByteToDecInt(bcdByte): decInt = (bcdByte >> 4) * 10 + (bcdByte & 0x0f) return decInt

def str2Digit(int): strNdigit = str(int) if len(strNdigit) == 1: str2Digit = ‘0’ + strNdigit else: str2Digit = strNdigit return str2Digit

*** Clock ***

*** Operation delays ***

def clockWriteDelay(): timer.sleepMilliSeconds(200) return

def clockReadDelay(): timer.sleepMilliSeconds(200) return

def temperatureConversionDelay(): timer.sleepMilliSeconds(250) return

def pushButtonDebounceDelay(): timer.sleepMilliSeconds(300) return

def oscStopDelay(): timer.sleepMilliSeconds(150) return

*** write/read ***

def clockReadRegOneByte(regName): i2cPortNum = i2cPortNum0 deviceAddr = i2cClockAddr regAddrByte = regAddr[regName] readByte = i2c.readRegOneByte(i2cPortNum, deviceAddr, regAddrByte) clockReadDelay() return readByte

def clockWriteRegOneByte(regName, writeDataByte): i2cPortNum = i2cPortNum0 deviceAddr = i2cClockAddr regAddrByte = regAddr[regName] i2c.writeRegOneByte(i2cPortNum, deviceAddr, regAddrByte, writeDataByte) clockWriteDelay()
return

def pingClock(dvNum): print(‘ Begin pingClock(), …’)

dataByte = 0x55
clockWriteRegOneByte('Year', dataByte)   
readByte = clockReadRegOneByte(dvNum, 'Year')     
print('          writeByte to   register "Year" = ', hex(dataByte))
print('          readByte  from register "Year" = ', hex(readByte))

dataByte = 0x88
clockWriteRegOneByte('Year', dataByte)   
readByte = clockReadRegOneByte(dvNum, 'Year')     
print('          writeByte to   register "Year" = ', hex(dataByte))
print('          readByte  from register "Year" = ', hex(readByte))

print('        End   pingClock(), ...')
return    

def configClock(mdCnfg, dvNum): print(”) print(‘ Begin configClock(), …’) demuxChNum = mdCnfg[str(dvNum)][‘DemuxChNum’] selectDemuxChannel(demuxChNum)

    configByte  = controlByte['BaseControl']
    configByte |= controlByte['StartOscillator']
    configByte |= controlByte['DisableBatteryBackedSquareWaveEnable']
    configByte |= controlByte['DisableTemperatureConversion']
    configByte |= controlByte['SelectFrequency1Hz']
    configByte |= controlByte['EnableSquareWaveOutput']
    configByte &= ~controlByte['EnableSquareWaveOutputMask']
    configByte &= ~controlByte['SquareWaveFreq1HzMask']
    clockWriteRegOneByte('Control', configByte)
    clockWriteDelay()
    clockWriteRegOneByte('StatusControl', controlByte['EnableOsf32Khz'])
    print('        End   configClock().')
    return

def setDateTime(mdCnfg, dvNum): dtDict = mdCnfgList[testMdNum][str(dvNum)][‘DtDict’] year = dtDict[‘Year’] month = dtDict[‘Month’] date = dtDict[‘Date’] day = dtDict[‘Day’] hour = dtDict[‘Hour’] minute = dtDict[‘Minute’] second = dtDict[‘Second’]

demuxChNum = mdCnfg[str(dvNum)]['DemuxChNum']
selectDemuxChannel(demuxChNum)
    
clockWriteRegOneByte('Year', decIntToBcdByte(year))
clockWriteRegOneByte('Month', decIntToBcdByte(month))
clockWriteRegOneByte('Date', decIntToBcdByte(date))
clockWriteRegOneByte('Day', decIntToBcdByte(day))
clockWriteRegOneByte('Hour', decIntToBcdByte(hour))
clockWriteRegOneByte('Minute', decIntToBcdByte(minute))
clockWriteRegOneByte('Second', decIntToBcdByte(second))

clockWriteDelay()

return

def syncClock(mdCnfg, dvNum): print(‘ Begin syncClock(), …’) dtDict = mdCnfgList[testMdNum][str(dvNum)][‘DtDict’]

sysDtDict = sys.getDateTimeNowDict()

dtDict['Year']   = sysDtDict['Year']    
dtDict['Month']  = sysDtDict['Month']
dtDict['Date']   = sysDtDict['Date']
dtDict['Hour']   = sysDtDict['Hour']
dtDict['Minute'] = sysDtDict['Minute']
dtDict['Second'] = sysDtDict['Second']

setDateTime(mdCnfg, dvNum)

print('        End   syncClock().')

return

def readClock(mdCnfg, dvNum): print(‘ Begin readClock(), …’) dtDict = mdCnfgList[testMdNum][str(dvNum)][‘DtDict’]
dateStr = str(2000 + dtDict[‘Year’]) + ‘-‘ + str2Digit(dtDict[‘Month’]) + ‘-‘ + str2Digit(dtDict[‘Date’]) timeStr = str2Digit(dtDict[‘Hour’]) + ‘:’ + str2Digit(dtDict[‘Minute’]) dateTimeStr = dateStr + ‘ ‘ + timeStr tempStr = getTemperatureStr(dvNum) print(‘ Year = ‘, (2000 + dtDict[‘Year’])) print(‘ Month = ‘, str2Digit(dtDict[‘Month’])) print(‘ Date = ‘, str2Digit(dtDict[‘Date’])) print(‘ Hour = ‘, str2Digit(dtDict[‘Hour’])) print(‘ Minute = ‘, str2Digit(dtDict[‘Minute’])) print(‘ End readClock(), …’) return

def readDateTime(dvNum): print(”) print(‘ Begin readClock(), …’)

yearBcdByte   = clockReadRegOneByte(dvNum, regName = 'Year')
monthBcdByte  = clockReadRegOneByte(dvNum, regName = 'Month')
dateBcdByte   = clockReadRegOneByte(dvNum, regName = 'Date')
hourBcdByte   = clockReadRegOneByte(dvNum, regName = 'Hour')
minuteBcdByte = clockReadRegOneByte(dvNum, regName = 'Minute')
secondBcdByte = clockReadRegOneByte(dvNum, regName = 'Second')

yearDecInt = bcdByteToDecInt(yearBcdByte)
monthDecInt = bcdByteToDecInt(monthBcdByte)
dateDecInt = bcdByteToDecInt(dateBcdByte)
hourDecInt = bcdByteToDecInt(hourBcdByte)
minuteDecInt = bcdByteToDecInt(minuteBcdByte)
secondDecInt = bcdByteToDecInt(secondBcdByte)

selectDemuxChannel(mdCnfgList[testMdNum][str(dvNum)]['DemuxChNum'])

print('          Clock Num = ', mdCnfgList[testMdNum][str(dvNum)]['DvNum'])
print('          City      = ', mdCnfgList[testMdNum][str(dvNum)]['DvId'])

print('          Time      = ', (2000 + yearDecInt), monthOfYear[monthDecInt],
      dateDecInt, (str2Digit(hourDecInt) + ':' + str2Digit(minuteDecInt)))

print('        End   readClock(), ...')
return

#def readClock(dvNum):

readDateTime(dvNum)

return

def getDateTimeDict(dvNum): print(”) print(‘ Begin getDateTime(), …’) selectDemuxChannel(mdCnfgList[testMdNum][str(dvNum)][‘DemuxChNum’])

dayOfWeek =  {
    1: 'Mon', 2: 'Tue', 3: 'Wed', 4: 'Thu', 5: 'Fri', 6: 'Sat', 7: 'Sun'}

monthOfYear = {1: 'Jan', 2: 'Feb', 3: 'Mar',  4: 'Apr',  5: 'May',  6: 'Jun', 
               7: 'Jul', 8: 'Aug', 9: 'Sep', 10: 'Oct', 11: 'Nov', 12: 'Dec'}

yearBcdByte   = clockReadRegOneByte(dvNum, regName = 'Year')
monthBcdByte  = clockReadRegOneByte(dvNum, regName = 'Month')
dateBcdByte   = clockReadRegOneByte(dvNum, regName = 'Date')
dayBcdByte    = clockReadRegOneByte(dvNum, regName = 'Day')
hourBcdByte   = clockReadRegOneByte(dvNum, regName = 'Hour')
minuteBcdByte = clockReadRegOneByte(dvNum, regName = 'Minute')
secondBcdByte = clockReadRegOneByte(dvNum, regName = 'Second')

yearDecInt = bcdByteToDecInt(yearBcdByte)
monthDecInt = bcdByteToDecInt(monthBcdByte)
dateDecInt = bcdByteToDecInt(dateBcdByte)
dayDecInt = bcdByteToDecInt(dayBcdByte)
hourDecInt = bcdByteToDecInt(hourBcdByte)
minuteDecInt = bcdByteToDecInt(minuteBcdByte)
secondDecInt = bcdByteToDecInt(secondBcdByte)

dtDict = {
             'Year'  : yearDecInt,
             'Month' : monthDecInt,
             'Date'  : dateDecInt,
             'Day'   : dayDecInt,
             'Hour'  : hourDecInt,
             'Minute': minuteDecInt,
             'Second': secondDecInt
            }

print('        End   getDateTime(), ...')

return dtDict

def printTemperature(dvNum): print(‘ Begin printTemperature(), …’) selectDemuxChannel(mdCnfgList[testMdNum][str(dvNum)][‘DemuxChNum’])

temperatureMsbByte   = clockReadRegOneByte(dvNum, regName = 'TempMsb')
temperatureConversionDelay()
temperatureLsbByte   = clockReadRegOneByte(dvNum, regName = 'TempLsb')
temperatureConversionDelay()
temperatureInteger  = temperatureMsbByte   
temperatureFraction = (temperatureLsbByte >> 6) * 25
print('          Temperature = %d.%d degrees C ' % (temperatureInteger,temperatureFraction))
print('        End   printTemperature(), ...')  
return

def getTemperatureStr(dvNum): selectDemuxChannel(mdCnfgList[testMdNum][str(dvNum)][‘DemuxChNum’])

temperatureMsbByte   = clockReadRegOneByte(regName = 'TempMsb')
temperatureConversionDelay()
temperatureLsbByte   = clockReadRegOneByte(regName = 'TempLsb')
temperatureConversionDelay()
tempInteger  = temperatureMsbByte   
tempFraction = (temperatureLsbByte >> 6) * 25
tempStr      = str(tempInteger) + '.' + str(tempFraction)
return tempStr

def setSquareWaveFreq(dvNum, frequencyMaskName): currentControlByte = clockReadRegOneByte(dvNum, ‘Control’)
newControlByte = sys.updateNbits(currentControlByte, controlByte[‘SquareWaveFreqClearMask’], controlByte[frequencyMaskName]) clockWriteRegOneByte(‘Control’, newControlByte) return

*** Eeprom ***

*** Eeprom operation delay ***

*** operation delay ***

def eepromWriteDelay(): # AT24C32 write cycle time tWR = 10mS max timer.sleepMilliSeconds(500) return

*** Write/read ***

def eepromWriteOneByte(i2cPortNum, devAddrByte, memAddrWord, writeByte): memAddrMsb = memAddrWord >> 8 memAddrLsb = memAddrWord & 0x00ff i2c.writeDeviceThreeBytes(i2cPortNum, devAddrByte, memAddrMsb, memAddrLsb, writeByte)
eepromWriteDelay() return

def eepromReadOneByte(i2cPortNum, devAddrByte, memAddrWord): memAddrMsb = memAddrWord >> 8 memAddrLsb = memAddrWord & 0x00ff
i2c.writeDeviceTwoBytes(i2cPortNum, devAddrByte, memAddrMsb, memAddrLsb) eepromWriteDelay() readByte = i2c.readDeviceOneByte(i2cPortNum, devAddrByte) eepromWriteDelay() # not sure if necessary!
return readByte

*** Tests ***

*** Clock ***

def pingClockN(): dvNum = fprint.askNum(‘Device number’, 9, 28) selectDemuxChannel(mdCnfgList[testMdNum][str(dvNum)][‘DemuxChNum’]) pingClock(dvNum) return

def readDateTimeClockN(): dvNum = fprint.askNum(‘Device number’, 9, 28) selectDemuxChannel(mdCnfgList[testMdNum][str(dvNum)][‘DemuxChNum’]) readDateTime(dvNum) return

def setDateTimeClockN(): dvNum = fprint.askNum(‘Device number’, 9, 28) selectDemuxChannel(mdCnfgList[testMdNum][str(dvNum)][‘DemuxChNum’]) dtNum = fprint.askNum(‘DateTime dict number’, 9, 28) setDateTime(dvNum, dtNum) readDateTime(dvNum) return

def configClockN(): dvNum = fprint.askNum(‘Device number’, 9, 28) selectDemuxChannel(mdCnfgList[testMdNum][str(dvNum)][‘DemuxChNum’]) configClock(dvNum) return

def printTemperatureClockN(): dvNum = fprint.askNum(‘Device number’, 9, 28)

printTemperature(dvNum)
return

def selectDemuxChannelN(): print(‘ Begin selectDemuxChannel(), …’, end = ”) fprint.printNewlineTitleStrNoNewLine(‘Clock demux channel number’, 9, 28, ‘? ‘) buzzer.beep(1) clockDemuxChNum = int(input()) selectDemuxChannel(clockDemuxChNum)
print(‘ End selectDemuxChannel().’) return

def setSquareWave8192HzClockN(): dvNum = fprint.askNum(‘Device number’, 9, 28) selectDemuxChannel(mdCnfgList[testMdNum][str(dvNum)][‘DemuxChNum’]) freqMaskName = ‘SquareWaveFreq8192HzMask’
setSquareWaveFreq(dvNum, freqMaskName) return

def setSquareWave1HzClockN(): dvNum = fprint.askNum(‘Device number’, 9, 28) selectDemuxChannel(mdCnfgList[testMdNum][str(dvNum)][‘DemuxChNum’]) freqMaskName = ‘SquareWaveFreq1HzMask’ setSquareWaveFreq(dvNum, freqMaskName) return

*** LCDM display clock ***

def userReadClock(): dvNum = fprint.askNum(‘Clock Device number’, 9, 28) selectDemuxChannel(dvDictList[dvNum][‘DemuxChNum’]) dtDict = getDateTime(dvNum) print(‘ Year = ‘, (2000 + dtDict[‘Year’])) lcdm.initLcdm(dvNum = 0) dateStr = str(2000 + dtDict[‘Year’]) + monthOfYear[dtDict[‘Month’]] + str(dtDict[‘Date’]) + dayOfWeek[dtDict[‘Day’]] timeStr = str(dtDict[‘Hour’]) + ‘:’ + str(dtDict[‘Minute’]) dateTimeStr = dateStr + ‘ ‘ + timeStr lcdm.displayMessage(dvNum = 0, messageStr = dateTimeStr, lineNum = 1) return

def displayTimeInitClockDvNumInitLcdmDvNumList():

dvNum = initClockDvNum

dtDict = getDateTimeDict(dvNum)

# *** translate date time data to print strings ***
print('          Year = ', (2000 + dtDict['Year']))
dateStr = str(2000 + dtDict['Year']) + '-' + str2Digit(dtDict['Month']) + '-' + str2Digit(dtDict['Date'])
timeStr = str2Digit(dtDict['Hour']) + ':' + str2Digit(dtDict['Minute'])
dateTimeStr = dateStr + ' ' + timeStr
tempStr = getTemperatureStr(dvNum)

# *** display on lcdm ***

for lcdmDvNum in initLcdmDvNumList:
    lcdm.clearDisplay(lcdmDvNum)
    lcdm.displayMessage(lcdmDvNum, messageStr = 'lcdm = ' + str(lcdmDvNum), lineNum = 1)
    lcdm.displayMessage(lcdmDvNum, messageStr = 'date = ' + dateStr, lineNum = 2)
    lcdm.displayMessage(lcdmDvNum, messageStr = 'time = ' + timeStr, lineNum = 3)
    lcdm.displayMessage(lcdmDvNum, messageStr = 'temp = ' + tempStr + ' deg C', lineNum = 4)
return

def syncRpiTimeInitClockDvNum(): syncClock(initDvNum) return

def userResetClock(): mdCnfg = mdCnfg0 dvNum = fprint.askNum(‘Clock number’, 9, 28) selectDemuxChannel(mdCnfgList[testMdNum][str(dvNum)][‘DemuxChNum’]) configClock(dvNum) syncClock(dvNum) readClock(mdCnfg0, dvNum) return

/ to continue, …


ShareEditDeleteFlagedited 3 hours agoanswered Apr 7 at 1:53tlfong013,65133 gold badges88 silver badges2222 bronze badges

  • 1FWIW, this is the module I need to program. – Seamus Apr 8 at 7:21
  • Ah, your DS3231 RTC module is a “mini” version. It is small and therefore good if you want to save space. For prototyping, my module is better for the following reasons: (1) with address jumpers A0, A1, A2 to set 8 device address, so to use more than a DS3231 on the same bus. (2) With an EEPROM to store data. (3) Generously spaced components to easily modify circuits. eg. remove pullup resistors, modify battery charging options. See Ref 15 for more details. – tlfong01 Apr 8 at 14:47   
  • You recommended tutorial by All About Circuits is as good as mine. So I have included in to my reference list (Ref #18). Cheers. – tlfong01 Apr 9 at 13:44   
  • You still have / to continue, ... remarks in several places, but since it’s been over a week since your last edit, I assume you’re finished. I don’t understand how you mis-interpreted my question. It’s not a long, detailed question – but you even summarized it incorrectly. With no disrespect intended, this answer is not helpful. I’d like to delete my question. I don’t want to impact your efforts, so perhaps you could post your own question, and then copy & paste your answer there? – Seamus 9 hours ago
  • Ah I did hesitate to update with this info. seeedstudio.com/…. I now have 6 or more Pico in hand, and 10 more are on their way from RS. I also have perhaps 10 Pico breakout boards in hand, mostly by perorder,. as soon as the morning I read the Google alert. I do have 3 Pico and 6 breadout boards from Seeed. RTS is not urgent for me, so I might just order them after I see the reviews. I also have more than 10 breakout boards from Piromori. Perhaps they have already been making RTC boards for Pico. – tlfong01 4 hours ago   
  • There might be some misunderstand. I told you that your RTC breakout is a minimal version without terminals so not easy to extract the squarewave and 32k signal. So I thouht you either (1) gave up, because it was just a weekend fun project, (2) you have ordered the full version from Ebay, AliExpress, which I know might take 2 to 5 weeks to deliver. Recently I ordered MCP23S17 and the 4g LET box from AliExpress and it indeed take three weeks. / tonctinue, – tlfong01 4 hours ago   
  • I usually order from TaoBao, and direct from Factory Flagship shop, and because I have a VIP account in most of the shops I regularly shop, and they can see my old orders are usually 10 times than the average clients, and almost pay my bill within 4 hours, so they usually give me special treatment and ship my goods within average 24 hours. – tlfong01 4 hours ago   
  • I vaguely remember that I gave you a list of my old blog posts which include python programs on how to read DS3231 temperatue, ping a register, and include a program showing the dictionry struacure of the DS3231 registers (yes, borrowed from Arduino). I forgot if I told you that once you know how to read/write a DS3231 register, then the rest is easy. I know my python program in my blog is mingled with MCP23017 and mux with 8 DS3231 on the same I2C bus, so I thought you were able to handle it. Perhaps you are not experience in python.so if my program was in C, you could rewrte it in 1 hour. – tlfong01 3 hours ago   
  • Anyway, perhaps I would try to search my old file directories and see if I can find a 3 year fold newbie friendly demo program for your reference. I will let you know perhaps in a couple of days. – tlfong01 3 hours ago   
  • I am back. I have luck and quickly found from my messy old file box a year 2017 DS3231 program with the basic functions on read temperature, read DS3231 register, ping, set date, set alarms etc. They are all in functional programming style, ie no side effects, no global variable. So you can almost just copy an paste functions and their dependent functions upwards. PS – my old program is in last appendix. I did not upload the complete program listing, because I already hit the SE’s 30k word limit. – tlfong01 3 hours ago    
  • So I actually cut the EEPROM part of the program. The original file in in Chinese Window file format. If you have problems or reading funncy charaters, I can try to compile a PenZu lab log for you. – tlfong01 3 hours ago   
  • And because my program is actually a “package”, so I can import it to other programs. You see many of the mid level functions have parameters such as “demux number” and “device num”, because most of the low level stuff like device address, reg addr etc are also abstracted to numbers which can freely transfer among different levels of functions (but not “objects” which cannot flow up/down levels. If you have been doing functional programming in LISP, Scheme, ML, Haskell, LUA, Scala, Python, … you might find my programs very “expressive” and “self documenting”, with little/no comments. 🙂 – tlfong01 3 hours ago   

Add a comment

Categories: Uncategorized

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.