2020/11/13 07:21:09
muhzd
Hi guys,
 
Imagine your interrupt routine updates a 32 bit global variable processing as it will take a few instructions to process. Then back at the main routine it is not the same number.
What do you do?
 
Edit:  Write '32 bit' and not '32bit' 
2020/11/13 07:36:18
BroadwellConsultingInc
I'm assuming you have issues where you're dealing with a 32 bit variable on an 8 or 16 bit micro?
 
Create an accessor function for that variable that stores the interrupt enable state, shuts off the interrupt that accesses the variable, makes a copy, then restores the interrupt state and returns the copy.  
2020/11/13 07:58:05
oliverb
Perhaps you could describe what you want to do in a little more detail. Sometimes the answer is to mask off the interrupt, but you might use flag bits to implement a "lock" on the variable.
 
Sometimes the simple answer is to find a way to use a smaller variable that can be read/written in one operation.
2020/11/13 08:10:15
1and0
muhzd
Imagine your interrupt routine updates a 32 bit global variable processing as it will take a few instructions to process. Then back at the main routine it is not the same number.
What do you do?

 
Here is pseudo-code that disables/enables interrupt:

save_GIE = GIE;    // or the ISR that updates the variable
GIE = 0;
foo = 32bit_var;
GIE = save_GIE;

and here's one that does NOT disable interrupt:

irq_flag = 0;      // irq_flag = 1 in ISR that updates the variable
foo = 32bit_var;
if (irq_flag == 1)
  foo = 32bit_var;



2020/11/13 08:58:27
NorthGuy
There's no need to disable interrupts. Every time you disable interrupts, you increase interrupt latency. It's much easier actually:
 
// global variable in question
volatile int32_t variable;
 
// to extract the variable in main:
int32_t variable_copy;
 
do  {
  variable_copy = variable;
} while (variable_copy != variable);
// at this point variable_copy contains un-corrupted copy of the variable, which you can use

 
2020/11/13 09:08:31
1and0
NorthGuy
There's no need to disable interrupts. Every time you disable interrupts, you increase interrupt latency. It's much easier actually:
 
// global variable in question
volatile int32_t variable;
 
// to extract the variable in main:
int32_t variable_copy;
 
do  {
  variable_copy = variable;
} while (variable_copy != variable);
// at this point variable_copy contains un-corrupted copy of the variable, which you can use


Hmmm... I think there may be a chance the variable is being updated during the while() statement. ?. That is, lower byte/word compared equal, interrupt updates lower byte/word, then upper byte/word compared equal resulting in incorrect equal comparison.
2020/11/13 09:13:29
crosland
NorthGuy
There's no need to disable interrupts. Every time you disable interrupts, you increase interrupt latency. It's much easier actually:
 
// global variable in question
 
volatile int32_t variable;
 
 
 
// to extract the variable in main:
 
int32_t variable_copy;
 
 
 
do  {
 
  variable_copy = variable;
 
} while (variable_copy != variable);
 
// at this point variable_copy contains un-corrupted copy of the variable, which you can use
 

 




Incurs a re-read and test on every pass and if variable is updated during the test you will spin again, possibly unnecessarily, reading variable 4 times.
 
It a trade off between interrupt latency and main loop latency. If you are that tight for time that you can't afford to disable interrupts for an atomic access I would suggest you need to re-architect the design or get a faster part.
 
2020/11/13 09:20:25
BroadwellConsultingInc
1and0
 
Hmmm... I think there may be a chance the variable is being updated during the while() statement. ?. That is, lower byte/word compared equal, interrupt updates lower byte/word, then upper byte/word compared equal resulting in incorrect equal comparison.


I agree.  The do while can be an option in some cases such as if you're looking at a relatively slowly changing variable that is predictable such as a variable that increments in a timer. 
 
But without knowing the full context of what the person is doing disabling the interrupt is the safe course.  The do/while test would pass if you happened to be unlucky enough to get two non-coherent accesses that behaved the same way in both fetches of variable.
A simple case is changing the variable back and forth between 0 and 0xFFFFFFFF on an interrupt that happens nearly back-to-back.
You could potentially catch the variable being set to 0x0000FFFF twice in both cases and see that as a valid value.
2020/11/13 10:05:32
davea
irq_flag = 0;      // irq_flag = 1 in ISR that updates the variable
foo = 32bit_var;
if (irq_flag == 1)
  foo = 32bit_var;

and put the flag byte bit in common RAM using NEAR qualifier
you will have 7 more fast bits to use elsewhere with no bank switching
2020/11/13 10:09:22
NorthGuy
crosland
It a trade off between interrupt latency and main loop latency. If you are that tight for time that you can't afford to disable interrupts for an atomic access I would suggest you need to re-architect the design or get a faster part.



The interrupt latency is the time from the event that causes the interrupt to the point where the ISR is called and you can take a meaningful action. This is a hardware characteristics, and doesn't depend on whether you're tight on time or not, whether you're busy doing something or not.
 
Say, in newer PIC18s, if you have an INT interrupt, you can start processing it in 200 ns (3 Tcy) since it happens (with most context already saved). Thus you can watch for an edge, and then generate the response signal in as little as 250 ns.
 
If you now disable the interrupts for a dozen of instruction cycles, the processing of the interrupt event may have to wait, and interrupt may be delayed, say by 750 ns. Instead of 200 ns latency, you get 950 ns latency.  Now your reaction time goes from 250 ns to 1 us - 4 times worse.
 
Worse yet, your reaction time becomes unpredictable - it is usually 250 ns, but if the interrupt event coincides with you disabling the interrupt, it may be anywhere between 250 ns and 1 us. This may cause bad things. For example, if you used a timer interrupt to do something at regular intervals, your regular intervals become not so regular, but get sporadic jitter.
 
What happens if you take a faster part, say PIC32? It might have interrupt latency worse than your PIC18. See this for example:
 
https://www.microchip.com/forums/m709091.aspx
 
Also, these architectures were not designed for real time, so they have things which make latency worse. For example, when an interrupt is entered, all other interrupts are disabled - so a low level ISR will disable high level interrupts upon entry and your high level interrupts will remain disabled until the low level ISR enables them back. If, in addition to this, you disable interrupts all the time manually, you make it even worse. In short, getting a faster part may actually give you worse latency.
 
Of course, the main doesn't have any latency, as there's no originating event.
 
© 2021 APG vNext Commercial Version 4.5

Use My Existing Forum Account