DS1302 RTC Driver

JBWolfJBWolf Posts: 366
edited 2020-07-21 - 02:51:17 in Propeller 1
I am having trouble finding a working driver for the DS1320 RTC I purchased from the parallax shop.
The driver resource links are to the now disabled old OBEX, and when I search github it returns just a mess of files that crosslink to other files that I cannot identify which is the correct associated one.
for example there are multiple spin files relying on other .c or .h files for which there are many of those all with the same name and no identifying header notes

Comments

  • Here is a DS1302 Demo package that I got from OBEX in the past.

    It contains all the spin files needed to Demo the DS1302.
  • Thank you... can you verify, the following commands look as if they change the trickle charge setting to ON regardless as what it is currently set to.
    The one sold be the parallax shop contains the battery and warns not to enable trickle charge or it will damage the unit
    'change the tricle charger setup from that currently defined in the config function
      'Trickle charger setup                       tc_enable     diodeSel   resistSel
      '                                                |            |          |
      rtc.write(rtc.command(rtc#clock,rtc#tc,rtc#w),(%1010 << 4) + (1 << 2)+ ( 1 ))
      out:=rtc.read(rtc.command(rtc#clock,rtc#tc,rtc#r))
      Debug.Str(string("Trickle charge register contents = "))
      Debug.bin(out,8)
      Debug.Str(String(13,13))
    
  • JBWolf wrote: »
    Thank you... can you verify, the following commands look as if they change the trickle charge setting to ON regardless as what it is currently set to.
    The one sold be the parallax shop contains the battery and warns not to enable trickle charge or it will damage the unit
    'change the tricle charger setup from that currently defined in the config function
      'Trickle charger setup                       tc_enable     diodeSel   resistSel
      '                                                |            |          |
      rtc.write(rtc.command(rtc#clock,rtc#tc,rtc#w),(%1010 << 4) + (1 << 2)+ ( 1 ))
      out:=rtc.read(rtc.command(rtc#clock,rtc#tc,rtc#r))
      Debug.Str(string("Trickle charge register contents = "))
      Debug.bin(out,8)
      Debug.Str(String(13,13))
    

    Yes, it does seem that the trickle charge has been turned on using 1 diode in the Demo code.

    So I would change the diodeSel value from 1 to 0 to turn-off the Trickle charge.

    I overlooked the warning in the DS1302 module's documentation that you noticed, so I didn't realize that the Demo code was turning on the trickle charge which it shouldn't for Parallax's DS1302 module.

    I have been running an adaptation of this Demo code with a Parallax Flip Module, OLED Display, DS1302 module and 5-button switch since December 2019. I hadn't noticed any problems, but I went ahead and changed my code to keep the trickle charge off. [If you want a copy of my adapted code, let me know.]

    So thank you, for noticing this and helping us both out...
  • That would be great thank you, please do

    so for turning off trickle charge in this code, should it be:
    'change the tricle charger setup from that currently defined in the config function
      'Trickle charger setup                       tc_enable     diodeSel   resistSel
      '                                                |            |          |
      rtc.write(rtc.command(rtc#clock,rtc#tc,rtc#w),(%0000 << 4) + (0 << 2)+ ( 0 ))
      out:=rtc.read(rtc.command(rtc#clock,rtc#tc,rtc#r))
      Debug.Str(string("Trickle charge register contents = "))
      Debug.bin(out,8)
      Debug.Str(String(13,13))
    
  • Yes, according to the DS1302 driver documentation setting a 0 or 3 for diodeSel should turn-off the trickle charge.

    I've attached an archive of my code using the DS1302 as part of implementing an AC Fan Controller.

    The file "AC_Controller.spin" is the main program in the archive.

    I haven't finished the AC control/Relay part yet, but the Displaying and Setting of Time/Date is working, enjoy...
  • @Francis Bauer

    Would you be willing to post your schematic and or pictures of your controller?
  • DaveJenson wrote: »
    @Francis Bauer

    Would you be willing to post your schematic and or pictures of your controller?

    Sure, I'll post something soon, it is a work in progress and I have been focusing on other things lately.
  • This is still a work in progress but it's functional and you may enjoy playing with it. It's an interactive demo that allows you to manipulate the DS1302 RTC. This is NOT a bare minimum driver. It's a BEAR. Written entirely in SPIN. It's meant to be educational. It has limit checking. It even changes the date limit in the menu based on month and leap year. It allows you to start/stop the clock, toggle 12/24 hour and AM/PM modes and correctly adjust the hours. You can read/write the RAM locations. It has a very SIMPLE interface usually a single keystroke followed by the data, if needed. No enter key or backspace correction. If you mistype just push try and retry. Compile the top level object, DS1302_demo, open the Parallax Serial Terminal and press the 1 key to update the terminal. The code is based on existing code in the parallax repository just more of it. The only thing you have to modify is line 7 in DS1302_demo.spin to specify the pins you'll use. Currently I'm using 22 as Chip Enable, 23 as the clock and 24 for I/O. I do some interesting things with the DAT section and the BYTE and BYTEMOVE commands to manipulate the menus. Enjoy.
  • CJMJ,
    Thanks for posting your interactive driver for the DS1302 RTC.
    I wish it was available a few months ago when I was integrating a RTC into a project.
    I eventually used a DS3231, persuaded by the following online notes;
    "DS3231 and DS1307 are functionally the same, except that DS3231 has a built-in temperature compensated crystal, which makes it more accurate, but also the chip is much larger. They both use the same I2C address and libraries that work for DS1307 should work for DS3231 too
    DS3231
    The DS3231 is an extremely accurate I²C-integrated temperature-compensated crystal oscillator (TCXO) and crystal".

    It would be very useful if you extended your interactive driver to cover the DS3231 and variants.
  • Peter JakackiPeter Jakacki Posts: 9,340
    edited 2020-07-25 - 14:44:05
    @macrobeak - If you are not shy of smd then the best rtc I have found is the RV3028-C7. It's the size of a 4 way smd resnet, so really small, its internal crystal is calibrated to 1ppm and standby current is a mere 45na, so I use a supercap no bigger than the chip itself. I've used a lot of different RTC chips from the original parallel bus monsters, to I2C and SPI, including DS3231 and even the old DS1302 back in the day.
    What's so good about the RV3028? Just read the info at the link. This is the chip I use on the P2D2 module and unless you knew what you were looking for your wouldn't spot it, neither the chip nor the supercap. BTW - I very rarely never use a battery to power an RTC. A supercap never leaks, explodes, or fails nor does it require a battery holder. If the unit is off power that long that the cap can no longer maintain power, then it must be out of service and so the clock would be reset in the workshop.

    1877 x 1536 - 369K
  • JRoarkJRoark Posts: 480
    edited 2020-07-25 - 17:39:34
    @Peter Jakacki Can you ballpark how long the timekeeping keeps going after Vcc drops with the supercap? Are we looking at days? Weeks? Months?

    You've got me interested now...

    Edited to add: I'm liking the RV3028 a lot. The only nit is the use of an internal crystal without any temperature compensation. The 1 ppm accuracy is at 25c and it falls-off with temperature. At the operational temperature limits of the chip that 1 ppm becomes 110-140 ppm, which is about the same drift as a DS1302 with a modern, garden-variety crystal. In real-world terms this gives the RV3028 a drift of ~12 seconds per day (73 mins/yr) under extreme conditions. In contrast the DS3231 does automatic active correction based on temperature, and the accuracy doesn't change much (like 2 ppm max across the entire temperature profile if I'm reading the data sheet right). So if very high accuracy over a wide temperature range is needed, the DS3231 is a better choice. But lacking that requirement, the RV3208 is about a third the cost of the DS and gives UNIX DT stamp as a bonus.

    I ordered a couple from Mouser to play with. Thanks for posting this, Peter.
  • Peter JakackiPeter Jakacki Posts: 9,340
    edited 2020-07-26 - 01:40:27
    The tiny 11,000uF supercap keeps it going for many days but my board does allow for a larger (but still tiny) 0.2F supercap. I've had DS3231 drift badly when in standby since the compensation circuitry draws some power and normally only makes adjustments when it is already powered on (IIRC). Those cheap ebay modules use fake DS3231s too, and while you can read the temperature, they don't seem to do any kind of compensation and I have had them drift by as much as 10 minutes/month.

    But the RV3028 is rock stable, I can come back to it days later in standby and it is spot on, and if plugged in for even a brief period, it is totally recharged. The I2C bus seems to work fine at 1MHz too although I normally do a block read of the first 7 bytes (RV3028 can latch 7 bytes internally) to access time & date in one hit rather than do multiple reads. In Tachyon on the P1 it has an RTC driver that handles all the most common I2C devices and basically does a read at boot time, then a general-purpose background task maintains that time in software, only refreshing it once every 24 hours. That way software does not have to wait for any I2C bus transfers, it just reads the time from memory or as a FAT32 or millisecond timestamp.

    I can set the clock on my P2D2 from a Linux terminal even while the serial port is already being used by a serial terminal emulator, since it allows multiple write access to the device. This is my script and usage which resets the RTC time and date from Linux.
    13:07:59 TAQOZ$ cat dt
    date +'%g%m%d DATE! %u DAY! %H%M%S TIME! %s UTIME!' > /dev/ttyUSB$1 && echo -e "\r" > /dev/ttyUSB$1
    00:45:08 TAQOZ$ ./dt 0
    

    and this is how it looks on the serial terminal emulator.
    TAQOZ# 200726 DATE! 7 DAY! 113530 TIME! 1595727330 UTIME! ---  ok
    

    Oh, I almost forgot, here is some interaction with the chip from TAQOZ.
    TAQOZ# .FDT --- 2020/07/26 SUN 11:38:10 ok
    TAQOZ# 0 $40 RTC DUMP --- 
    00000: 15 38 11 07  26 07 20 80  80 80 00 00  00 00 31 00     '.8..&. .......1.'
    00010: 00 00 00 00  00 00 00 00  00 00 00 86  DE 1C 5F 00     '.............._.'
    00020: 00 00 00 00  00 00 17 00  33 00 00 46  62 13 16 17     '........3..Fb...'
    00030: 00 00 00 00  00 C0 FF B4  99 19 00 00  00 00 00 00     '................' ok
    TAQOZ# UTIME@ . --- 1595727505  ok
    
  • Interesting about the fake DS3231’s. I get mine from Digikey or Mouser and these seem to be the real deal. The temp compensation in the “real” ones runs every 64 seconds when on Vbatt. I used one in a design that was disciplined by a Neo7 gps module and after a week “off” it would lose/gain maybe a second. They’re pretty good little beasties, albeit power-pigs compared to the RV.

    TAQOZ is amazing. I havent even scratched the surface yet, but its very cool what you have done.
  • Peter, do you assemble the P2D2 yourself or do you have a service do it?
  • CJMJ wrote: »
    Peter, do you assemble the P2D2 yourself or do you have a service do it?

    Ah, I wish I had a service, but until I know that the first few I do are right, there isn't much point, plus the run is too small and there aren't any margins, at least for these modules that are being sold to aid P2 development. Maybe with a larger production run and knowing that the design is stable I wouldn't have any hesitation in getting them assembled. I'm not doing this for business, that's for sure.

    That shot was of a prototype I made up myself and I wasn't happy with the quality of the solder paste so I had gone around with the soldering iron touching it up.
  • ugh maybe im just too dumb but i cant get this to work with any of the objects.
    simply trying to set the date/time and read out with basic display on pst to confirm its working.

    ive tried every object in the github obex and the ones provided here. tried as is, also modified to strip down to basics... here the kind of output i keep getting
    Initializing...
    Date: 83 : 43 : 0 : 1
    Time:
    0 : 0 : 10
    0 : 0 : 11
    0 : 0 : 8
    0 : 0 : 49
    0 : 0 : 8
    0 : 0 : 9
    0 : 0 : 90
    0 : 0 : 51
    0 : 0 : 8
    0 : 0 : 9
    0 : 0 : 0
    0 : 0 : 1
    0 : 0 : 0
    0 : 0 : 41
    0 : 0 : 0
    0 : 0 : 1
    0 : 0 : 82
    0 : 0 : 43
    0 : 0 : 0
    0 : 0 : 1
    0 : 0 : 0
    0 : 0 : 1
    
  • JBWolfJBWolf Posts: 366
    edited 2020-07-27 - 05:51:45
    CON
      _clkmode = xtal1 + pll16x 
      _xinfreq = 5_000_000                           ' Set clock to 80MHz
                         
    
      'RTC Pins
      rCLK    = 9
      rIO     = 8
      rCS     = 10
    
                         
    
    OBJ
      SN     : "Simple_Numbers"                      ' Collection of simple numeric functions.
      rtc    : "DS1302_full"                              ' DS1302 (RTC with scratchpad RAM) driver
      pst    : "Parallax Serial Terminal"
    
    VAR
      byte hour, minute, second, day, month, year, dow ' Global variable for RTC values.
      byte cmd, out
      byte data[30]
      
    PUB main
    
        waitcnt(clkfreq * 5 + cnt)                   ' wait 5 secs, start FullDuplexSerial
        pst.start(115200)
        pst.Str(String("Initializing...",13))
     
      InitRTC                                        ' Initialize RTC  (Real-Time-Clock)
      ReadTimeDate
    
    PUB InitRTC
      '==================================================================================
      'call this function each time the propeller starts
      rtc.init( rCLK, rIO, rCS )                     ' ports Clock, IO, chip select
    
    
    PUB ReadTimeDate
    
      rtc.readDate( @day, @month, @year, @dow )      ' read date from DS1302
      pst.str(string("Date: "))
      pst.dec(month)
      pst.str(string(" : "))
      pst.dec(day)
      pst.str(string(" : "))
      pst.dec(year)
      pst.str(string(" : "))
      pst.dec(dow)
      pst.newline
    
      pst.str(string("Time: "))  
      
      repeat
        rtc.readTime( @hour, @minute, @second )      ' read time from DS1302
    
        pst.newline    
        pst.dec(hour)
        pst.str(string(" : "))
        pst.dec(minute)
        pst.str(string(" : "))
        pst.dec(second)
        waitcnt(clkfreq + cnt) 
    
    
  • JBWolf wrote: »
    CON
      _clkmode = xtal1 + pll16x 
      _xinfreq = 5_000_000                           ' Set clock to 80MHz
                         
    
      'RTC Pins
      rCLK    = 9
      rIO     = 8
      rCS     = 10
    
                         
    
    OBJ
      SN     : "Simple_Numbers"                      ' Collection of simple numeric functions.
      rtc    : "DS1302_full"                              ' DS1302 (RTC with scratchpad RAM) driver
      pst    : "Parallax Serial Terminal"
    
    VAR
      byte hour, minute, second, day, month, year, dow ' Global variable for RTC values.
      byte cmd, out
      byte data[30]
      
    PUB main
    
        waitcnt(clkfreq * 5 + cnt)                   ' wait 5 secs, start FullDuplexSerial
        pst.start(115200)
        pst.Str(String("Initializing...",13))
     
      InitRTC                                        ' Initialize RTC  (Real-Time-Clock)
      ReadTimeDate
    
    PUB InitRTC
      '==================================================================================
      'call this function each time the propeller starts
      rtc.init( rCLK, rIO, rCS )                     ' ports Clock, IO, chip select
    
    
    PUB ReadTimeDate
    
      rtc.readDate( @day, @month, @year, @dow )      ' read date from DS1302
      pst.str(string("Date: "))
      pst.dec(month)
      pst.str(string(" : "))
      pst.dec(day)
      pst.str(string(" : "))
      pst.dec(year)
      pst.str(string(" : "))
      pst.dec(dow)
      pst.newline
    
      pst.str(string("Time: "))  
      
      repeat
        rtc.readTime( @hour, @minute, @second )      ' read time from DS1302
    
        pst.newline    
        pst.dec(hour)
        pst.str(string(" : "))
        pst.dec(minute)
        pst.str(string(" : "))
        pst.dec(second)
        waitcnt(clkfreq + cnt) 
    
    

    Your above code works fine on my DS1302 setup, I get the output below for July 26, 2020 11:16:xx. Granted my DS1302 was already initialized with the current Time & Date.
    Initializing...
    Date: 7 : 26 : 20 : 7
    Time:
    23 : 16 : 1
    23 : 16 : 2
    23 : 16 : 3
    23 : 16 : 4
    23 : 16 : 5
    23 : 16 : 6
    23 : 16 : 7
    23 : 16 : 8
    23 : 16 : 9
    23 : 16 : 10
    23 : 16 : 11
    23 : 16 : 12
    23 : 16 : 13
    23 : 16 : 14
    23 : 16 : 15
    23 : 16 : 16
    23 : 16 : 17
    23 : 16 : 18
    23 : 16 : 19
    23 : 16 : 20
    23 : 16 : 21
    23 : 16 : 22
    23 : 16 : 23
    23 : 16 : 24
    23 : 16 : 25
    23 : 16 : 26
    23 : 16 : 27
    23 : 16 : 28
    23 : 16 : 29
    23 : 16 : 30
    23 : 16 : 31
    23 : 16 : 32
    23 : 16 : 33
    23 : 16 : 34
    23 : 16 : 35
    23 : 16 : 36
    

    Your posted code only reads the current Time & Date from the DS1302, you don't have anything that actually sets the initial Time & Date values in the DS1302.

    You need to add/use code like:
    'call this function only after DS1302 power on
      rtc.config                                     ' Set configuration register
    
      'call this function to set DS1302 time
      rtc.setDatetime( month, day, year, dow, hour, minute, second ) 'month, day, year, day of week, hour, minute, second
    

    Now if you already used similar code as above to previously set your DS1302, perhaps your DS1302 is damaged or the battery isn't holding the DS1302 values between being powered-up.

  • JBWolfJBWolf Posts: 366
    edited 2020-07-27 - 07:27:30
    I did run the setdate already... I will try again... but one thing I am not sure about is the trickle charger.
    Should all of these values for TC, diode & resist be 0?
    rtc.write(rtc.command(rtc#clock,rtc#tc,rtc#w),(%0000 << 4) + (0 << 2)+ ( 0 ))
    

    Since the parallax module requires trickle charging to be set to OFF or face damage... I went with all 0's
    here is the origional as per an obex module that used trickle set to on.
    'change the tricle charger setup from that currently defined in the config function
      'Trickle charger setup                       tc_enable     diodeSel   resistSel
      '                                                |            |          |
      rtc.write(rtc.command(rtc#clock,rtc#tc,rtc#w),(%1010 << 4) + (1 << 2)+ ( 1 ))
    
  • JBWolfJBWolf Posts: 366
    edited 2020-07-27 - 07:50:23
    Modified code to:
    CON
      _clkmode = xtal1 + pll16x 
      _xinfreq = 5_000_000                           ' Set clock to 80MHz
                         
    
      'RTC Pins
      rCLK    = 9
      rIO     = 8
      rCS     = 10
    
    OBJ
      SN     : "Simple_Numbers"                      ' Collection of simple numeric functions.
      rtc    : "DS1302_full"                         ' DS1302 (RTC with scratchpad RAM) driver
      Term   : "SerialMirror"                        ' Same as fullDuplexSerial, but can also call from subroutines
      pst    : "Parallax Serial Terminal"
    
    VAR
      byte hour, minute, second, day, month, year, dow ' Global variable for RTC values.
      byte cmd, out
      byte data[30]
      
    PUB main
    
        waitcnt(clkfreq * 5 + cnt)                   ' wait 5 secs, start FullDuplexSerial
        pst.start(115200)
        pst.Str(String("Initializing...",13))
     
      InitRTC                                        ' Initialize RTC  (Real-Time-Clock)
      SetDate     '*** run only once
      ReadTimeDate
    
    PUB InitRTC
      '==================================================================================
      'call this function each time the propeller starts
      rtc.init( rCLK, rIO, rCS )                     ' ports Clock, IO, chip select
    
    PUB SetDate
      rtc.config
      month := 7
      day := 27
      year := 20
      dow := 7
      hour := 2
      minute := 36
      second := 0
      rtc.setDatetime( month, day, year, dow, hour, minute, second ) 'month, day, year, day of week, hour, minute, second  
    
    PUB ReadTimeDate
    
      rtc.readDate( @day, @month, @year, @dow )      ' read date from DS1302
      pst.str(string("Date: "))
      pst.dec(month)
      pst.str(string(" : "))
      pst.dec(day)
      pst.str(string(" : "))
      pst.dec(year)
      pst.str(string(" : "))
      pst.dec(dow)
      pst.newline
    
      pst.str(string("Time: "))  
      
      repeat
        rtc.readTime( @hour, @minute, @second )      ' read time from DS1302
    
        pst.newline    
        pst.dec(hour)
        pst.str(string(" : "))
        pst.dec(minute)
        pst.str(string(" : "))
        pst.dec(second)
        waitcnt(clkfreq + cnt) 
    
    

    output is:
    Initializing...
    Date: 83 : 43 : 0 : 83
    Time:
    0 : 90 : 0
    0 : 90 : 1
    0 : 90 : 0
    0 : 90 : 81
    0 : 90 : 0
    0 : 90 : 1
    0 : 90 : 2
    0 : 90 : 83
    0 : 90 : 0
    0 : 90 : 1
    0 : 90 : 0
    
  • using:
    out := rtc.read(rtc.command(rtc#clock,rtc#tc,rtc#r))
      pst.str(string("Config: "))
      pst.bin(out,8)
    

    I am set to:
    Config: 00000000
    
  • is this a bad unit?
  • JBWolf wrote: »
    is this a bad unit?

    There certainly appears to be something wrong with your unit/setup. I ran your modified code and everything worked as it should, my DS1302 unit's time changed to the values you have stored.

    I even tried adding rtc.write code to change the Config value to other settings and I can't duplicate what you are seeing.

    At this point I don't have an answer other than you have some kind of hardware problem. To be thorough perhaps you should change the propeller pins you are using from 8,9,10 to another set of 3 pins, just to make sure that your propeller doesn't have pin problems. If nothing changes, then I guess your DS1302 is sick.
  • OKAY!!!
    Figured it out... one of the original obex's said to use resistors between the the RTC and prop... they were the problem!
    While changing to different pins as you suggested Francis, I left the resistors behind, it worked and so I removed the resistors and went back to the same old pins and it worked again.
    It is now working as expected :smile:
  • JBWolfJBWolf Posts: 366
    edited 2020-07-27 - 11:11:16
    Here is my working code for anyone else needing just a basic spin driver.
  • JBWolf wrote: »
    OKAY!!!
    Figured it out... one of the original obex's said to use resistors between the the RTC and prop... they were the problem!
    While changing to different pins as you suggested Francis, I left the resistors behind, it worked and so I removed the resistors and went back to the same old pins and it worked again.
    It is now working as expected :smile:

    Congratulations on finding the issue :smiley:
  • DaveJenson wrote: »
    @Francis Bauer

    Would you be willing to post your schematic and or pictures of your controller?

    @DaveJenson

    I've attached a Schematic and other Images/documents about my AC_Controller. It is still a work in progress, eventually I'll get back to finishing it.

    The eventual goal is to use Light & Temperature sensors and Time as trigger sources in controlling the turning ON/OFF of AC Devices like Fans.
  • @Francis Bauer
    Did you include the Dual Relay to control multiple AC devices?
    Or do you need to break both "Hot" and "Neutral" to control them?
  • DaveJenson wrote: »
    @Francis Bauer
    Did you include the Dual Relay to control multiple AC devices?
    Or do you need to break both "Hot" and "Neutral" to control them?

    I planned to use the Dual Relay board mainly since that is what I have available in a reasonably small package. I also have one of Parallax's Digital I/O boards (#27113) that can have up to 8 Relays (mechanical or solid state), that could also be used as well if I needed more switching abilities.

    But you are right, the Dual Relay could be used to either control two AC devices or break two lines on the same AC device.

    We have an enclosed Sun/Patio room that frequently gets over 125 deg. F, so we have window fans to help move air from the outside into the inside to try and keep things cooler. I have had trouble finding good room/window fans (that last more than a year) that can automatically turn ON/OFF based upon Temperature. So the plan was to create my own AC controller that will have the ability to use a number of different triggers (i.e. Temperature, Time and/or Light Levels, in any combination) that I could plug-in any Fan. Of course the AC Controller could be used for other AC devices too.

    Eventually once I get everything fully implemented in hardware/software, I'll post the finished project...
Sign In or Register to comment.