Space Limit--What is expendable?

My problem is this: it appears that i am reaching the limit on the EDU controller for space. It has gotten to the point where i need to comment out portions of my code to get it to even transfer.

I am able to compile it with no problem using MPlab.

When i transfer, it says opennign port, the “Erasing Device” where it stays for about 10 seconds, then, it says device not connected.

When i comment stuff out, or use less memory by using ints instead of floats, it works fine.

My real problem is that i only have the guidence program created, no autonomous control, no braking, no arms, etc. What in the default code can i get rid of? I need to recover as much space as possible so that i only use the absolute necessary code.

Any help is appreciated.

Hmm, well yes, you want to stick with as many ints as possible. The math is processed faster for them, and they take up less space.
There are a number of routines you can erase from the default code. Mainly, I would read through the Default_Routine sub and then clear it out.
Depending on your method of executing auto mode, you could be eating lots of memory. If you’re doing it case-by-case with lost of IFs, or a switch or something, that needs to change. The method I use is to hold an array of movement data and then have a small piece of code that executes it. It works fine, and you can have some massive arrays too.
It also sounds like something might’ve gotten modified that shouldn’t have…:smiley:
We had someone do this on our team and we had memory problems too. We had to restart from scratch from that point.

*Originally posted by ErichKeane *
using ints instead of floats

You should avoid using floats if at all possible. The PIC inside the EDU controller does not support floating point math in hardware, which means that if you use floating point math, then the compiler has to include a bunch of software floating point routines. This undoubtedly takes up a lot of space and is also really slow.

Also, if you haven’t done it already, get rid of the printf_lib stuff. It takes up a ton of code space for essentially a debugging function. If you remove printf_lib, you can still output stuff to the serial port, just not as nicely as with printf.

I did delete all of the Default section as well as a few functions that were not being used. I did keep the printf section, at least for now.

I believe i figured out the problem. I did not realize that floats were not native to the chip archetecture, so, in my one line i did a cast promotion to do : pwm01=pwm02*((float)in1/127.00)

this i guess must have taken up a lot of memory, so instead i made it like this: pwm01=pwm02*in1/127, keeping it entirely integer mathematics. Shoulda thought of this in teh first place!.

I do need to do a lot of if statements for my auto control, because my team plans on using only sensors to direct the bot, instead of some pre set auto control. We feel that this will work best for the Auto at teh end setup.

And another note: which is more efficent in this chipset, the Switch statements, or nested ifs? And how do you do spanned switch cases? I know in Basic you could to Case 127 to 255, is there a similar way to do it in this langauge? And a final note, does using a void function take more processing power than incoded systems? or the same?

ETA 30 seconds later: What can i do to figure out if it takes too much memory? with the pbasic editor i had a memory chart i could pull down to see my % on program and variable memory. Is there a similar way to do this in picc? And what are the hex limits for variable space and program space as reported by IFI loader?

limits for variable and program space are given at the innovations first webiste. As for putting ranges in the switch-case loop, to the extent of my knoledge, it cannot be done like in PBasic; you need to use some if statements. If it is just for one range and everything else is a single value, put it as a comparison in the default: tag, or as just the default tag if the situation permits. The other meathod is to create a char variable just for your switch-case loop and do some comparisons first, so it would look something like this:

char case_range
if(x<60)
{
   case_range=0;
}
else if(x<127)
{
   case_range=1;
}
else
   case_range=2;

switch(case_range)
{
   case 1:
      *statements*
   case 2:
      *statements*
   case 3:
      *statements*
}

And do that for however many cases you need. If you only need 2, you can even go with the whole ? : operator–case_range=(127<=x && 225>=x) ? 1 : 0.

On that note, does anybody know if you can nest the ?: operator? i.e. x=(condtion 1) ? 1 : (condition 2) ? 2 : (condition 3) ? 3 : … (condition n) ? n : 0

really i only have like 4 ifs/ifelse statements, to cover the 4 sections of the stick. (x axis, y axis, left turn, and right turn), so its not too bad. I dont wanna create any more variables, but i think that i am fairly low now after taking out all printf statements(had 8 in there at one point. hehehe…)

*Originally posted by ErichKeane *
**
ETA 30 seconds later: What can i do to figure out if it takes too much memory? **

Two comments…
First of all, there is a separate code space and data space. One could be full and the other virtually empty.

If you want to find out all about the program you are down-loading to the controller, the linker generates a file called…

FNAME.LST

where FNAME is the name of your project (for instance: IFI Default Code.LST).

This file contains your C code, with the assembly next to it, with the line numbers of the code addresses where this code is getting dumped. It also contains the machine code translation of your instructions.

If your code is getting too big, you should see addresses above 008000 in this file.

[NOTE: this LST file only contains code which is being compiled. The library code is not disassembled in this file.]

You can also look in the FNAME.map file (if you have the “generate map file” option checked in your MPLAB environment). This will show you the section information.

At the end of the code section there is a little block which says:
“Program Memory Usage”
It gives start and end address.

You will have a little subblock that says:
xxx out of 33816 program addresses used, …

You get similar information for the data memory. Only, you’ll have to look at the “data” section address of the last symbol to figure how close you are to full in the data space.

Thank you andrew, that is exactly what i was looking for. Just 1 final question, what is the hex Address Limit for the data variables?
I found out that with program memory, im only at 25%(yay!), and i got my data memory down to 000fab or something like that.

A new version of IFI_Loader (1.0.5) is now available for download at: http://innovationfirst.com/FIRSTRobotics/documentation.htm

Version 1.0.5 allows you to download the full 32k bytes of code to the User processor. If you are using an older version you will be unable to download any code which is over 16k bytes in size.

Thank you for letting me know about this! It will be a big help in the future.

*Originally posted by ErichKeane *
**Thank you andrew, that is exactly what i was looking for. Just 1 final question, what is the hex Address Limit for the data variables?
I found out that with program memory, im only at 25%(yay!), and i got my data memory down to 000fab or something like that. **

According to the data sheet for the PIC 18FXX20 family (available from www.microchip.com, look for PIC18F8520), the data space is 0x800 bytes.

This can also be seen in the 18f8f20user.lkr file, which contains the memory map. Although 0x754…0x7ff is allocated to something called “dbgspr” whatever that is and is listed as “PROTECTED.”

*Originally posted by Sachiel7 *
Hmm, well yes, you want to stick with as many ints as possible.

I would even stay away from ints wherever possible. Unsigned chars take up the least code space and process the fastest. Also, try turning on the compiler optimizations.

Whats wrong with signed chars? I’ve converted all my PWM signals to signed to simplify the math.

If you do it correctly, and dont need to do any extra math on those two values, its no problem. The Conversion should look like this:
signedpwm01=(char)pwm01-127;

That way you dont loose any information. Now, in processing, remmeber that the values for your pwm’s can NEVER reach a number higher than 127 or less than -127 without a well planned promotion.

Actually it’d be better to use this:

signedpwm01 = (char) pwm01 - 128;

A signed char can range from -128 to 127. Thus, if you subtract 128 it will give you a reasonable value for any value of pwm01. If you subtract 127, then you get into a problem if pwm01 = 255. 255-127 = 128, however a signed char cannot be 128, and will actually end up being -128! (This is a side effect of the way a computer stores a negative number). Realistically, pwm01 isn’t supposed to be larger than 254, but in software it’s usually better to make something work for all cases rather than assume that certain cases won’t occur.

Ah, correct on that one. The reason i put -127 is it correctly centers it every time, and i have a cleaning function run that basically limits the pwm values before hand, so 254 is the max necessary. The other thing you could do would be to use INT’s, which allows a large amount more of integer mathematics, another thing my team found necessary.

yes, you can nest the ?: operator, although i am not certain of the order of operations so you might want to type it like

x=(condition1 ? 1 : (condition2 ? 2 : (condition3 ? 3 : …(condition n ? n : 0)…))

also a range of case statements cannot be used as in PBasic however the following is a way to simulate this.

**
switch(statement) {
case 1:
case 2:
case 3:
[INDENT]doSomething();[/INDENT]
[INDENT]break;[/INDENT]
case 4:
case 5:
case 6:
[INDENT]doSomethingElse();[/INDENT]
[INDENT]break;[/INDENT]
}
**

However this would not be practical for a very large range of values.

Also, if the compiler compiles the sane way as the C compiler I have studied, a switch/case statement uses up more code space than if/else statements, especially when there is a large range of skipped values such as. …

**
switch(statement) {
case 1:
[INDENT]doSomething();[/INDENT]
[INDENT]break;[/INDENT]
case 1000000:
[INDENT]doSomethingElse();[/INDENT]
[INDENT]break;[/INDENT]
}
**

Switch/case statements are quicker than several if/else statements though because it jumps to a calculated address rather than having to make many comparisons, but this will not be noticeable if there are only a few choices.

I have done the same. The reason i specified unsigned chars is bc they take more instructions to process. This translates into larger programs and slower execution times. If you arn’t having problems with speed and or space i wouldn’t worry about it. If you want to demonstrate this for yourself, write a program that does some signed and unsigned operations, and then look at the assembly code.

Technically yes, you are correct, the difference between signed and unsigned mathematics is a little more processor intensive. It does not take more space though in the memory banks at all afaik. I believe all it does is use an unsigned Char, and then subtract the 127/128 or whatever in implementaiton. The difference is so minimal between the two, i never saw it as a problem.

I did a few things that helped me save a huge amount of space.
1- I reverted to completely integer mathematics, as opposed to floating point mathematics, which are horrid!
2- got rid of all unnecessary portions of the default code. That removed a large amount of the space (about 12% of our programming memory!), and left a good amount of the programming to me instead of some default setup.
3- Got rid of that printf library. It is easily the worst written print library i have seen in ages. Instead, my team is using the printword and printbyte and etc library in the utilities.

You guys have been a great help, keep the good posts comming.

The IFI_Loader will also give you the space used.
Just hit return when IFI_Loader is active and you’ll get a report in the bottom message bar.