0

I develope a new bus system (uartbus) which includes a host application that can handle new program uploads throught the bus.

How it's work in short: The host application flashed to the AVR. This located between 0-2000 addresses and the flashing function at the end in the NRWW section. Application is written between 2000 and before NRWW section when it's received from the bus.

It's worked for a while with small AVR codes, but now as i try to integrate with the arduino system i've faced a weird problem: sometimes a page between 100 and 180 (one 128 byte page) been erased and some code filled almost at the beginning.

I thought the flashing function has been called with some wild parameter that results this fault, so i added some guard condition to check before write the flash:

__attribute__((section(".bootloader"))) void bootloader_main()
{
    asm ("jmp 0x0");
}

//modified version of:
//https://www.nongnu.org/avr-libc/user-manual/group__avr__boot.html#gaeb0dba1dd9d338516a94c0bd8a8db78a
__attribute__((section(".bootloader")))  void ubh_impl_write_program_page(const uint32_t page,const  uint8_t *buf,const uint8_t size)
{
    if(page < 0x2000 || (page > 0x7900+SPM_PAGESIZE) || size > SPM_PAGESIZE)
    {
        return;
    }

    uint16_t i;
    uint8_t sreg;
    // Disable interrupts.
    sreg = SREG;
    cli();
    eeprom_busy_wait ();
    boot_page_erase (page);
    boot_spm_busy_wait ();      // Wait until the memory is erased.
    for (i=0; i<size; i+=2)
    {
        // Set up little-endian word.
        uint16_t w = *buf++;
        w += (*buf++) << 8;

        boot_page_fill (page + i, w);
    }
    boot_page_write (page);     // Store buffer in flash page.
    boot_spm_busy_wait();       // Wait until the memory is written.
    // Reenable RWW-section again. We need this if we want to jump back
    // to the application after bootloading.
    boot_rww_enable ();
    // Re-enable interrupts (if they were ever enabled).
    SREG = sreg;
}

But the problem remained. Because the host code has been partially overwritten, the AVR can't receive new code from the bus. After dumped the AVR's flash and disassembled to invesigate what's happened.

avrdude -p atmega328p -b 19200 -P /dev/ttyUSB0 -c avrisp -U flash:r:flash.hex:i
avr-objdump -j .sec1 -d -m avr5 flash.hex > flash.asm

  ... good code ...
      fc:       fb 01           movw    r30, r22
      fe:       31 83           std     Z+1, r19        ; 0x01
     100:       ff ff           .word   0xffff  ; ????
     102:       ff ff           .word   0xffff  ; ????
     104:       ff ff           .word   0xffff  ; ????
     106:       ff ff           .word   0xffff  ; ????
     108:       ff ff           .word   0xffff  ; ????
     10a:       ff ff           .word   0xffff  ; ????
     10c:       ff ff           .word   0xffff  ; ????
     //looks like this code is from the application space between 2b8e and 2b96
     10e:       ff 1f           adc     r31, r31
     110:       05 90           lpm     r0, Z+
     112:       f4 91           lpm     r31, Z
     114:       e0 2d           mov     r30, r0
     116:       09 94           ijmp
     118:       ff ff           .word   0xffff  ; ????
     11a:       ff ff           .word   0xffff  ; ????
     11c:       ff ff           .word   0xffff  ; ????
     11e:       ff ff           .word   0xffff  ; ????
 ....

     17c:       ff ff           .word   0xffff  ; ????
     17e:       ff ff           .word   0xffff  ; ????
     180:       9f 93           push    r25
     182:       8f 93           push    r24
     184:       0e 94 9e 0a     call    0x153c  ;  0x153c
   ...good code ...

How is this possible to happen even after adding some guard condition before writing the flash?

(Another guard is also installed: when AVR accidentally starts in bootloader mode it's jumps immedialty to 0x00). I also checked, there's no SPM instruction in the code i uploaded and as far as i know they can be run outside of the NRWW section.

  • doesn't page 100 start at 0x3200 byte address? – Juraj Oct 7 at 20:05
  • Yes, the 0x3200 is the 100th page of the memory. (On the atmega328, the SPM_PAGESIZE is 128. The 0x3200 in decimal is 12800.). Hmm, that address is acutally writeable and previously i uploaded only shorter codes (under 2 Kbytes, so under the 0x2000+0x800). Maybe that's the root of this weird connection, but i don't have an idea how they connected. – Dankó Dávid Oct 8 at 21:18
  • then the 'guarding' if can't apply. so what is the problem? – Juraj Oct 9 at 4:08
  • It can. However the variable name 'page' is a bad name for that, it's actually stores the start address of the page, not the page offset itself. (This name comes from the original source of this flash function: nongnu.org/avr-libc/user-manual/group__avr__boot.html) There's no call example attached, but this code worked prevously with shorter codes to upload and absolute code addresses. – Dankó Dávid Oct 9 at 9:27
  • but I don't understand why it is a problem that the page 100 at byte address 0x3200 is written and how and why should the if(page < 0x2000 || (page > 0x7900+SPM_PAGESIZE) prevent it? – Juraj Oct 9 at 9:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.