We write C code in an object oriented manner for our S12XE-based units.
This means that all the functions take pointers to data as arguments.
This way we produce nice, portable, reusable and testable code. And we have a lot of it.
We recently needed to create a multi-CAN router capability.
That meant that we needed to have a lot of message buffers of considerable size.
So we ended up having around 10kB of RAM consumed.
By default, only 8kB of non-paged RAM is available in the CodeWarrior project.
I added page FC to get additional 4kB of RAM (additionally to already available 8kB of non-paged area between 0x2000 and 0x4000 address space).
In linker file (.prm) this page is assigned to DEFAULT_RAM segment, so we have it like this:
SEGMENTS /* Here all RAM/ROM areas of the device are listed. Used in PLACEMENT below. */ RAM = READ_WRITE 0x2000 TO 0x3FFF; ROM_C000 = READ_ONLY 0xC000 TO 0xFEFF; PAGE_E0 = READ_ONLY 0xE08000 TO 0xE0BFFF; PAGE_E1 = READ_ONLY 0xE18000 TO 0xE1BFFF; PAGE_E2 = READ_ONLY 0xE28000 TO 0xE2BFFF; PAGE_E3 = READ_ONLY 0xE38000 TO 0xE3BFFF; PAGE_E4 = READ_ONLY 0xE48000 TO 0xE4BFFF; PAGE_E5 = READ_ONLY 0xE58000 TO 0xE5BFFF; PAGE_E6 = READ_ONLY 0xE68000 TO 0xE6BFFF; PAGE_E7 = READ_ONLY 0xE78000 TO 0xE7BFFF; PAGE_F8 = READ_ONLY 0xF88000 TO 0xF8BFFF; PAGE_F9 = READ_ONLY 0xF98000 TO 0xF9BFFF; PAGE_FA = READ_ONLY 0xFA8000 TO 0xFABFFF; PAGE_FB = READ_ONLY 0xFB8000 TO 0xFBBFFF; PAGE_FC = READ_ONLY 0xFC8000 TO 0xFCBFFF; PAGE_FE = READ_ONLY 0xFE8000 TO 0xFEBFFF; RAM_FC = READ_WRITE 0xFC1000 TO 0xFC1FFF; END PLACEMENT /* here all predefined and user segments are placed into the SEGMENTS defined above. */ _PRESTART, STARTUP, ROM_VAR, STRINGS, NON_BANKED, COPY INTO ROM_C000; DEFAULT_ROM INTO PAGE_FE, PAGE_FC, PAGE_FB, PAGE_FA, PAGE_F9, PAGE_F8, PAGE_E7, PAGE_E6, PAGE_E5, PAGE_E4, PAGE_E3, PAGE_E2, PAGE_E1, PAGE_E0; DEFAULT_RAM INTO RAM, RAM_FC; END
I got linked warning L1128: Cutting value _Range beg data member from 0xFC1000 to 0x1000.
This means that linker placed some RAM data into address 0x1000 instead of 0xFC1000 because no __FAR_DATA compilation macro has been added to compilation command.
Anyway this will work now because page FC is mapped to 0x1000 address so refering to data at address 0x1000 actually refers to data at address 0xFC1000.
But this will not work when we need more pages (FD and so on).
According to Technical Note TN 238 to use more RAM pages I should mark my data (variables) with special pragma like:
#pragma DATA_SEG __RPAGE_SEG PAGED_RAM unsigned char rub_far_var; #pragma DATA_SEG DEFAULT
#pragma DATA_SEG __GPAGE_SEG PAGED_RAM unsigned char rub_far_var; #pragma DATA_SEG DEFAULT
to tell compiler/linker to place that data into RAM pages.
This is not nice (portability) but acceptable.
What is not acceptable is that to reffer to this data with a pointer, that pointer has to be specially qualified like:
unsigned char * __rptr ptr_on_far_var;
unsigned char *__far ptr_on_far_var;
This means that all our libraries that use non-qualified ("normal") pointers will not work with data allocated to paged RAM.
I checked that and this is true, for data allocated to address 0xFC1020 its pointer inside one of our libraries will show address 0x1020...
So effectively for us we can only reach 12kB of RAM memory even if we use S12XEP that has 64kB of RAM...
Otherwise our libraries won't work.
It is not possible to rewrite those libraries to have (for example) far pointers because they will stop compiling on other targets (windows, linux, other MCUs)...
Did anyone of you faced this kind of problem?
Do you have any idea what to do now?
We are lucky we needed "only" 10kB.
I don't know what would happen if we needed more than 12kB of RAM...
But I know I need to figure something out because some new projects will require lot more RAM...
Should we start to think about looking for another MCU?
Waiting for your ideas.
The S12XE has a neat feature that allows the lower fixed page of Flash (0x4000 - 0x7fff) to be replaced with RAM. This allows access of 24K of contiguous RAM in the local map from 0x2000 - 0x7fff. Setting the ROMHM and RAMHM bits in the MMCCTL1 register will replace the Flash with RAM.
The RAM segment definition would change to:
RAM = READ_WRITE 0x2000 TO 0x7FFF;
In the compiler options you would need to set the 'MAP' option as shown here:
I believe setting this option will automatically set up the MMCCTL1 register in the startup code, but you should check.
You also need to make sure that a segment definition for Flash in the 0x4000 - 0x7fff area does not exist in the .prm file.
Note that this does not require the use of the Large memory model.
Hope this helps.
nice idea with RAMHM, but RAMHM=1 bit description tells this
If this is correct, then 0x2000..0x3FFF and 0x6000..0x7FFF should be identical instances of the same physical RAM. So not 24k, but only 16k, right?
With RAMHM=1, fixing RPAGE to 0xB it is possible to have contiguous 20k RAM at 0x1000..0x5FFF.
No, there is 24K of RAM available in the local map from 0x2000 - 0x7fff and if the RPAGE window isn't needed to access the remaining RAM (it could still be accessed via GPAGE addressing), a total of 28K is available from 0x1000 - 0x7fff if the RPAGE register is set to 0xf9 and not changed. Take a look at these two tables from Section 184.108.40.206, Memory Configuration, of the MC9S12XE-Family Reference Manual Rev. 1.25:
Not really true. There must be some target specific predefined macros enabled like __MWERKS__ or something. Then instead of __far you use some FAR macro, which using few #if #else's should be tuned for specific target. Not very nice, but doable and portable.
Thanks for commenting Edward :smileyhappy:
So we really can't do anything else than creating dedicated macro for pointer qualification?
I understand that it is possible to write new module this way but what I meant is that it is not possible to rewrite ALL our EXISTING libraries, seems like a nightmare... :smileyplain:
Did you try to use large memory model? Code will be slower, but data pointers will be "far" by default. You existing code should work.
S12XE project wizard shows large memory model grayed, use custom instead and keep settings on the next wizards page default. You should verify memory model looking at compiler command line string, -Ml should be there.