QE128: Using whole flash memory area for my routines

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

QE128: Using whole flash memory area for my routines

4,809 Views
BasePointer
Contributor II
Hi,
 
I'm using CW 6.1 and I need space bigger than 64K for my functions.
Can you please tell me easiest way of doing this step by step?
 
I looked at QE128 Demos LAP_Dictionary but I did't understant any think at all. I don't have such as huge array. I just want to define some more functions and be able to use them inside my main or interrupt handlers.
 
My current project is using SMALL memory model and I don't know it is really important.
 
Please define MMU and tell QE128 support it?
 
Also, What should I take care of when writting a code after 64K?
 
Thank you,
BP.
 
Labels (1)
Tags (1)
0 Kudos
16 Replies

1,217 Views
CompilerGuru
NXP Employee
NXP Employee
I would suggest to use the banked memory model.
The main thing to look out for are that the interrupt routines have to be explicitly allocated non banked,
pretty much the same way as for the S12 with the banked memory model.

The use of the LAP support as described in the LAP_Dictionary is for large > 16k constants only,
it is not about how to use the 128 for code.

Daniel


0 Kudos

1,217 Views
BasePointer
Contributor II
Hi,
 
I changed the memory model to banked.
 
Now the linker gives an error:
L1907: Fixup overflow in _Vector_17, to intI2C type 1 at offset 0x0
How can I solve this?
Code:
interrupt VectorNumber_Viicx void intI2C(void){ ..}

 
10x
 
0 Kudos

1,217 Views
Lundin
Senior Contributor IV
You get that because all isr addresses in the vector table are now 24 bit instead of 16 bit, as required by the mcu.

Sadly, the only solution is to resort to non-standard C:

void near intI2C(void)

This will force the pointer to be 16-bit.
0 Kudos

1,217 Views
CompilerGuru
NXP Employee
NXP Employee
Actually near does not apply here for multiple reasons.

First, as near changes the calling convention, not the location where it is placed.
For the location as pragma (as noticed by BasePointer) is necessary:
#pragma CODE_SEG __NEAR_SEG NON_BANKED
Second, for interrupt functions as in the question, near as calling convention specifier is against that interrupt handlers have the "interrupt" calling convention. Functions are either near, far or interrupt handlers. I think a near specified for an interrupt handler is ignored.

In usual cases, the location of a function should match where it is allocated,
therefore I would recommend to use a #pragma with an __NEAR_SEG as above to define both
(the calling convention and the placement) at once.
Using __near as calling convention specifier is rarely needed, if the #pragma CODE_SEG is properly used.

Daniel
0 Kudos

1,217 Views
BasePointer
Contributor II
Hi Lundin,
 
I moved all my interrupt handlers to NON_BANKED segment. And finally it was linked successfully. is all that? Can I use whole flash memory area like this without problem?
 
Are all pointer types 24 bit in this mode such as " unsigned char* "? I have some tables defined globally such as "const signed int TempDevtoPpm[] = {...};". Can I freely use TempDevtoPpm[1] in my functions?
 
Thank you.
 
Code:
#pragma CODE_SEG NON_BANKEDinterrupt VectorNumber_Viicx void near intI2C(void){  ..}#pragma CODE_SEG  DEFAULT

 
0 Kudos

1,217 Views
Lundin
Senior Contributor IV
Only function pointers are "24 bit". Meaning, when you use a function pointer or call a function, the compiler will use CALL / RTC rather than JSR / RTS, and it will append the PPAGE address to the CALL automatically.

I suppose you only need to use "near" if you have implemented your vector table in C, ie as an array of function pointers.

Regular pointers are unaffected by the memory model. I would recommend to place both isrs and flash data in non-banked memory, it saves you a lot of fuss. If you don't have room for them there and must place data in banked memory, you need 24 bit pointers. Either the non-standard "far" keyword, or something like this:

/* Disable interrupts without destroying the i-bit in CCR. */

unsigned char cond;

#define SAFE_DisableInterrupts asm PSHA;      \
                               asm TPA;       \
                               asm STAA cond; \
                               asm PULA;      \
                               asm SEI;   
                                
#define SAFE_EnableInterrupts  if(!(cond & 0x10)) \
                                 asm CLI;


#pragma CODE_SEG NON_BANKED_ROUTINES

unsigned char readFromPage (unsigned char page, const unsigned char* address)
{
    unsigned char value;
    unsigned char tmp = PPAGE;
   
    SAFE_DisableInterrupts;

    PPAGE = page;
    value = *address;
    PPAGE = tmp;

    SAFE_EnableInterrupts;

    return value;
}



It is necessary to shut down all interrupts. Otherwise an interrupt may occur after the line setting PPAGE, and the return address from the isr will then be rubbish.
0 Kudos

1,217 Views
CompilerGuru
NXP Employee
NXP Employee
Just wondering, why does this readFromPage need to
disable the interrupts during its read access?
I would think that placing it non banked is mandatory and sufficient.

Daniel

0 Kudos

1,217 Views
Lundin
Senior Contributor IV
As a late reply to this...

I'm not sure if non-banked is sufficient. What happens if you try to CALL an address at for example 0x304000? Will the code end up at 0x4000 or in the middle of nowhere? It is not documented in the manual as far as I know.

From the bottom of my post:

"It is necessary to shut down all interrupts. Otherwise an interrupt may occur after the line setting PPAGE, and the return address from the isr will then be rubbish."

For example:

- Code is running from non-banked at 0x4000.
- Write 0x30 to PPAGE.
- Interrupt occurs.
- Interrupt returns to address 0x304000.

So the reason is "thread safety". The disabling of interrupts will work as a semaphore.
0 Kudos

1,217 Views
CompilerGuru
NXP Employee
NXP Employee
In an interrupt the S08 just stacks and unstacks a 16 bit PC,
so the core resumes at a "local address" (using a S12 term here) of 0x4000.
There is no difference just after the interrupt to just before the interrupt, in both cases the PC is 0x4000
and PPAGE contains 0x30.
There is no "paged/flash" address 0x304000, not before the interrupt and not as return address of the interrupt.
I don't see how why disabling interrupts is necessary here, I don't think it is necessary because of the PPAGE handling. Of course it does not hurt apart from performance and interrupt response time.

>What happens if you try to CALL an address at for example 0x304000?
I don't have the manual in front of me, but when I remember right it states that 0x30 gets loaded into PPAGE and 0x4000 gets set into the PC in one instruction. With this definition of CALL, the affect of a "CALL 0x304000" is just as well defined as a common "CALL 0x048000". A call "CALL 0x304000" calls 0x4000 and sets the PPAGE as side effect.
Therefore a CALL instruction could be used as a efficient way to set and restore the PPAGE instread of the explicit C code inreadFromPage. One restriction is that the PPAGE value is a part of an instruction and therefore this pattern can only be used for link time known addresses (at least for the page address part).

Daniel
0 Kudos

1,217 Views
Lundin
Senior Contributor IV
Ok, RTI from the interrupt is indeed 16 bits. I might have confused things a bit and the scenario I described is perhaps not an issue.

Still, the code for disabling the interrupts needs to be there to make the function re-entrant. PPAGE can be regarded just as a static/global variable. With the interrupts disabled you can safely call the function from inside an interrupt without worrying about ruining any code calling the same function from the main loop.

If you never need to read paged memory from inside interrupts, then the code might be superfluous.
0 Kudos

1,217 Views
CompilerGuru
NXP Employee
NXP Employee
Not saving PPAGE in an interrupt routine is deadly if you ever execute any paged code.
So I would recommend stronly that an interrupt handler which touches PPAGE should save it in the entry code and restore it before returning.
And once every interupt handler does not invalidate the PPAGE (something I was assuming) then the disabling of the interrupts is not necessary.

Daniel
0 Kudos

1,217 Views
HUST
Contributor I

hi ,

         i  attemp to port one project  to "banked mode"  from "small mode"    on  the  08DZ128.

         in small mode ,the project works well  ( code  size about 55k). but link error occured in banked mode.
         the following details  the steps

        Step 1:  initial new project with "banked" mode.
        Step 2:  inport all source code ( .c , .h  and .asm  files)
          Step 3:     rebuilt the .prm
          Step 4:     locate the ISR in non_banked area using #pragma code_seg  ISR_NON_BANKED
                           in c function    including  all others called in ISR
          Step5:      locate the ISR in non_banked area using ISR_NON_BANKED: SECTION in
                           assemble function including all others called in ISR.
          Step 6: link error L1102 out of allocation space in segment APP_CALL_ TABLE at address
                       0xDA80.

         when i check the  .map  show the calltable would occupy more than 50% space. and CallTable1,VectorTable,VectorTable1 similar.

      CallTable                                    0'Error      18      24       0   CALL_TABLE 
      CallTable1                                   0'Error      5D      93       0   CALL_TABLE1
      VectorTable                                  0'Error      18      24       0   ToVectorTable
      VectorTable1                                 0'Error      60      96       0   ToVectorTable1
         

         but as you know, the CallTable  is  capable   of  storing the 8 interrupt vector(16 bytes)
        Actually, i ever tried  to  delet the pointer function, and directly provide the isr vector in .prm, and everything is OK.
       therefore i suppose some setting wrong. pls refer  to the .prm, isr.c and  .map attached!
       Did i make myslef  clear ?

       using _NEAR_SEG will remedy the issue?

        any advice or suggestion will be appreciated!
         
         

0 Kudos

1,217 Views
CrasyCat
Specialist III
Helllo
 
Interrupt function must be implemented in a section with qualifier __NEAR_SEG in C source files
Example:
  #pragma CODE_SEG __NEAR_SEG ISR_NON_BANKED
In assembler source files the sections must also have the qualifier SHORT
 
Example
 ISR_NON_BANKED: SECTION SHORT
 
Place the section ISR_NON_BANKED in non banked memory in the application .prm file
 
Finally make sure you define the vector table as a table of near function pointer:
 
Example:
typedef void (*near tIsrFunc)(void);
tIsrFunc APP_CALL_ TABLE [] = {
....
}
 
That should be it
 
CrasyCat
0 Kudos

1,217 Views
CompilerGuru
NXP Employee
NXP Employee
Small correction. The C part is as Crazycat writes, and that's the main problem here.
Assembly interrupt functions should be however in
a non qualified section allocated in the 64k near area.
The SHORT qualifier is for 8 bit zero page access. There is no assembly qualifier comparable to the C __NEAR_SEG because the assembler does not need this distinction to create code.



Message Edited by CompilerGuru on 2008-11-24 09:57 AM
0 Kudos

1,217 Views
HUST
Contributor I
many thanks!
 
 
0 Kudos

1,217 Views
Navidad
Contributor III
Hi,

If your PRM file is similar to the one generated by the wizard the strings and constants are placed in the non-banked flash. The banked memory model means that all your functions are banked by default, but the data is treated in the same way as in the small memory model. This  means that all the data pointers are by default 16-bit. If you need to place large constants in flash than you need to use __linear pointers to access them (that is what the dictionary example was all about). But note that the compiler offers no support for dereferencing this kind of pointers so you have to use some macros defined in mmu_lda.h or write some inline assembly yourself.

But if you don't have large amounts of constants having only the code banked should suffice and you can go on with your code (yes, you can access TempDevtoPpm[1] in all your functions).

Navidad
0 Kudos