NXP LPC1768 looks so slow (?)

10 Aug 2010

Dear All,

I am using mbed NXP LPC1768, why it looks so slow?

I use it to read low-cost IMU @100Hz and 115200bps, via a serial port (p28, p27), using 'attach' interrupt function. A PPM RC receiver connected to p11 set as 'InteruptIn' and I use timer to capture the 5 0.7-1.5mS signals with 16mS of period. 4 I2C devices driven by an i2C bus (p9, p10) by 100Hz update rate. I send some data trough RF Modem via a serial (p13, p14) @36Hz and 115200bps.

When I try the tasks one-by-one, it is okay.

But when I integrate the whole system: the IMU data can not be acquired perfectly, the PPM signals can not be captured correctly and so many error data unit in data sending. When I increase over 36Hz in 115200bps, it is more terrible.

In some project file I meet error "Expected a member name (E133)" when I call the timer start() function. But it not happen  when make another new project file and I just copy paste the whole code from the old project file.

Please explain to me why? I love the way to use this board but these unexpected problems make me stuck to continue my prototyping project.

Thank you,

/rhj

10 Aug 2010

Hi Raharja,

It's hard to tell where the bottle neck is without the code.

You might be using too many different interrupts. As a general rule, you should try to perform similar tasks in the same interrupt service routine. The PPM code in the other post uses a rising interrupt and a falling interrupt. You should try to re-write the code to use only one type of interrupt (therefore halving the interrupt overhead).  Also, there has been an issue with the Serial class when you use the same object inside and outside of interrupt service routines. I don't know if this has been fixed (or if it is an issue for you), but at the time the suggestion was to declare seperate Serial objects. One to use inside interrupts and the other to use outside of interrupts.

11 Aug 2010

Thank you for your advice Mr Igor, I will try  to do so.

Anyway you can  see my code here: http://mbed.org/users/agiembed/programs/FlightController/5zdzh, if anyone want try to analyze the problem from the code structure

 

Thanks,

/rhj

11 Aug 2010

Hey,

It looks like you've put in a fair bit of work into your project!

I haven't looked over the code in depth but I did notice a few things. The error E113 you were experiencing is fixed if you include rcrx.h at the beginning rather than at the end of the include list, (i.e. incude rcrx.h right after mbed.h). This seems to fix that problem.

The other issue I saw is in main.cpp:

int main() {
    setup();
    SendData.attach(&toGCS, 0.02777);
    Proccess.attach(&eyetosee, 0.1);      <-- THIS
    ahrs.attach(&ahrs_rec);
    rc.rise(&PPM_rise);  // attach the address of the PPM_rise function to the rising edge
    rc.fall(&PPM_fall);  // attach the address of the PPM_fall function to the falling edge  
    wait(0.5);
    
    while(1) {
        eyetosee();               <-- AND THIS
        myled = !myled;
        for(char i=0; i<6; i++){
            printf("%d\t", buf_ppm[i]);
            if(i == 5) printf("\n");           
            wait(0.02);
            }         
    }
}


You seem to call eyetosee() both in an interrupt (Ticker Process) and in the main while loop. You should really use one or the other. This could have something to do with the slowdown issues. From my experience, I2C is pretty slow and it does have a noticeable effect on the performance of the program if you are not using it properly. I had enough trouble with a single accelerometer, let alone four devices as you are doing. I had better luck using I2C in the main (where it can be preempted by other interrupts) rather than a dedicated I2C interrupt (where the program could lock if something goes wrong with the read/write).

Another thing with I2C devices... Some devices can only pump out data so fast. If you are trying to read or write too frequently you might either end up getting garbage or end up slowing down everything.

 

11 Aug 2010

Thank you sir, but sorry i forgot to '//' that. Actually when I compile it even though the code like this:

    setup();
    //SendData.attach(&toGCS, 0.02777);
    //Proccess.attach(&eyetosee, 0.1);
    ahrs.attach(&ahrs_rec);
    rc.rise(&PPM_rise);  // attach the address of the PPM_rise function to the rising edge
    wait(0.5);
    
    while(1) {
        myled = !myled;
        for(char i=0; i<6; i++){
            printf("%d\t", buf_ppm[i]);
            if(i == 5) printf("\n");           
            wait(0.02);
            }
It is still not good, mean's that the PPM signal reading is not correct. But if only interrupt of PPM signal that activated alone (as shown below), it is OK.

int main() {
    setup();
    //SendData.attach(&toGCS, 0.02777);
    //Proccess.attach(&eyetosee, 0.1);
    //ahrs.attach(&ahrs_rec);
    rc.rise(&PPM_rise);  // attach the address of the PPM_rise function to the rising edge
    wait(0.5);
    
    while(1) {
        myled = !myled;
        for(char i=0; i<6; i++){
            printf("%d\t", buf_ppm[i]);
            if(i == 5) printf("\n");           
            wait(0.02);
            }         
    }
}

11 Aug 2010

Hi Raharja,

I had a look at your code, and I think the problem you are seeing is due to some of your timer interrupt routines that do large amounts of work (e.g. printing buffers to serial) stopping your PPM interrupt being handled quickly. As all the priorities are the same, if a PPM interrupt occurs whilst one of the timer interrupts is running, it wont get handled until the timer interrupt routine is finished.

We haven't exposed priorities (although it seems a natural enhancement), so you have some other options that would work:

  • call your toGCS and eyetosee functions from your main while loop, as regularly as needed; that way they can be interrupted
  • make the toGCS and eyetosee timer interrupt functions simply set a volatile flag, which can be polled in the main loop to see if the function bodies should be run; much the same as above, but using a timer interrupt to control the timing

Have a try with these approaches, and see if this helps fix some of your problems.

Thanks,

Simon

12 Aug 2010

Thank you sir,

But as shown in this 2 previous replies: even-tough I deactivate the toGCS and eyetosee function, means now only PPM interrupt and IMU/AHRS interrupt, it is still not works properly. Why this  LPC1768 cannot handle this tasks whereas the AVR that only 8bit and 16MHz can do that in the same way (same code structure, even more complicated with other tasks)?

Thanks anyway

/rhj

12 Aug 2010

It can. It just might not be as straightforward. As mentioned before, the PPM routine is time critical. You have to make sure that it does not get pre-empted or queued. The InterruptIn does not support different priorities so you have to get somewhat creative with the code and come up with a workaround.

I am sorry we can't be more of help, but all we can do is suggest where the problem might be.

People have given you a few good suggestions, I hope they are good places to start.

17 Aug 2010

Hi Raharja,

Just to clarify, the problem is not that the mbed is slow; it will certainly beat a AVR 16MHz hands down; the problem is in the program logic. The program has two interrupts, and it is simply that when your interrupt that runs for a long time is active (Ticker), it stops your timing critical interrupt from firing (InterruptIn), as they are at the same priority level.

A solution that we'll fold in to the libraries is to run the timers at a lower priority level, and also expose the priorities so they are configurable by the user, but in the mean time here is an example to show how you can solve the problem yourself. Basically, just set the timer interrupts to be at a lower priority, and all should work fine! The timers all use TIMER3, so we can call the NVIC_SetPriority function to change it's priority.

Here is an example program showing the behaviour, both before and after changing the priority.

// Example running the mbed Tickers at a lower priority

#include "mbed.h"

volatile int counter = 0;
void timing_critical() {
    counter++;
}

void long_event() {
    wait_ms(50);
}

PwmOut out(p25);
InterruptIn in(p26);
Ticker tick;

int main() {
    out.period_ms(10);
    out.pulsewidth_ms(5);
    in.rise(&timing_critical);

    printf("1) InterruptIn only...\n");    
    for(int i=0; i<5; i++) {
        counter = 0;
        wait(1);
        printf("counts/sec = %d\n", counter);
    }

    tick.attach(&long_event, 0.1);    
    
    printf("2) InterruptIn plus long running occasional ticker event...\n");    
    for(int i=0; i<5; i++) {
        counter = 0;
        wait(1);
        printf("count/sec = %d\n", counter);
    }
    
    printf("3) InterruptIn plus long running occasional ticker event at lower priority...\n");    
    NVIC_SetPriority(TIMER3_IRQn, 255); // set mbed tickers to lower priority than other things
    for(int i=0; i<5; i++) {
        counter = 0;
        wait(1);
        printf("counter = %d\n", counter);
    }
}

You can see the results here:

Importantly, the problem you are seeing has very little to do with the speed of the processor, and speed is not the source of your issue. We'll fold this in to the libraries as a fix so you get this result by default for the common case.

Hope this helps clear up the problem you were seeing, and shows it is not about speed, but simply what we are telling the microcontroller to do!
Simon