bootloader won't re-start atmega328p

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

Hi all,

This is my work:

1. I have stored application binary file in 24c256, wired by 2wire to atmega328p;

2. I have wrote bootloader and compiled it with appropriate directive to upload starting from 0x3800 (for ex. include boot.h … int BOOTLOADER_SECTION main(void)…. )

So, I programm atmega and after reset, it copy program from external eeprom to flash, then jump to 0x0 to start application.

Everything seems to be done, but my problem is that after a subsequent hardware reset it always starts the application instead of the bootloader and I don't understand why.
Any suggestions?

In attachement my fuse setting

 

Attachment(s): 

This topic has a solution.
Last Edited: Thu. Oct 17, 2019 - 01:41 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

autsel wrote:
I have wrote bootloader and compiled it with appropriate directive to upload starting from 0x3800
I trust you mean WORD address 0x3800 which is BYTE address 0x7000. 

 

if you have actually placed the code at BYTE address 0x3800 it would explain exactly what you are observing.

 

(a lot of people are confused by Atmel's use of WORD addressing for flash when the rest of the world (and that includes the GCC tools) use byte addressing in all memory types)

 

Oh and as I wrote in the Bootloader FAQ (Tutorial Forum) the one thing BOOTLOADER_SECTION is *not* intended for is writing bootloaders !

 

If you want to move an entire program to the boot location you don't use BOOTLOADER_SECTION you simply use -Ttext=<byte addr of BLS> (or the longer form is -section-start=.text=<byte addr of BLS>)

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

Hi Clawson, I read your Bootloader FAQ and I made some checks and it seems to me that the bootloader is loaded correctly, I am probably wrong and I ask you to contradict me and correct me.
After programming the bootloader I read the flash before the copy of the program starts, I notice that actually the bootloader seems loaded starting from the address 0x7000, but there is something at the beginning of the flash that I can't identify.
Attached explanations on my use of BOOTLOADER_SECTION (which could be incorrect as you say) and the hex file read after programming the bootloader (before starting the copy of the program from the eeprom).

 

Thanks in advance

 

p.s. in boot.h I found: 
#define BOOTLOADER_SECTION    __attribute__ ((section (".bootloader")))

Attachment(s): 

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


 

autsel wrote:
but there is something at the beginning of the flash that I can't identify.
The is the exact reason NOT to use BOOTLOADER_SECTION. the only use of that macro is where you have a program that is predominantly based at 0x0000 (a "normal" app) with reset vector and interrupt table down near 0 but then you want to add a couple of SPM routines to store data to the program and they need to be "lifted up" into the bootloader section (because that's the only place where SPM works). In this case you have main() and most other functions "normal" but you add BOOTLOADER_SECTION to just one or two special functions to say "these are the ones that contain SPM and must be repositioned up at the bootlooader section. All that macro actually does is say "these functions to be in a section called .bootloader". Later you tell the linker -section-start=.bootloader=0x7000 to say "this is where I want those special functions". 

 

But if you do this you do NOT lift the reset vector or the IVT or any of the CRT. That all remains down near 0. That is exactly what you see in:

:100000000C9434000C9446000C9446000C9446006A
:100010000C9446000C9446000C9446000C94460048
:100020000C9446000C9446000C9446000C94460038
:100030000C9446000C9446000C9446000C94460028
:100040000C9446000C9446000C9446000C94460018
:100050000C9446000C9446000C9446000C94460008
:100060000C9446000C94460011241FBECFEFD8E03C
:10007000DEBFCDBF21E0A0E0B1E001C01D92A23003
:10008000B207E1F70E9461390C9448000C9400001B
:10009000F894FFCFFFFFFFFFFFFFFFFFFFFFFFFF12
:1000A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60
:1000B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50
:1000C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40
:1000D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF30
...

All of those 0C94's in there are the JMPs at the various interript vectors (and the very first one is the reset jump from 0 to the CRT). From about 0090 onwards it's then just all 0xFFs that are the padding that go all the way up to:

...
:106FD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1
:106FE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB1
:106FF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA1
:1070000083E084B915B88FE087B918B88EE08AB9E3
:1070100081E08BB995B795BF85BF82E085BF87E8D2
:107020008093610010926000089540E050E048179E
:10703000590764F420E030E02617370724F40000F5
:107040002F5F3F4FF9CF4F5F5F4FF1CF0895CF9341
:10705000DF93EC01209741F064E370E085E390E07A
:107060000E9415382197F6CFDF91CF9108951092A5
:10707000B90081E18093B80084E08093BC0080E097

and finally at 7000 we find the rest of this program (that is word location 0x3800). 

 

Like I say, go back to you code and remove any mention of BOOTLOADER_SECTION then just add ONE additional command for the linker that is -Wl,-Ttext=0x7000 and then look at the .hex you create. Now you will find that EVERYTHINg has been moved up to 7000 onwards. It will start with the reset jump (that should now locate at the BOOTSZ/BOOTRST entry point) and then all those 0C94's for the IVT,  then the CTR, then your code.

 

It was a very sad day indeed when the authors of AVR-LibC and avr/boot.h in particular chose to call that macro "BOOTLOADER_SECTION". If they had called it "SPM_ROUTINE" and it assigned the nominated functions to ".spm_section" or something it would have been a LOT clearer what the intention of the macro is.

 

The very last thing it is for is writing bootloaders !!

 

PS this is one of the bits of Brad's bootloader FAQ that I actually wrote....

 

 

PPS another bit of the FAQ (actually the very first bit) tells you this:

 

 

To be honest I actually prefer -Wl,-Ttext=0xnnnn rather than -Wl,-section-start=.text=0xnnnn simply because it's less typing but has exactly the same effect. (Using a -section-start of .text is so common that they added support for -Ttext= instead, there is also -Tdata= too)

Last Edited: Thu. Oct 17, 2019 - 12:32 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Clawson for the in-depth explanation.
That note you pointed out to me in the bootloader FAQ has evidently escaped me, also because of my terrible English.
I removed any reference to BOOTLOADER_SECTION, I added -Wl, -Ttext = 0x7000 to the linker and actually before 0x7000 there is absolutely nothing (verified by the hex file).
The bootloader works and makes the correct copy of the program (verified by the hex file) only that now it no longer works jumpToApp () but continues the bootloader in loop.
void (* jumpToApp) (void) = 0x0000;

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

Is the app actually there at 0 when jumptoApp is done. If not (and there's just erased 0xFFFF words at 0) then the AVR will just execute each 0xFFFF as "NOP" (it's really more like SBRSR31,7 in fact) until it gets to the start of the boot code at 0x7000 anyway.

 

The thing to do is run the bootloader, deliver the app code, then stop everything and use ISP to extract the entire flash. What do you find at 0x0000 ?

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

In attachement hex file

(read from atmel)

Attachment(s): 

Last Edited: Thu. Oct 17, 2019 - 01:05 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That sure looks like it has both bootloader and app in place.

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

this means?
sorry but this is the first time I've tried on a bootloader, I'm probably missing out on something stupid

Last Edited: Thu. Oct 17, 2019 - 01:24 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It means I would expect it to work. If in the bootloader you  have something like:

void (*start_app)(void) = 0;

int main(void) {
    if (trigger) {
        start_bootloading();
    }
    else {
        start_app();
    }
}

then I would expect the start_app() to ICALL to 0 (and once there the app will start and reset the stack anyway)

 

EDIT: Actually I do see this when I disassemble your hex file:

    73b6:	e0 91 00 01 	lds	r30, 0x0100
    73ba:	f0 91 01 01 	lds	r31, 0x0101
    73be:	09 95       	icall

so I guess it kind of depends what is in SRAM locations 0x100/0x101 when this executes as to whether it does go to 0 or not.

Last Edited: Thu. Oct 17, 2019 - 01:40 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Read this in the datasheet-

26.8.6 Prevent Reading the RWW Section During Self-Programming

Bit 4 in SPMCSR - RWWSRE: Read-While-Write Section Read Enable

 

My guess, you do not enable the RWW section after programming, which means you cannot execute code in the RWW section.

 

edit- guessed wrong.

 

Your hex file shows an icall which loads its data from 0x100/0x101, which is initialized as bss (0) in init code, so is most likely ok.

Last Edited: Thu. Oct 17, 2019 - 01:43 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Solved...

among the various attempts I had made there was also an attempt to move the interrupt vectors (which did not work) which I had not removed.

MCUCR = (1<<IVCE);
MCUCR = (1<<IVSEL);

Now I have removed the two lines everything works perfectly.
Thank you so much for your help.

 

Last question...
if I want to insert the firmware version in the binary file, to decide whether to update the flash or not, it is correct if I refer to your indications in the post?

 

https://www.avrfreaks.net/forum/...

 

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

curtvm wrote:
My guess, you do not enable the RWW section after programming, which means you cannot execute code in the RWW section.
I think you could be right. SPMCSR is 0x37 on this micro but I see no "out 0x37" in the entire disassembly. (I only see it read a couple of times)

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

autsel wrote:
Now I have removed the two lines everything works perfectly.
Don't tell me you are using interrupts in a bootloader? There should be no need for that. The idea of a bootloader is that it is simple code with no bugs (as it's the one bit you can't replace) and you keep the complexity down by not using interrupts. In fact if you are not using interrupts you can then use -nostartfiles so there is no IVT (which saves 100+ bytes and may mean you can squeeze it into a smaller boot section thus freeing more space for the growing application code).

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

I had only done some tests to try to understand what was not working, but I don't use them in the bootloader.
Of all the 1000 changes I made, I simply forgot to delete these two lines

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

>but I see no "out 0x37" 

 

RWW section is enabled. All is well.

 

    728c:    81 e1           ldi    r24, 0x11    ; 17
    728e:    80 93 57 00 sts    0x0057, r24    ;  0x800057
    7292:    e8 95          spm

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

curtvm wrote:

>but I see no "out 0x37" 

 

RWW section is enabled. All is well.

 

    728c:    81 e1           ldi    r24, 0x11    ; 17
    728e:    80 93 57 00 sts    0x0057, r24    ;  0x800057
    7292:    e8 95          spm

 

rww_enable is at the end of code after every page write, and now bootloader is OK, it charge program to the flash and jump to app correctly. After harware reset, bootloader start again

 

boot_rww_enable();

 

 

Last Edited: Thu. Oct 17, 2019 - 02:03 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why, I wonder, when SPMCSR is in range of OUT did the compiler choose to use STS ?!?

 

Methinks boot_rww_enable() is actually an inline Asm macro ;-)

 

EDIT: yup, so a missed optimisation in the hand-crafted Asm:

#define __boot_rww_enable()                      \
(__extension__({                                 \
    __asm__ __volatile__                         \
    (                                            \
        "sts %0, %1\n\t"                         \
        "spm\n\t"                                \
        :                                        \
        : "i" (_SFR_MEM_ADDR(__SPM_REG)),        \
          "r" ((uint8_t)(__BOOT_RWW_ENABLE))     \
    );                                           \
}))

 

Last Edited: Thu. Oct 17, 2019 - 02:25 PM