CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

ROM use is 46%, then Out of ROM message when add bootloader
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Greg Richter



Joined: 15 Feb 2008
Posts: 18
Location: Atlanta, Tulsa, Asheville

View user's profile Send private message Visit poster's website

ROM use is 46%, then Out of ROM message when add bootloader
PostPosted: Wed Sep 25, 2024 4:19 pm     Reply with quote

I've searched and read about optimizations but I'm not understanding how to solve this one.

Clean compile on a 16F1517, 46% ROM used. To the working code I added in the bootloader header and loader.c, the #org statement below after the clock and rs232 lines:

#use delay(crystal=16MHz)

#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)

// bootloader
#define _BOOTLOADER

#include "bootloader.h"
#include <loader.c>

#org LOADER_END+1,LOADER_END+3

... and got the dreaded Out of ROM error:

*** Error 71 "C:\xxx\Acc.c" Line 550(1,2): Out of ROM, A segment or the program is too large Write7SegmentDigit
Seg 00340-00342, 0003 left, need 00083 Orged


I think I'm running out of space in a segment, it's not that the bootloader doubled the code size. The offending routine is the first one in the source file, after the bootloader:

void Write7SegmentDigit(int digit, BYTE b) // write 8 bit value to 7 segment digit -- segments are active LOW
{ // digit 0-7, b is byte mask for 7 segments, isDotOn is boolean set
output_high(DIGITS[(digit+9)%10]); // turn off previous digit
output_bit(Segment_A, bit_test(b, 0)); // pick apart bit mask to set segments while dark
output_bit(Segment_B, bit_test(b, 1));
output_bit(Segment_C, bit_test(b, 2));
output_bit(Segment_D, bit_test(b, 3));
output_bit(Segment_E, bit_test(b, 4));
output_bit(Segment_F, bit_test(b, 5));
output_bit(Segment_G, bit_test(b, 6));


if(digit == 7) output_bit(Segment_Dot, 0); // enable dot for digit 7 only
else output_bit(Segment_Dot, 1);

output_low(DIGITS[digit]); // turn on current digit
}

Question is how to debug? #separate didn't seem to do much. Yes, bit_test() should be an AND mask, save a ton of cycles. Am doing that now. ;-)

Any further details that might help, or pointers along the way?

Thx!

Greg
_________________
Madness takes it toll; please have exact change.
temtronic



Joined: 01 Jul 2010
Posts: 9221
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed Sep 25, 2024 4:38 pm     Reply with quote

re: A segment or the program is too large

yes, 'classic' and easy to fix, as you've got LOTs of ROM left.

ROM is in 'banks' of a certain size ( say 8 KB ). If a function is 9 KB it won't fit,so you need to break it apart.
You simply 'breakdown' functions into smaller sizes.
say function A is 'too big' . create function A1 and A2.

Another possible way is to rearrange the order of the functions.
The 2nd problem is 'spanning' banks. Say a function is 3 KB ,so will fit into a bank but 7 KB is already used. Sorry, cannot 'span' banks error. That's when 'rearranging' the functions may help.
I don't know if newer versions of the compiler can do this for you , maybe 'optimize' can ??? Others will know.

I started with PCM 2.523..yeah I'm THAT old.
Greg Richter



Joined: 15 Feb 2008
Posts: 18
Location: Atlanta, Tulsa, Asheville

View user's profile Send private message Visit poster's website

PostPosted: Wed Sep 25, 2024 6:16 pm     Reply with quote

I'm that old too... I've read a your posts (and ~Hamlett, and
PCM for decades now. :-)

I know break 'em up, but you'll note that function is a tiny little thing. Is there anyplace helpful to look besides the LST file?

Thx!

G
_________________
Madness takes it toll; please have exact change.
Greg Richter



Joined: 15 Feb 2008
Posts: 18
Location: Atlanta, Tulsa, Asheville

View user's profile Send private message Visit poster's website

PostPosted: Wed Sep 25, 2024 6:22 pm     Reply with quote

Shuffloing things about I get:

*** Error 71 "C:\xxx\acc.c" Line 553(1,2): Out of ROM, A segment or the program is too large @DIVFF
Seg 0001E-0033F, 0019 left, need 000CC
Seg 00340-00342, 0003 left, need 000CC Orged
Seg 00343-007FF, 04BD left, need 000CC Reserved
Seg 00800-00FFE, 07FF left, need 000CC Reserved
Seg 00FFF-00FFF, 0001 left, need 000CC Reserved
Seg 01000-017FE, 07FF left, need 000CC Reserved
Seg 017FF-017FF, 0001 left, need 000CC Reserved
Seg 01800-01FFE, 07FF left, need 000CC Reserved
Seg 01FFF-01FFF, 0001 left, need 000CC Reserved
Seg 00000-00003, 0001 left, need 000CC Reserved
Seg 00004-0001D, 0000 left, need 000CC Reserved

@DIVFF is inlined. My somewhat sheepish question is: How do I see which segment or function is the offending Too Big one?

-G
_________________
Madness takes it toll; please have exact change.
temtronic



Joined: 01 Jul 2010
Posts: 9221
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed Sep 25, 2024 7:15 pm     Reply with quote

If you look at the listing, you'll see the address and machine code for the program.
It will be 'jumbled up' , ie not in memory linear sequence, but it'll show you 'what went where'.
In the 'good old days', I used the MSDOS program 'sort' to rearrange the listing into how it'd be put into ROM. Back then I had lots of time on my hands as it took 15 minutes to erase the PICs.
Greg Richter



Joined: 15 Feb 2008
Posts: 18
Location: Atlanta, Tulsa, Asheville

View user's profile Send private message Visit poster's website

PostPosted: Wed Sep 25, 2024 7:39 pm     Reply with quote

Just took a long look, doesn't ake sense just yet. Without the bootloader #ORGing up 0x33F or low ROM, everything fits with two segments of 2048 bytes still unused.

Adding the little bootloader code, seems like the compiler doesn't fill the space by itself. I did a PIC bootloader a few years back, remember this issue but not how to fix it!

The offending function is a little tiny thing, and commenting out the function body leaving just { } changes the offending segment to:

*** Error 71 "C:\xxx\acc.c" Line 588(1,2): Out of ROM, A segment or the program is too large @MULFF
Seg 0001E-0033F, 004C left, need 00077
Seg 00340-00342, 0002 left, need 00077 Orged
Seg 00343-007FF, 04BD left, need 00077 Reserved
Seg 00800-00FFE, 07FF left, need 00077 Reserved
Seg 00FFF-00FFF, 0001 left, need 00077 Reserved
Seg 01000-017FE, 07FF left, need 00077 Reserved
Seg 017FF-017FF, 0001 left, need 00077 Reserved
Seg 01800-01FFE, 07FF left, need 00077 Reserved
Seg 01FFF-01FFF, 0001 left, need 00077 Reserved
Seg 00000-00003, 0001 left, need 00077 Reserved
Seg 00004-0001D, 0000 left, need 00077 Reserved

I suspect there's something fundamental I'm missing. Once I get it figured out I'll post a nice consolidated post. This is a frustration since it's not clear what broke...


Thanks to everyone reading, btw.

G
_________________
Madness takes it toll; please have exact change.
Ttelmah



Joined: 11 Mar 2010
Posts: 19495

View user's profile Send private message

PostPosted: Thu Sep 26, 2024 1:58 am     Reply with quote

OK. You need to post the bit of code in acc.c (a few lines in front and behind),
and the types of all the variables.

MULFF is a floating point multiply. Now floating point is bulky. Wonder if
some little change in the variable types is happening when you are adding
the bootloader, and this is what actually causes the problem?.
Same applies to DIVFF.
Floating point is always better avoided. Scaled integer is faster, smaller,
and more accurate.
Now if you have floating point actually used somewhere, and have to have it,
then consider making the code that has this into a subroutine, and calling
this. Gets rid of the 'INLINE' behaviour.
Greg Richter



Joined: 15 Feb 2008
Posts: 18
Location: Atlanta, Tulsa, Asheville

View user's profile Send private message Visit poster's website

PostPosted: Thu Sep 26, 2024 11:18 am     Reply with quote

It's a lot of code! I'll post the top chunk that it's complaining about first.

Looks like we've got plenty of space, just not sure how to get the compiler to use it! If I comment out most of the code in the bigger routines it then complains about the very first one:

#include <16F1517.h>

#device ADC=10

#fuses PUT // power up timer
#fuses PROTECT // code protected from reading
#fuses WRT // program memory write protect
#fuses BROWNOUT // brownout reset enable
#fuses BORV25 // brownout reset at 2.5 volts
#fuses WDT_NOSL // use watchdog timer
#fuses NOVCAP // not using VCAP for internal shunt regulator
#fuses NOLVP // no low voltage programming
#fuses STVREN // reset on stack overflow
#fuses HS // use crystal oscillator

#use delay(crystal=16MHz)

#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)

#include <bootloader.h>
#include <loader.c>


// analogs
#define OTTOMAN_ANGLE 9
#define ANGLE_SETTING 24
#define TENSION_SETTING 27
#define PROGRAM_SETTING 26
#define TIME_SETTING 25
#define LOAD_CELL 23
#define ANALOGS sAN9 | sAN27 | sAN26 | sAN25 | sAN24 | sAN23

// digital inputs
#define START_STOP_BUTTON PIN_B5

// digital outs
#define PWM_ANGLE_DIR PIN_D1
#define PWM_ANGLE PIN_C2

#define PWM_TENSION_DIR PIN_D0
#define PWM_TENSION PIN_C1

#define T0FREQ 977 // timer 0 freq in Hz, ticks to 1s
#define BLINK_TICKS T0FREQ/4 // display blink time ~256ms
#define START_STOP_TICKS T0FREQ/40 // ~25ms
#define ANGLE_TICKS T0FREQ/2 // update ottoman angle every ~500ms after control or motion stops

#define RTZ_SECONDS 10 // time to return ottoman to zero extension
#define FORWARD 1 // motor direction
#define REVERSE 0

#define Segment_A PIN_C3
#define Segment_B PIN_C5
#define Segment_C PIN_B2
#define Segment_D PIN_B1
#define Segment_E PIN_B0
#define Segment_F PIN_C4
#define Segment_G PIN_A4
#define Segment_Dot PIN_D2

#define SPACE 10+48 // blank space, all segments off (0 is char 48, subtracted from all subscripts)
#define DASH 13+48 // "-"

// 0 1 2 3 4 5 6 7 8 9 spac E r -
unsigned char SegmentTable[14]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0x06,0x2f, 0xbf};

int1 IsButtonPushed=0, // button pushed?
IsTreatmentRunning=0, // is treatment state machine running?
IsOttomanMoving=0, // is ottoman moving into position?
IsTensionMoving=0, // is tension rack moving?
IsStopTreatment=0, // ISR-safe stop treatment flag
IsReturnToZero=0, // is ottoman returning back to zero, PWM running?
JustOnce=1; // init flag - 1 to do once, 0 is done

int8 LED_Display[10+1], // constructed display string
DigitPtr=0, // which digit is lit: 0-7
DIGITS[10] = {PIN_C6, PIN_C7, PIN_C0, PIN_E2, PIN_E1, PIN_E0, PIN_A3, PIN_A2, PIN_A1, PIN_A0},
DesiredAngle=0, PrevDesiredAngle=0, // control settings
DesiredTension=0,
DesiredProgram=0,
DesiredTimeMinutes=0,
AngleTarget=0, // angle target updated from DesiredAngle every NN seconds
PrevAngleTarget=30, // different than zero above
IntegerTension=0, // integer tension value from low-pass
TargetTension=0, // tempory for use in SetTension
TensionDirection=FORWARD, // detect direction change for tension
MinDisplay,SecDisplay; // minutes and seconds to be displayed

int16 AD=0, // scratch AD value
tempAD, // for 16 bit calculations
scratch16,
ISRCounter=0, // clock variable
StartStopCounter=0, // N ticks to debounce start/stop switch
OttomanAngle=0, // from pot on actuator
PrevOttomanAngle=0, // for motion detect
TreatmentLoopSeconds=0; // N seconds in this treatment loop

int32 MonotonicSeconds=0, // rolls over ~ 136 years of continuous running
TreatmentSeconds=0, // seconds treatment has been running
TreatmentSecondsRemaining=0, // seconds until end of treatment
RTZCounter=0, // return to zero countdown
AngleCounter=0; // for ottoman angle update cycle

float LoadCellVolts=0, // amplifier voltage output for debug and calibration
LoadCellPounds=0, // filtered load cell reading
TensionPercent=1; // state machine scale percentage for treatment loop



void TreatmentStopReset() // reset timer, intregrators, etc.
{
TreatmentSeconds = IsTreatmentRunning = 0; // treatment complete

TreatmentLoopSeconds=0; // loop at zero
IsStopTreatment=0; // flag down

// return to zero

IsReturnToZero=1; // return to zero
RTZCounter = RTZ_SECONDS; // set counter to NN seconds out

output_high(PWM_TENSION_DIR); // set reverse
delay_ms(10); // wait for relay to move
output_high(PWM_TENSION); // gets turned off in main loop
}

void SetOttomanAngle()
{
if(AngleTarget == PrevAngleTarget) return; // nothing to do but jitter

IsOttomanMoving = 0; // assume we're done

if(!IsTreatmentRunning) // OK to move
{
if(OttomanAngle < AngleTarget) // move forward
{
if(input_state(PWM_ANGLE_DIR))
{
output_low(PWM_ANGLE_DIR); // was high, set low
delay_ms(10); // wait for relay to move
}
output_high(PWM_ANGLE);
IsOttomanMoving = 1; // note moving
}

if(OttomanAngle > AngleTarget) // go backward
{
if(!input_state(PWM_ANGLE_DIR))
{
output_high(PWM_ANGLE_DIR); // was low, set high
delay_ms(10); // wait for relay to move
}
output_high(PWM_ANGLE);
IsOttomanMoving = 1;
}
}

if(!IsOttomanMoving) // within limits
{
output_low(PWM_ANGLE);
output_low(PWM_ANGLE_DIR); // was high, set low
delay_ms(10); // wait for relay to move

PrevAngleTarget = AngleTarget; // keep last position
}
}


Remove the bootloader lines, and clean compile with 46% ROM used. Add them in, and it fails as:

*** Error 71 "C:\xxx\acc.c" Line 556(1,2): Out of ROM, A segment or the program is too large TreatmentStopReset
Seg 0001E-00342, 0004 left, need 0001C
Seg 00343-007FF, 04BD left, need 0001C Reserved
Seg 00800-00FFE, 07FF left, need 0001C Reserved
Seg 00FFF-00FFF, 0001 left, need 0001C Reserved
Seg 01000-017FE, 07FF left, need 0001C Reserved
Seg 017FF-017FF, 0001 left, need 0001C Reserved
Seg 01800-01FFE, 07FF left, need 0001C Reserved
Seg 01FFF-01FFF, 0001 left, need 0001C Reserved
Seg 00000-00003, 0001 left, need 0001C Reserved
Seg 00004-0001D, 0000 left, need 0001C Reserved

I apologize for this possibly being obvious, but it's vexing. Got plenty of space, but as Temtronic suggested I think no one chunk big enough.

Question is, how do I find which chunk?

Thx!
_________________
Madness takes it toll; please have exact change.
Greg Richter



Joined: 15 Feb 2008
Posts: 18
Location: Atlanta, Tulsa, Asheville

View user's profile Send private message Visit poster's website

PostPosted: Thu Sep 26, 2024 12:51 pm     Reply with quote

Git it to compile by commenting out large blocks of code. I'll separate them, slim the big ones down, and post the procedure.

Wish there was a place to see how big each offending chunk was.

G
_________________
Madness takes it toll; please have exact change.
temtronic



Joined: 01 Jul 2010
Posts: 9221
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Thu Sep 26, 2024 1:44 pm     Reply with quote

if you dump the listing, look at a function, sub the end adrs from the beg adrs, that should be the size of the function.
helps to have Windows calc set to 'hex'/ programmer mode ....
Greg Richter



Joined: 15 Feb 2008
Posts: 18
Location: Atlanta, Tulsa, Asheville

View user's profile Send private message Visit poster's website

PostPosted: Thu Sep 26, 2024 2:29 pm     Reply with quote

The hard part it's a moving target. I comment out everything in the offending routine and it's all good. Then I break it up, and the erro moves to another place. It's like #ORGing the bootloader space make the thing not load the other empty segments?
_________________
Madness takes it toll; please have exact change.
Greg Richter



Joined: 15 Feb 2008
Posts: 18
Location: Atlanta, Tulsa, Asheville

View user's profile Send private message Visit poster's website

PostPosted: Thu Sep 26, 2024 3:08 pm     Reply with quote

Well, found it. bootloader.h has in pertinent part:

#ifndef _bootloader
#if defined(__PCM__)
#build(reset=LOADER_END+1, interrupt=LOADER_END+5)
#elif defined(__PCH__)
#build(reset=LOADER_END+1, interrupt=LOADER_END+9)
#endif

#org 0, LOADER_END {}
#warning/information Org 0 to (LOADER_END) //Added for debug GvR

#else
#ifdef __PCM__
#if getenv("PROGRAM_MEMORY") <= 0x800
#org LOADER_END+4, (getenv("PROGRAM_MEMORY") - 1) {}
#else
#org LOADER_END+4, 0x7FF {}
#if getenv("PROGRAM_MEMORY") <= 0x1000
#org 0x800, (getenv("PROGRAM_MEMORY") - 1) {}
#else
#org 0x800, 0xFFF{}
#if getenv("PROGRAM_MEMORY") <= 0x1800
#org 0x1000, (getenv("PROGRAM_MEMORY") - 1) {}
#else
#org 0x1000, 0x17FF {}
#if getenv("PROGRAM_MEMORY") <= 0x2000
#org 0x1800, (getenv("PROGRAM_MEMORY") - 1) {}

#warning/information ORG from 0x1800 to getenv("PROGRAM_MEMORY") //Added for debug GvR

If I #define _bootloader, the header ORGs out 0-0x3FF for the bootloader, and follows with ORG 0x1800 to 0x2000. Not much left!

I think I misunderstood what #define _bootloader means -- this is a standalone bootloader, not embedded as part of an application. No way I can fit much is 1800-2000...

Am I reading this correctly?
_________________
Madness takes it toll; please have exact change.
Ttelmah



Joined: 11 Mar 2010
Posts: 19495

View user's profile Send private message

PostPosted: Fri Sep 27, 2024 1:52 am     Reply with quote

No, You are misunderstanding how that works.
The code you are showing is for the bootloader, to protect the upper memory
from having stuff written into it by this. This code is only applied
when '_bootloader' is defined. Otherwise the code used is:

Code:

.................... #ifndef _bootloader
....................  #if defined(__PCM__)
....................   #build(reset=LOADER_END+1, interrupt=LOADER_END+5)
....................  #elif defined(__PCH__)
....................   #build(reset=LOADER_END+1, interrupt=LOADER_END+9)
....................  #endif
....................
....................  #org 0, LOADER_END {}

"not defined" '_bootloader'. The bit you are looking at is the #else, which
is what applies to the bootloader. This is done to ensure that certain stuff
normally put at the top of memory isn't put there in the bootloader code.

In the applicable bit, the #org prevents the mein code from using anything
used by the bootloader. The #build defines where the main code goes. On
your chip with the default bootloader, stuff will start at 0x344.

That is not your problem, unless you are defining _bootloader in your
main code.

Aargh!. Yes you do:
Code:

// bootloader
#define _BOOTLOADER //This must _only_ be in the bootloader, not
//in the main 'bootloaded' code. No wonder it doesn't work.


You are telling the compiler that your main code is a bootloader.
Did you actually look at the examples?.
temtronic



Joined: 01 Jul 2010
Posts: 9221
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Fri Sep 27, 2024 5:21 am     Reply with quote

just a comment...
this line....

#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)

needs to have 'ERRORS' added to the options ,otherwise the UART could 'hang'.
Assuming the bootloader does use the UART, change 'could' to 'will probably'.
Ttelmah



Joined: 11 Mar 2010
Posts: 19495

View user's profile Send private message

PostPosted: Fri Sep 27, 2024 5:40 am     Reply with quote

The annoying thing is that had he used the code buttons, I think I'd have
spotted the booytloader line early on. However I was skimming the stuff
at the start of the program, and focusing on the size of the stuff below.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
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