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

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

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


From: Peter LaDow
Subject: [avr-gcc-list] Function Pointers on AT90USB1287 and ATmega2561
Date: Thu, 21 Feb 2008 17:51:45 -0800

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]