SOLVED! How To: extract byte from 64 bit integer ???

Esteemed Forum Participants and Lurkers:

I am trying to program an application using the 64 bit microsecond timer. It rolls over in less than 2 hours, and I am trying to deal with the rollover in as short a time as possible.

I can read the timer and store it in an 8 byte unsigned long long integer. What I would LIKE to be able to do is to access the top 1 byte of that variable through an assign. I've scoured the K&R C book and the internet, but haven't come across a solution yet. K&R says I can use "type void * for a generic pointer", but I can't get the Arduino IDE to allow assignment of the pointer to any other data type. Here is code I have tried without success:

#unsigned long long atime = 0x1112131421222324ULL;
void setup(void) {
  
  void * apoint;
  uint8_t * cpoint;
  
  apoint = &atime;  // no error
  cpoint = apoint;  // "cannot convert" error

  println( *cpoint, HEX );  // I need to see "11" here
  
}

I know I can do a shift and mask operation to extract the byte, but access by address reference would be much faster. I understand the value of strong typing, but is there a way around it for this simple task?

Thank you for any and all comments, suggestions, and assistance with this question. Blessings in abundance, all the best, & ENJOY! Art in Carlisle, PA USA

What about a memcpy to an 8 byte array?

uint8_t b[8];
memcpy(b, &atime, 8);

uint8_t target_byte = b[0];

Or not even a simple pointer type cast . . .

uint8_t* b = (uint8_t*)&atime;
uint8_t target_byte = b[0];
#unsigned long long atime = 0x1112131421222324ULL;

What's that?

64 bit microsecond timer. It rolls over in less than 2 hours

A 64 bit microsecond timer rolls over (you'll understand I have no personal experience of this) in about 585000 years.

webtest: I am trying to program an application using the 64 bit microsecond timer. It rolls over in less than 2 hours, and I am trying to deal with the rollover in as short a time as possible.

That doesn't make any sense.

A 32-bit microsecond timer like provided by the "micros()" function rolls over in a little bit less than 70 minutes.

A 64-bit microsecond timer would run for ((2^64)-1)/1E6 = 18446744073709 seconds = 213503982 days without rolling over.

Like AWOL wrote, this is in (just a roughly estimation) 584942 years.

So why do you think you have "to deal with the rollover in as short a time as possible" if the rollover actually would happen in 584942 years from now?

A union can be used to allow you to index into the bytes of a long integer.

union {
  unsigned long MyULong;
  byte MyArray[4];
} atime;

atime.MyULong = 0x12345678;

Serial.print("First Byte: 0x");
Serial.print(atime.MyArray[0], HEX);

But why? Do you expect to do arithmetic on this byte? You must read http://www.gammon.com.au/millis if you haven't already.

Thanks Camel … Your second post is EXACTLY what I am looking for!!!

MY BAD … the timer is only 32 bits, but the question is still how to access bytes of a variable by address reference regardless of the type/size of the variable.

Here is what works …

unsigned long long atime = 0x1112131421222324ULL; // 64 byte unsigned integer - initialized
uint8_t* b;

void setup(void) {
  Serial.begin(9600);
  
  void * apoint;
  apoint = &atime;
  apoint += 7;           // change to select any byte
  b = (uint8_t*)apoint;  // Thanks to Camel!

  Serial.println( *b, HEX );  //  = "11"  YES!!!
}

Lines 7 through 10 set up the pointer to the desired byte. Merely change the offset in line 9 to point to any byte in the variable … 7 points to the MOST SIGNIFICANT BYTE. Line 12 merely shows that you can perform an operation on a byte of the variable by memory access. The actual program will do a compare of the byte to test for rollover.

Thanks for the great assistance in solving this question.

you could also just shift the ULL to get that byte:

unsigned long long atime = 0x1112131421222324ULL; // 64 byte unsigned integer - initialized

void setup(void) 
{
  Serial.begin(9600);
  byte b = atime >> 7 * 8;  // shifting seven times eight or 56 bits
  Serial.println( b, HEX );  //  = "11"  YES!!!
}

void loop()
{
}

Interesting. You have not mentioned the standard (and extremely simple) way of dealing with rollover, a typical example being the BlinkWithoutDelay sketch. Any particular reason why you can't do it that way?

BulldogLowell: you could also just shift the ULL to get that byte:

Yeah, but OP said no shifts.

aarg: Interesting. You have not mentioned the standard (and extremely simple) way of dealing with rollover, a typical example being the BlinkWithoutDelay sketch. Any particular reason why you can't do it that way?

Yes ...

1) (www.arduino.cc/en/Tutorial/BlinkWithoutDelay): millis() only yields 1,000 microsecond resolution. I need MUCH faster resolution, and I need it as accurate as possible. micros() is good to about 4 microseconds for a single reading but accurate to the crystal accuracy in the long term.

2) Even millis() has a rollover problem ... except it only happens about every 50 days.

Even millis() has a rollover problem .

It does? Who knew?

MorganS: You must read http://www.gammon.com.au/millis if you haven't already.

Thanks ... this looks interesting and may be very helpful.

webtest: 1) [...] micros() is good to about 4 microseconds for a single reading but accurate to the crystal accuracy in the long term.

2) Even millis() has a rollover problem ... except it only happens about every 50 days.

1) How do you plan to improve on that?

2) millis has no rollover "problem". It rolls over but the rollover can be automatically handled in user code with one simple subtraction.

aarg: 1) How do you plan to improve on that?

2) millis has no rollover "problem". It rolls over but the rollover can be automatically handled in user code with one simple subtraction.

1) I don't plan to "improve on that" - I plan to use it to get within 20 microseconds of an accurate repeating time.

2) The Arduino is an 8 bit processor. To implement the timer requires at least reading 32bit micros() and storing the value in memory, 2 32bit subtractions, and a 32bit addition. That's quite a few instructions, and I hope to use the fewest number possible.

webtest:

  1. I don’t plan to “improve on that” - I plan to use it to get within 20 microseconds of an accurate repeating time.

  2. The Arduino is an 8 bit processor. To implement the timer requires at least reading 32bit micros() and storing the value in memory, 2 32bit subtractions, and a 32bit addition. That’s quite a few instructions, and I hope to use the fewest number possible.

So, you are going to utilize an AVR hardware timer directly?

AWOL: ```

unsigned long long atime = 0x1112131421222324ULL;



What's that?
A 64 bit microsecond timer rolls over (you'll understand I have no personal experience of this) in about 585000 years.

That is under the assumption you start with 0 ;)

Maybe the 64-bit counter is initialized with a value and has a reference date (like NTP, UNIX windows etc) but this could be some 6000 centuries ago? Or it is not incremented by 1 but by a magic 42 bit value .... who knows....

robtillaart: That is under the assumption you start with 0 ;)

Maybe the 64-bit counter is initialized with a value and has a reference date (like NTP, UNIX windows etc) but this could be some 6000 centuries ago? Or it is not incremented by 1 but by a magic 42 bit value .... who knows....

It is a 64 bit [u]test number[/u] in 32bit halves which is only to prove that the code works to reference bytes in a variable by address. The most significant byte is "11, the next is "12", etc. The 5th byte (Most significant byte in the low 32bits) is "21", and the very least significant byte is "24". That way when I fetch ANY byte and print it out HEX, I know EXACTLY which byte (if any!) my code fetched from the test number. Too simple!

In my 'success' code (post #6) try the numbers 0 through 7 in line 9 (apoint += 7;) and see what prints out. That's why I marked this thread "SOLVED". It shows how to extract any byte from any size/type variable by address reference, again, many thanks to [u]Camel[/u].

Or it is not incremented by 1 but by a magic 42 bit value .... who knows....

In which case, it rolls over only every 14000 years.