You are right about the far pointer, at least on the 2560/2561.  For
normal functions, the gcc linker creates a "trampoline" in the lower 64K
word (128K byte) space of flash.  This is a table of EIJMP (3-byte jump)
pointers to routines in high (> 128K byte) flash.   Once there, RJMP
seems to be used, which avoids specification of a 3-byte address. 
 
You are absolutely right, though, that function pointers in the current
gcc are 2-byte pointers.
 
I'm using FreeRTOS, and have done as you -- I've placed all my
pointer-refererenced routines in low (< 128K) memory.  So far, I've had
little problem with the RTOS getting confused, other than needing to
define my task stacks with 3 byte pointers, and defining the context
switch functions to save/restore the extension bit.  Since I've defined
all of my task routines to be in bottom memory, I can easily push an
extra 0 byte on the task stack at initialization time, and I'm done.
 
BTW, the compiler switches I use are:
 
    #if defined(__AVR_ATmega2560__)|| defined(__AVR_ATmega2561__)

Feel free to email me directly for the m2560-specific FreeRTOS code.
This might help you with your uC/OS-II, although it sounds like you have
that well in hand.
 
In the short term, I think you will need to keep all of your
pointer-referenced functions in low memory, even if all they do is then
call the real function in high memory.
 
One final comment about your last paragraph.  AVR instructions are
addressed by the 16-bit word, not by the 8-bit byte.  So, a 16-bit PC
can address 64 K *words*, or 128 K *bytes*.  It's only in the m2560/2561
with 256 K bytes of Flash do you run into trouble.

Best regards, 

Stu Bell 
DataPlay (DPHI, Inc.) 

 

________________________________

From: [EMAIL PROTECTED]
[mailto:[EMAIL PROTECTED] On Behalf Of
Peter LaDow
Sent: Thursday, February 21, 2008 6:52 PM
To: avr-gcc-list@nongnu.org
Subject: [avr-gcc-list] Function Pointers on AT90USB1287 and ATmega2561


The AT90USB1287 and ATmega2561 push/pop 3 byte PC's with call/ret and
reti.  However, function pointers on these parts seem to be 2 bytes.
 
Compiling the following:
 
typedef void (*FPTR_T)(void);
 
const unsigned char sizeof_fptr_t = sizeof(FPTR_T);
 
Yields the following assembly for both the AT90USB1287 and ATmega2561:
 
sizeof_fptr:
        .byte   2
 
Now I know that the USB1287 only has 128K, so it doesn't need a 3 byte
PC, but the mega2561 could need it.
 
In my specific case, I discovered the problem when trying to get
uC/OS-II to run.  I'm using the port on the Micrium website, and in
OSTaskStkInit (in os_cpu_c.c) it does:
 
OS_STK *OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK
*ptos, INT16U opt)
{
    INT8U  *stk;
    INT16U  tmp;
 
    opt     = opt;            /* 'opt' is not used, prevent warning  */
    stk     = (INT8U *)ptos;  /* AVR return stack ("hardware stack") */
    tmp     = (INT16U)task;
 
    /* "push" initial register values onto the stack */
    *stk-- = (INT8U)tmp;        /* Put task start address on top of
stack */
    *stk-- = (INT8U)(tmp >> 8);
 

Of course this then fails later when using the ret to pop the return
address.  So I modified it to do:
 
    tmp     = (INT32U)task;
 
    /* "push" initial register values onto the stack */
    *stk-- = (INT8U)tmp;        /* Put task start address on top of
stack */
    *stk-- = (INT8U)(tmp >> 8);
    *stk-- = (INT8U)(tmp >> 16);
 
And, voila!  uC/OS starts running fine.
 
However, it works because all of my task entry points are in the bottom
of flash.  If a task entry point were to live beyond the bottom 64K
words, it wouldn't.  Even doing something like this would not work:
 
void foo()
{
  extern void task(void *);
 
  uint32_t addr;
 
  addr = (uint32_t)task;
}
 
Yields the following assembly to set addr:
 
        ldi r24,lo8(gs(task))
        ldi r25,hi8(gs(task))
 
Which still is only a 16-bit pointer.
 
So, how does one get a pointer to a function deep in flash?  I've spent
a considerable amount of time today searching for information on this,
and all I can find is in the AVR LIBC documentation:
 
char is 8 bits, int is 16 bits, long is 32 bits, long long is 64 bits,
float and double are 32 bits (this is the only supported floating point
format), pointers are 16 bits (function pointers are word addresses, to
allow addressing the whole 128K program memory space on the ATmega
devices with > 64 KB of flash ROM).
 
But they apparently aren't words, but half-words.  Am I missing
something here?  Is there a switch I am missing?
 
Thanks for your help,
Pete
-- 
"To love for the sake of being loved is human;  to love for the sake of
loving is Angelic."  -- Alphonse de Lamartine

_______________________________________________
AVR-GCC-list mailing list
AVR-GCC-list@nongnu.org
http://lists.nongnu.org/mailman/listinfo/avr-gcc-list

Reply via email to