|
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 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 |
[Prev in Thread] | Current Thread | [Next in Thread] |