Solved: Boot loader is not updating the program

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

 

In my application, the main program decides that it is out of date and then calls the bootloader to do the update. It also marks that in the EEPROM, in case there is a failure, so that the bootloader keeps on retrying on next power up.

 

The issue I am having is that the boot loader runs, but does not modify the program. It reports back to the host correct checksums, so I know it ran and received the data OK. However, after reboot, the MCU is still running the old program.

 

int main(void)
{
    DDRD  = 0x1C;
    PORTD = RED;

    uint8_t needsReflash = eeprom_read_byte((uint8_t*)EEPROM_BOOT_LDR_REFLASH);

    if(needsReflash)
    {
        cli();

        USART_Init();

        while(1)
        {
            uint8_t i;
            uint16_t pAddr = USART_Receive(); // Get the page address. The host will retry pages that had a bad checksum.
            pAddr += USART_Receive() << 8;

            if(pAddr == 0xFFFF)
            {
                break;
            }

            eeprom_busy_wait ();
            boot_page_erase (pAddr);
            boot_spm_busy_wait ();

            uint16_t sum = pAddr;

            for (i=0; i<SPM_PAGESIZE; i+=2)
            {
                uint16_t w = USART_Receive();
                w += USART_Receive() << 8;

                sum = (sum + w) & 0xFFFF;
                             
                boot_page_fill (pAddr + i, w);
            }

            boot_page_write (pAddr);

            USART_Send(sum); // Verify on the host.
            USART_Send(sum >> 8);

            PORTD ^= BLUE;

            boot_spm_busy_wait();
            boot_rww_enable ();
        }

        eeprom_write_byte((uint8_t*)EEPROM_BOOT_LDR_REFLASH, 0);
    }

    asm("jmp 0"); // reset
    return 0;
}

 

One warning sign that things are not working well is that the bootloader doesn't run on startup even if set unconditionally with:

 

    uint8_t needsReflash = 1

 

(The red LED is not lit up)

 

Details:

 

 

Solution: 0x3E00 as seen in the fuses is a word address, while the linker flag is a byte address. The latter needs to be 0x7C00.

 

Hex:

 

:020000040000FA
:200000000C9434000C9451000C9451000C9451000C9451000C9451000C9451000C94510075
:200020000C9451000C9451000C9451000C9451000C9451000C9451000C9451000C94510038
:200040000C9451000C9451000C94E1000C9451000C9451000C9451000C9451000C94510088
/* ... */
:20060000CB01FC01F999FECF06C0F2BDE1BDF89A319600B40D9241505040B8F70895262F31
:20062000F999FECF92BD81BDF89A019700B4021639F01FBA20BD0FB6F894FA9AF99A0FBEB4
:080640000895F894FFCF0101B9
:203E00000C94341F0C943E1F0C943E1F0C943E1F0C943E1F0C943E1F0C943E1F0C943E1FC4
:203E20000C943E1F0C943E1F0C943E1F0C943E1F0C943E1F0C943E1F0C943E1F0C943E1F9A
:203E40000C943E1F0C943E1F0C943E1F0C943E1F0C943E1F0C943E1F0C943E1F0C943E1F7A
/* ... */
:203FE000F89A992780B50895262FF999FECF1FBA92BD81BD20BD0FB6F894FA9AF99A0FBE61
:0840000001960895F894FFCF2A
:0400000500003E00B9
:00000001FF

 

Any help is appreciated - this is my first bootloader. Thanks.

 

This topic has a solution.
Last Edited: Mon. May 20, 2019 - 03:53 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It'll do things like that if the bootloader is actually allowed to use the SPM instruction.  I had a fun time before I noticed that an ATtiny I was using needed to have the SELFPGM fuse set :-)

Are you sure your fuses are actually set as show in your screenshot?   What about the lock bits?   Is the bootloader properly positioned in the boot section?

 

 

Ahh.   You have the common "byte address vs word address" problem. "-section-start" for a 328 with a 1k bootloader should be 0x7C00...

 

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

Thanks! Your comment explains the boot problem, but what about the no write? I call the pointer properly from app code and the bootloader code does run (LED blinking and USART responding).

Fuse bits are set as in the screenshot and all lock bits are 0xF (ie everything allowed). I'm not seeing such a program lock fuse in the GUI.

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

But the way, when running the application and it wants to update itself, it just calls the bootloader main(), is there anything else I need to do to tell the MCU we are entering bootloader code? I assumed it uses the program counter to check whether we are allowed to reprogram.

Last Edited: Mon. May 20, 2019 - 01:27 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

purple_beam wrote:
Thanks! Your comment explains the boot problem, but what about the no write?
Bill already told you the answer.

 

:203E00000C94341F0C943E1F0C943E1F0C943E1F0C943E1F0C943E1F0C943E1F0C943E1FC4
:203E20000C943E1F0C943E1F0C943E1F0C943E1F0C943E1F0C943E1F0C943E1F0C943E1F9A

 

The 3E00 here is supposed to be 7C00

 

When you built this code you built it at the wrong address. A 32K micro ends at 7FFF (32K) not 3FFF (16K) so your code is only half way up the chip. As it is not in the BLS the execution of SPM will not work.

 

Where you do -Ttext=3E00 or -section-start=.text=3E00 the number should be 7C00

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

Worked like a charm! Thanks and apologies for not thinking Bill's response through at first.

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

The confusion here is because Atmel insist on talking about the flash memory of the AVR as if it were 16 bit (the smallest possible AVR opcode size). When they say 3E00 in the datasheet they mean "word address 3E00" but that is 3E00 lots of 16bit which is actually 7C00 lots of 8 bit. GCC tools do everything in terms of 8 bit addressing which is why a section-start or whatever needs the address given as 7C00.

 

You are not the first to be caught by this - in fact almost anyone who's ever done bootloaders in AVRs have been bitten by this when they first start. (I know I was).