Hello,
I am using the KL04 chip.
Some of the pins are being used in the PWM mode.
But, I need to make measurements during the PWM off time.
How can I monitor or do that.
How can I make sure that the measurements are being made during the
off time and not the on time.
One way is to monitor the TPM0_CNt. But this will keep adding latencies.
Page 511 of the datasheet says this -
30.4.6 Edge-Aligned PWM (EPWM) Mode
The edge-aligned mode is selected when (CPWMS = 0), and (MSnB:MSnA = 1:0). The
EPWM period is determined by (MOD + 0x0001) and the pulse width (duty cycle) is
determined by CnV.
The CHnF bit is set and the channel (n) interrupt is generated (if CHnIE = 1) at the
channel (n) match (TPM counter = CnV), that is, at the end of the pulse width.
This type of PWM signal is called edge-aligned because the leading edges of all PWM
signals are aligned with the beginning of the period, which is the same for all channels
within an TPM.
But this is not working fine. The reason being -
I have configured the interrupt to be at 50uSecs. Also , CHnIE = 1.
So as per this text it should go to the ISR twice - once for the end of the
PWM on time(i.e - end of the pulse width) and then at the end of the period.
So, if its 50% duty cycle it will go to the ISR at 25uSecs and the at 50uSecs.
But, it is entering it only once. Hence, we can say that the interrupt is done only at the end of the period.
So, how to find if the pwm on time is over.
Vinod.
Hi Vinod,
I have some concerns regarding your setup and I would like to get some more information from you.
Firstly, you mention that you are trying to get an edge-aligned PWM. However, I see in your initialization code that you have set the CPWMS bit (with the instruction TPM0_SC |= TPM_SC_CPWMS_MASK;). This configures your PWMs for center alignment.
Secondly, I see in your setPWMDutyCycle function that you are disabling the clock to the TPM to update the channel value. I would recommend not doing that. It is not necessary. The channel value can be updated with the clock to the TPM still running. This may have something to do with some erratic operation that you are seeing.
Third, I want to make sure that we can get a PWM going, so can you try to setup your PWM with MOD / 2 as the channel value? This should produce a 50% PWM on your scope. Are you trying to get low-true pulses or high-true pulses? I see in your initialization you have both configurations and one will override the other.
Thanks,
Chris
Hello Vinod,
I'm a little bit confused with your issue, so I was wondering if you could states your issue simply and upload your whole demo.
I'm looking forward to your reply.
Have a great day,
Ping
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hello Vinod:
I think you misunderstood the reference manual:
The CHnF bit is set and the channel (n) interrupt is generated (if CHnIE = 1) at the
channel (n) match (TPM counter = CnV), that is, at the end of the pulse width.
This means that only one interrupt should be generated, but not at the end of the period, but at the end of the Pulse Width (channel match with CnV). So if you have a 50 us period with 50% duty cycle, then interrupt should trigger at 25 us, then 75 us, 125 us and so on.
Regards!,
Jorge Gonzalez
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hello Jorge,
I did a small expt. The code is as stated below -
static void setPWMDutyCycle(uint16_t dutyCycle,uint8_t channel)
{
float roughVal;
uint8_t xRough = 0; // comment later //
uint8_t result0A = 0; // comment later //
TPM0_SC &= ~(TPM_SC_CMOD_MASK);
// timer off //
TPM0_CNT = 0; // counter value. NOTE :- when debug is aactive
TPM0_CONF |= 192; // counter runs in debug mode as well //
switch(channel){
// '-' or low drivers are pulled high without PWMs as they don't make a difference //
case 0:
TPM0_C0V = dutyCycle;
// U1+ turned ON // uncomment
TPM0_C2V = 0; // V1+ turned OFF // uncomment
TPM0_C4V = 0; // W1+
//turned OFF // uncomment
break;
case 2:
TPM0_C2V = dutyCycle;
// V1+ turned ON // uncomment
TPM0_C0V = 0; // U1+ turned OFF // uncomment
TPM0_C4V = 0; // W1+ turned OFF // uncomment
break;
case 4:
TPM0_C4V = dutyCycle; // W1+ turned ON // uncomment
TPM0_C2V = 0; // V1+ turned OFF // uncomment
TPM0_C0V = 0; // U1+ turned OFF // uncomment
break;
}
TPM0_SC |= TPM_SC_CMOD(1); // timer started //
}
In either of the 3 cases (0,2 and 4) one of the channels is given PWM. The other 2 are fed '0' to not give out any PWM from them. For e.g - in case 4 -> PWM is given out via C4V, while C2V and C0V are disabled as PWMs. Now, when the TPM0_CxSC registered is manipulated as -
TPM0_C0SC |= (TPM_CnSC_MSB_MASK | TPM_CnSC_ELSB_MASK); // PWM - edge ,...etc for centre alligned mode //
TPM0_C2SC |= (TPM_CnSC_MSB_MASK | TPM_CnSC_ELSB_MASK); // PWM - edge ,...etc for centre alligned mode //
TPM0_C4SC |= (TPM_CnSC_MSB_MASK | TPM_CnSC_ELSB_MASK);
it works fine.
But when I make it as -
TPM0_C0SC |= 0x24;
TPM0_C2SC |= 0x24;
TPM0_C4SC |= 0x24;
It fails. I get PWM on one channel, while the others also give out PWMs with very large dutycycles. Why this behaviour.
Vinod.
Hello Jorge,
I get your point.
In the conventional PWM, with a 50% duty cycle. There is a high for 25uSecs,interrupt, PWM low for 25uSecs,PWM high for 25uSecs,interrupt and so on and so forth.
So, measuring the relevant data during the low part of the PWM should not be a problem as the pwm low starts after the interrupt.
This is true if I select the following -
1) Edge-aligned PWM.
2) High-true pulses (clear Output on match, set Output on reload).
Hope this is clear.
I added this code -
TPM0_C0SC |= (TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK); // PWM - edge ,...etc for centre alligned mode //
TPM0_C2SC |= (TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK); // PWM - edge ,...etc for centre alligned mode //
TPM0_C4SC |= (TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK);
SO it should give me the needed thingy. But the pin is always high.
But this code -
TPM0_C0SC |= (TPM_CnSC_MSB_MASK | TPM_CnSC_ELSB_MASK); // PWM - edge ,...etc for centre alligned mode //
TPM0_C2SC |= (TPM_CnSC_MSB_MASK | TPM_CnSC_ELSB_MASK); // PWM - edge ,...etc for centre alligned mode //
TPM0_C4SC |= (TPM_CnSC_MSB_MASK | TPM_CnSC_ELSB_MASK);
works with PWM
The ISR is -
void FTM0_IRQHandler(void){
uint8_t rough = 0;
// added for wait of ADC //
// GPIOB_PSOR |= 0x00000018;
counterAdc++;
TPM0_SC &= ~TPM_SC_CMOD_MASK;
if((TPM0_SC & TPM_SC_TOF_MASK) == TPM_SC_TOF_MASK){
TPM0_SC |= TPM_SC_TOF_MASK;
}
adcFlag = 1;
TPM0_SC |= 8;
//adcChannel = "W";
// pitStart(2); //issue - probably 5 is not 5 us.
// commutationFlag = 1;
//pitStart(2);
}
Consider the above image.
The blue is the PWM. At each interrupt of the TPM0 I am making a pin high and low(the yellow pin).
TPM0_C0SC |= 0x28;
TPM0_C2SC |= 0x28;
TPM0_C4SC |= 0x28;
The code is for " Edge-aligned PWM High-true pulses (clear Output on match, set Output on reload)"
This is as per the datasheet and correct to my understanding. But the yellow toggle is done done properly. It
should rather be done at the end of the PWM on (so its a delay of 25uSecs). How is this so.
But, in case I change the code to
TPM0_C0SC |= 0x24;
TPM0_C2SC |= 0x24;
TPM0_C4SC |= 0x24;
I get the following image. The PWM never has a low period. Though it does do the interrupt action . Pls see the image below.
The blue is always high. The yellow (diagnostic) is manipulated in the ISR as expected. Strange behavior :smileyhappy:
The pwm initialisation code is as stated-
static void pwmInit(void)
{
// PWM //
//timer0 - PWM //
SIM_SOPT2 |= SIM_SOPT2_TPMSRC(1); // clk source for TPM0 and TPM1 as well
SIM_SCGC6 |= SIM_SCGC6_TPM0_MASK; // clk gated for TPM0
SIM_SCGC5 |= SIM_SCGC5_PORTA_MASK; // clk gated for PORTA
SIM_SCGC5 |= SIM_SCGC5_PORTB_MASK; // clk gated for PORTB
TPM0_SC |= 3; // 8 prescale factor
SIM_SCGC5 |= 0x00000400; // gating of clock for PORTA/B //
// port settings //
PORTB_PCR7 &= PORT_PCR_MUX_MASK; // U1+
PORTA_PCR6 &= PORT_PCR_MUX_MASK; // V1+
PORTB_PCR11 &= PORT_PCR_MUX_MASK; // W1+
PORTB_PCR7 |= PORT_PCR_MUX(2); // U1+
PORTA_PCR6 |= PORT_PCR_MUX(2); // V1+
PORTB_PCR11 |= PORT_PCR_MUX(2); // W1+
// added 040412014 //
TPM0_SC &= ~(TPM_SC_CMOD_MASK); // timer off //
TPM0_CNT = 0; // counter value. NOTE :- when debug is aactive
TPM0_CNT = 0; // counter value. NOTE :- when debug is aactive
TPM0_CONF |= 192; // counter runs in debug mode as well //
TPM0_MOD = 131;
TPM0_SC |= TPM_SC_TOIE_MASK; // INTERRUPT ENABLED //
// -- add ends -- //
//timer0//
TPM0_CNT = 0; // counter value. NOTE :- when debug is aactive
TPM0_CONF |= 192; // counter runs in debug mode as well //
//Pins of PWM //
//--- alternate selection (all PWM are ALT2)---//
// TPM0_SC |= TPM_SC_CPWMS_MASK; // edge/centre alligned mode //
// TPM0_C0SC |= (TPM_CnSC_MSB_MASK | TPM_CnSC_ELSB_MASK); // PWM - edge ,...etc for centre alligned mode //
// TPM0_C2SC |= (TPM_CnSC_MSB_MASK | TPM_CnSC_ELSB_MASK); // PWM - edge ,...etc for centre alligned mode //
// TPM0_C4SC |= (TPM_CnSC_MSB_MASK | TPM_CnSC_ELSB_MASK);
TPM0_C0SC |= 0x24;
TPM0_C2SC |= 0x24;
TPM0_C4SC |= 0x24;
// TPM0_C0SC |= (TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK); // PWM - edge ,...etc for centre alligned mode //
// TPM0_C2SC |= (TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK); // PWM - edge ,...etc for centre alligned mode //
// TPM0_C4SC |= (TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK);
// TPM0_SC -- turn on timer //
}
Vinod.