|
|
View previous topic :: View next topic |
Author |
Message |
prayami
Joined: 22 Dec 2004 Posts: 78
|
Stack over flow problem.... |
Posted: Sat Jul 08, 2006 6:32 pm |
|
|
Dear all....
This time very bad experiences, I have passed through. And in big trouble. As our project is finished and about to release and just come to know that sometimes values of the variables are changed themselves.
To test that, I have declared one #locate function register in my program and just assign value 10 to it and display it, rest of the huge code is as it is. When I turn the power off and on then everytime the value displaying is different.
Code: |
#locate test_display = 0x0069
. .. ... ..
test_display = 10;
.. .. .. ..
//displaying this variable.....
|
I did write #SEPARATE before three functions in my program. And I assumed that rest of the 13 functions will be #INLINE by default. And two interrupts are there.
But as I faced this problem then from CCS Reference Manual, I come to know that compiler manages internally whether to keep function inline or separate when nothing is written.
Problem is, if I declare all rest 13 functions inline then it is giving out of ROM error. And If I keep them separate or without any declaration some variable values are changed it self seems like stack overflow.
It is really hard to reduce the code and product is about to release, so in big trouble....don't know how to adjust this memory issue.
I am using 18F4525 and follwing is the beginning part of my .lst file....when I declared just three function #SEPARATE....
Code: |
CCS PCH C Compiler, Version 3.249, 30169 08-Jul-06 14:34
Filename: Boost_Con1.lst
ROM used: 36392 bytes (74%)
Largest free fragment is 12756
RAM used: 245 (6%) at main() level
292 (7%) worst case
Stack: 9 worst case (5 in main + 4 for interrupts)
|
Can anybody give some idea to balance this "out of ROM" and stack overflow problem....any clue.....any advice welcome.....most thanks in advanced....... |
|
|
asmallri
Joined: 12 Aug 2004 Posts: 1634 Location: Perth, Australia
|
|
Posted: Sat Jul 08, 2006 7:25 pm |
|
|
The 18F family has a 31 level stack. So it does not look like stack overflow is your problem however you have an option to set a fuse to cause a PIC reset in the event of underflow or overflow so you could use this fuse to help debug this issue.
If you variables are being overwritten, ignoring a compiler bug, a few of common cultrits are:
Incorrect use of pointers and arrays for example creating a character array to hold a fixed length string but forgetting to allow the extract byte for the end of string terminator.
Declaring a variable of some type but storing a larger typed value in it (often via incorrect typecasting) this overwrites the variable or variables next to it.
Using a pointer in the main code body that is also modified in the interrupt handler but forgetting to disable interrupts in the main body of code before using the pointer.
Uninitialised pointer
Silicon bug in the chip - some 18F series had a problem where they skipped an address when returning from an interrupt. This situation happened in applications that used both high and normal priority interrupts together - check the errata for the chip you are using _________________ Regards, Andrew
http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!! |
|
|
prayami
Joined: 22 Dec 2004 Posts: 78
|
|
Posted: Sat Jul 08, 2006 9:09 pm |
|
|
Thanks for replay....
Here with I come with more detail. I have reduced around 32 bytes of variables' in my program now. Everything is same....And now it seems working. This means in the case of previous program it was using more RAM.
The RAM of 18F4525 is 3980 bytes. And compiler is showing that it is using max of 9% then, why it is over written perticular address. The #locate test_display = 0x0069 variable was totally newly introduced for testing and it was not using any where in the program. The same variable for less RAM, it is preserving its value.
When I compile the old program then it was giving following :
Quote: |
Memory usage: ROM=70% RAM=8% - 9%
|
After removing some aroung 32bytes of variables the compiler message :
Quote: |
Memory usage: ROM=84% RAM=5% - 6%
|
Variable I declared for old program are as under:
Code: |
#include <18F4525>
#device ADC=10
#fuses H4, NOWDT, NOLVP, BROWNOUT, BORV43, NOPBADEN, PUT, NOXINST, NOMCLR, NOLPT1OSC, NOWRT, NOWRTD, EBTR, NOCPB, EBTRB, NOWRTC, NOWRTB, PROTECT, NOCPD, CCP2B3
#use delay(clock=40000000)
/*
------------------------------------------------------------------------
Note:
-->Freq=30Hz, Timer1 is set to 62202 to overflow every (33.33mSec/100)=0.3333mSec
------------------------------------------------------------------------
*/
#define DUTY_CYCLE_OUT PIN_D0
#define CAL_BUTTON PIN_B0
#define DOWN_BUTTON PIN_B1
#define UP_BUTTON PIN_B5
#define TRIG_BUTTON PIN_B3 //CCP2(1)
#define DOWN_LED PIN_D7
#define UP_LED PIN_D6
//----Start EEPROM mapping-------------------
#define CALIBRATED 0x00
#define LOW_CAL_PRESS 0x01
#define HIGH_CAL_PRESS 0x03
#define UNIT_STATUS 0x05
#define WARN_BOOST 0x07
#define SCRAM_SEC 0x09
#define SCRAM_PERCENT 0x0A
#define WARN_BOOST_STATUS 0x0B
#define TRIGGER_STATUS 0x0C
#define MEMORY_SELECTED 0x0D // 0x06
#define SPIKE_PERCENT 0x0E
#define BOOST_PRESSURE 0x10
#define DC_CLOSE 0x20
#define GAIN_CLOSE 0x30
#define DC_OPEN 0x40
#define GAIN_OPEN 0x50
#define CLOSE_OPEN_STATUS 0x60
#define BOOST_SET 0x70
//----End EEPROM mapping---------------------
unsigned int16 PULSE_TIME = 62270; // 30Hz Time = 33.24ms
unsigned int16 ScrCount, WarnBoostKpa, CurPressKpa_update, CurPressKpa, DesireBoostKpa;
unsigned int16 LowLevelPressValue, MaxNormalPressValue, FixCorrectionValue;
unsigned int16 UpCount, DownCount, MemModeCount, AvgSamplesKpa, highV,lowV, CurrentValue;
unsigned int16 BoostP=0, PreviousBoostP=0, BoostP_Save=0, WarnBoostP, AtLeastLessGainValue;
unsigned int16 SampleValues[10],TempSampleValue, TempCurrentValue;
unsigned int16 BoostPSaveBackup=0;
unsigned int16 AntiSpikeLimitValue, AntiSpikeUpperValue, temp_boost; //, DispOffAtValue=0;
unsigned int16 BoostOpenRange=0, BoostRangeValue=0;
const unsigned int8 MaxMemory=6;
unsigned int8 BarLbKpa=0, SetDC1, SetDC2, Memory=1, MemoryChangeCount;
unsigned int8 Mode=1, select1=0, select2=0, select3=1, ScrSec=0, ScrPercent=0;
unsigned int8 count1, DCOnDuty=10, DCOnDutyTimer1=10, SetGain1, SetGain2;
unsigned int8 flash_count, speed_count=0, num_count=0, MySecCount, SampleInt;
unsigned int8 Speed, SlowSpeed = 45, HighSpeed = 10, OneSecCount=0;
unsigned int8 NoOfSamples, Scramble=0, LEDCount, TwoSecCount, CurrentTrig, TriggerCount;
unsigned int8 GrabBoostCount=0, SpikePercent=0, AntiSpikeTime=0;
unsigned int8 AntiSpikeCount, TempDuty;
BYTE CONST LED_MAP[10] = {0x81,0xBD,0xC8,0x98,0xB4,0x92,0x82,0xB9,0x80,0xB0}; // 0 to 9
BYTE CONST LED_DOTMAP[10] = {0x01,0x3D,0x48,0x18,0x34,0x12,0x02,0x39,0x00,0x30}; // 0 to 9
float GainTemp1, GainTemp2, CurPressure, MaxBoost=3.5, MaxCalBoost=1.0, m, DesireBoost, WarnBoost;
float CurPressure_update, AvgSamples;
float LowLevelPress = 0.1378951399; // (0.1378951399 Bar = 2 Lb)
float MaxNormalPress = 0.27; // (0.27 Bar = 4 Lb)
float FixCorrection = 0.0344737849; // (0.0344737849 Bar = 0.5 Lb)
float AtLeastLessGain = 0.068947569; // (0.068947569 Bar = 1 Lb)
//const float DispOffAt = 0.01378951399; // (0.01378951399 Bar = 0.2 Lb)
char input_str[5];
char int_str[4];
int1 StartUpCount=0, StopUp=0, StartDownCount=0, StopDown=0, WarnBoostStatus=0;
int1 isCal=0, Close_Open=0, SaveBoost=0, CalTime=0, StopCmg=0, StopCmgIn=0;
int1 BothPressed=0, start_flash=1, GrabCurPress=0, BoostSet1=0, BoostSet2=0, DoBoostSet=0;
int1 doScramble=0, LEDStatus=0, FreezeSetting=0, SecTime=0;
int1 StopAntiSpike=0, DoAntiSpike=0, isTwoSec=0, StopTrig=0, BoostReset=0, DispScr=0, TriggerFast=0;
int1 StartLookBoost=1, MemoryChanged=0, StartGrabCount=0, GrabBoost=0;
int1 StartAntiSpike=0, CheckDropping=0, FirstTimeEnter=0, GetNextDuty = 0;
int1 DoStartGrab=0;
char scroll_text[14];
unsigned int8 DispCount, MyPoint;
|
Last edited by prayami on Mon Jul 10, 2006 5:16 pm; edited 1 time in total |
|
|
Ttelmah Guest
|
|
Posted: Sun Jul 09, 2006 8:58 am |
|
|
Without seeing what you are doing, it is impossible really to answer. But the most likely culprits, are code dealing with the arrays 'sample_values', 'input_str', 'int_str', and 'scroll_text'. Common things to forget, are that a 14 character string, will need a 15 character array, and that arrays in C are zero referenced (so indexes are 0 to 13, not 14). Any code accessing this type of variable, can walk over other variables. The PIC, does not have any form of hardware memory protection. Asmallri, has given a good list of the likely problems.
Posting a list of variables, is pretty nigh pointless. If you know that address 69, is being affected, then look in the symbol map for anything using addresses close to this, which you access using pointers or arrays. You need to identify what part of your code actually changes the value.
Best Wishes |
|
|
prayami
Joined: 22 Dec 2004 Posts: 78
|
|
Posted: Sun Jul 09, 2006 3:54 pm |
|
|
Thanks Ttelmah and asmallri.....
I have increased the size of arrays for null termination. And it is still doing the same. I have looked at the manual but couldn't find such things. I have still few questions which might solve the problem....
(1) Just want to confirm:
Upto this, I know that it is require to have (required array size+1) for sprintf function. But is it require for any array no mater it is constant or simple array (i.e. one not gonna used with sprintf).
(2)
Is it fine if I only declare one size greater than I require. Or I require to assign it null terminated value.
e.g. I require only SampleValues[10] but declared
unsigned int16 SampleValues[11] ;
Is it require to assign SampleValues[10] = '\0';
(3)
I have two more constant array in one function like under. Which are declared like below.
BYTE CONST LED_MAP[10] = {0x81,0xBD,0xC8,0x98,0xB4,0x92,0x82,0xB9,0x80,0xB0}; // 0 to 9
BYTE CONST LED_DOTMAP[10] = {0x01,0x3D,0x48,0x18,0x34,0x12,0x02,0x39,0x00,0x30}; // 0 to 9
But as you said, is it require to declare like under. Please let me know if below declaration is not OK...see last element is null terminated.
BYTE CONST LED_MAP[11] = {0x81,0xBD,0xC8,0x98,0xB4,0x92,0x82,0xB9,0x80,0xB0, '\0'}; // 0 to 10
BYTE CONST LED_DOTMAP[11] = {0x01,0x3D,0x48,0x18,0x34,0x12,0x02,0x39,0x00,0x30,'\0'}; // 0 to 10
(4)
In the previous program, as you said to see the File Registers' symbol mapping. I can see that before #locate test_display 0x0069 address there is no array assingned. The sequence is as under
BarLbKpa
SetDC1
test_display
SetDC2
Memory
Then how can the arrays effect to address 0x0069. I have checked that there is no incorrect type casting. Is there any way they can affect that address?
(5)
If it was the problem of array with null termination. Then why it was working when I had reduced some variables and code but the arrays' size was still the same.
(6)
As I have 16 functions in my program + two ISR. And wright now I have written #SEPARATE before three small functions. And before rest of the functions nothing written. Is it fine if I don't write anything. Because I just tried to make total 5 #SEPARATE for function and 2 #SEPARATE for two ISR then my memory is full. So leave it as it is and let compiler to do it.
(7)
Is there any book or manual available from which I can know these kind of things.....
Thanks...... |
|
|
asmallri
Joined: 12 Aug 2004 Posts: 1634 Location: Perth, Australia
|
|
Posted: Sun Jul 09, 2006 7:02 pm |
|
|
The string length + 1 applied to any string related function. You do not need the terminator for non string related functions.
When using string related functions in C, For example puts(mystring), The puts function extracts characters byte by byte from mystring until it gets to the string terminator with is the value 0x00.
When you use any of the C functions that assign contents to the string they will automatically add this terminator.
Lets say the string test (previously declared as char test[10];) was initialised with the strcpy to contain "Hello" If we examine the contents of test we have
test[0] = H
test[1] = e
test[2] = l
test[3] = l
test[4] = o
test[5] = 0x00 or \0
test[6] .. test[9] = undefined (has not been initialized)
If we puts(test) we get Hello
If we now set test[2] = 0 we get
test[0] = H
test[1] = e
test[2] = 0x00 or \0
test[3] = l
test[4] = o
test[5] = 0x00 or \0
test[6] .. test[9] = undefined (has not been initialized)
If we now puts(test) we get He
So the string functions will stop when they hit to string terminator but if I access the array contents individually I can read all elements. If there is no terminator the string functions we attempt the continue printing the contents of memory until they eventually find one.
If I have a character array that will not be access by string functions then I do not need a terminator. If I create an array and initialize it by placing by putting values into each location manually but want to use printf type functions to print the string then I need to have a NULL terminator at the end of the string.
Another problem (the most common for beginners of C) is they declare a string that is too short. Often by 1 because they forget the terminator, but also when they make changes to the code (send longer stings to functions like gets()) without increasing the size of the variable. In this case variable that are place in memory after our string get overwritten by the string.
The stuff mentioned above is standard C behaviour as documented by K & R _________________ Regards, Andrew
http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!! |
|
|
prayami
Joined: 22 Dec 2004 Posts: 78
|
|
Posted: Sun Jul 09, 2006 7:56 pm |
|
|
Thanks...asmallri....
My array declaration is OK.
Still question, I have reduced some code in my program. And now I have declared #SEPARATE or #INLINE statement before all the function. And it seems working.
Now it is not modifying any variable. When I say reduced the code means I have reduced some of the variable declared and wrote it with direct value.
Where can I see int1 variable mapping in the memory?
I got type casting at many places in my program can it create problem....
e.g.
Code: |
CurrentValue = (unsigned int16)(SumSampleValues/4);
write_eeprom( CALIBRATED, (unsigned int8)isCal ); // as isCal is int1
|
I got lots of float related calculation in my code, does this can have shortage of RAM and over writting one of File Register.
Thanks... |
|
|
prayami
Joined: 22 Dec 2004 Posts: 78
|
|
Posted: Sun Jul 09, 2006 8:22 pm |
|
|
Hi...
Here there was my code....But as it is too long I have deleted it. As I come to know what was the problem.
Check the last post which can be useful to many and give comments if you want......
Last edited by prayami on Mon Jul 10, 2006 5:15 pm; edited 2 times in total |
|
|
asmallri
Joined: 12 Aug 2004 Posts: 1634 Location: Perth, Australia
|
|
Posted: Sun Jul 09, 2006 8:49 pm |
|
|
The problem with type casting over writing variables typically occurs when a pointer of one type is cast to be a pointer of another type. When this mechaism is used incorrectly it can trash adjacent variables.
This is why strict type casting languages such as PASCAL were developed. PASCAL is a far better language to use for developing applications that need to be brought to market quickly because it is very hard for an application developer to make these types of errors. By contrast, PASCAL lacks the flexibility of C for allowing a developer to get down and dirty with the hardware.
Giving guidance is oone thing but I don't have the time to wade through your code (sorry) I have my own fires to put out :-) _________________ Regards, Andrew
http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!! |
|
|
Ttelmah Guest
|
|
Posted: Mon Jul 10, 2006 3:40 am |
|
|
Like Asmallri, the amount of code is just too long to spend time looking through. You need to use a debugger, or some simple tests internally, to 'narrow down' what part is going wrong. However looking at the interrupt handler, a couple of things 'leap out:
Code: |
set_timer1(62270); //30Hz
count1++;
//if(count1<DCOnDutyTimer1)
if(count1<DCOnDutyTimer1>=99) //count is unsigned int8
|
Setting a timer 'to' a value, unless it is running from a very slow clock, inside the handler, is almost certain to give timing errors. Remember the timer _will_already have counted a significant number of pulses (but probably a _variable_ number of pulses depending on what else is going on), by the time it reaches this point. If timing accuracy is important, you might want to consider an alternative. Then, I have to ask what the 'if' statement is meant to do?...
This will evaluate 'left to right', since '<', and '>=', have the same precedence in C. So the compiler will test count1<DFCOnDutyTimer1, and will generate a logical 'true' or 'false' for this,and will then test for _this_ logical value being greater than or equal to 99. Not I think what you intend.
This will then result in the next part of the code being reached with different values to what you think.
I'd suspect you need to go through all the code, looking for this type of fault. Something like this, could easily lead to an unexpcted value, giving access to the wrong memory area.
Best Wishes |
|
|
prayami
Joined: 22 Dec 2004 Posts: 78
|
|
Posted: Mon Jul 10, 2006 2:50 pm |
|
|
Thanks....Ttelmah and asmallri....
First the if statement Ttelmah have written was comment and shifted to next line so just i gnore it. You guys wright that code is too long to debug. And My actual code is longer than that but when I post it some portion is not displaying, I don't know why...might be some character in the code preventing to display.
My problem is some register values are over written and changed unexpected. Timer thing is fine.....I can't figure out why..?? I got lots of RAM left....then why..?? Only one array is associated with sprintf function and thus declared one element more for null termination.
I want to let you know that I have used following kind of casting code in my program...if you find to take care of something then let me know...
Code: |
DcOnDuty = 100 - (signed int8)( (( ((float)CurrentValue)-GainTemp1)*((float)(100-SetDC1)) )/( ((float)BoostP) - GainTemp1) ) ;
GainTemp2 = ((-1.0)*((float)BoostP)) + ( ((float)SetGain2) * (float)((2*BoostP)-AtLeastLessGainValue) )/100.0;
if( ((unsigned int16)ScrCount) >= (((unsigned int16)ScrSec)*30) )
write_eeprom(WARN_BOOST_STATUS, (unsigned int8)WarnBoostStatus); //WarnBoostStatus is int1
if(BoostP > (lowV+((unsigned int16)(((float)lowV)*0.05))) )
AntiSpikeLimitValue = lowV + (unsigned int16)((DesireBoost * 0.25)/m);
AntiSpikeUpperValue = lowV + (unsigned int16)((DesireBoost * 0.80)/m);
|
Thanks.... |
|
|
prayami
Joined: 22 Dec 2004 Posts: 78
|
|
Posted: Mon Jul 10, 2006 5:26 pm |
|
|
Hi...Thanks everybody.....
Here with I come to know what was the problem. And I would like to share it to all so can be useful for other. Masters' comments are welcome.
In my variable declaration there was following line:
Code: |
unsigned int8 flash_count, speed_count=0, num_count=0, MySecCount, SampleInt;
|
The variable SampleInt which was not initialized by zero as under:
Code: |
unsigned int8 flash_count=0, speed_count=0, num_count=0, MySecCount=0, SampleInt=0;
|
And unfortunately that variable was used to deal with array SampleValues[10]. So very first time when I turn ON the POWER and if it is not initialized by 0 then bydefault it should be zero that is what I have assumed. But As I displayed it on starting it was come up with different values everytime on power ON. and turn to modified array address out of range thus changing some variable values. So you guys were absolutely wright.
Now I have initialzed with 0 and everything seems fine. But yet I have to test in depth.
Thanks.... |
|
|
Ttelmah Guest
|
|
Posted: Tue Jul 11, 2006 3:41 am |
|
|
You can make all variables default to zero on power up, by using #zero_ram
However this takes significant time to execute.
Normally the data sheet definition of what to expect in a RAM cell, is 'xxxxxxxx' after power on (undefined).
Safest, and quickest, is to do what you are now doing, and initialise everything, that is not inherently initialised before use.
Glad you have found it.
Best Wishes |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|