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.) ________________________________ From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Dusan Ferbas Sent: Monday, August 04, 2008 8:37 AM To: avr-gcc-list@nongnu.org Subject: [avr-gcc-list] eicall on ATmega2561 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 <http://www.etech.cz/>
_______________________________________________ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list