Unexpected Disabling of interrupt

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Unexpected Disabling of interrupt

Jump to solution
2,075 Views
TDKamalAru
Contributor I

In HCS08SG8 controller, I am using TPM2CH1 as a compare channel (- software interrupt only) to generate the MonoStable Output(OneShot signal). ie ON duration of the pulse is fixed and the off duration is undetermined. When ever iw want to generate the signal just i trigger the signal by switching on the port pin and load the timer for 1 ms. After the 1 ms, th eport pin will be switched off at the compare interrupt.

           From the datasheet i studied that there is a latchng mechanism to be taken care while writting the compare register. otherwise the compare register will not be wriiten ar per our expectation.

 

So i wrote code as below:

 

Main:

      if((System Input Conditions) && (InterruptStatus == DISABLED))

     {

          Switch ON the Port Pin;

 

          Enable the Compare Interrupt;

 

          /* Flag holding the status of Timer Interrupt */

          InterruptStatus = ENABLED;

 

          TPM1C1V = TPM1CNT + One Ms Equivalent Count;

     }

 

ISR:

   /* Interrupt Flag clearing mechanism */ 

  

      DummyVariable = TPM2CH1SC;

      TPM2CH1IF = 0;

 

      TPM2CH1IE = 1;

     

      InterruptStatus = ENABLED;

 }

 

 

 

 Thiw code works 99 %. But at 1 % the output signal has been stopped after some hours.

When i debug this, InterruptStatus Flag remains ENABLED but the actual interrupt enable bit in the hardware register was disabled.so signal genartor doesnt works after that time.

 

Could anyone encountered similar problems before? Did i make any mistake in my code?

 

 

Message Edited by TDKamalAru on 2009-11-20 05:09 AM
Labels (1)
0 Kudos
1 Solution
836 Views
kef
Specialist I

TDKamalAru,

 

Please look again at your pseudocode. If old compare setting can match after you clear flag and before you update CxV, then interrupt can fire before you set InterruptStatus to ENABLED! It may fire immediately after you enable interrupt and before InterruptStatus is set to ENABLED. 1) ISR will be called first, 2) ISR will set InterruptStatus to DISABLED. 3) Finally CPU will return back from ISR and will execute the rest of MAIN, setting InterruptStatus to ENABLED. Result: interrupt mask ==0, InterruptStatus == ENABLED.

No coherency guaranteed, unless you set up CxV=CNT+N first, then clear flag. These two steps guarantee compare match and flag=1 won't occur for N next timer ticks.

 

I played yesterday with latching mechanism. Clocking TPM from bus clock and using small prescalers no delay between CxV=.. and flag=0 is required.

Message Edited by kef on 2009-11-23 08:51 AM

View solution in original post

0 Kudos
11 Replies
836 Views
TDKamalAru
Contributor I

Dear Kef, Lundina and BigMac,

I am really sorry as i mistyped the main thing. Once again ask you to forgive me please.

 

Exact PseudoCode :

 

Main:

      if((System Input Conditions) && (InterruptStatus == DISABLED))

     {

          Switch ON the Port Pin;

 

          TPM2CH1IF = 0;

 

          /* Enable the Compare Interrupt */

          TPM2CH1IE = 1;

 

          /* Flag holding the status of Timer Interrupt */

          InterruptStatus = ENABLED;

 

          TPM1C1V = TPM1CNT + One Ms Equivalent Count;

     }

 

ISR:

   /* Interrupt Flag clearing mechanism */ 

  

      DummyVariable = TPM2CH1SC;

 

      TPM2CH1IF = 0;

 

      /* Disabling the interrupt */

      TPM2CH1IE = 0;

     

      InterruptStatus = DISABLED;

 }

 

Thanks for your replies and please let me know the views on this.

0 Kudos
836 Views
kef
Specialist I

It is clear now.

Timer is always ticking. I guess System Input Conditions gets true not every timer overflow period? But timer output compare match occurs every timer period. Now, since you update compare registers in main after clearing flag and enabling interrupt, chances are older output compare match setting will match CNT anytime between marked lines:

 

Main:

      if((System Input Conditions) && (InterruptStatus == DISABLED))

     {

          Switch ON the Port Pin;

 

          TPM2CH1IF = 0;

 

          /* Enable the Compare Interrupt */

          TPM2CH1IE = 1;

 

          /* Flag holding the status of Timer Interrupt */

          InterruptStatus = ENABLED;

 

          TPM1C1V = TPM1CNT + One Ms Equivalent Count;

     }

 

You get desired results in case older compare match doesn't occur before or during red line, before C1V gets updated. To fix it, update C1V before clearing timer flag

 

Main:

      if((System Input Conditions) && (InterruptStatus == DISABLED))

     {

          Switch ON the Port Pin;

 

          TPM1C1V = TPM1CNT + One Ms Equivalent Count;

 

          TPM2CH1IF = 0;

 

          /* Enable the Compare Interrupt */

          TPM2CH1IE = 1;

 

          /* Flag holding the status of Timer Interrupt */

          InterruptStatus = ENABLED;

 

     }

 

Also I'd move  InterruptStatus = ENABLED; above CH1IE=1. It won't change anything while +1ms is enough to execute code from C1V update to Interrupts = ENABLED. But if you decide later to shorten that drastically, you will be guaranteed ISR always sees InterruptStatus == ENABLED.

Message Edited by kef on 2009-11-21 01:17 PM
0 Kudos
836 Views
TDKamalAru
Contributor I

Dear Kef,

Thanks for your reply. But in the datasheet it is given that after updating the C1V register, the value will be latched to the C1V only at the next increment of the CNT register(since it is being used as a Compare module).If we write the SC register before CNT increments, then the latching mechanism will be reset and the C1V reg will not get updated.Hope so it is clear to you

 

Case:1

 

C1V = 0xAA;  /* Execution point:1 - say CNT = 4 at this instant of execution */

IF = 0;

IE = 1;

                  /* Execution point:2 - say CNT = 5 at this instant of execution */

 

So since IF and IE bits in SC register has been written before CNT increments to next value 5, the latching mechanism got reset and the C1V will be updated by 0xAA. What shall we do for this.

I have tested with debugger also. At the Execution point:2, the C1v doesn't holds 0xAA but the old value.

0 Kudos
836 Views
bigmac
Specialist III

Hello,

 

Why don't you post your actual problem code, rather than pseudo code?  This may clarify the situation, and would permit others to also test the code.

 

For a one millisecond output compare period, you shouldn't need a high prescale value.  However, if you suspect that the write to TPM2C1SC is reseting the latching mechanism, because of the prescale setting, the maximum cycles you would need to wait would be equivalent to the prescale value.

 

Perhaps alter the sequence so that TPM2C1V is written first, then manipulate the port pin, and set any other status flag.  This should give a delay of a few cycles.  You could add a bit more padding, if your prescale value is more than 4, before then writing to TPM2C1SC.

 

Regards,

Mac

 

0 Kudos
836 Views
kef
Specialist I

What's your CNT clock? Is it prescaled so that you write IF=0 before CNT gets incremented? Then you should wait a bit, until CNT gets incremented and C1V updated. Anyway C1V should be updated first, then flag cleared, and only then interrupt should be enabled.

Thanks for pointing me at latching mechanism issue. I didn't take that into account because I'm not that familiar with S08. But I believe what bites your pseudocode is previous output compare setting matched some timer overflow periods later.

 

0 Kudos
836 Views
TDKamalAru
Contributor I

Kef,

     Yes,my CNT is prescaled from Source Clock.There might be a chance to had a compare event interrupt due to older value. But for what ever may be the compare event, my InterruptStatus bit variable should also get updated in coherent with the timer interrupt disable right. Because in freescale interrupt architecture, they dont have any interrupt controller which controls the priorities etc. When ever an interrupt occurs, the global interrupt will be automatically disabled and will be enabled when it returns from the isr. In such a case the timer interrupt disable and InterruptStatus = DISABLED should happens with out any fail. The problem could be the wrong pulse width if the compare event occured fro older compare value. But here since timer gets disabled and the InterruptStatus Flag remains Enabled causes the no output(pulse).

 

0 Kudos
837 Views
kef
Specialist I

TDKamalAru,

 

Please look again at your pseudocode. If old compare setting can match after you clear flag and before you update CxV, then interrupt can fire before you set InterruptStatus to ENABLED! It may fire immediately after you enable interrupt and before InterruptStatus is set to ENABLED. 1) ISR will be called first, 2) ISR will set InterruptStatus to DISABLED. 3) Finally CPU will return back from ISR and will execute the rest of MAIN, setting InterruptStatus to ENABLED. Result: interrupt mask ==0, InterruptStatus == ENABLED.

No coherency guaranteed, unless you set up CxV=CNT+N first, then clear flag. These two steps guarantee compare match and flag=1 won't occur for N next timer ticks.

 

I played yesterday with latching mechanism. Clocking TPM from bus clock and using small prescalers no delay between CxV=.. and flag=0 is required.

Message Edited by kef on 2009-11-23 08:51 AM
0 Kudos
836 Views
TDKamalAru
Contributor I

Dear Kef,

Thanks i got it.Yes this could be the only reason behined the death of my code.i will do change and give u the feedback. Hav confidnce that it will work more than 100%.

 

Once again i thank Mr Kef and Mr Mac for giving our views and helped me to know the cause and to take the corrective action.

0 Kudos
836 Views
bigmac
Specialist III

Hello,

 

I might have expected that that the TPM2C1SC_CH1IE bit would be set within the main code, and would then be cleared within the ISR code.  That is, once the OC interrupt has occurred, and the ISR entered, there are no further interrupts required until after the next pulse has been initiated.

 

The additional InterruptStatus flag would appear unnecessary since the TPM2C1SC_CH1IE bit already represents the status, and may be read at any time.  I would also suggest globally disabling interrupts during the pulse start process.

 

#define InterruptStatus  TPM2C1SC_CH1IE 

 

void pulse_start( word pwidth) 

{

   if (!InterruptStatus) { 

      DisableInterrupts;

      // Switch on port pin here

      TPM2C1V = TPM2CNT + pwidth

      TPM2C1SC = 0x50;   // Output compare, interrupt only

      TPM2C1SC_CH1F = 0; // Ensure flag is clear

      EnableInterrupts;

   } 
}

 

Regards,

Mac

0 Kudos
836 Views
Lundin
Senior Contributor IV
It is hard to tell with just that pseudo. One typical cause for such unexpected, rarely appearing bugs is lack of semaphores, ie the main loop and the ISR attempt to access the same memory at the same time. Another cause could be forgetting to declare the variables shared with the ISR as volatile, which will lead to completely random behavior.
0 Kudos
836 Views
kef
Specialist I

Where you set InterruptStatus to DISABLED? Where you disable interrupt? In your pseudocode you only enable interrupts and set InterruptStatus to ENABLED. Please show all writes to InterruptStatus and TPM2CH1IE. Do you clear timer flag before enabling interrupt?

0 Kudos