Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
9 years, 10 months 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, 10 months 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; }
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 16 Apr 20159 years, 10 months 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/
9 years, 10 months 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 17 Apr 2015