[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
RE: [avr-gcc-list] eicall on ATmega2561
From: |
Stu Bell |
Subject: |
RE: [avr-gcc-list] eicall on ATmega2561 |
Date: |
Mon, 4 Aug 2008 09:02:40 -0600 |
This is not a complete answer to your problem, but it's mostly
there.
Following is the code I use to call my DownloadFirmware entry point in
the bootloader:
/* We don't care about a result because we'll be reloaded
and never
* come back to this point.
*
* We have to assemble this instruction because we're
using an ATmega2560,
* and have to address the high memory
in flash. That means the address
* of
AppDownloadFirmware MUST be 0x1F400 (0x3E800, byte addressed).
*/
// AppDownloadFirmware();
asm volatile (
"ldi r24,
0x01 \n\t"
"out 0x3C,
r24 \n\t"
"ldi r30,
0x00 \n\t"
"ldi
r31,
0xf4 \n\t"
".word
0x9519 ;eicall \n\t"
);
The reason I say
this is "incomplete" is that I know the call to AppDownloadFirmware() in the
bootloader will not return. Instead, the firmware will be overwritten and
the CPU reset. That means I don't care about clobbered registers.
Also, the jump location is hardwired.
You can take this to
the next step by making this an inline function, passing in the function
address, and protecting the registers you clobber so the processor can return
(if you want).
Also, when I
wrote this, the inline assembler did not grok the EICALL instruction so I had to
hand-assemble it. You may be able to just use the instruction
now.
I hope this
helps!
Best
regards,
Stu Bell
DataPlay
(DPHI, Inc.)
Hi,
we are trying to call a bootloader function from
application. According to data, different function is used there (eeprom, flash,
SPI flash).
We have a problem, because it does not work. I consulted with
Andy Hutchinson a while ago, we investigated little more, but something more is
needed :-).
In other words it looks like EIND seeding does not
work.
Are we missing to setup something ?
Is there a way, how to
say to a GCC compiler, that asm part modifies specific regs ?
For AVR, they
are used to pass arguments.
Or is it a better way to create an inline
function ?
...
it did not work leaving all work to compiler
(WinAVR-20080610 used)
-----------------------------------------
unsigned char eind_local = EIND;
EIND = 0x3F800 >> (16 + 1);
//highest LoadAddr bits (for Atmega2561 == 1, because it is a word
address)
BootInfoHeader->fn[id](address, p_data, size);
EIND = eind_local;
to be sure, what is happening (EIND seeding and
restore left in C)
---------------------------------------
unsigned short
call_address = (unsigned short)BootInfoHeader->fn[id];
asm volatile
(
"movw r30,%3" "\n\t" //indirect
call
"push r20" "\n\t"
//preserve regs, used for args
"push r21"
"\n\t"
"push r22" "\n\t"
"push r23"
"\n\t"
"movw r20,%0" "\n\t" //load
args
"movw r22,%1" "\n\t"
"movw
r24,%2" "\n\t"
"eicall" "\n\t"
"pop
r23" "\n\t" //restore
regs
"pop r22" "\n\t"
"pop r21"
"\n\t"
"pop r20"
::
"r" (size),
"r"
(p_data),
"r" (address),
"r"
(call_address)
);
the only way, how it works (push
return address, push call address and make a "ret" to it, EIND is not
needed)
-------------------------------------
unsigned char low_address =
call_address & 0xFF;
unsigned char high_address = (call_address >>
8 ) & 0xFF;
unsigned char low_pc =
0x38;
//computed from .lst and
.map
unsigned char high_pc = 0xFA;
asm volatile (
"push r20"
"\n\t"
"push r21" "\n\t"
"push r22" "\n\t"
"push
r23" "\n\t"
"push %5" "\n\t"
"push %6" "\n\t"
"ldi
r20,lo8(1)" "\n\t"
"push r20" "\n\t"
"push %3"
"\n\t"
"push %4" "\n\t"
"push r20" "\n\t"
"movw
r20,%0" "\n\t"
"movw r22,%1" "\n\t"
"movw r24,%2" "\n\t"
"ret" "\n\t"
"pop r23" "\n\t"
"pop r22"
"\n\t"
"pop r21" "\n\t"
"pop r20"
::
"r"
(size),
"r" (p_data),
"r" (address),
"r"
(low_address),
"r" (high_address),
"r" (low_pc),
"r" (high_pc)
);
Dusan Ferbas
www.etech.cz