PIC18 Stack / Memory Management Tips?

The limited stack size of budget PICs is a problem area, and I adjusted my code to account for this reality. Currently, I accept the crude paradigm of grouping closely related functions into a module and declaring all global static variables in a module (to reduce the number of variables stored in auto-psect, and the variability problems apply only to ISRs that I take into account.) I do not , because this is good practice, but in fact you have limited space to allocate all the local functions that exist in the whole project. In a built-in 8/16 chip chip, is this the appropriate method if I will definitely take the necessary precautions? I also do things like allocating> 256 bytes of RAM for Ethernet (I know it should be 1500 as a standard MTU, but we have a custom situation and very limited RAM) buffers and they need to access this memory through pointers so I can avoid the semantics of banking. Am I doing it wrong? My application works, but I am 100% open for suggestions for improvement. [FROM]

+6
c stack memory
source share
7 answers

I know that this was asked 4 years ago, but he still has not received a proper answer. I believe that the question that the OP asks is their approach to working on whether the HiTech PICC18 C compiler is valid and / or best. As mentioned in a later comment, the limitation (rather bad and poorly advertised by Hitech) is that "the Hi-Tech compiler allows only 256 bytes of automatic variables." In fact, the restriction is worse than the total 256 bytes for local variables and parameters. The linker warning when this is exceeded is rather cryptic. If functions are in different branches of the call tree, then the compiler can overlap variables to reuse space. This means that you can have more than 256 bytes. But keep in mind that the interrupt handler (or handlers, if you use the priority scheme) has its own call tree, which divides the local / paragraph block by 256 bytes.

Locals Two solutions to reduce the space required by locals are as follows: make locales global or static. With their static storage, the scope is the same and, provided that the function is not called from interrupts, it is safe (in any case, the compiler does not allow the use of resources). This is probably the preferred option. The disadvantage is that the compiler cannot reuse these location variables to reduce overall memory consumption. Moving variables to the global area is reusable, but reuse management must be managed by the programmer. Probably the best balance is to make simple variables static, but make global chunks of memory, such as string buffers, global and reuse them carefully.

Be careful with initialization.

foo() { int myvar = 5; } 

should change to

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

Parameters If you go through the transfer of large amounts of data through the call tree in the parameters, you will quickly encounter the same 256-byte limit. Your best option here might be to pass a pointer to the globally allocated struct / s "options". Alternatively, you can have global parameter variables that are set by the upper party and read by polling through the tree. It really depends on the software design whose approach is better.

I struggled with the same problems as the OP, and I think the best option in the long run is to switch from using the Hitech compiler. The optimization decision made by the compiler authors to highlight all locals / params in one block is really suitable for very small PICS sizes. For large PICSs, you will come across a local / parameter far before you press the size of the device plunger. Then you need to start hacking your code to match the compiler, which is perverted.

In conclusion ... Yes, your approach is valid. But think about it by simply setting locals static if appropriate, since, in general, reducing the size makes your code more secure.

+3
source share

While the C18 compiler used some FSR (pointers) to control the data stack, it looks like Microchip's new XC8 compiler uses the compiled stack, so you need to know exactly how much space the stack takes during compilation, you also know exactly where it is stored each stack variable. I read all about it in the XC8 user manual and it sounds great. This feature should make this question moot if you are using the XC8.

+2
source share

My experience with compilers / linkers for limited memory chips is that until you use recursive functions and tell the compiler about it, the compiler is very capable of determining the minimum amount of stack space that is needed. I even saw compilers that provide each variable with automatic storage with a globally fixed address (no stack at all), where several variables were allocated for overlapping memory if their lifetimes did not overlap.

General recommendations when performing optimizations (speed or space): take measurements to prove that your optimization really has a positive effect.

+1
source share

Since you almost run out of memory, you have to count every byte of RAM. Using local variables (auto) allows you to reuse memory where you need it (locally in a function). When you move variables to the global static address space, you give each variable a unique space. It was an address space.

The Microchip compiler allows different variables to share the same address. I have no documents, but this can be done using pragma.

But you need an analysis of RAM requirements. When you see that the stack cannot contain all the variables, but automatic variables will reduce the use of global memory, you should consider increasing the size of the stack using the startup code and the linker script.

0
source share

It is best to choose equipment that meets the requirements.

There are microcontrollers around the cost of just a few dollars more, but they save technology development costs or thousands of dollars. If this is a hobby, your efforts may not count. But in the real world, you can often find hardware that is designed only with hardware in mind.

In particular, PIC18 is not the best example for compact code, which could also be a flash issue.

0
source share

A bit late, but you should also take a closer look at the C18 compiler user guide (if you used this compiler).

You can significantly reduce the stack by statically allocating local variables (overriding the auto keyword). Moreover, you can use an overlay storage identifier that allows you to place different non-overlapping life span variables at the same address, minimizing RAM. (The C18 compiler should work in Non-Extended mode).

0
source share

This blinking sound is obvious, but try not to use 16-bit variables for 8-bit presses. 16-bit variables are accurate and necessary for large architectural objects, but in limited (8-bit) architectures, 16-bit arithmetic is a quick way to instantly discharge RAM and ROM memory.

If you try to increase a 16-bit variable, the compiler will include a 16-bit incremental library, which in most cases consumes a lot of space.

In addition, try not to split or multiply, as for some controllers they are implemented.

Personally, I go through alwais for char , and when you need a split operation, use rotate rigth 'n' times to split 2 n times.

hope this helps!

0
source share

All Articles