EICALL from app to bootloader on atmega 2560 jumps to address 0x1FE01 without EIND set

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

The Optiboot bootloader offers for the application a call to do_spm function and has an Arduino example. I test it on atmega2560, so a hard way, because the bootloader is far away.


In the example the flash pages are allocated as PROGMEM byte array. It worked. The I modified the example and tested with different addresses in flash. It worked until byte address 0x1FC00. There it crashed. After that the example worked again on lower address only after new flashing of the bootloader. I still don't know why it happened, but I think is related to next part.


I want to add to Optiboot a function to copy flash pages. I am not the first. This PR on github supposedly has it for 328p. The do_sdm is located by 'vector' table at the beginning of the bootloader in pre-main section. The header file in example locates the function as const do_spm_t do_spm = (do_spm_t)((FLASHEND-1023+2)>>1); So I added my function to the 'vector table', I used (FLASHEND-1023+4)>>1 and it crashes. It crashed even when I add do_sdm second time and locate it as (FLASHEND-1023+4)>>1 . So I looked really under the hood. I don't understand how it works at all. In assembly there is a EICALL instruction. ZH and ZL are set, but EIND is not set. So how does it jump to word address 0x1FE01 and executes the do_spm function there?


from bootloader source


void pre_main(void) {
  // Allow convenient way of calling do_spm function - jump table,
  //   so entry to this function will always be here, indepedent of compilation,
  //   features etc
  asm volatile (
    "    rjmp    1f\n"
    "    rjmp    do_spm\n"


from application lst

00000c5e <_Z10do_spm_climhj>:
     c5e:	cf 92       	push	r12
     c60:	df 92       	push	r13
     c62:	ef 92       	push	r14
     c64:	ff 92       	push	r15
     c66:	cf 93       	push	r28
     c68:	dc 01       	movw	r26, r24
     c6a:	cb 01       	movw	r24, r22
     c6c:	64 2f       	mov	r22, r20
     c6e:	cf b7       	in	r28, 0x3f	; 63
     c70:	f8 94       	cli
     c72:	6d 01       	movw	r12, r26
     c74:	ee 24       	eor	r14, r14
     c76:	ff 24       	eor	r15, r15
     c78:	cb be       	out	0x3b, r12	; 59
     c7a:	a9 01       	movw	r20, r18
     c7c:	e1 e0       	ldi	r30, 0x01	; 1
     c7e:	fe ef       	ldi	r31, 0xFE	; 254
     c80:	19 95       	eicall
     c82:	cf bf       	out	0x3f, r28	; 63
     c84:	cf 91       	pop	r28
     c86:	ff 90       	pop	r15
     c88:	ef 90       	pop	r14
     c8a:	df 90       	pop	r13
     c8c:	cf 90       	pop	r12
     c8e:	08 95       	ret

I attached the example with my modification. sorry for the Arduino example. and the complete lst file of the example application is attached too


This topic has a solution.
Last Edited: Mon. Dec 31, 2018 - 12:00 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Did you see this example, where the existing do_spm() code has an API wrapped around it that explicitly sets RAMPZ/etc?


Presumably something similar is needed for the new vector.



This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I ask about function call, not about data access. it behaves as if in the middle of the flash at word address 0xFE01 (byte address 0x1FC02) were a trampoline that forwards the jump to word address 0x1FE01 (byte address 3fc02 of the do_sdm 'vector table') and as if the trampoline was deleted if I write to page at byte address 0x1FC00 with do_spm (or to any page above 0x1FC00). but at that address is at default only FFFFFFFF. has 2560 some logic that makes it EICALL to 0x1FE01 if at 0xFE01 is FF? and why for 0x1FE01 and not for 0x1FE02?




FFFF behaves like SBRS R31 (https://www.avrfreaks.net/forum/...). so that is why 0x1FE02 doesn't work


conclusion. the call to do_spm at atmega 2560, jumps to word address 0xFE01 finds FFFF interpreted as skip one word if bit set. it is set so it execute every other FFFF in the rest of the flash until bootloader where it hits the rjmp to do_sdm. it 'works' unless I write something in the flash above word address 0xFE01. for 0x1FE02 it executes every FFFF and hits the rjmp to bootloader main at 0xFE00



Last Edited: Wed. Jan 2, 2019 - 06:47 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

info about EIND https://gcc.gnu.org/onlinedocs/gcc-4.9.4/gcc/AVR-Options.html#index-g_t_0040code_007bEIND_007d-1308


the solution

void do_spm_cli(uint32_t address, uint8_t command, uint16_t data) {
  uint8_t sreg_save;

  sreg_save = SREG;  // save old SREG value
  asm volatile("cli");
  // disable interrupts
#ifdef RAMPZ
  RAMPZ = (address >> 16) & 0xff;  // address bits 23-16 goes to RAMPZ
#ifdef EIND // AVR with more then 128 kB flash
  uint8_t eind = EIND;
  EIND = FLASHEND / 0x20000; // bootloader is in the last 0x20000 words of the flash
  do_spm((address & 0xffff), command, data); // do_spm accepts only lower 16 bits of address
#ifdef EIND
  EIND = eind;
  do_spm(address, command, data); // 16 bit address - no problems to pass directly
  SREG = sreg_save; // restore last interrupts state
Last Edited: Mon. Dec 31, 2018 - 10:04 AM