Single TPM for IN and OUT

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

Single TPM for IN and OUT

Jump to solution
822 Views
d0ct0r
Contributor III

For simlicuty, lets say I need to use two channels from the same TPM. Not at the same time.

 

Ex.: TPM1

CH0: capturing (from sensor)

CH1: pwm out (to buzzer)

Bus: 24Mhz

 

I could initialise TPM1 as follow:

TPM1SC = 0x17;

TPM1C0SC = 0x44;

TPM1C1SC = 0x38;

 

TPM1MODH=0x03;

TPM1MODL=0x54;

TPM1C1VH=0x03;

TPM1C1VL=0x54;

 

I am able to use Interrupt for TPM1CH0 for capturing some data from sensor (data coming in microsecond intervals). This part working fine.

 

But then, for some uncertain reason, I cannot change TPM1MOD from zero to anything else to produce PWM signal. As well I can't write to TPM1CH1V. It just ignore anything I try to put there. However, buzzer could produce some sounds after long period of time. Then I am able turn it OFF (TPM1SC=0) and ON (TPM1SC=0x17). Its a mistery why its working in that manner.

 

Any ideas, what is wrong in theory ?

Labels (1)
0 Kudos
1 Solution
527 Views
bigmac
Specialist III

Hello,

 

Whenever you update the TPMxMOD or TPMxCnV registers, there is a coherency mechanism involved, before the value can change.  This mechanism differs slightly for different versions of the TPM module.  The update of these registers will occur more quickly if the TPM module is disabled when the values are altered, i.e TPMxSC is zero.  During initialisation, TPMxSC should then be the last register to be set.

 

I note that you have a large prescale setting of 128, and a relatively small TPM1MOD setting.  I would suggest to greatly reduce the prescale value to, say 2, and increase the TPM1MOD value by a factor of 64.  This will increase the resolution of the input capture process, but retain the same overflow period.  I note that you are writing individual byte values to the 16 bit registers.  This is unnecessary - it is simpler to write the full 16-bit value to these registers, It is also possible that you may not have taken into account that the PWM period is actually equal to (TPM1MOD+1)

 

The input capture range will be zero to TPM1MOD value.  The calculation of the period between input capture events must therefore compensate for the truncated range. 

 

I note that, with TPM1C1V equal to TPM1MOD, your PWM duty setting will be very close to 100 percent, which may cause the buzzer to be inaudible.  For 50 percent duty, you would require TPM1C1V = (TPM1MOD+1)/2;

 

Your initialisation code might then become -

TPM1MOD = 0xD4FF;

TPM1C0SC = 0x44;         // Input capture on +ve edge

TPM1C1SC = 0x38;         // Edge aligned PWM mode

TPM1C1V = (TPM1MOD+1)/2; // 50% duty

TPM1SC = 0x11;           // Fixed system clock, prescale 2

 

Within your input capture ISR, you might incorporate the following code to determine the period between events -

static word oldval;

 

period = TPM1C0V - oldval;

oldval = TPM1C0V;

if (period >= (TPM1MOD+1))

   period -= (TPM1MOD+1);  // Corrected period value

...

 

The global (or static) word variable period would need to be defined as volatile.

 

Regards,

Mac

 

View solution in original post

0 Kudos
5 Replies
528 Views
bigmac
Specialist III

Hello,

 

Whenever you update the TPMxMOD or TPMxCnV registers, there is a coherency mechanism involved, before the value can change.  This mechanism differs slightly for different versions of the TPM module.  The update of these registers will occur more quickly if the TPM module is disabled when the values are altered, i.e TPMxSC is zero.  During initialisation, TPMxSC should then be the last register to be set.

 

I note that you have a large prescale setting of 128, and a relatively small TPM1MOD setting.  I would suggest to greatly reduce the prescale value to, say 2, and increase the TPM1MOD value by a factor of 64.  This will increase the resolution of the input capture process, but retain the same overflow period.  I note that you are writing individual byte values to the 16 bit registers.  This is unnecessary - it is simpler to write the full 16-bit value to these registers, It is also possible that you may not have taken into account that the PWM period is actually equal to (TPM1MOD+1)

 

The input capture range will be zero to TPM1MOD value.  The calculation of the period between input capture events must therefore compensate for the truncated range. 

 

I note that, with TPM1C1V equal to TPM1MOD, your PWM duty setting will be very close to 100 percent, which may cause the buzzer to be inaudible.  For 50 percent duty, you would require TPM1C1V = (TPM1MOD+1)/2;

 

Your initialisation code might then become -

TPM1MOD = 0xD4FF;

TPM1C0SC = 0x44;         // Input capture on +ve edge

TPM1C1SC = 0x38;         // Edge aligned PWM mode

TPM1C1V = (TPM1MOD+1)/2; // 50% duty

TPM1SC = 0x11;           // Fixed system clock, prescale 2

 

Within your input capture ISR, you might incorporate the following code to determine the period between events -

static word oldval;

 

period = TPM1C0V - oldval;

oldval = TPM1C0V;

if (period >= (TPM1MOD+1))

   period -= (TPM1MOD+1);  // Corrected period value

...

 

The global (or static) word variable period would need to be defined as volatile.

 

Regards,

Mac

 

0 Kudos
527 Views
d0ct0r
Contributor III

Yes ! It did the trick. Now its working as expected. Much thanks !!!

 

0 Kudos
527 Views
d0ct0r
Contributor III

Another interesting observation: as soon as I write to SCI2D, TPM1 (CH1) produce PWM output (my buzzer starts beeping).

 

Here is the code (fragments):

 

[skip]

 

TPM1MOD = 0xD4FF; // MODULO (period or frequency)

TPM1C0SC = 0x44; // Input capture

TPM1C1SC = 0x38; // Edge aligned PWM mode

TPM1C1V = (TPM1MOD+1)/2; // 50% duty

TPM1SC = 0x11; // Fixed system clock, prescale 2

 

[skip]

 

while (SCI2S1_TDRE == 0); // Wait until SCI2 ready to send next byte

SCI2D = buf[i];

 

 

0 Kudos
527 Views
bigmac
Specialist III

Hello,

 

I might have expected that the buzzer would be active immediately the TPM1SC register was initialized.  I see no relationship between the PWM output and the SCI2 output (assuming they do not share the same pin).

 

In practice, you will need the capability to control the state of the buzzer.  I would usually accomplish this by writing to the TPM1C1SC register.  A zero value would turn the buzzer off, by reverting to GPIO.

 

In my previous post, I included a code snippet that purported to provide an adjustment for the input capture period calculation, for a TPM module that was not free-running.  This code was wrong.  Here is a corrected version (I think) -

 

static word oldval;

 

if (TPM1C0V < oldval)

   period = TPM1C0V + (TPM1MOD + 1 - oldval);

else

   period = TPM1C0V - oldval;

oldval = TPM1C0V;

 

Regards,

Mac

 

0 Kudos
527 Views
d0ct0r
Contributor III

I found that case with  SCI2D and TPM1 was just coincedent. Basically setup TPM1 PWM required some time to complete this task. And that amount of time expired exactly on the command to write to SCI2D. 

0 Kudos