Four PwmIn inputs at 5 kHz each, KL25Z not keeping up?

30 Dec 2013

Hi there,

I have four sensors connected to the KL25Z. Each sensor produces a PWM pulse train at 5 kHz, the test signal has a fixed duty cycle of 50%.

With only one sensor connected the program works fine it give nice stable reading, perfect. With two sensors connected the results fluctuate say 10%, With 3 or more sensors the readings fluctuate unacceptably.

The PwmIn library (by Simon Ford) works on basis of interrupts, start timer at the rising transition, read the timer at the falling transition. So the total number of interrupts is 4 (sensors) x 5 (kHz) x 2 (transitions) 40 k/second. Is the KL25Z being overloaded ?

Any suggestions or idea's ?

Thanks,

Gerrit

#include "mbed.h"
#include "PwmIn.h"
#define NR 20

PwmIn a(PTD2);  
PwmIn b(PTA17); 
PwmIn c(PTA13);
PwmIn d(PTA16); 
Serial pc(USBTX, USBRX); // tx, rx

struct product {
    float pulse;
    float width;
    float duty;
} acc_a[NR], acc_b[NR], acc_c[NR],acc_d[NR];

int main()
{
    char pbuffer[60]="---";
    int i;
   
    while(1) {
        for (i=0; i<NR; i++) {
            acc_a[i].duty= a.dutycycle();
            acc_b[i].duty= b.dutycycle();
            acc_c[i].duty= c.dutycycle(); 
            acc_d[i].duty= d.dutycycle();
        }
        for (i=0; i<NR; i++) {
            sprintf(pbuffer, " a= %f, b= %f, c= %f, d= %f \n\r", acc_a[i].duty, acc_b[i].duty, acc_c[i].duty, acc_d[i].duty);
            pc.puts(pbuffer);
        }
    }
}
30 Dec 2013

I had a small test program still around which tests the InterruptIn speed: roughly 90kHz max, so that is close to what you observe. I did look into improving it, but a small note for myself: First check if what you want to do is possible: The LPC1768 could be improved by using a special instruction that the core M3 has, the core M0+ of the KL25Z doesn't have that instruction. So no luck there.

So for you a plan B: is it really needed to continiously check the duty cycle of everyone of those sensors? It isn't only checked when you read the value, it is always calculated.

Two options I see: 1. Modify the library so you can disable and enable the measurements. Then keep one enabled, get the value, disable it, do the next one, etc. Downside is that you have to wait a bit after enabling one to get the duty cycle.

2. Combine the four PwmIns into one big class. Then in the class automatically if the pulsewidth of one is measured, measure the pulsewidth of the next one, etc. Upside is that the duty cycle of all your sensors is always known (well it can be delayed a few cycles, but you never have to wait). Downside is that the Interrupts are always being called, method 1 only does it when you need to know the value. Still I think this is the nicest option.

31 Dec 2013

Dear Erik,

I think 2 PMW inputs will also do the job. The most important thing for this project is to get as many readings as possible from both sensors for a period of say 100 ms. The measuring results are processed later this is not time critical.

An interesting idea is option 1 to disable all interrupts except one, read the input, then read the next one and so on (the other option is also interesting but i do not have any experience with libraries)

Looking at the InterruptIn cookbook http://mbed.org/users/mbed_official/code/mbed/docs/dc225afb6914/classmbed_1_1InterruptIn.html#af0810e0eb56d5504c46a89d1e86c045b i noticed disable_irq and enable_irg. See the enclosed program without the enable_irg and disable_irg the program works, with them it does not. What is happening ?

I cannot find any example programs where these functions are used. Any help is appreciated,

Thanks, Gerrit

#include "mbed.h"
#include "InterruptIn.h"

#define NR 10
InterruptIn a(PTA17);       // Sensor 1
Serial pc(USBTX, USBRX);    // tx, rx

Timer timer_a;
float pulse, period;
float duty_a[NR];

//-----------Interrupts Service Routine sensor a---------------------
void isr_rise_a()
{
    period= timer_a.read();
    timer_a.reset();
}

void isr_fall_a()
{
    pulse=timer_a.read();
}

int main()
{
    int i;

    //-----------Interrupts Service Routine sensor a---------------------
    a.rise(&isr_rise_a);    // attach the interrupt handling
    a.fall(&isr_fall_a);    // attach the interrupt handling
 
    timer_a.start();
     
    while(1) {
        //--------------------- sensor a---------------------
        timer_a.reset();
        //a.enable_irq();             // enable the interrupt handling
        for (i=0; i<NR; i++) {        // read the pulses
            duty_a[i]= pulse;
        }
        //a.disable_irq();            // disable the interrupt handling 

        for (i=0; i<NR; i++) {
            pc.printf("a= %f \n\r", duty_a[i]);
        }
     }
}
31 Dec 2013

For the enable and disable_irq functions, see: http://mbed.org/questions/2274/Dissable-IRQ-on-DigialIn-pin-stopping-sl/. I also only found out they were added recently due to that question. What they do however is disabling all interrupts of a port, so you cannot use them to enable/disable a single one. What you can use is anwered in that question.

Then your code. First of all, pulse and period should be defined as volatile float: Not the issue here, but in general if you have a global variable you modify in your interrupt handler it needs to be volatile, otherwise it might get optimized away by the compiler.

Your problem then is that you enable the irqs right before reading the values: But then no irqs have happened yet, and pulse is still zero. You need to give it time to measure edges. If you for example put a wait after the enable_irq it will work.

03 Jan 2014

Hi there,

Still have not yet solved my problem; accurately reading two PwmIn inputs at the same time but the enclosed program may be interesting for others. The program setup is following the Erik's suggestion. The interrupts of one input are "enabled-read-disabled" then we go to the next one and so on.

////////////////////////////////////////////////////
// Testing enable_irq and disable_irg on two inputs
// Works in combination with teraterm
// Both inputs are connected to a signal generator
// One input counts on the rising flank the other one
// on the falling flank otherwise both interrupts appear
// on the same time (just to prevent problems)
// Only one input is enabled and read then the next one
// is enabled and read, and so on
////////////////////////////////////////////////
#include "mbed.h"

#define NR 10
InterruptIn a(PTD2);        // Sensor a
InterruptIn b(PTA17);       // Sensor b

Serial pc(USBTX, USBRX);    // tx, rx

volatile int a_counter;
volatile int b_counter;

int duty_a[NR];
int duty_b[NR];

//-----------Interrupts Service Routine sensor a---------------------
void isr_a()
{
    a_counter +=1;
}

//-----------Interrupts Service Routine sensor a---------------------
void isr_b()
{
    b_counter +=1;
}

int main()
{
    int i;
    //-----------Interrupts Service Routines--------------------
    a.rise(&isr_a);    // attach the interrupt handling
    b.fall(&isr_b);    // attach the interrupt handling

    while(1) {
        for (i=0; i<NR; i++) {
            // ------------------- input A--------------------
            a.enable_irq();             // enable the interrupt handling
            wait_us(10);
            duty_a[i]= a_counter;       // read input A
            a.disable_irq();            // disable the interrupt handling
            wait_us(10);

            // ------------------- input B--------------------
            b.enable_irq();             // enable the interrupt handling
            wait_us(10);
            duty_b[i]= b_counter;       // read input B
            b.disable_irq();            // disable the interrupt handling
            wait_us(10);
        }

        // present results
        for (i=0; i<NR; i++) {
            pc.printf("a= %d, b= %d \n\r", duty_a[i], duty_b[i]);
        }
    }
}
04 Jan 2014

Just some measuring results.

The PwmIn library is used in combination with a KL25Z and a function generator connected to two pins, PTD2 and PTA17. See the first program mentioned in this topic.

The generator set to 1.9 kHz and it works well with an PWM signal varying between 8 and 92%. When set to 5 kHz, it works well when the signal is between 25 and 75%, outside these limits the Kl25Z starts missing the flanks, maybe it is better to swap to the LPC1768.

04 Jan 2014

That will be a bit faster, but I wouldn't expect it to be a large improvement. It uses more efficient code (because it is an m3), and it has higher clock speed. At the same time it has more pins on the same interrupt vector, so that means more search work to figure out which interrupt was called.

You can use timer match on the LPC1768, but that has limitted inputs on the mbed.