function pointer for atxmega128a1 (or big ATMEGAs)

Go To Last Post
10 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why does this

typedef void (*PointerToFuncInFlash)( void * );

generates a 2-byte-pointer?

To cover the whole flash memory I need at least a 3-byte-pointer. I need this for porting an OS. My OS proceeds a task switch with an Assembler 'RET'. And the RET reads out 3 bytes from stack. So how can I get a 3-byte-function-pointer?

/Christoph

(BTW: I try to port FreeRTOS for the XMEGA)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There are a lot of other threads that discuss this problem...so you will probably want check those out.

Short answer...function pointers with GCC are two bytes. This will work just fine for up to 128K bytes of flash (64K words).

There are other things you can do to minimize the effects of this on bigger parts.

And parts with 128K bytes of flash read 2 bytes from the stack on return, bigger parts read 3...kind of a pain...be can be delt with.

-Jim
http://www.noniandjim.com
Analog and Digital Electronics
Music Synthesizers

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, Jim. I read a lot of threads about flash pointers. And I learned that GCC only supports one pointer size (AVR-GCC: 16 bit). So is the only solution for me to switch to IAR? :?

(Or maybe I have to think about another RTOS than FreeRTOS...?)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But anyone using mega2560 has already faced this. I think it's Stu who's got a working system (in fact I think it's FreeRTOS he's using) so hopefully he'll be along in a minute with more detail. Or you may want to alert him to this thread with a PM to Stu_San

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Unless you're doing some tricky things like modifying the default value of EIND or relocating the entire .text section (eg. while writing a bootloader), 16-bit function pointers will work OOTB in conjunction with trampolines located in the lower half of memory to provide indirect access to the entire program space. I know this is true of the larger ATmega parts; I don't have first-hand experience with the Xmega series.

I have never personally used FreeRTOS, so you'll probably want to defer to the voice of experience (Stu) when he comes along. But here's my expectation:

When the OS is processing a command to start a new task, I suppose you could use a function pointer to obtain the lower 16 bits of the starting address of that task's trampoline. Then, because the trampolines are always located at the beginning of Flash, you can assume that the upper 8 bits of the trampoline's address are all zeros.

During subsequent context switches, the full 3-byte return address of the actual thread of execution will be pushed and popped as expected.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

lfmorrison wrote:
During subsequent context switches, the full 3-byte return address of the actual thread of execution will be pushed and popped as expected.
This is correct. The problem is not the task switch but the creation of a task. For this FreeRTOS needs a function pointer. As a kind of workaround for the task creation I push the 2-byte function pointer on the stack and add a 0x00 (the task/thread is started with a 'RET'). But in this case I have to ensure that the task/thread functions are located in the lower 64k.

FreeRTOS works now on my XMEGA and I can live with this restriction. But nevertheless I am interested in other (better?) solutions.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ce wrote:
The problem is not the task switch but the creation of a task. For this FreeRTOS needs a function pointer. As a kind of workaround for the task creation I push the 2-byte function pointer on the stack and add a 0x00. But in this case I have to ensure that the task/thread functions are located in the lower 64k.

The trampolines should take care of this in the larger ATmega parts by providing an alternate indirect entry point for every function in the lower 64K, regardless of the location of the main bodies of those functions. When you take the address of a function and assign it to a function pointer, the linker automatically substitutes the address of the trampoline where applicable.

I would expect the same to be true with the Xmegas.

(Have you tried it yourself to see what actually happens when you attempt to access a task which has been intentionally positioned beyond the 64K boundary?)

BTW, in this case, "64K" correctly refers to 65536 instruction addresses (or "words"), which is actually 131072 bytes.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

lfmorrison wrote:
BTW, in this case, "64K" correctly refers to 65536 instruction addresses (or "words"), which is actually 131072 bytes.
Ooops. :oops:
I am working with AVRs for about 5 years, but not exclusively. I always had smaller devices (tiny, ATMega164p and so on). And it was never necessary to have a closer look at the assmbler ocde and the memory setup. I concentrated myself on peripheral hardware registers (Timer, TWI,SPI UART, ADC and so on). This is something that I should have known. :oops:

This means the above mentioned workaround works in every case for my ATXmega128A1 (also ATXmega64A1). I would encounter the problem only with future devices like ATxmega192A1, ATxmega256A1 and ATxmega384A1.

And now I also understand what you mean with 'trampoline'. But I cannot test it because I only have 128k flash (which is addressed with 64k addresses)

Thanks to lfmorrison and sorry for my lack of knowledge. :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry, my work has kind of exploded so I haven't been following AVR Freaks as much this week.

Yes, you need to hack the task initializer to handle the 3-byte function pointer. Luckily, I've already done that :wink:. I've attached my FreeRTOS code. The initializer assumes that all task routines are in lower memory (0x0000xxxx) -- essentially it just pushes an extra 0 byte onto the stack when initializing the task stack. This could be modified, but it's pretty easy to put all of your task routines in bottom memory (hint below).

The context switch also needs to store a little more than on a 2-byte PC machine, so those routines are changed as well.

Once the task routine starts, the other routines can exist where ever you want since the linker will take care of jumping to them properly.

Now, I also use function pointers for routines pointed at by the parser. I store those pointers in flash, so I need to make sure they dereference properly. I get around the 2-byte pointer problem by forcing all of these routines into lower memory. Each "command routine is declared as:

typedef CmdError (*CmdProc) ( CmdPacket* pCmdPkt );

#define COMMAND_HANDLER   __attribute__ ((section (".fptr_target")))

. . .

CmdError 
CmdGetVersion( CmdPacket* pCmdPkt ) COMMAND_HANDLER;

Thus each "command" function is in the linker section .fptr_target. The linker script puts that section before the main .text section:

  .text :
  {
    *(.vectors)
    KEEP(*(.vectors))
. . .
    KEEP (*(.init7))
    *(.init8)
    KEEP (*(.init8))
    *(.init9)  /* Call main().  */
    KEEP (*(.init9))
    /* Interrupt Service Routine code needs to be in the lower 128K program */
    *(.isr)
    KEEP(*(.isr))
    /* Any code that is the target of a function pointer must also 
       reside in lower memory */
    *(.fptr_target)
    KEEP(*(.fptr_target))
    /* An RTOS task should also be in low mmeory. */
    *(.task)
    KEEP(*(.task))
    /* Main code starts here - this code can oveflow into the upper 128K program */
    *(.text)
    . = ALIGN(2);
    *(.text.*)
    . = ALIGN(2);
    *(.fini9)  /* _exit() starts here.  */
    KEEP (*(.fini9))

Note that I also force the FreeRTOS task routines to be in lower memory, although I haven't decided whether this is really needed or not.

I don't have enough time to really go through this right now, but this should get you started. PM me with other questions, or post here and I will (eventually :oops:) reply.

Stu

Attachment(s): 

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Stu,
this helps a lot. I like your smart solution with the 'COMMAND_HANDLER' macro.
But the most important thing is: It works! :D

/Christoph