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. |
|
Changing global variable in ISR
Started by ●September 20, 2004
Reply by ●September 20, 20042004-09-20
--- 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. |