lpc24xx PWM capture timer readout problem

Started by sneh...@gmail.com February 7, 2014
Hello everyone.

I am a newbie in lpc devices. I have been trying to interface the PWM based max6672 sensor with the PWM capture pin. I want to read the both the low time and high time of the PWM pulse. I am recieving an interrupt when the PWm input is received. But some how I am not able to calculate the rise and fall time correctly. I need this info to calculate the temperature of the sensor.

Steps in my code:
1. set up the PWM capture pin.
2. set the PWM capture registers.
3. Wait for interrupt on rise time. save the PWM0CR0 rise time value
4. set the register to low time interrupt.
5. wait for interrupt on low time. save the PWM0CR0 low time value = PWM0CR0 - high time.
6. calculate the temp using the high and low time of the pulse.

I am putting up my code here.

void Capture0IntrHandler(void)
{
if ((PWM0IR == 0x10)){
if((PWM0CCR_bit.CAP0RE == 1)){ //low to high transition rising edge
period = PWM0CR0 - rising_edg;
rising_edg = PWM0CR0;
PWM0CCR = 0x6;
}else{
duty = PWM0CR0 - rising_edg;
PWM0CCR = 0x5;
PWM0_Done =1;
}
}
PWM0IR=0xFF; //Reset the interrupt*/
VICADDRESS = 0;
}

void init_timer(void) // Timer 0 used as a counter
{
// PWM PCAP0.0 Pin: P1.12
// pclk = cclk/2 = 30MHz (cclk=ARM7 core clock)

unsigned int IRQ_priority= 0x1; // '0' = highest, '0xF' = lowest IRQ priority

PINSEL2 = 0x03000000; //PWM PCAP0.0 Pin: P1.12 //1 = pclk = 60 MHz or 72MHz
PCONP_bit.PCPWM0 |=1;
PCLKSEL0_bit.PCLK_PWM0 = 1; //pclk is set to 2 = pclk/2 = 36 MHz or 30MHz
//RISING EDGE CAPTURE

PWM0TCR_bit.CR = 0; //disable PWM counter reset
PWM0TCR_bit.CR = 1; //Reset PWM counter
PWM0TCR_bit.CR = 0; //disable PWM counter reset

PWM0CCR_bit.CAP0RE = 1; //capture of rising edge
PWM0CCR_bit.CAP0FE = 0; //disable falling edge capture
PWM0CCR_bit.CAP0INT = 1; //enable interrupt rising edge

PWM0CTCR_bit.CM = 0; //PWM0 is set in timer mode
PWM0CTCR_bit.CIS = 0;

PWM0PCR =0; //no external interrupt
PWM0PR = 59; //resolution of 1 us for a 60MHz cclk = pclk
PWM0IR = 0xFF; //reset the interrupts

VIC_SetVectoredIRQ(Capture0IntrHandler, IRQ_priority, VIC_PWM01); // setup PWM IRQ
PWM0TCR_bit.CE =1; //enable the PWM Capture timer

}

int main (void)
{
LPC2468_Init();
ConfigurePLL();
LPC2468GPIOInit();
__disable_interrupt();
LPC2468VICInit();
__enable_interrupt();

period = 0;
falling_edg = 0;
rising_edg =0;
duty = 0;

init_timer();
PWM0_Done =0;
while (PWM0_Done == 0){};
y = 3;
t1 = duty;
t2 = rising_edg;
k = (double)t1/t2;
x11 = (temp_coeff - k);
x1 = (double)powf(x11,y);
x2 = ((double)(temp_coeff2 * k)) - temp_coeff3;
temp_deg = ((double)((-temp_coeff1)* x1)) + x2 ;
peri = rising_edg + duty;

return 0;
}

Thanks
Sneha


Yahoo Groups Links

<*> To visit your group on the web, go to:
http://groups.yahoo.com/group/lpc2000/

<*> Your email settings:
Individual Email | Traditional

<*> To change settings online go to:
http://groups.yahoo.com/group/lpc2000/join
(Yahoo! ID required)

<*> To change settings via email:
l...
l...

<*> To unsubscribe from this group, send an email to:
l...

<*> Your use of Yahoo Groups is subject to:
http://info.yahoo.com/legal/us/yahoo/utos/terms/

An Engineer's Guide to the LPC2100 Series

Hello Sneha,

I have some points to mention:

1. You are using PWM as a freeruntimer. If you have a situation when PWM0CR0 < rising_edg

period = PWM0CR0 - rising_edg;

will give you erroneus result.

2. You are reading PWM0CR0 twice in the PWM ISR. It is good practice to use:

register uint32_t pwm0cr0 = PWM0CR0;
period = pwm0cr0 - rising_edg;
rising_edg = pwm0cr0;

Keep in mind that reading a register of the PWM address space is a read of an APB address space register. Which, as I remmember, takes about 13 cloks to complete for the leading read operation. So for consistency it is better to read PWM0CR0 just once in the ISR.

3. In the main() you have:

t1 = duty;
t2 = rising_edg;
k = (double)t1/t2;

I think it should be:

t1 = duty;
t2 = period;
k = (double)t1/t2;

Regards
Zdravko
Hello.

Thanks for your reply.

But I still have some questions. I wanted to read both high and low times
hence I was reading the PWM0CR0 register twice at rising and falling edge.
If I read it only once in the rising edge how do I get my falling edge? I
think I have a problem in counting the falling edge of the register.

Apart from that I also have some other doubts about the registers:

PCLKSEL0_bit.PCLK_PWM0 = 1; Can this be also used to set the pclk divisor
for the capture input or is it only for PWM funactionality.

I want to use this PCAP0.0 pin as a counter. In the datasheet we have to
set the
PWM0CTCR_bit.CM = 0;
PWM0CTCR_bit.CIS = 1; to enable the rising edge counter mode one needs to
set this pin.

And if the counter mode is enabled the pins @CCR as must be 000 as set. ref
UM10237 datasheet pg 643

PWM0CCR_bit.CAP0RE = 0; //capture of rising edge
PWM0CCR_bit.CAP0FE = 0; //disable falling edge capture
PWM0CCR_bit.CAP0INT = 0; //enable interrupt rising edge

But when I do this setting i am not receiving an interrupt from the sensor.

But if I set the PCAP0.0 pin as a timer
PWM0CTCR_bit.CM = 0;
PWM0CTCR_bit.CIS = 0; and CCR for rising edge 0x5 and falling edge 0x6

PWM0CCR_bit.CAP0RE = 1; //capture of rising edge
PWM0CCR_bit.CAP0FE = 0; //disable falling edge capture
PWM0CCR_bit.CAP0INT = 1; //enable interrupt rising edge 0x5
later I change in the interrupt to 0x6 for falling edge I am able to detect
the interrupt but the counter doesnt have the correct values.

Is there something wrong in my understanding of the code?

Thanks and Regards
Sneha
Hello,

First let me clarify that the code snippet which I posted is just an example.
Since PWM0CR0 is declared as volatile, the compiler issues a read operation every time you use it in a read context.

Of course you need to read PWM0CR0 for both falling and rising edge. But my remark was to read it once per IRQ.
In your code:

void Capture0IntrHandler(void)
{
if ((PWM0IR == 0x10)){
if((PWM0CCR_bit.CAP0RE == 1)){ //low to high transition rising edge
period = PWM0CR0 - rising_edg;
rising_edg = PWM0CR0;
PWM0CCR = 0x6;
}else{
duty = PWM0CR0 - rising_edg;
PWM0CCR = 0x5;
PWM0_Done =1;
}
}
PWM0IR=0xFF; //Reset the interrupt*/
VICADDRESS = 0;
}

In this code you have read of PWM0CR0 twice per IRQ. Twice per rising edge and twice per falling edge.
In some situations this may be unsafe if a capture event occurs between the two readings. Of course I can not bet that this is your case. But it will be good if you correct your code.

You are rigth if the PWM is used as a counter you can not use the capture feature. This I know from experience and it is not mentioned in the documentation.

Regards
Zdravko Dimitrov
Hello zdravko;

Thank you so much for your inputs.

Yes I realized that if I read the PWM0CR0 register multiple times in the
same interrupt it has different values and in the end it is confused me. I
was able to solve the problem and now I read the values correctly.
I read the register once per interrupt and store it in a variable and do
operations on the value in the variable rather than the PWM0CR0 register
itself.

Finally I can move on with my life :)
Regards
Sneha