CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Programming registers in the DS3231 RTC....

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
JAM2014



Joined: 24 Apr 2014
Posts: 138

View user's profile Send private message

Programming registers in the DS3231 RTC....
PostPosted: Mon Jul 16, 2018 1:20 pm     Reply with quote

Hi All,

I've been using the DS3231 RTC with success for a number of projects. On a new clock project, I've decided to add some additional functionality that allows for automatic DST correction, and the ability to sync time to an external GPS. I've written two routines that I use to manipulate individual registers of the RTC.

This routine seems to work fine for adjusting just the HOURS register:

Code:

void SetRTCHours(void){
//This subroutine sets the hours register of the RTC. This routine is called whenever DST begins/ends and it is necessary
//to adjust the hours register by +/- 1 hour.

   fprintf(Diag, "\n\rUpdating RTC hours register to: %d\n\r", DS3231SN_regs[HOURS_REG]);
   
   //Here we convert the new value to BCD...
   DS3231SN_regs[HOURS_REG] = BINtoBCD(DS3231SN_regs[HOURS_REG]);

      // write 1 byte of BCD data to DS3231
      i2c_start();
      i2c_write(WRITE_CNTRL);

      // start at hours register....
      i2c_write(HOURS_REG);

   i2c_write(DS3231SN_regs[HOURS_REG]);

      i2c_write(CONTROL_INIT_VAL);
      i2c_stop();

}


But, this routine for adjusting both MINUTES and SECONDS does not work. It seems to zero the HOURS register no matter what.

Code:

void SyncRTC(int8 SyncMinutes, int8 SyncSeconds){
//This subroutine 'syncs' the minutes and seconds registers of the RTC with the GPS derived time. The new minutes and seconds
//are passed into this routine, and are used to update the minutes and seconds registers of the RTC. 

   fprintf(Diag, "\n\rSync Minutes: %02u / Sync Seconds: %02u\n\r", SyncMinutes, SyncSeconds);

   //Here we convert the new values to BCD...
   DS3231SN_regs[MINUTES_REG] = BINtoBCD(SyncMinutes);
   DS3231SN_regs[SECONDS_REG] = BINtoBCD(SyncSeconds);

      // write 2 bytes of BCD data to DS3231
      i2c_start();
      i2c_write(WRITE_CNTRL);

      // start at seconds register....
      i2c_write(SECONDS_REG);

   i2c_write(DS3231SN_regs[SECONDS_REG]);
   i2c_write(DS3231SN_regs[MINUTES_REG]);

      i2c_write(CONTROL_INIT_VAL);
      i2c_stop();
}


It's probably something silly, but I can't see it....

Jack
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Mon Jul 16, 2018 1:34 pm     Reply with quote

You don't give us much to go on...
Show your register defines, and what CONTROL_INIT_VAL is defined as.

However I suspect you are not understanding how the time is meant to be set. If you set the seconds register, you _must_ set all the other time registers:
Quote:

The countdown chain is reset whenever the seconds register is written. Write transfers occur on the acknowledge from the DS3231. Once the countdown chain is reset, to avoid rollover issues the remaining time and date registers must be written within 1 second.
JAM2014



Joined: 24 Apr 2014
Posts: 138

View user's profile Send private message

PostPosted: Mon Jul 16, 2018 1:51 pm     Reply with quote

Hi Ttelmah,

Here are my defines for the DS3231:

Code:

// Dallas DS3231SN control bytes
#define WRITE_CNTRL 0xd0
#define READ_CNTRL 0xd1

// Dallas DS3231SN RTC register offsets
#define SECONDS_REG 0x00
#define MINUTES_REG 0x01
#define HOURS_REG 0x02
#define DAY_OF_WEEK_REG 0x03
#define DATE_REG 0x04
#define MONTH_REG 0x05
#define YEAR_REG 0x06
#define   ALARM1_SECONDS_REG 0x07
#define   ALARM1_MINUTES_REG 0x08
#define   ALARM1_HOURS_REG 0x09
#define   ALARM1_DAY/DATE_REG 0x0A
#define   ALARM2_MINUTES_REG 0x0B
#define   ALARM2_HOURS_REG 0x0C
#define   ALARM2_DAY/DATE_REG 0x0D
#define CONTROL_REG 0x0E
#define STATUS_REG 0x0F
#define   AGING_REG 0x10
#define   TEMPMSB_REG 0x11
#define   TEMPLSB_REG 0x12
#define DATE_TIME_BYTE_COUNT 19

#define DS3231SN_NVRAM_START_ADDR 8
#define CONTROL_INIT_VAL 0x80


I guess I need to dig into the DS3231 datasheet a bit more, but it seems like you are saying it's not OK to simply write to select registers in the DS3231, and NOT update all registers when writing?

Jack
temtronic



Joined: 01 Jul 2010
Posts: 9081
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Jul 16, 2018 2:00 pm     Reply with quote

Hay Jack, I sent you a PM with my driver(bodged version of the 1307) and I update everything,seemed simpler and it works... really the time involved(no pun) to update everything really isn't a lot.
Jay
JAM2014



Joined: 24 Apr 2014
Posts: 138

View user's profile Send private message

PostPosted: Mon Jul 16, 2018 7:28 pm     Reply with quote

Hi Jay,

Thanks, but my issue is not really using the 'normal' operations of the DS-3231 - I have a robust driver for that - it's for a couple of odd operations I'd like to perform. I know writing all the data doesn't take too long, it's just that my GPS data is in UTC format, and my RTC data is in LCL format, so I'd need to do a conversion for a full write of the RTC data, which can get quite messy.

I'd like to just write the values I need to write, and let the others be.

Maybe I'll read the RTC first to put the data in temporary variables, update the ones I want, and write it all back? Seems like a lot of work for a simple thing.....

Jack
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Mon Jul 16, 2018 10:40 pm     Reply with quote

You can set any register you want, _except_ the seconds register. If you write to this you must reset all the timing registers.
JAM2014



Joined: 24 Apr 2014
Posts: 138

View user's profile Send private message

PostPosted: Mon Jul 30, 2018 2:10 pm     Reply with quote

Hi All,

OK, so if I'm going to 'Sync' my RTC (local time) to the GPS (UTC time) then I'm going to have to be able to convert between the two. Below is some code I've written to do this. I've tested it a lot and it seems to work correctly, but there are so many different time scenarios that I doubt I'll be able to test them all! I'd appreciate it if you guys can have a look and offer any additions or improvements!

Code:

               //Here we adjust the UTC time to local time based on the user-defined UTC offset....
               //Here we correct the hours. No need to correct minutes or seconds.
               Hours += UTCOffset;
               if (Hours < 0){
                  Hours +=24;
                  Day--;
               }

               if (Hours > 23){
                  Hours -=24;
                  Day++;
               }
                  
               //Here we correct the day if we need to go back a day!
               if (Day < 1)
               {
                  if ((Month == 5) || (Month == 7) || (Month == 10) || (Month == 12)) //Previous month has 30 days
                     Day = 30;
                  else if (Month == 3)   //Month after February
                     if ((Year % 4) != 0) //Non leap year!
                        Day = 28;
                     else
                        Day = 29;
                  else if ((Month == 1) || (Month == 2) || (Month == 4) || (Month == 6) || (Month == 8) ||(Month == 9) || (Month == 11)) //Previous month has 31 days
                     Day = 31;
                  
                  Month--;
               }

               //Here we correct the day if we need to go forward a day!
               if ((Day > 31) && ((Month == 1) || (Month == 3) || (Month == 5) || (Month == 7) || (Month == 8) || (Month == 10) || (Month == 12))) //Months with 31 days
               {
                  Day = 1; Month++;
               }
               
               else if ((Day > 30) && ((Month == 4) || (Month == 6) || (Month == 9) || (Month == 11))) //Months with 30 days
               {
                  Day = 1; Month++;
               }
            
               else if ((Day > 29) && (Month == 2)) //Feb. with 29 days, ie. leap year!
               {
                  Day = 1; Month++;
               }
               
               else if((Day > 28) && (Month == 2) && ((Year % 4) != 0)) //Feb. with 28 days, ie. no leap year! 
               {
                  Day = 1; Month++;
               }

               //Here we correct the Month and Year!!
               if (Month < 1){
                  Month +=12;
                  Year--;
               }

               if (Month > 12){
                  Month -=12;
                  Year++;
               }


Thanks,

Jack
temtronic



Joined: 01 Jul 2010
Posts: 9081
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Jul 30, 2018 3:25 pm     Reply with quote

hmm.. would it not be easier to just take the UTC data from the GPS and stuff into the RTC, once you've adjusted for the time zone part?

just thinking out loud here....

Jay
JAM2014



Joined: 24 Apr 2014
Posts: 138

View user's profile Send private message

PostPosted: Mon Jul 30, 2018 6:21 pm     Reply with quote

Hi Jay,

If you think about it, it's a much bigger/more complicated problem than you are imagining. For example, when the 'adjustment' occurs, it's possible that the adjusted time/date is a different day, month, or year than the original depending on when it occurs.

Example: Right now, it's 12:18AM UTC on July 31st, but locally, it's 8:18PM on EDT on July 30th. A 'proper' conversion routine needs to deal with all that!

Jack
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Tue Jul 31, 2018 12:15 am     Reply with quote

When running RTC's, I've always had them run in UTC, and work internally in 'epoch seconds'. Then you only need to handle converting this too/from your local time for input, and display. That is simply done by adding a time offset, before converting to the display/storage format. I usually hold the offset as a 1/4 hour value. So in your case it'd be -16. You convert UTC to the 'epoch seconds' value (working from whatever origin you decide to use), then apply the offset (so 60*15*-16), then convert epoch seconds to the display format. The time.c library contains all the routines to do this.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group