Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best Practices for PIC18 Stack/Memory Management?

Tags:

c

stack

memory

The limited stack size of budget PICs is a problem area and I have adjusted my code to accommodate this reality. I currently adopt a rough paradigm of grouping closely related functions into a module and declaring all variables global static in the module (to reduce the amount of variables stored in the auto psect, and issues of mutability are only relevant in ISRs, which I account for.) I don't do this because it is good practice, but the reality is you have a finite amount of space to allocate all local function vars that exist in an entire project. In the embedded world of 8/16 bit chips, is this an appropriate method, provided I'm sure to take necessary precautions? I also do things like allocate > 256 bytes of RAM for Ethernet (I know it should be 1500 as standard MTU, but we have a custom situation and very limited RAM) buffers and have to access that memory via pointers so I can avoid the semantics of memory banking. Am I doing it wrong? My app works, but I am 100% open to suggestions for improvement. [c]

like image 393
Nate Avatar asked Nov 04 '10 03:11

Nate


People also ask

What is size of stack memory in PIC18F?

PIC18F Microcontroller Series The memory in general consists of 16 banks, each of 256 bytes. PIC18F452 has 1536 bytes of data memory (6 banks × 256 bytes each) occupying the lower end of the data memory.

How many bit stack is available in PIC18?

This makes function calls much easier to use, even though people who program them should be aware of some remaining gotchas [4]. 16 bit: A PIC microcontroller with a 16 bit core (all PIC18) has a "31-level deep" hardware stack depth. This is more than deep enough for most programs people write.

How do you preserve stack space?

The key to minimizing your stack usage is to minimize parameter passing and automatic variables. The space consumption of the actual function call itself is rather minimal. One way to address the parameter issue is to pass a structure (via pointer) instead of a large number of parameters.

What will happen if we cross the maximum limit of stack?

Infinite Recursion If an application is performing recursion, the maximum stack size can easily be reached and a Stack Overflow exception is thrown. The thread stack has a limited size and eventually its space will run out as the thread stack grows without bounds.


3 Answers

I know this was asked 4 years ago but it still has not been properly answered. I believe what the OP is asking is is their approach to working around a limitation of the HiTech PICC18 C compiler valid and/or best practice. As mentioned in a later comment the limitation (a rather bad one and not well advertised by Hitech) is "the Hi-Tech compiler only allows up 256 bytes of auto variables". Actually the limitation is worse than that as it is a total of 256 bytes for local variables and parameters. The linker warning when this is exceeded is pretty cryptic too. Provided that functions are on different branches of the call tree then the compiler can overlap the variables to reuse the space. This means that you can effectively have more than 256 bytes. But note that the interrupt handler (or handlers if you use the priority scheme) has it's own call tree that shares the 256 byte local/param block.

Locals The two solutions to reduce the space required for locals are: make the locals global or make them static. Making them static keeps the scope the same and provided the function is not called from interrupts is safe (rentrancy is not allowed by the compiler anyway). This is probably the preferred option. The drawback is that the compiler can not reuse those variable's locations to reduce overall memory consumption. Moving the variables to global scope allows reuse, but the reuse management must be managed by the programmer. Probably the best balance is to make simple variables static but to make large chunks of memory like string buffers global and carefully reuse them.

Be careful with initialisation.

foo()
{
 int myvar = 5;
}

must change to

foo()
{
 static int myvar;
 myvar = 5;
}

Parameters If you go around passing large lots of data down the call tree in parameters you will quickly run into the same 256 byte limitation. Your best option here may be to pass a pointer to a globally allocated struct/s of "options".Alternatively you can have global settings variables that are set by the top caller and read by callees down the tree. It really depends on the design of the software which approach is better.

I've struggled with the same issues as the OP and I think the best option in the long run is to move away from using the Hitech compiler. The optimisation decision the compiler writers took to allocate all locals/params in one block is only really appropriate for the very small ram size PICS. For large PICS you will run out of local/param far before you hit the ram size of the device. Then you have to start hacking your code around to fit the compiler which is perverse.

In summary... Yes your approach is valid. But do consider simply making locals static if that is appropriate as, in general, reducing the scope makes your code safer.

like image 99
Felix Avatar answered Oct 13 '22 19:10

Felix


Whereas the C18 compiler used some FSRs (pointers) to manage the data stack, it sounds like the new XC8 compiler from Microchip uses a compiled stack, so you should know exactly how much space is taken up by the stack at compile time. You will also know exactly where each stack variable is stored. I read all about this in the XC8 user's guide and it sounds great. That feature should make this question be moot, assuming you are using XC8.

like image 2
David Grayson Avatar answered Oct 13 '22 21:10

David Grayson


My experience with compilers/linkers for chips with limited memory is that, as long as you don't use recursive functions and inform the compiler about that, then the compiler is very capable of determining the minimal amount of stack-space that is needed.
I have even seen compilers that give each variable with automatic storage a globally fixed address (no stack at all), where several variables got allocated to overlapping memory, as long as their lifetimes did not overlap.

The general advise when doing (speed or space) optimisations is: make measurements to prove that your optimisation actually has a positive effect.

like image 1
Bart van Ingen Schenau Avatar answered Oct 13 '22 20:10

Bart van Ingen Schenau