AnsweredAssumed Answered

TPM behavior on KL05

Question asked by Jan Rychter on Nov 10, 2013
Latest reply on Nov 25, 2013 by Jan Rychter

Hi!

 

I am trying to generate a precisely timed series of pulses with the FRDM-KL05 board, using the TPM0 timer. This would not be a serious problem, except for the fact that the period is 1.3µs, with duty cycle varying between 350ns and 650ns. Which means I can't use interrupts to load the next pulse's duty cycle data (not enough cycles), and even without interrupts cycles are *really* scarce. I am not even sure if it is possible, but in the meantime I stressed the TPM module quite a bit and was surprised by what I found.

 

I am using TPM0 with channel 0 set to EPWM (MSB|ELSB are set), and a 20.971MHz TPM clock.

 

Here are the three main questions:

 

1. The channel flag (TPM0_C0SC & TPM_CnSC_CHF_MASK) gets set when I reset the counter to 0 by writing to TPM0_CNT, even though TPM0_C0V is set to 0, this happens regardless of whether the timer is enabled (CMOD bits) or not.

 

Is this a documentation problem or a bug?

 

2. I have a program that gets the timer into a state where after my pulses have been generated, TPM0_C0V is set to 0, but pulses continue to appear on the output pin. Indefinitely.


Documentation says nothing about the possibility of TPM0_C0V write *failing*. I know about the buffering (I use it, after all), but from what I understand, writing a 0 to TPM0_C0V should stop EPWM on the output pin starting with the next timer overflow.

 

Is there a scenario where writing a 0 to TPM0_COV can fail?

 

3. I could not find a procedure to predicably start the timer and generate pulses relying on the CnSC_CHF flag (TPM0_C0SC & TPM_CnSC_CHF_MASK). My first attempt was to try busy-waiting on the TPM_CnSC_CHF flag: "while(!(TPM0_C0SC & TPM_CnSC_CHF_MASK));". The problems with this:

 

a) resetting the timer sets the CHF flag for channel 0,

b) if I reset the timer and the CHF flag for channel 0 while the timer is disabled, enabling the timer will still set the CHF flag,

c) clearing the CHF flag after the timer starts running means that I'm introducing a delay where I'd rather not,

d) this is compounded by the fact that I have to reset the CHF flag *twice* (if I understand the docs correctly) to make sure it is really reset.

 

So, what would be the procedure to predictably start the timer in a known state, with CHF cleared, C0V set to 0, so that I can write the new C0V value within the first period and continue on subsequently?

 

To give you a rough idea of the code we're talking about, here's one of the C versions (I subsequently rewrote this in assembly):

 

  TPM0_C0SC |= TPM_CnSC_CHF_MASK;

  TPM0_C0SC |= TPM_CnSC_CHF_MASK;

  TPM0_CNT = 0;

 

  for(i=0; i < count; i++) {

      byte = data[i];

      bit = 8;

      do {

          bit--;

          TPM0_C0V = timings[(byte >> bit) & 1];

          while(!(TPM0_C0SC & TPM_CnSC_CHF_MASK));

          TPM0_C0SC |= TPM_CnSC_CHF_MASK;

      } while(bit);

  }

  TPM0_C0V = 0;

 

This does not work reliably, for a number of reasons, but I'm posting it to make it easier to understand what I'm trying to do.

Outcomes