what's wrong with this bootloader jump?

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

now I'm using

Code:

void (*start_bootloader)(void) = (void *)BOOTLOADER_ADDRESS;
...
...
start_bootloader();

and this is the asm code for start_bootloader();

Code:

a78: ff 95 00 f8 call 0x7ff000 <__stack+0x7fdf01>

Then I'm confused, the cpu is mega1281, so shouldn't the value after call < 64K ?
Cos mega1281 just has 128KB of flash and 16bits PC, so what's this 0x7ff000 all about??

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

Any chance of us seeing the #define for BOOTLOADER_ADDRESS ?

Cliff

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

yes,

#define BOOTLOADER_ADDRESS							0xF000 // the start of bootloader flash address in byte
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well the bytes shown:

ff 95 00 f8

appear to be the word values:

95ff f800

And the AVR opcode documentation says that the encoding of the CALL instruction is:

1001 010k kkkk 111k kkkk kkkk kkkk kkkk

So it looks like the encoded opcode is:

1001 0101 1111 1111 1111 1000 0000 0000

and therefore k is

1 1111 1 1111 1000 0000 0000

which is

11 1111 1111 1000 0000 0000

which is word address

3FF800

So that does indeed look like a CALL to byte address 0x7FF000

However if only the lower 16 of the 22 bits of k are signficant then it is

1111 1000 0000 0000

which is word address:

F800

which in bytes is:

1F000

If the leading 1 itself is dropped then perhaps this DOES give the F000 you expected?

Cliff

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

Cliff, I got confused further by what you said.
mega1281 is 128K byte, so according to AVR Instruction Set, the k should be < 64K, right?
and why should the leading 1 be dropped in 1F000?

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

The "128K flash so k=16 bits" is my reading of the opcode manual yes.

As for dropping the leading 1 - I don't know I was just saying where the F000 might come into it. What happens when you simulate the call instruction as it stands - where does the simulator position you after the instruction?

Cliff

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

a conventional way to invoke the bootloader from an application, without having to know where it is, is to cause a watchdog timer timeout which resets the processor. Fuse bit settings cause the reset to startup the bootstrap loader.

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

I agree with Steve... so just set the fuses to bootstrap at bootloader space and check for a flag to jump to app. If that flag is on, stay at bootloader section if not jump to application section... then at application section make a forever loop when you want to reset the micro using the watchdog behaivor... bingo!

my 2 cents!

---
ARod

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

Looks like you've been bitten by the sign extension of your value.

Try as an unsigned value (note the U suffix)

#define BOOTLOADER_ADDRESS                     0xF000U // the start of bootloader flash address in byte 

or as a long (note the L suffix, and the additional leading 0, which is very important in this case)

#define BOOTLOADER_ADDRESS                     0x0F000L // the start of bootloader flash address in byte 

Constants for the preprocessor are signed int's by default, so in your code, when it had to promote it to a long, it sign extended the value. By forcing it to be unsigned, or as a long, with a leading zero, you can correct this.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

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

great, thanks for this important constants rule.

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

and all the pointer should have the value in word address in AVR, right?

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

I tried both 0xF000U and 0x0F000L, the asm result are still the same

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

Is it because I use word address, but WINAVR actually recognized it as byte address?
should I use 0x1E000UL instead?

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

no, I think that's wrong, it should be 0xF000U or 0x0F000L

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

If you want to be certain, you could always bypass the word/byte confusion if you implement this as inline assembly using the Z pointer and an IJMP instruction.

But I also strongly agree with Steve and ARod that the using bootloader reset fuse, and triggering a watchdog reset is the right way to go here. Unless there's some other reason we don't know about which makes that solution unacceptable...?

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

yes, there is. My bootloader is controled by RF command and I don't want to set the fuse reset to always start at bootloader section.

Anyway, I should always use word address for the pointer value in C code for AVRs, right?

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

darthvader wrote:
...and I don't want to set the fuse reset to always start at bootloader section.

That by itself doesn't necessarily eliminate the boot reset option.

The solution is simple. Consider this example:

When the AVR boots up, it jumps to the bootloader. There, it sits in a loop waiting for a specific set of bytes from he UART signaling that a bootload sequence is about to begin.

If it doesn't receive that sequence within, say 500 milliseconds, then the bootloader aborts and jumps back to the beginning of the application section.

Inside the application section, if a command comes in through the UART saying "I want to jump to the bootloader now", the application obliges by triggering a watchdog reset.

Quote:
Anyway, I should always use word address for the pointer value in C code for AVRs, right?

Easy enough to experiment with this.

Try writing some code that creates a volatile instance of a function pointer, and then assign that function pointer a hard-coded hexadecimal value.

Then run this code through the AVR Studio simulator and watch the memory associated with that function pointer. It should be immediately obvious whether an implicit BYTE->WORD translation takes place or not.

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

Hello Lord Vader

I tried various permutations of your code, even going through indirectly through a constant variable but could not achieve the desired result.

I'm beginning to suspect a bug is at work here.

Quote:
My bootloader is controled by RF command and I don't want to set the fuse reset to always start at bootloader section.

Snap. I do exactly the same in my code but use

__asm__ ( " jmp 0x7E00 \n" : : );

to execute my bootloader. I really suggest you do similar.

Nigel

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

Quote:
My bootloader is controled by RF command and I don't want to set the fuse reset to always start at bootloader section.

A common technique is for RESET (or watchdog timeout) to invoke the bootloader. That code then waits 2 seconds or so for serial port handshaking of special characters from a PC loader, such as chars. After waiting say 2 seconds with no response, the bootloader does a JMP 0 to startup the application that it assumes was already loaded into flash.

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

Hi, lfmorrison and stevech, thanks for your explanation. I think I will consider this option.

General Nigel, finally someone start to appreciate the power of the dark side, after I executed several stupid colleague of you...
I will suggest to promote you to admiral the next time I meet emperor :)

BTW, I tried start_bootloader() in another test code and simulated in AVR studio and get the warning that the opcode is 0xFFFF at address 0xF000, so I think it works.

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

I have to correct my mistake, the bootloader address in the C code of WINAVR has to be byte address!!!
so in my case it should be 0x1E000UL instead of 0xF000U

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

Lord Vader,

I sensed a disturbance in the force when you posted

Quote:

I have to correct my mistake, the bootloader address in the C code of WINAVR has to be byte address!!!
so in my case it should be 0x1E000UL instead of 0xF000U

I wrote a snippet of code to take the address of a function (bit_demo) and assign to a global unsigned long . Here's the important bits of the lss
ulGlobal=bit_demo;
  9c:	8b eb       	ldi	r24, 0xBB	; 187
  9e:	90 e0       	ldi	r25, 0x00	; 0
  a0:	aa 27       	eor	r26, r26
  a2:	97 fd       	sbrc	r25, 7
  a4:	a0 95       	com	r26
  a6:	ba 2f       	mov	r27, r26
  a8:	80 93 00 01 	sts	0x0100, r24
  ac:	90 93 01 01 	sts	0x0101, r25
  b0:	a0 93 02 01 	sts	0x0102, r26
  b4:	b0 93 03 01 	sts	0x0103, r27

...

void bit_demo (void)
{
bool sixth_bit = (X >> 6) & 1;
 176:	80 91 05 01 	lds	r24, 0x0105
 17a:	82 95       	swap	r24
 17c:	86 95       	lsr	r24

As you can see bit_demo is at byte addr 0x176 but avr-gcc thinks the address of bit_demo is the word address 0xBB. I am now convinced there IS a bug because you can see it has been sign extended. Therefore word addresses >= 0x8000 would become negative which is what you've seen.

Nigel (General)