Quality RTOS & Embedded Software

 Real time embedded FreeRTOS RSS feed 
Quick Start Supported MCUs PDF Books Trace Tools Ecosystem


PIC18 heap issue

Posted by lcj on December 20, 2008

From the PIC MPLAB port for 18F4520 thread...

Re-state in as few words as possible? What are you trying to say? :)

I think I may be on my own, but here's my issue. John Franklin's attempt to solve this problem is in the FreeRTOS doc's along with a link to his solution. I don't see how his solution can work, and suspect that it worked for him by fluke. This, I hope, means I don't understand it, not that it won't work.

The issue is specific not to PIC18 peripherals but to the PIC18's internal RAM. Memory is organized in 256 byte banks. The manual for the linker (MPLINK, not the C18 compiler) specifically says not to combine banks as the compiler won't generate code that can navigate across a bank boundary. For instance a 32-bit variable might live at 0x1fe:0x201.

Here's what I'm hoping for: If you must combine banks into a large section, you can protect the space (use PROTECTED keyword in linker command file) and allocate it to the heap with the right #pragma directives and section assignments wrapped around said heap declaration. This will allow pointers and arrays to grow past 256 bytes with proper addressing.

Where I see it going pear-shaped is that the heap is not a single array, but a space into which variables are allocated. If this is the case, I can't see how this will ever work, other than by providence. Is there something I don't get about how space is allocated to variables on the heap? I'm really struggling to understand this.

OK, so I failed to keep it short, it's not that easy of a problem to explain.


RE: PIC18 heap issue

Posted by mike on December 23, 2008
Hello Lawrence

As I understand the Microchip C18 compiler/linker, the compiler assumes that the variables in a single file live in the same page of RAM, and doesn't use the bank select register for these accesses. Similarly an array or structure must not span more than one page (256 bytes) (no use of bank select).

However when variables are accessed via pointers, they can exceed the 256 byte limit. To allow this, the linker must be told of some large area that can be used.

To avoid the linker putting 'ordinary' variables into these larger areas, they must be 'PROTECTED' ie only specified variables can be put into this area.

The heap is always doled out as pointers, so should always be safe.

The stack (by default) also is assumed to be within one page. The compiler will complain is one function places too much stuff on the stack, but not (of course) if further calls break the size limit. There is a compile time option for a larger stack, under Build Option/MPLAB C18, category Memory Model called Stack Model is Multibank, which is selected for the demo projects.

So everything should be safe.

I am using freeRTOS on the atmel SAM7S, and have not used the Microchip version although I have used the PIC18s quite extensively.

Best regards

Mike Newsome
Hitek Power Ltd England

RE: PIC18 heap issue

Posted by mike on December 23, 2008
I have had another look at the rtos demos (in v5.1.0) and notice that the region BIG_BLOCK is not PROTECTED, which means the compiler can allocate any variables here, and not necessarily generate bank select statements to access them.

So I think that a region of RAM should be allocated (say called 'BIG_BLOCK') to use for that purpose, which must be PROTECTED:

This needs to be connected to a section:

Some RAM is needed to be declared outside this protected area for users global and static allocations:

The definition of the heap (in heapx.c) needs to identify to the linker that that section should be used:
#pragma udata HEAP
static struct xRTOS_HEAP
unsigned portLONG ulDummy;
unsigned portCHAR ucHeap[ configTOTAL_HEAP_SIZE ];
} xHeap;
#pragma udata

Note that the heap is 4bytes larger than configTOTAL_HEAP_SIZE because of the ulDummy used for byte alignement purposes, and the STACK is declared in here also.

I think the demos ought to be adjusted with these changes in mind. It seems to be accidental that they work, and may not do when a user starts adding his/her code. It is difficult to find the problem of incorrect bank access.

As a final question, what is the STACK region that is declared in the linker used for? As I understand it, this is only used by the start up code prior to running tasks, and could possibly be used as part of the system RAM after this time.

Best regards

Mike Newsome
Hitek Power Ltd England

RE: PIC18 heap issue

Posted by Richard on December 23, 2008
Excellent information! Could you send your new linker script to r (dot) barry [at] freertos.org so I can ensure I get the changes correct. I can then check it into SVN to ensure it is included in the next release.

Thanks for taking the time to make this contribution to the project.


RE: PIC18 heap issue

Posted by lcj on December 24, 2008
Yes, you're right, the BIG_BLOCK region is not protected. IIRC, if you use the PROTECTED keyword, you have to explicitly assign variables to the space, as the linker won't touch it. You can cheat by declaring the BIG_BLOCK region to be just big enough to hold the heap. The linker will figure out that the only place the heap can go is into that space, and give you the same result.

Looking at the example in the compiler manual, I get the impression that the pagesel directives are related to how the array is accessed, not how the array is declared. I admit I haven't tried compiling with or without the #pragma and/or PROTECTED keywords.

The trouble is that the correct (only?) way of accessing the multi-bank array is via a pointer. If variables are allocated from the heap, presumably you won't be accessing them exclusively via pointers. If I'm wrong on this, it means I'm ignorant (wouldn't be the first time) and don't understand how the heap is really used. Reading the manual for FreeRTOS, it looks like it's the Kernel that uses the heap to allocate space for tasks, queues, and semaphores. Is the allocated space strictly addressed via pointers? If so, the pagesel directives should be included and all should be well. I'm still grappling with this.

The STACK region is supposed to be for the software stack (not the hardware call-stack). Local variables and function parameters are stored to it (anything with storage class auto). See section 11.7 and the glossary of the linker manual. You have to explicitly tell the linker where to put the stack. The PROTECTED keyword is not required for this, just the linker command file STACK declaration.

If you want a stack bigger than a bank, there's information on this in the compiler manual. When specifying STACK in the linker script, first combine the number of sections you want, much like the BIG_BLOCK declaration for the heap. In this case, you MUST specify the PROTECTED keyword, unlike with a smaller stack. Specify STACK as before, assigning it to the bigger space just created. When compiling (not linking), specify -ls on the command line. This causes pagesel directives to be included when addressing the stack.

So, you can't use the stack space for anything else, your program's using it.

RE: PIC18 heap issue

Posted by lcj on December 31, 2008
On the issue of the stack, my confusion continues. The stack is defined in the linker command file as being less than 1 section:

STACK SIZE=0x80 RAM=gpr15

Given the stack is less than 256 bytes, the -Ls option is not required when compiling.

I have tried compiling with and without this option, and...the 1st demo won't run without the -Ls option set. wtf?!? In the scheduler, the program appears to get stuck here:

for( pxIterator = ( xListItem * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext )
/* There is nothing to do here, we are just iterating to the
wanted insertion position. */

Can anybody explain why I need the -Ls option if I never use the compiler-generated software stack, once the scheduler has started?

RE: PIC18 heap issue

Posted by mike on January 5, 2009

When the scheduler is started, all tasks use individual stacks located in the heap, with a size allocated when each task is started, and the system stack is no longer used. Since we don't know where the actual stack will be, nor how large we must use the -ls flag to ensure the compiler produces proper code to use 16 bit stack accesses.

This is why I wondered if the system stack space could be used by the heap manager.

Possibly if no task stack crosses a page boundary, the flag could be dropped, but enforcing this would be difficult.

RE: PIC18 heap issue

Posted by mike on January 5, 2009
Hello lcj

Variables allocated from the head can only be accessed via pointers, as absolute addresses cannot be defined at run time. So there should be no problem with accesses.

According to the manual, the -ls flag causes 16 bit arithmetic to be done for push/pop, rather than sungle byte when the stack is within a page.

Finally, the stack is accessed via the frame pointer (FSR2) which doesn't use the banksel register, as it a 16 bit wide register.

Hope all this helps - it has certainly helped me trying to explain it all!

Best regards, and wishes for the new year


RE: PIC18 heap issue

Posted by lcj on January 6, 2009
Hi Mike,

Thank-you, great information! I got out your point about the stack not being used a couple of days after your original post. I'm a little slow on the uptake. :)

The only use I can see is that if the scheduler can't allocate enough space for everything, it will return to main(). If you want to do something at this point, like display a message on an LCD or send a message off through one of the processor ports it might be nice to still have a stack, since I think any variables declared within main() will still be sitting there.

Running the RTOS and getting "Error, return from scheduler" on the LCD is annoying but at least I'm not left wondering what went wrong.

Just to be clear though, which stack is accessed via FSR2, the task stack allocated from heap space or the stack as defined by the compiler? I thought push/pop instructions used bank select registers, hence the compiler explanation of the -ls option. This implies push/pop instructions are used for each task's stack. Aren't bank select registers still required in this case?


[ Back to the top ]    [ About FreeRTOS ]    [ Privacy ]    [ Sitemap ]    [ ]

Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.

Latest News

FreeRTOS v10.2.1 is available for immediate download. MIT licensed, includes 64-bit RISC-V, NXP Cortex-M33 demo, Nuvoton Cortex-M23 demo & STM32H745 dual core (AMP) demo.

NXP tweet showing LPC5500 (ARMv8-M Cortex-M33) running FreeRTOS.

View a recording of the "OTA Update Security and Reliability" webinar, presented by TI and AWS.


FreeRTOS and other embedded software careers at AWS.

FreeRTOS Partners

ARM Connected RTOS partner for all ARM microcontroller cores

Cadence Tensilica Cortes

Espressif ESP32

IAR Partner

Microchip Premier RTOS Partner

RTOS partner of NXP for all NXP ARM microcontrollers





STMicro RTOS partner supporting ARM7, ARM Cortex-M3, ARM Cortex-M4 and ARM Cortex-M0

Texas Instruments MCU Developer Network RTOS partner for ARM and MSP430 microcontrollers

OpenRTOS and SafeRTOS

Xilinx Microblaze and Zynq partner