ISR don't update bit

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've noticed that in the case where I have to wait in a while loop until some special bit is set by an ISR, the program never goes past this point even though the interrupt does occur.

while( (sfr & (1 << BIT_VAL)) == 0 );

So I've tried putting a NOP in the while loop using a macro that looks like this:

#define NOP() asm volatile("nop\n\t"::)

while( (sfr & (1 << BIT_VAL)) == 0 )
{
NOP();
}

but it makes no difference. When I put in the winavr delay function though, the ISR updates the variable and the program can continue.

What is the reason for this?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just so you know, the ISR is always updating the bit. It's just that the main program is not looking in the right place. The main program is taking a copy of the variable when the function begins, and storing it in a register for faster access.

Normally, the compiler has no way of recognizing the fact that ISRs might execute asyncronously in the middle of the mainline of execution, so it doesn't realize that the bit might change at any time. So, the register copy is assumed to be good to work with, even though you and I know that the ISR may have modified the global copy long ago.

When you place an explicit function call in (such as delay_ms), the main program is forced to refresh its copy of the variable after returning from the function call, because it doesn't know whether or not the delay_ms() function might have been able to modify the global copy of the bit in question.

To avoid the need to make superfluous function calls, look in the avr-libc reference manual. Under the FAQ (frequenly answered questions) section, question #1. It deals with the use of the "volatile" keyword.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi lfmorrison,
I'm well aware of the volatile keyword and use it a lot in other placed. I just didn't realise the the compiler make a copy of the SFR. So all I have to do is something like this, right:

volatile INT8U my_sfr;

do
{
my_sfr = SFR;
}
while( (my_sfr & (1 << BIT_VAL)) == 0 );

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oh! It was in an SFR? That's neat... I didn't notice that in your first post. The compiler is supposed to be able to recognize transitions in SFR's automatically... that's why code such as

while(!(UCSRA & (1<<RXC)));

is able to work correctly...

Is it an SFR in the lower address space (reachable by "sbis/sbic"), or is it one that's only accessible by means of memory-mapped I/O?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How is sfr defined?? Is it set to something like PORTA or TIMSK? AFAIK, there is nothing named sfr.

Randy

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

special function register

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

yes, by SFR I meant any Special Function Register.

But I also made a mistake in my question - I just looked at the code again to refresh my memory and it looks like this:

while(enum_val != _NONE)
{
delayMs(1);
}

and enum_val is a normal enumerated type which is changed in an ISR. So I think the problem here is that it is not defined as 'volatile' so the compiler optimised my loop completely out. I cannot believe I never thought of this.
Thanks for the replies.