|
|
View previous topic :: View next topic |
Author |
Message |
Wolf
Joined: 23 Sep 2011 Posts: 32
|
Out of ROM, A segment or the program is too large |
Posted: Fri Sep 23, 2011 11:55 pm |
|
|
Ok, I'm having this problem trying to compile a float into my code. I'm using PIC 16F627A and it's giving me the Out of ROM error. The objective of this code is to gather as many pulses from a flow sensor possible in a 1 second period so that I can get a measurement of how many GPM of water is flowing through a pipe (k factor is 344 pulses per gallon). The results of this is suppose to go into variable fltGallonsPerMinute so that I can divide it by 60 (to convert gallons per second to gallons per minute) then display the results on an LCD screen. However the program stops compiling at fltGallonsPerMinute /= 344;. Does anyone have any idea on how to fix this?
Code: |
void main() {
unsigned long int uliMicroseconds, uliMilliseconds, uliSeconds;
unsigned long int uliSecondsBuffer, uliPulses, uliPulseBuffer;
unsigned char uchToggleBuffer, uchLCDBuffer[20];
float fltGallonsPerMinute;
StartupSettings();
uliMicroseconds = 0;
uliMilliseconds = 0;
uliSeconds = 0;
uliSecondsBuffer = 0;
uliPulses = 0;
uchToggleBuffer = 0;
InitializeDisplay();
delay_ms(400);
sprintf(uchLCDBuffer, "Testing?");
WriteString(uchLCDBuffer, 8);
while(1) {
if (input(SENSOR) == 1) {
output_bit(LED_GREEN, 1);
uliPulses++;
}
else {
output_bit(LED_GREEN, 0);
}
//-----------------------------
if (input(CRYSTAL) == 1) {
uliMicroseconds++;
if (uliMicroseconds > 1000) { //1000
uliMicroseconds = 0;
uliMilliseconds++;
}
if (uliMilliseconds > 10) { //10
uliMilliseconds = 0;
uliSeconds++;
}
if (uliSeconds > 0) {
uliSeconds = 0;
if (uchToggleBuffer == 0) {
uchToggleBuffer = 1;
output_bit(LED_RED, 1);
uliPulseBuffer = uliPulses;
fltGallonsPerMinute = (float)uliPulses;
}
else {
uchToggleBuffer = 0;
output_bit(LED_RED, 0);
fltGallonsPerMinute /= 344; //stalls program
fltGallonsPerMinute /= 60;
sprintf(uchLCDBuffer, "%Lu",uliPulseBuffer);
DataCommand(0x80);
WriteString(uchLCDBuffer, 8);
sprintf(uchLCDBuffer, "%f", fltGalonsPerMinute);
DataCommand(0xC0);
WriteString(uchLCDBuffer, 8);
uliPulses = 0;
uliPulseBuffer = 0;
}
}
}
}
return;
}
|
|
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Sat Sep 24, 2011 2:47 am |
|
|
The microseconds counter will never work. Use a processor timer to generate a one seconds interval. Depending on the actual number of pulses per second, you probably would want to use a longer counting interval to achieve some accuracy.
Regarding out of ROM error, you should determine if the available code space is nearly exhausted when omitting a few instructions, or if it's only a problem of the main() function size. I think, the calculations can be performed with fixed point integer as well. If float is needed in your opinion, you should replace the dual float divison by a reasonable constant multiplication.
Code: | fltGallonsPerMinute /= 344;
fltGallonsPerMinute /= 60;
fltGallonsPerMinute *= (1.0/(344*60)); |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19505
|
|
Posted: Sat Sep 24, 2011 4:24 am |
|
|
and, of course, just try searching here for this error, to find many dozens of explanations/suggestions...
Best Wishes |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Sat Sep 24, 2011 5:08 pm |
|
|
You could also lookup 'tachometer' and find code as well.
Basically same thing.
count pulse for a fixed time period( 1 second),do some math, display result... |
|
|
Wolf
Joined: 23 Sep 2011 Posts: 32
|
|
Posted: Sun Sep 25, 2011 11:48 pm |
|
|
temtronic wrote: | You could also lookup 'tachometer' and find code as well.
Basically same thing.
count pulse for a fixed time period( 1 second),do some math, display result... |
You see, I got that, http://www.instrumart.com/products/31039/lake-monitors-flowstat-sensors that flow sensor basically behaves like a tachometer. I can get my pulses counted per 1 second, thats no problem its stuffing the float calculated number into the sprintf(); function....
Code: |
void main() {
unsigned long int uliSeconds, uliPulses, uliPulseBuffer;
unsigned char uchLCDBuffer[20];
StartupSettings();
uliSeconds = 0;
uliPulses = 0;
uliPulseBuffer = 0;
InitializeDisplay();
delay_ms(400);
sprintf(uchLCDBuffer, "FlowCtrl");
WriteString(uchLCDBuffer, 8);
while(1) {
if (input(CRYSTAL) == 1) {
uliSeconds++;
}
if (uliSeconds > 15000) {
uliSeconds = 0;
output_toggle(LED_RED);
sprintf(uchLCDBuffer, "%f", (((float)uliPulseBuffer)/1000));
DataCommand(0xC0);
WriteString(uchLCDBuffer, 8);
uliPulseBuffer = uliPulses;
uliPulses = 0;
}
else {
if (input(SENSOR) == 1) {
uliPulses++;
output_bit(LED_GREEN, 1);
}
else {
output_bit(LED_GREEN, 0);
}
}
}
return;
}
|
the sprintf(uchLCDBuffer, "%f", (((float)uliPulseBuffer)/1000)); is what causes the program to overload. And I cannot find any better way to do this. |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Mon Sep 26, 2011 1:30 am |
|
|
You are asking a 1K flash PIC to do floating point... it should come as no surprise that you are getting out of ROM, i.e. flash. If you are going to get this to fit in such a small flash space then you are going to have to:
a) Use integer arithmetic all the way through. Float library code takes up a lot of space.
b) Get hardware to do as much as possible for you. This reduces the amount of code you need.
c) Format the values for output yourself. Generic formatting code, such as printf and its relatives, is bloated compared to well written application specific code.
In short you are trying to squeeze a quart into a pint pot and it simply won't go. The compiler is telling you it won't go, end of story.
Another answer is to simply get a bigger PIC.
RF Developer. |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Mon Sep 26, 2011 2:13 am |
|
|
RF_Developer wrote: |
b) Get hardware to do as much as possible for you. This reduces the amount of code you need.
|
Thinking about it, if I were a tutor setting this as an assignment, and I have to add I'm not, then I'd have a particular reason for requiring the use of a PIC16F627A. That's because it is very limited and that naive approaches cannot be successful. A software only approach is doomed due to code space limits and even if it can be shoehorned into the device, it will give poor accuracy. So... what would I be hoping for? I'd hope that someone would think laterally and see this is not an assignment about software. Its about using the hardware resources effectively. To get this to work, and I confess I haven't actually tried this approach, I'd be expecting a solution along the lines of using a timer to give a hardware accurate timebase and using the CCP module in capture mode, probably with prescale to reduce capture frequency and hence processor load, to capture the timer count based on the unknown input frequency. I'd then expect the software to just compute the final result and output it, bearing in mind that this is not direct frequency counting but period measurement. I.e. that capture value represent timer counts per tick/ticks of the input, not ticks per time interval.
The temptation to go float is still there however, and I'd hope for my students to avoid that, but fully expect none of them to actually do so.
In short I'd have set this up as an assignment I'd expect them to "fail". However that's because that "failure" sets up important lessons in how to approach problems from more than one direction.
RF Developer. |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Mon Sep 26, 2011 7:18 am |
|
|
Two suggestions:
- You can save some code space by writing *0.001 instead of /1000, as previously mentioned.
- You should look for the %w format option. It allows you to print integer as fixed point without using float |
|
|
|
|
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
|