9 years ago.

LPC1768 crashes(complete freeze) when using Ticker routine

I am trying to make an energymeter using LPC1768. My application requires that i continuously sample voltage and current values @ 2KHz sampling rate. To do this i am using the Ticker routine. the ticker is attached to a function which reads the ADC inputs. Also my project requires that i transmit certain data to another LPC1768 wirelessly through the serial port. Now without the serial transmission the application is working fine. But as soon as i try to send the data serially, the microcontroller crashes. A similar problem happened during the initial stages of development while i was trying to display the data locally on an LCD. I was using the "TextLCD" library available here: http://developer.mbed.org/components/HD44780-Text-LCD/ but the microcontroller crashed as soon as i attempted to print the data on the LCD. I figured out that the problem was with the wait statements(wait function) used in the TextLCD.cpp program. So i edited all the wait statements to for loops (to generate the required delays wherever necessary) and it started working as expected. But to transmit the data serially i am using the serial routine (i am using device.putc() function to send a byte of data) . Now as soon as it encounters this statement, the microcontroller crashes. I cannot figure out what the problem is in this case, since no wait statement is involved here. The code is given below:

energymeter code

#include "mbed.h"
#include "TextLCD.h"

float THD_sine(int,int);
float THD_cos(int,int);
void sample(void);
void display(void);

Ticker Spike;
Ticker disp;

//InterruptIn button(p30);
AnalogIn current(p15);
AnalogIn voltage(p17);
DigitalOut myled(LED1);
DigitalOut myled2(LED2);
DigitalOut myled3(LED3);
DigitalOut myled4(LED4);
DigitalOut unused1(p16);
DigitalOut unused2(p18);

Serial device(p28, NC);  // tx, rx
//Serial pc(USBTX, USBRX); // tx, rx
TextLCD lcd(p20, p19, p8, p7, p6, p5); // rs, e, d4-d7

int i,m,h,flag=0,tflag=0,dflag=0,lead=-1,v_start=0,i_start=0,k=0,l=0,a=1,n=1,count=-1,screen=0,lscreen,z=-1;
//const int cycle=125;    
const int Ns=40; //has to be greater than 20 and even numbers only 
float i_samples[Ns],i_inst=0.0f,i_rms=0.0f,i_sum=0.0f,i_dc=0.0f;
float v_samples[Ns],v_inst=0.0f,v_rms=0.0f,v_sum=0.0f,v_dc=0.0f,_v_rms=0.0f,_i_rms=0.0f;
float p_sum=0.0f,p_avg,_p_app=0.0f,p_avg1,p_app,p_react,energy=0.0f,pf,_pf=0.0f,pf1,pf_angle,v_zero,i_zero,_p_avg=0.0f,_p_react=0.0f;
float v_past,i_past,angle;
float THDv=0.0f,THDi=0.0f,_THDv=0.0f,_THDi=0.0f;
float Bv[8]={0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f};
float Cv[8]={0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f};
float Bi[8]={0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f};
float Ci[8]={0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f};
float Av[8]={0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f};
float Ai[8]={0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f};
float vtheta[8]={0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f};
float itheta[8]={0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f};
float theta[8]={0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f};

//function to generate sine component of a given harmonic for a given sample
float THD_sine(int j,int har)
{
    float sine;
    sine=sin(2*3.141*j*har/Ns);
    return sine;
}

//function to generate cosine component of a given harmonic for a given sample
float THD_cos(int j,int har)
{
    float cosine;
    cosine=cos(2*3.141*j*har/Ns);
    return cosine;
}

void sample()
{
    
    count++;
    i_samples[count]=current.read();
    v_samples[count]=voltage.read();
    
    if(count==Ns)
        count=-1;
    
}

/*void display1()
{
    dflag=1;
}

void display()
{
    if(dflag==1)
    {
        lscreen=screen;
        screen++;
        if(screen>8)
            screen=0;
        dflag=0;
    }
} */

void time()
{
    tflag=1;
}

void transmit(int id, float fdata, int precision) //function to transmit a floating point data bytewise over RF link
{
    int data=0;
    data=fdata*pow(10.0f,precision);
    int dbyte0=0,dbyte1=0,dbyte2=0,dbyte3=0; //extract 32bit data into seperate bytes
    dbyte0=(data & 0x000000FF);
    dbyte1=((data>>8) & 0x000000FF);
    dbyte2=((data>>16) & 0x000000FF);
    dbyte3=((data>>24) & 0x000000FF);
    myled4=1;
    
    while (device.writeable()==0);  //wait till there is space available to transmit
    
    myled3=1;
    device.putc(255);  //framing byte HIGH /* to help receiver
    device.putc(255);  //framing byte HIGH       lock on to
    device.putc(0);    //framing byte LOW       transmitter signal */
    device.putc(170);  //framing byte to indicate start of transmission
    device.putc(dbyte0);  //databyte0 (LSB)
    device.putc(dbyte1);  //databyte1
    device.putc(dbyte2);  //databyte2
    device.putc(dbyte3);  //databyte3 (MSB)
    device.putc(id);  //data id
    device.putc(precision);  //precision of data
    device.putc(180);  //framing byte to indicate end of transmission
    myled3=0;
}

int main()
{
    unused1=0;
    unused2=0;
    lcd.cls();
    lcd.printf(" 1Phase Digital");
    lcd.locate(2,1);
    lcd.printf("Energymeter");
    //pc.printf("Single Phase Digital Energymeter\n\n");
    wait(1);
    Spike.attach(&sample, (0.02f/Ns));
    disp.attach(&time,2);
    //button.rise(&display);
    //button.fall(&display1);
    /*while(cycle_count<cycle)
    { 
        for(i=0;i<Ns;i++)           
        {
            i_samples[(cycle_count*20)+i]=current.read();
            v_samples[(cycle_count*20)+i]=voltage.read();
            wait_us(20000/Ns);
        }
        cycle_count++;
    } */
    
    //cycle_count=0;
    while(1)
    {
        flag=0;
        v_dc=0.0f;
        i_dc=0.0f;
        i_sum=0.0f;
        v_sum=0.0f;
        p_sum=0.0f;
        THDv=0.0f;
        THDi=0.0f;
        p_avg=0.0f;
        p_react=0.0f;
        k=0;l=0;
        float Bv[8]={0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f};
        float Cv[8]={0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f};
        float Bi[8]={0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f};
        float Ci[8]={0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f};
        
        if(count<0)
            continue;
        
        z++;
        if(z%50==0)
            myled=!myled;
        
        if(z%50==10)
            myled2=!myled2;
        
        for(i=0;i<Ns;i++)
        {
            i_inst=((i_samples[i]*3.3f)-1.74f); //adc conversion factor=3.3V; 1.74V is DC shift of the level shifter  
            v_inst=((v_samples[i]*3.3f)-1.77f); //adc conversion factor=3.3V; 1.77V is DC shift of the level shifter
            i_dc+=i_inst;
            v_dc+=v_inst;
            i_sum+=(i_inst*i_inst);
            v_sum+=(v_inst*v_inst);
            p_sum+=(v_inst*i_inst);
            
            //algorithm for zero crossing detection to determine lag/lead
            if(flag>-1 && i>=0)
            {
                if(((v_past<0)&&(v_inst>=0))||((v_past>0)&&(v_inst<=0)))           //zero crossing detection of voltage
                {
                    flag++;
                    v_start=1;
                    if(v_inst==0)
                        v_zero=i;
                    else
                        v_zero=(-v_past/(v_inst-v_past))+(i-1);
                }

                if(((i_past<0)&&(i_inst>=0))||((i_past>0)&&(i_inst<=0)))           //zero crossing detection of current
                {
                    flag++;
                    i_start=1;
                    if(i_inst==0)
                        i_zero=i;
                    else
                        i_zero=(-i_past/(i_inst-i_past))+(i-1);
                }
                if(flag>1)
                {
                    if((fabs(v_zero-i_zero))<=(Ns/4))             //maximum possible lead or lag can be 90deg equivalent to 5 sample lengths
                    {
                        angle=fabs(i_zero-v_zero)*(360/Ns);
                        flag=-1;
                        if(v_zero<i_zero)
                            lead=0;
                        else
                            lead=1;
                    }
                    pf1=cos((3.141f/180.0f)*angle);
                }
            } //end of zero crossover and lag/lead detection
            
            //start of harmonic coefficient calculations (odd components only upto 7th harmonic)
            if(k<Ns)
            {
                for(n=0;n<=7;n++)      //voltage harmonics
                {
                    Bv[n]+=v_inst*THD_sine(k,n);  //sine coefficient
                    Cv[n]+=v_inst*THD_cos(k,n);   //cosine coefficient 
                }
                
                k++;
            }

            if(l<Ns)
            {
                for(n=0;n<=7;n++)      //current harmonics
                {
                    Bi[n]+=i_inst*THD_sine(l,n);  //sine coefficient
                    Ci[n]+=i_inst*THD_cos(l,n);   //cosine coefficient  
                }
                
                l++;
            } 
            //end of harmonic coefficient calculations
            
            v_past=v_inst;
            i_past=i_inst;
        } //end of for loop
        
        //parameter calculations for 1 cycle (20 Samples)
        
        for(n=0;n<=7;n++)  
        {
            vtheta[n]=atan(Bv[n]/Cv[n]);
            itheta[n]=atan(Bi[n]/Ci[n]);
            if(fabs(vtheta[n]-itheta[n])>1.5708f)
            {
                if(vtheta[n]<0) vtheta[n]=vtheta[n]+3.1416f;
                if(itheta[n]<0) itheta[n]=itheta[n]+3.1416f;
            }  
            theta[n]=vtheta[n]-itheta[n];
            //if(fabs(theta[n])>1.5708) theta[n]=3.1416-fabs(theta[n]);        
        }
        
        i_rms=(sqrt(i_sum/Ns))*(25.0f/3.049f);   //(25/3.0875) is the conversion factor for current sensor
        v_rms=(sqrt(v_sum/Ns))*(600.0f/2.7f);   //(600/2.75) is the conversion factor for voltage sensor
        v_dc=(v_dc/Ns)*(600.0f/2.7f);
        i_dc=(i_dc/Ns)*(25.0f/3.049f);
        p_avg1=(p_sum/Ns)*1822.09f;   //multiplying the conversion factors for current and voltage sensors(P=V*I)   
        energy+=((p_sum/(50.0f*Ns))*1822.09f)*(1.0f/3600000.0f);
        p_app=v_rms*i_rms;
        pf_angle=(180.0f/3.1416f)*acos(pf); //in degrees
        //p_react=sqrt((p_app*p_app)-(p_avg*p_avg)); 
        //p_react=p_app*sin((3.141f/180.0f)*angle);
        
        //harmonic amplitude calculations
        for(n=0;n<=7;n++)  //voltage
        {
            Av[n]=(2.0f/Ns)*sqrt((Bv[n]*Bv[n])+(Cv[n]*Cv[n]));
            Ai[n]=(2.0f/Ns)*sqrt((Bi[n]*Bi[n])+(Ci[n]*Ci[n]));        
        }
        
        for(n=2;n<=7;n++)  //current
        {
            THDv+=Av[n]*Av[n];
            THDi+=Ai[n]*Ai[n];    
        }
        //end of harmonic amplitude calculations
        
        THDv=sqrt(THDv/(Av[1]*Av[1]))*100.0f;  //voltage THD as percent of fundamental
        THDi=sqrt(THDi/(Ai[1]*Ai[1]))*100.0f;  //current THD as percent of fundamental
                 
        for(n=1;n<=7;n++)  //current
        {
            p_avg+=Av[n]*Ai[n]*cos(fabs(theta[n]));
            p_react+=Av[n]*Ai[n]*sin(fabs(theta[n]));    
        } 
        p_avg=((p_avg/2.0f)*1822.09f)+(v_dc*i_dc);
        p_react=(p_react/2.0f)*1822.09f;
        pf=p_avg/p_app;         
        //end of parameter caculations
        
        _v_rms+=v_rms;
        _i_rms+=i_rms;
        _p_app+=p_app;
        _THDv+=THDv;
        _THDi+=THDi;
        _p_avg+=p_avg;
        _p_react+=p_react;
        _pf+=pf;
        
        //cycle_count++;
        if(tflag==1)
        {
        _v_rms=_v_rms/z;
        _i_rms=_i_rms/z;
        _p_avg=_p_avg/z;
        _p_app=_p_app/z;
        _p_react=_p_react/z;
        _pf=_pf/z;
        _THDv=_THDv/z;
        _THDi=_THDi/z;
        
        switch(screen)
        {
            case 1: lcd.cls();
                    lcd.printf("Voltage(RMS)");
                    lcd.locate(0,1);
                    lcd.printf("%3.2fV         ", _v_rms);
                    break;
            case 2: lcd.cls();
                    lcd.printf("Current(RMS)");
                    lcd.locate(0,1);
                    lcd.printf("%3.2fA         ", _i_rms);
                    break;    
            case 3: lcd.cls();
                    lcd.printf("Avg. Power   ");
                    lcd.locate(0,1);
                    lcd.printf("%3.2fW         ", _p_avg);
                    break;
            case 4: lcd.cls();
                    lcd.printf("App. Power     ");
                    lcd.locate(0,1);
                    lcd.printf("%3.2fW         ", _p_app);
                    break;
            case 5: lcd.cls();
                    lcd.printf("React. Power   ");
                    lcd.locate(0,1);
                    lcd.printf("%3.2fW         ", _p_react);
                    break;
            case 6: if(lead==1)
                    {
                        lcd.cls();
                        lcd.printf("Power Factor   ");
                        lcd.locate(0,1);
                        lcd.printf("%3.4f leading", _pf);
                        break;
                    }
                    else
                    {
                        lcd.cls();
                        lcd.printf("Power Factor   ");
                        lcd.locate(0,1);
                        lcd.printf("%3.4f lagging", _pf);
                        break;
                    }
            case 7: lcd.cls();
                    lcd.printf("THD(Voltage)   ");
                    lcd.locate(0,1);
                    lcd.printf("%3.2f%%          ", _THDv);
                    break;
            case 8: lcd.cls();
                    lcd.printf("THD(Current)   ");
                    lcd.locate(0,1);
                    lcd.printf("%3.2f%%          ", _THDi);
                    break;
            default: lcd.cls();
                     lcd.printf("Energy");
                     lcd.locate(0,1);
                     lcd.printf("%3.8f kWh", energy);  
                     break;
        }  //end of switch
        screen++;
        if(screen>8)
            screen=0;
        
        //transmit data over RF link to remote terminal
        transmit(0,_v_rms,3);
        transmit(1,_i_rms,3);
        //transmit(2,v_dc,3);
        //transmit(3,i_dc,3);
        transmit(2,_p_avg,3);
        transmit(3,_p_app,3);
        transmit(4,_p_react,3);
        transmit(5,_pf,5);
        transmit(6,lead,0);
        transmit(7,energy,9);
        transmit(8,_THDv,3);
        transmit(9,_THDi,3);
        //end of transmission   
        
        _v_rms=0.0f;
        _i_rms=0.0f;
        _p_avg=0.0f;
        _p_app=0.0f;
        _p_react=0.0f;
        _pf=0.0f;
        _THDv=0.0f;
        _THDi=0.0f;
        z=0;   
        tflag=0;
        //lscreen=screen;
        }   
    }
    //end of while
}
//end of code

I have tried without the ticker routine and the code works fine. But without continuous sampling an energymeter will never measure the correct energy value so i need to make the ticker work.

3 Answers

9 years ago.

This may not be causing the issues you are seeing but you are writing past the end of your arrays. Never a good idea if you want stable code.

Also you never use array index 0 in your results array.

void sample()
{
    
    count++;  // could be a value between 1 and Ns after this line
    i_samples[count]=current.read(); // i_samples[Ns] has a valid index range of 0 to Ns-1
    v_samples[count]=voltage.read();
    
    if(count==Ns)
        count=0;
    
}

To fix the error change it to

void sample()
{   
    i_samples[count]=current.read();
    v_samples[count]=voltage.read();
    
    if(++count==Ns)
        count=0;    
}

Accepted Answer

Thanks Andy for pointing out the error. i intended to do (count=-1) as i have done in the initial initialization. I guess since it was taking 40 values per cycle not much difference was coming in the result due to this error. Any idea why the crash is happening though? Or any work-arounds?

posted by Anuvab Biswas 16 Apr 2015
9 years ago.

If you change Ticker sampling rate from 2kHz to lower, does it crash then?

Have you measured how long do these 2 reading take?

    i_samples[count]=current.read();
    v_samples[count]=voltage.read();

You know it's blocking. You can test that write own routine, to trigger a measurement, and then in the next ticker irq, to collect samples. AnalogIn does not provide this API, but you can look at HAL for LPC1768 and prototype it, or somebody else already done that. An example which can help you : http://developer.mbed.org/users/meriac/code/rgb_sensor/

Yeah its crashing for 1kHz also. i cant go below that at any cost (Nyquist rate). And no i have not checked that but since its working fine till i try to transmit via serial port it is probably caused due to the device.putc() statement.

posted by Anuvab Biswas 16 Apr 2015
9 years ago.

Within the device.putc there is surely a wait. You test "device.writeable()" but afterwards you send 11 bytes without rechecking.
Do you have a logical analyzer with several channels ? I use this to check a real time program like yours: toggle a pin at some place in the program, another pin further ...and so on .
Then you can see where are the delays in the processing
Robert

No i checked device.putc() and there was no wait statement in that. The above mentioned correction by Andy solved the crash problem. It was crashing because it was trying to access i_samples[40] and v_samples[40] which do not exist. i wrote a simple program afterward trying to access out of bound array location and the microcontroller crashed again. So that was causing the problem. But i could not figure out why it wasnt crashing without the transmit part earlier. Anyway the issue seems resolved after the correction.

posted by Anuvab Biswas 17 Apr 2015