MCF51QE128 timer module

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

MCF51QE128 timer module

2,772 Views
gaminn
Contributor IV
Hi all,
in the MAIN part of my program, I have this init code for TPM1:
 
Code:
SCGC1_TPM1 = 1;TPM1MOD = 0x3F;TPM1SC = 0b01001111;

 
(mod value = 0x3F, bus clock divided by 128, overflow interrupt enabled)
 
Interrupt service rutine is here:
 
Code:
void interrupt VectorNumber_Vtpm1ovf commutationTime(void) {  TPM1SC_TOF = 0;  SCGC1_TPM1 = 0; // stop clock  TPM1SC = 0b01000111; // stop clock  TPM1CNT = 0; // reset timer  TPM1MOD = 0x2; // change mod value  TPM1SC = 0b01001111; // start clock   SCGC1_TPM1 = 1; // start clock      PTGD_PTGD7 ^= 1; // here I toggle one pin to see what timer does
}

Output signal should be first toggled after timer reaches 0x3F, in the interrupt service routine the mod value is changed to 0x02, so then the signal should have higher frequency. 
 
My problem is, that the mod value never changes to 0x02, I don't know why. Any advice?
 
And is there any manual how to operate TPM modules? I think there is not said all in the datasheet of MCF51QE128, because this is not my only problem with TPM modules, they just don't work as they should.
 
Thanks
 
Martin
Labels (1)
0 Kudos
10 Replies

651 Views
kef
Specialist I
You are using TPM module. Then why you are disabling/enabling TPM module clock (SCGC1 clock gating)? You should not touch any module register when corresponding SCGC1 bit is 0!
If I remove this line from ISR, then a write to TPM1MOD starts working.
 
SCGC1_TPM1 = 0;
 
 
Also, why are you resetting TPM1CNT? TPM overflow does it for you automatically. Purpose of disabling (TPM1SC = 0b01000111) and reenabling TPM clock is also not clear.
0 Kudos

651 Views
gaminn
Contributor IV
Sorry, I didn't read the datasheet carefully...
 
I have another problem with TPM. What happens, when I write to TPMxCNT register? Datasheet says that it simply resets TPMxCNT... But I have this code:
 
Code:
void interrupt VectorNumber_Vtpm1ch0 zeroCrossing(void) { // TPM1CH0 interrupt service  // another code here  TPM1CNT = 0;
  TPM1SC = (unsigned char) (TPM1SC & 0b00000111); // stop counter, but keep clock divider
  if(TPM2CNT == 0) {    // here I test TPM2CNT for 0, and it is 0  }    TPM2CNT = 0; // this is THE line
  TPM2MOD = (unsigned short) (someVar); // set new modulo value for TPM2  TPM2SC = (unsigned char) (0b01001000 | TPM1SC); // set TPM2 clock divider the same as TPM1 clock divider, start timer
  // another code here
  TPM1SC = (unsigned char) (TPM1SC | 0b01001000); start timer
  // another code here
  TPM2SC;
  TPM2SC_TOF;

  TPM1C0SC;
  TPM1C0SC_CH0F = 0;}
void interrupt VectorNumber_Vtpm2ovf commutationTime(void) { // TPM2 overflow interrupt service
  TPM2SC = 0b00000111; // stop counter
  // another code here
  TPM2SC;
  TPM2SC_TOF = 0;

}

 
TPM1CH0 is configured as input capture, TPM2 is modulo counter which generates overflow interrupt.
 
When I delete the line "TPM2CNT = 0;" in TPM1CH0 interrupt service, program does something different than when the line is there (it doesn't matter what the difference is). I test if TPM2CNT is zero right before the line "TPM2CNT = 0;" and it is, so the "TPM2CNT = 0;"  line should not have any effect, as it resets already reseted counter. TPM2 counter is also stopped as you can see from the code.
 
So in fact, what "TPM2CNT = 0;" does?
 
Thanks


Message Edited by gaminn on 2009-02-08 12:41 PM

Message Edited by gaminn on 2009-02-08 01:27 PM
0 Kudos

651 Views
kef
Specialist I
As the doc say, a write to TPMxCNT register clears TPMxCNT. Also TPMxCNT overflow to zero causes overflow interrupt. But it takes some time for CPU to reach code in your commutationTime ISR, and all this time TPMxCNT keeps counting! So when you stop TPM2 counter in commutationTime ISR, TPM2CNT most probably is already not zero. Hope this answers your question.
0 Kudos

651 Views
gaminn
Contributor IV
As I have written, I know that TPM2CNT is zero in zeroCrossing ISR. You can see there code:
 
  if(TPM2CNT == 0) {
    // here I test TPM2CNT for 0, and it is 0
  }
 
and program everytime goes inside this if. Additionally, I clear TPM2CNT in commutationTime ISR (I forgot to write it):
Code:
void interrupt VectorNumber_Vtpm2ovf commutationTime(void) {  TPM2SC = 0b00000111;  TPM2CNT = 0;    // another code here  TPM2SC;  TPM2SC_TOF = 0;}

 
If I specify that different behaviour between zeroCrossing ISR with and without "TPM2CNT = 0;" - program without that line does what I want, program with the line causes that TPM2CNT overflow interrupt is somehow masked and the commutationTime ISR routine is not performed.
 
Thanks
 
PS: I know I have one version of functional program, but I would like to know what causes that difference in behaviour.
0 Kudos

651 Views
kef
Specialist I
How do you test if TMP2CNT is zero. Did you put breakpoint at // ?
 
  if(TPM2CNT == 0) {
    // here I test TPM2CNT for 0, and it is 0
  }
 
Without any code between {}, branch to past {} could be eliminated.
 
I believe write to TPM2CNT clears TPM2CNT.
0 Kudos

651 Views
gaminn
Contributor IV
Code:
#include <hidef.h> /* for EnableInterrupts macro */#include "derivative.h" /* include peripheral declarations */   #define SAMPLES 3
word samplesHistory[SAMPLES];unsigned char samplePosition = 0;char waitingForZeroCrossing = 1; // 1 = zero crossing expected ; 0 = commutation planned
/********************************************/Commutation routine/********************************************/
void commutate(void) {  PTGD_PTGD7 ^= 1; // toggle this pin  }
/********************************************/TPM1CH0 ISR/********************************************/void interrupt VectorNumber_Vtpm1ch0 zeroCrossing(void) {  samplesHistory[samplePosition] = TPM1C0V; // store timer value when input capture occurs  if(++samplePosition > SAMPLES) { // calculate next position in the samplesHistory array    samplePosition = 0;  }  TPM1SC = (unsigned char) (TPM1SC & 0b00000111); // stop timer but keep divider  TPM1CNT = 0; // reset counter     int sum = 0;  unsigned char i;  if(!waitingForZeroCrossing) { // there was a commutation planned but zero crossing occured earlier    commutate();  }    for(i = 0 ; i < SAMPLES ; i++) { // calculate sum of last samples    sum += samplesHistory[i];   }  TPM2MOD = (unsigned short) (sum / (2*SAMPLES)); // TPM2MOD = half of last samples average, this makes 90 degrees shift of output signal  TPM2SC = (unsigned char) (0b01001000 | TPM1SC); // start TPM2 with the same clock divider as TPM1  TPM2CNT = 0;    waitingForZeroCrossing = 0;    TPM1SC = (unsigned char) (TPM1SC | 0b01001000); // start TPM1    TPM1SC;  TPM1SC_TOF = 0;  TPM1C0SC;  TPM1C0SC_CH0F = 0;  }/********************************************/TPM1 overflow ISR/********************************************/void interrupt VectorNumber_Vtpm1ovf zeroCrossingOverflow(void) {  TPM1SC;  TPM1SC_TOF = 0;
// I don't use this ISR but if I disable TPM1 overflow interrupts, the program doesn't work...why?}
/********************************************/TPM2 overflow ISR/********************************************/void interrupt VectorNumber_Vtpm2ovf commutationTime(void) {  TPM2SC = 0b00000111; // stop counter  TPM2CNT = 0; // reset counter    commutate(); // make commutation    waitingForZeroCrossing = 1;    TPM2SC;  TPM2SC_TOF = 0;}/********************************************/MAIN/********************************************/void main(void) {  PTGDD_PTGDD7 = 1; // output signal will be here    ICSC2_BDIV = 0; // divider = 1 // TPM1CH0 will be input capture //    TPM1MOD = 0xFFFF;  TPM1C0SC = 0b01001100;  TPM1SC = 0b01001111;      EnableInterrupts; /* enable interrupts */  for(;;) {    __RESET_WATCHDOG(); /* feeds the dog */  } /* loop forever */}

 
This is whole code of my program. On TPM1CH0 pin (input capture) there is an rectangular input signal (e.g. 1kHz, its edges are called zero crossing in the context of my use). On PTG7 pin there is output signal, which should be also rectangular, of same frequency but shifted by 90 degrees (left or right it doesn't matter). The program will drive BLDC motor....if it works sometimes.
 
Also (it is another remark), my program stops working when I disable TPM1 overflow interrupt. But the overflow interrupt is unused in fact, it doesn't make any work there.
 
I am really confused about it....


Message Edited by gaminn on 2009-02-08 10:02 PM

Message Edited by gaminn on 2009-02-08 10:04 PM

Message Edited by gaminn on 2009-02-08 10:07 PM
0 Kudos

651 Views
kef
Specialist I
I see a bug in your code
 
 
#define SAMPLES 3
word samplesHistory[SAMPLES];
...
void interrupt VectorNumber_Vtpm1ch0 zeroCrossing(void) {
  samplesHistory[samplePosition] = TPM1C0V; // store timer value when input capture occurs


  if(++samplePosition > SAMPLES) { // calculate next position in the samplesHistory array
    samplePosition = 0;
  }
...
 
Max samplesHistory index is 2. Now consider you run your ISR with samplePosition=2. It will increment to 3 but won't reset to 0...
0 Kudos

651 Views
gaminn
Contributor IV
Thanks, you are right, I'm stupid... So there must be another bugs, if you can see them, please tell me. Now, when I fixed this bug (if(++samplePosition >= SAMPLES)......), program runs correctly with TPM1 overlow interrupt disabled, but with  "TPM2CNT = 0;" line, it behaves in the same way.
0 Kudos

651 Views
gaminn
Contributor IV
I have simplified the code, it should do what I want:
 
Code:
#include <hidef.h> /* for EnableInterrupts macro */#include "derivative.h" /* include peripheral declarations */   void commutate(void) {  PTGD_PTGD7 ^= 1;  }void interrupt VectorNumber_Vtpm1ch0 zeroCrossing(void) {  TPM1SC = (unsigned char) (TPM1SC & 0b00000111);  TPM1CNT = 0;    TPM2MOD = (unsigned short) (TPM1C0V/2);  TPM2SC = (unsigned char) (0b01001000 | TPM1SC);  TPM2CNT = 0; // without this line it works  TPM1SC = (unsigned char) (TPM1SC | 0b00001000);    TPM1SC;  TPM1SC_TOF;  TPM1C0SC;  TPM1C0SC_CH0F = 0;  }void interrupt VectorNumber_Vtpm2ovf commutationTime(void) {  TPM2SC = 0b00000111;  TPM2CNT = 0;  commutate();  TPM2SC;  TPM2SC_TOF = 0;}void main(void) {  PTGDD_PTGDD7 = 1;    ICSC2_BDIV = 0; // bus clock /= 1 // TPM1CH0 will be input capture //    TPM1MOD = 0xFFFF;  TPM1C0SC = 0b01001100;  TPM1SC = 0b00001111;      EnableInterrupts; /* enable interrupts */  for(;;) {    __RESET_WATCHDOG(); /* feeds the dog */  } /* loop forever */}

 
What is wrong here, does anybody know? I'm really confused.


Message Edited by gaminn on 2009-02-10 04:34 PM
0 Kudos

651 Views
gaminn
Contributor IV
Datasheet says that input capture can occure for rising, falling or any edge. My program is configured, that it should generate input capture interrupt on any edge. But my program works in the way that when TPM1CH0 pin is high, CPU doesn't stop to generate interrupts. The situation is the same, when interrupts should be generated on rising edge. On the other hand everything is ok when configured to generate interrupt for falling edge (CPU generates interrupt really at the moment of falling edge on TPM1CH0 pin). What is wrong?
0 Kudos