Interrupt variable exceeds volatile long's 8bit size

Hello,

I need some support, I'm attempting to have a program which checks when the counts (or pulses) on an encoder exceeds a required counts variable. I understand that the volatile qualifier must be used when dealing with interrupts, but I'm concerned that the counts may exceed the 8bit size of a volatile long.

If the required counts variable is say 1,000,000, can the count variable ever reach this value? My understanding is that the largest 8 bit number is 255. If so is there a work around?

Thanks for your help!

As far as I know, the minimum size of a long is 4 bytes. What system are you working with where declaring it volatile reduces it to 1 byte?

1 Like

This counter will fit to an uint32 variable.
You have to dis- and enable the interrupt during reading the counter from the loop() function.

1 Like

I don't know why you're limited to 8-bits or if that's what's really happening.

...With serial communications you usually send/receive one byte at a time and the software has to take care of splitting & reassembling longer types/variables but I assume you're not using serial communication.

Look at the Data Types in the Language Reference.

I don't believe there are any additional or artificial limits in interrupts but you need to be aware of variable scope and volatility in functions (and objects).

1 Like

Thanks for the help everyone. I've confused myself, I misunderstood ' If the volatile variable is bigger than a byte (e.g. a 16 bit int or a 32 bit long), then the microcontroller can not read it in one step, because it is an 8 bit microcontroller. This means that while your main code section (e.g. your loop) reads the first 8 bits of the variable, the interrupt might already change the second 8 bits. This will produce random values for the variable.' this part of the documentation.

So just to clarify if I have a variable: 'volatile long counts;'. It can store values greater than 255?

'This means that while your main code section (e.g. your loop) reads the first 8 bits of the variable, the interrupt might already change the second 8 bits. This will produce random values for the variable.' this part of the documentation. ' Can someone please explain in simple terms what is meant by this?

Exactly which Arduino board are you using?

1 Like

Arduino mega 2560

Prevent that from happening by turning off interrupts, make a copy of the variable, and use the copy. For example:

volatile long counts = 0;
...

//in loop

noInterrupts();
long count_copy = counts; //make a copy
interrupts();

Serial.println(count_copy); //display the copy
1 Like

Then long is 32 bits and can hold numbers between around -2000 million and +2000 million.

1 Like

To answer the first question, volatile is a modifier that tells the compiler that a variable might be updated externally so it doesn't accidentally optimize it out. It doesn't affect the size of the variable.

The second question is a common concern in shared-data systems. It's possible that while the main loop is in the middle of accessing a multi-byte variable, an interrupt occurs and changes that variable, leading to corrupted data. There are many ways of handling this situation (and in fact, asking about this is one of my favorite interview questions). On an arduino the easiest way is probably to disable interrupts before accessing the shared data and re-enable it later. e.g.,

volatile unsigned long interruptedVar = 0;
.....

void loop()
{
  noInterrupts();
  interruptedVar = x+5;
  interrupts();
}

void ISR()
{
  interruptedVar++;
}

This temporarily disables interrupts so that loop() can access the variable safely.
HTH.

1 Like

Wow so simple, thank you! Presumably a few counts may be missed while the interrupts are off?

Sorry, what do you mean by 'then long is 32bits'? Is there a case when long wouldn't be 32bits. Am I missing something, like is it not 32bits during an interrupt?

Depends on how fast they are coming in. Making the copy takes a microsecond or less.

1 Like

Unlikely. Keep the code as short as possible while interrupts are disabled, and if an interrupt should occur, it won't be missed.

1 Like

only if your counts rush in at a very high frequency
executing the lines

  noInterrupts();
  interruptedVar = x+5;
  interrupts();

takes less than a millisecond

1 Like

Long is always 32 bits on every type of Arduino I have encountered. Making it volatile or updating it during interrupts doesn't change it's size, as @cedarlakeinstruments already said.

1 Like

The size of a variable can vary between processor types or operating systems, etc. If you are doing something where the variable size is significant, it's best to be explicit about it.

e.g., using uint32 instead of unsigned long clearly defines the variable to be 32 bits in size.

2 Likes

So interrupts are considered an external update, which means they require the volatile modifier?

'asking about this is one of my favorite interview questions' - love it, I think I would've walked out at that point :laughing:. Thanks for taking the time to explain, its starting to make sense!

Doesn't matter if the interrupt is external or internal, you need to make it volatile if it's going to be updated in an interrupt routine and read in the main code. Otherwise the optimiser within the compiler will make incorrect assumptions about when the value might have changed.

2 Likes

I've got the case where the the variable could be anywhere between 0 & 1e6 so I guess long is overkill. Would you recommend using using something with a smaller bit size, is there any benefit to making the bit size of the variable smaller?