Problem casting time_t as uint32_t ?

Hi,
I'm trying to get the time out of a PCA8565 RTC and things just aren't behaving.

When I scope the I2C lines things look as expected but somewhere when converting the time_t tm to an uint32_t things go awry.

Here is my function which is refusing to work for me the way I expect:

uint32_t ReadRTCTime()
{
  uint32_t fnltm;
  tmElements_t tm;
  byte wireVal;
  
  Wire.beginTransmission(RTC_CLOCK);
  Wire.write(RTC_CMD_REG2); // reset register pointer  
  Wire.endTransmission();
  
  Wire.requestFrom(RTC_CLOCK, 7);
  
  wireVal = Wire.read();  
  tm.Second = BCD2DEC(wireVal & 0x7f); 
  wireVal = Wire.read();  
  tm.Minute = BCD2DEC(wireVal & 0x7f);
  wireVal = Wire.read();
  tm.Hour =   BCD2DEC(wireVal & 0x3f); 
  wireVal = Wire.read();
  tm.Day = BCD2DEC(wireVal & 0x3f);
  wireVal = Wire.read();
  tm.Wday = BCD2DEC(wireVal & 0x07);
  wireVal = Wire.read();
  tm.Month = BCD2DEC(wireVal & 0x1F);
  wireVal = Wire.read();
  tm.Year = y2kYearToTm((BCD2DEC(wireVal)));
  

   fnltm = (uint32_t)makeTime(tm);
//   fnltm = 0x55A9AFAF;
   return fnltm;

}

Uncommenting the fnltm line properly passes across the hardcoded hex value but otherwise it seems like either:
a. casting makeTime(tm) as a uint32_t messes things up
b. makeTime(tm) doesn't work the way I understand
c. the tm.xxx functions aren't working they way I understand

Any hints or suggestions will be greatly appreciated!

Tomorrow I'm going to try (again) hard coding the Wire.read() values and confirm they are what I expect.

Cheers

When I scope the I2C lines things look as expected but somewhere when converting the time_t tm to an uint32_t things go awry.

According to the code, tm is not a time_t. So, this statement contains some errors that need correcting.

Uncommenting the fnltm line properly passes across the hardcoded hex value but otherwise it seems like either:
a. casting makeTime™ as a uint32_t messes things up
b. makeTime™ doesn’t work the way I understand
c. the tm.xxx functions aren’t working they way I understand

I’d say that those are reasonable assumptions. Without knowing which makeTime() function you are calling, we can’t know what it’s return type is, so we can’t determine the reasonableness of casting it to a uint32_t.

We don’t know how you understand makeTime() to be working. so it is hard to comment on that statement.

tm is a struct, with fields, not functions. So, there is nothing to work, or not work, about the fields.

So, where is the makeTime() function that you are using implemented?

It's implemented in the Time library. It takes a tmElements struct as an argument and should return a time_t.

Since time_t is typedef'ed to unsigned long, quite often you don't need a cast and can simply use the time_t just as you would a uint32_t.

Have you tried it this way? What happens? What happens if you define fnltm as unsigned long rather than uint32_t?

fnltm = makeTime(tm);

Thanks so much for those replies!

PaulS - you're correct, my description was incorrect, tm is of type tmElements_t but the output of makeTime(tm) is of time_t

Delta_G - you're correct, I don't need to cast it explicitly when I did. Unfortunately I still don't get the results I expect.

For example, when I hardcode the wireVal values into the code:

//time_t ReadRTCTime()
uint32_t ReadRTCTime()
{
  uint32_t fnltm;
  tmElements_t tm;
  byte wireVal;
  
  Wire.beginTransmission(RTC_CLOCK);
  Wire.write(RTC_CMD_REG2); // reset register pointer  
  Wire.endTransmission();
  
  Wire.requestFrom(RTC_CLOCK, 7);
  
//  wireVal = Wire.read();
  wireVal = 0x09;
  tm.Second = BCD2DEC(wireVal & 0x7f); 
//  wireVal = Wire.read();  
  wireVal = 0x04;
  tm.Minute = BCD2DEC(wireVal & 0x7f);
//  wireVal = Wire.read();
  wireVal = 0x12;
  tm.Hour =  BCD2DEC(wireVal & 0x3f); 
//  wireVal = Wire.read();
  wireVal = 0x15;
  tm.Day = BCD2DEC(wireVal & 0x3f);
//  wireVal = Wire.read();
  wireVal = 0x03;
  tm.Wday = BCD2DEC(wireVal & 0x07);
//  wireVal = Wire.read();
  wireVal = 0x07;
  tm.Month = BCD2DEC(wireVal & 0x1F);
//  wireVal = Wire.read();
  wireVal = 0x15;
  tm.Year = y2kYearToTm((BCD2DEC(wireVal)));
  // 55A64C39 for 15 July, 2015, 12:04:09 PM
  // Get back 56 05 A9 A9
  
   fnltm = makeTime(tm); 

   return fnltm;


}

I expect to get back 55A64639 but I keep getting 56 05 A9 A9.

Thanks!

I expect to get back 55A64639 but I keep getting 56 05 A9 A9.

There is NO way that the function returns a 32 bit number that has spaces. You need to explain this statement, and show the code that displays the value.

If you're trying to set the year to 2015, does

  wireVal = 0x15;

really work? Why wouldn't it be 0x0F?

econjack:
If you're trying to set the year to 2015, does

  wireVal = 0x15;

really work? Why wouldn't it be 0x0F?

It's BCD. Converted to an integer with BCD2DEC [sic] it's 15.

PaulS - you're correct, the spaces simply came out of a copy and paste

But I think things are fixed...

Not entirely clear on the details but it turns out it was the BCD2DEC macro...

The macro was defined in one of my header files as:

#define BCD2DEC(bcd) ((bcd/16 * 10) + (bcd % 16))

but when the compiler inserted "wireVal & 0x07" in each of the instances of "bcd" something went awry.

Changing the code to (for example)

byte s = Wire.read() & 0x7f;
tm.Second = BCD2DEC(s);

Gives the correct result.

Thanks for all the hints!

The author of that header file needs to learn how to write safer macros. At the very least it should look like this:

#define BCD2INT(bcd) (((bcd)/16 * 10) + ((bcd) % 16))

At the very least it should look like this:

With the correct name, anyway... 8)

I took the liberty in fixing the name to something more descriptive of what it actually does. It doesn't return a "decimal" (as implied by the "DEC" part of the name). It returns an integer which has no base. You could argue that it returns a "binary" since that's how the computer stores it, but even that would be incorrect.