nobody wrote on Saturday, March 26, 2005:
Using the freeRTOS PIC18 port. MPLAB C18 memory model set for: Small code model, large data model, multi-bank model. I.e. as per freeRTOS demos.
I have discovered what I think is a problem with the linker script used with the PIC port of freeRTOS.
This only showed up recently, despite the fact that I have been using freeRTOS for many weeks. I discovered that by declaring an arbitrary char array of a particular length, I could make my application fail to run correctly. Investigation revealed that variables defined in tasks.c were not being correctly addressed by the code generated by the C18 compiler. This was only a problem if task.c defined variables crossed a bank boundary, hence the dependence on the size of my char array.
The RAM data defined in a C source file is placed in a section specific to the source file. I.e. the RAM data defined in tasks.c is placed in either idata_tasks.o or udata_tasks.o The linker will place this in one of the data memory regions defined in the linker script. The linker ensures that a section will never cross a region boundary, they will always be placed in just one region. However, it is a requirement of the C18 compiler that every section is located within a single bank. If there is a region that spans more than one bank, it is possible that the section placed in this region will end up crossing a bank boundary. This causes the compiler generated variable access code to fail. The following is an extract from the MPLAB linker manual:
You must not combine data memory regions when using MPLINK Linker with MPLAB C18 C compiler. MPLAB C18 requires that any section be located within a single bank.
As the freeRTOS linker script defines one large area crossing multiple banks, the linker will place sections within this area, without restraining them to separate banks.
The default freeRTOS heap size is 1024 bytes long, leaving just two banks for variables. I suppose it is therefore unlikely that a section will finish up crossing a bank boundary. I had reduced the heap size to make more room for global variables. Perhaps this is why this problem appears not to have been experienced by others.
My fix, which admittedly lacks elegance, is as follows:
Mod the heap_1.c file to place the heap in a section named heap_section.
#pragma udata heap_section
static struct xRTOS_HEAP
unsigned portLONG ulDummy;
unsigned portCHAR ucHeap[ portTOTAL_HEAP_SIZE ];
Change the linker script to:
CODEPAGE NAME=vectors START=0x0 END=0x39 PROTECTED
CODEPAGE NAME=page START=0x3A END=0x7DBF
CODEPAGE NAME=debug START=0x7DC0 END=0x7FFF PROTECTED
CODEPAGE NAME=idlocs START=0x200000 END=0x200007 PROTECTED
CODEPAGE NAME=config START=0x300000 END=0x30000D PROTECTED
CODEPAGE NAME=devid START=0x3FFFFE END=0x3FFFFF PROTECTED
CODEPAGE NAME=eedata START=0xF00000 END=0xF000FF PROTECTED
ACCESSBANK NAME=accessram START=0x0 END=0x7F
DATABANK NAME=gpr0 START=0x80 END=0xFF
DATABANK NAME=heapregion START=0x100 END=0x3FF PROTECTED
DATABANK NAME=gpr4 START=0x400 END=0x4FF
DATABANK NAME=gpr5 START=0x500 END=0x5F3
DATABANK NAME=dbgspr START=0x5F4 END=0x5FF PROTECTED
ACCESSBANK NAME=accesssfr START=0xF80 END=0xFFF PROTECTED
SECTION NAME=CONFIG ROM=config
SECTION NAME=heap_section RAM=heapregion
STACK SIZE=0x60 RAM=gpr4
If the heap size exceeds the heap_region defined in the linker script, the linker will complain. However, it is possible to waste precious RAM by defining the heap to be significantly smaller than heap_region. It is therefore advisable to ensure that the size of heap_region is only slightly larger than the actual heap size. I would appreciate learning of a more elegant solution.
As all heap allocated data is accessed via pointers, Im assuming that there is no bank problem here, but would like confirmation.