Forums

Changing global variable in ISR

Started by jackson_cp September 20, 2004

Here I am trying to implement an interrupt based square wave
generator using interrupts (Timer Compare2 interrupt). I am using
Embedded GNU compiler for making the code. But the program is not
working because; I have used a global variable to indicate the ON-OFF
status of the PORT pin. The global variable is supposed to be changed
in the Interrupt Service Routine. But actually what is happening is
as soon as I leave the interrupt service routine the global variable
value is reset to zero. I had found out the reason for this.

The global variable is assigned the SRAM location 0x0000,
Before executing the ISR this value is pushed into the stack
And in the ISR the value of the variable is changed.
When we leave the ISR the pushed value is popped in the memory
location , so the changed value is lost.

The following is the Source code I have used
#define bitset_reg(var,bitno) ((var) |= bitno)
#define bitclr_reg(var,bitno) ((var) &= ~(bitno))
volatile unsigned char pol=0 ;

void __premain ();
void start(void);
int main(void);
void __premain ()
{
TMSK2=0x00; // Selecting clock prescaler
BPROT = 0x1F; /* protect all eeprom
*/
} int main(void)
{
DDRA=0x0F;
TOC2=0x1000; // Initialize compare register2
TMSK1=0x40; // Enable Timer outputcmp2 interrupt
TFLG1=0x40; // Clear timer compare2 interrupt flag
__asm__ __volatile__ (" cli "); /* start
interruptions !! */
;

while(1)
{

}; /* do endless loop */

}
void INTERRUPT main_outcmp2(void)
{

TOC2+=0x0200; // Initialize compare register2
if(pol==0)
{
bitset_reg(PORTA,PA1);
pol=1;
}
else
{
bitclr_reg(PORTA,PA1);
pol=0;

}

TFLG1=0x40;

}

How we can avoid these situation. How I can declare a Global variable
which can be changed in the ISR.



--- In , "jackson_cp" <jackson_cp@y...> wrote:
>
> Here I am trying to implement an interrupt based square wave
> generator using interrupts (Timer Compare2 interrupt). I am using
> Embedded GNU compiler for making the code. But the program is not
> working because; I have used a global variable to indicate the ON-
> OFF status of the PORT pin. The global variable is supposed to be
> changed in the Interrupt Service Routine. But actually what is
> happening is as soon as I leave the interrupt service routine the
> global variable value is reset to zero. I had found out the reason
> for this.
>
> The global variable is assigned the SRAM location 0x0000,
> Before executing the ISR this value is pushed into the stack
> And in the ISR the value of the variable is changed.
> When we leave the ISR the pushed value is popped in the memory
> location , so the changed value is lost.
>
> The following is the Source code I have used
> #define bitset_reg(var,bitno) ((var) |= bitno)
> #define bitclr_reg(var,bitno) ((var) &= ~(bitno))
> volatile unsigned char pol=0 ;

Well, I have not had an opportunity to use the GNU HC11/12 toolchain
yet (I have it installed but have not configured or experimented
much with it yet) so I cannot speak with authority on the quirks and
limitations of the compiler. About all I can suggest is that you
change your definition of the variable 'pol' to this:

volatile static unsigned char pol=0 ;

Usually, the 'static' modifier is not required for global variables,
but the compiler might be 'optimizing' <pol> as a 'auto' type
variable ('auto' ~= 'stored on stack') since it is never referenced
in main() or anywhere else other than in your interrupt service
routine.

You might also try placing some reference to <pol> in your main().
One way you could do this would be to remove the initializer in the
variable declaration (the =0 part) and explicitly initialize <pol>
in main() before you enable interrupts.

I will also point out that if your goal is to simply toggle an
output pin every time you get a timer compare match, this can be
done for you automatically by the timer subsystem IF you use the
appropriate PAx port pin associated with the output compare you are
using. Each output compare has a PAx pin that can be (optionally)
associated with it. With exception of TOC1 (which can actually
control PA3-PA7 in a single compare operation but cannot do a auto-
toggle), the output compare logic can optionally force-set, force-
reset or toggle a PAx output upon a successful TOCx match. The
specific Port A pin that is affected by a output compare is fixed;
for example, the Port A pin associated with TOC2 is PA6. The TCTL1
register is used to specify the port pin action that will take place
upon a OCx (x=2..5) match. OC1M and OC1D can be set to specify how
all 5 output-compare pins (PA3..PA7) should be set when a OC1 match
occurs.

The CFORC register (in conjunction with appropriate settings in
TCTL1) can be used to 'simulate' a TOCx match for purposes of
setting/initializing output port pin levels. When a given PAx pin
is configured to associate with a timer output compare (e.g. OLx,OMx
<> 00), changes to the associated pin control bit in PORTA will not
have any effect on the pin state.

My explanation of the operation of the various output compare
control registers discussed above is admittedly not very good. I
would suggest that you read the much better written documentation
that Mot provides on the subject - at least read the sections that
discuss the control registers I've cited above.

If you are free to change your port pin assignments at this stage of
your design, I would recommend that you move the logic you are
presently controlling with PA1 to PA6, as PA6 is the port pin
associated with OC2. In your main(), initialize the TCTL register
such that bit 6 (OL2) is set and bit 7 (OM2) is clear. This will
configure the timer subsystem to toggle PA6 on every TOC2 match.
You can then remove the entire if-else block from your timer ISR,
and eliminate the <pol> variable.