avr-gcc-list
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: [avr-gcc-list] Function Pointers on AT90USB1287 and ATmega2561


From: Stu Bell
Subject: RE: [avr-gcc-list] Function Pointers on AT90USB1287 and ATmega2561
Date: Fri, 22 Feb 2008 08:50:59 -0700

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: address@hidden [mailto:address@hidden On Behalf Of Peter LaDow
Sent: Thursday, February 21, 2008 6:52 PM
To: address@hidden
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

reply via email to

[Prev in Thread] Current Thread [Next in Thread]