TPM misbehaves in QD4

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 
已解决

TPM misbehaves in QD4

跳至解决方案
2,410 次查看
abicash
Contributor III

Hello

 

I am using QD4 for a Universal IR capture algorithm.

 

I am using TPM1CH1 (Pin 7,alternate function is PTAD1 as GPIO).This pin is used as an Interrupt driven

 

counter which will measure duration of incoming pulses between rising and falling edges (interrupts).

 

I am using a Timeout of 90msec after the first edge intr occurs.I also use some 70 bytes for this train

 

of pulses.So that after acquiring 70 bytes of info I fall out of that routine.

 

This works fine for a RC5/6 type of protocol which has a repeatabilty of ~100msec,but with some

 

others like SIRC,which has repeatable w/f in ~15msec,multiple packets of data are captured.

 

Here as an error correction mechanism,I will lookout for a TPMCNT>my threshold,after which I skip all 

 

the data ,so effectively only a single frame is put up for conditioning.

 

This is used in some Compare and Actions based on those Compares.

 

My Channel ISR is attached here

 

 

 //TPM1 channel INTR Service Routine //-------------------------------------------------------------------------------------// //---------------------------------------------------------------------// TPM1channel 1 edge Interrupt//----------------------------------------------------------------------interrupt 6 void TPM1C1_ISR (void){       TPMC1SC;     TPMC1SC_CH1F=RESET;         if(i==70)       {                 TPMC1SC_CH1IE=RESET;          TPMCNT=0;          TPMSC=0x00;       }                  if(i>1)       {            TPM2SC=0x00;            //Stop Timer2 or Stop timeout timer            store[i].period[0]=TPMC1VH;            store[i].period[1]=TPMC1VL;             TPM2MOD=0x7000;         //Timeout of 86msec.            TPM2SC=0x4D;            //Restart Timer       }                                       TPMCNT=0;   i++;       }

 

 
interrupt 10 void Timer2_Overflow_INTR(void){               TPMC1SC_CH1IE=RESET;     TPMCNT=0;             if(common.LEARN==SET)     common.LEARN_DONE=SET;          else     common.ACTION_READY=SET;        common.TIME_OUT=SET;     TPM2SC;     TPM2SC_TOIE=RESET;       }

 

 

 My problem is that often it will recv the waveform correctly but some of times I cannot get the 

 

correct waveform..I am not sure if the algorithm I am using is correct.

 

Can someone help?..I can tell more..

 

Expecting help as usual..

 

Thanks and regards

标签 (1)
0 项奖励
回复
1 解答
1,133 次查看
bigmac
Specialist III

Hello,

 

My previous response was badly worded.  The unorthodoxy that I was referring to was not the modification of the registers from within the ISR, but the stopping, starting and clearing of the TPM counter, and the changing of the TPMMOD value - it is usually possible to avoid these.  The reason they should generally be avoided is they affect all channels of the TPM module, and may prevent the use of spare channels for other purposes.

 

For the case of TPM2, with only a single channel, this issue is probably not of importance, but I was alluding to the fact that there is an alternative way of handling the timing that avoids the issue.  I did not mean to imply that your method could not be made to work, and had any bearing on your current problem.

 

The alternative method in more detail -

Within the TPM1 channel (input capture) ISR:

TPM2C0SC = 0x50;             // Software output compare interrupt

TPM2C0V = TPM2CNT + 0x7000;  // Setup timeout period

TPM2C0SC_CH0F = 0;           // Clear flag (if set)

 

When timeout occurs, a TPM2 channel 0 interrupt would take place.  Within this ISR:

TPM2C0SC = 0x00;    // Disable output compare mode

TPM2C0SC_CH0F = 0;  // Clear flag

 

Your input capture ISR code might then become something like the following -

 

#define RESET 0

byte i;
word store[70];

interrupt 6 void TPM1C1_ISR (void)
{
  //TPM1C1SC;      Unnecessary for flag clearing
  TPM1C1SC_CH1F = RESET; Clear flag 
  if (i == 70) {      
    //TPMC1SC_CH1IE = RESET;
    //TPMCNT=0;
    //TPMSC=0x00;
    TPM1C1SC = 0x00;  // Disable input capture operation
    TPM2C0SC = 0x00;  // ?? Disable output compare operation
  }
  else if (i > 1) {   // I presume this is what is really intended
  //if (i > 1 ) {
    //TPM2SC=0x00; //Stop Timer2 or Stop timeout timer

 

    store[i] = TPM1C1V; // Simpler to handle a word value
    //store[i].period[0]=TPMC1VH;
    //store[i].period[1]=TPMC1VL;
 

    TPM2C0SC = 0x50;             // Software output compare interrupt

    TPM2C0V = TPM2CNT + 0x7000;  // Setup timeout period 86ms

    TPM2C0SC_CH0F = 0;           // Clear flag (if set)

    //TPM2MOD = 0x7000;   //Timeout of 86msec.
    //TPM2SC = 0x4D;      //Restart Timer

    i++;  // May be better placed here
  }
  //TPMCNT = 0;
  //i++;   
}

One other point about input capture operation - it may be more reliable to capture on a single edge at a time, rather than both edges. This may prevent phasing errors occurring in the event of spurious interrupts - you will always be assured of the edge polarity that each capture event represents. During the input capture ISR simply toggle to the opposite edge for the next event.

 

Regards,

Mac

在原帖中查看解决方案

0 项奖励
回复
3 回复数
1,133 次查看
bigmac
Specialist III

Hello,

 

I wonder if it is possible that the period you are attempting to measure may exceed the overflow period for TPM1?  If so the capture results will be meaningless (without also tracking overflows).  Try increasing the prescale value for TPM1, and see if the problem persists.  I presume that TPM1 does not have a reduced modulo setting.

 

I notice that you are altering TPM2 settings within the TPM1 ISR, including stopping the timer and changing the modulo value.  This is rather unorthodox.  The more traditional aproach would be to utilize output compare interrupt, and leave the TPM running continuously with full modulo count. From within the TPM1 ISR, simply read the current 16-bit counter value for TPM2, add the required timeout delay (0x7000), and update the TPM2 channel register.  A channel interrupt will occur upon expiry of the timeout period. 

 

Regards,

Mac

0 项奖励
回复
1,133 次查看
abicash
Contributor III

Hello Mac and thank you so much for the reply..:smileyhappy:

 

The TPM1 Channel interrupt is invoked on every edge (rising and falling) and in the ISR i reset the TPM2CNT,so that largely,the overall code is trying to look for a Timeout.

This is to insure that multiple packets are not processed.

 

Why is TPM2 altering not suitable within another ISR?

 

I did not understand the part where you said to add the req. timeout delay after reading the current 16-bit cnt value.

Did you mean that I subtract current cnt from the req. cnt and then add this cnt to the existing cnt?

 

Why is this beneficial?

 

Please reply

Thanks and regards

Message Edited by abicash on 2009-03-30 12:58 PM
0 项奖励
回复
1,134 次查看
bigmac
Specialist III

Hello,

 

My previous response was badly worded.  The unorthodoxy that I was referring to was not the modification of the registers from within the ISR, but the stopping, starting and clearing of the TPM counter, and the changing of the TPMMOD value - it is usually possible to avoid these.  The reason they should generally be avoided is they affect all channels of the TPM module, and may prevent the use of spare channels for other purposes.

 

For the case of TPM2, with only a single channel, this issue is probably not of importance, but I was alluding to the fact that there is an alternative way of handling the timing that avoids the issue.  I did not mean to imply that your method could not be made to work, and had any bearing on your current problem.

 

The alternative method in more detail -

Within the TPM1 channel (input capture) ISR:

TPM2C0SC = 0x50;             // Software output compare interrupt

TPM2C0V = TPM2CNT + 0x7000;  // Setup timeout period

TPM2C0SC_CH0F = 0;           // Clear flag (if set)

 

When timeout occurs, a TPM2 channel 0 interrupt would take place.  Within this ISR:

TPM2C0SC = 0x00;    // Disable output compare mode

TPM2C0SC_CH0F = 0;  // Clear flag

 

Your input capture ISR code might then become something like the following -

 

#define RESET 0

byte i;
word store[70];

interrupt 6 void TPM1C1_ISR (void)
{
  //TPM1C1SC;      Unnecessary for flag clearing
  TPM1C1SC_CH1F = RESET; Clear flag 
  if (i == 70) {      
    //TPMC1SC_CH1IE = RESET;
    //TPMCNT=0;
    //TPMSC=0x00;
    TPM1C1SC = 0x00;  // Disable input capture operation
    TPM2C0SC = 0x00;  // ?? Disable output compare operation
  }
  else if (i > 1) {   // I presume this is what is really intended
  //if (i > 1 ) {
    //TPM2SC=0x00; //Stop Timer2 or Stop timeout timer

 

    store[i] = TPM1C1V; // Simpler to handle a word value
    //store[i].period[0]=TPMC1VH;
    //store[i].period[1]=TPMC1VL;
 

    TPM2C0SC = 0x50;             // Software output compare interrupt

    TPM2C0V = TPM2CNT + 0x7000;  // Setup timeout period 86ms

    TPM2C0SC_CH0F = 0;           // Clear flag (if set)

    //TPM2MOD = 0x7000;   //Timeout of 86msec.
    //TPM2SC = 0x4D;      //Restart Timer

    i++;  // May be better placed here
  }
  //TPMCNT = 0;
  //i++;   
}

One other point about input capture operation - it may be more reliable to capture on a single edge at a time, rather than both edges. This may prevent phasing errors occurring in the event of spurious interrupts - you will always be assured of the edge polarity that each capture event represents. During the input capture ISR simply toggle to the opposite edge for the next event.

 

Regards,

Mac

0 项奖励
回复