Search code examples
avr

AVR128DB28 USART bootloader page


I have a problem writing data to flash memory. If I use int main, programming runs normally, but if I use __attribute__((naked)) __attribute__((section(".ctors"))) void boot(void), programming can't write to address memory I want to page.

#include "libcomp.h"

const flash_adr_t address = 0x1fc00;

#ifndef MAIN_TEST
/*
 * Main boot function
 * It represents the enter point for the device to start execution
 * It represents the enter point for the device to start execution
 * Naked attribute instructs the compiler to omit the function prologue and epilogue
 */
  __attribute__((naked)) __attribute__((section(".ctors"))) void boot(void)
#else
int main(void)
#endif
{
    int value;
    /* Initialize system for AVR GCC support, expects r1 = 0 */
    asm volatile("clr r1");
    SYSTEM_Initialize();
    
    uint8_t buffer[PROGMEM_PAGE_SIZE];
    uint8_t data_flash[PROGMEM_PAGE_SIZE] = "Main boot function. It represents the enter point for the device to start execution.";
    
    value = strlen((char)data_flash);
    FLASH_WriteFlashPage(address, data_flash);
    
    _delay_ms(500); 
    BLD_Init();
    uint16_t i = 0;
    
    while (1)
    {
        if (USART0_IsTxReady()) {
            for (int k = 0; k < value; k++) {
                USART0_Write(FLASH_ReadFlashByte(address + k));
            }
            USART0_Write('\n');
        }
    
        ClrWdt();
        BLD_Tasks();
        
        if (++i == 0)
            LED3_Toggle();
    }

#ifdef MAIN_TEST
return 0;
#endif
}

Solution

  • I use __attribute__((naked)) __attribute__((section(".ctors"))) void boot(void)

    These attributes make no sense. Section .ctors contains addresses of static constructors; it does not contain executable code.

    asm volatile("clr r1");

    This is hack and might not work as you expect. Avoid it or move it to the assembly part of your startup code.


    If you need custom start-up code, you can use

    Static Constructors

    This feature is specific to GCC. The syntax is like

    __attribute__((__constructor__))
    static void init (void)
    {
        // C/C++ code
    }
    

    Notice that the static in the code limits visibility of the constructor, it has nothing to do with the constructor being static. The generated code will be something like:

    .global __do_global_ctors
    .section .ctors,"a",@progbits
    .p2align    1
    .word   gs(init)
    

    __do_global_ctors will traverse .ctors and call the static constructors. It lives in libgcc and avr-gcc references it so it is dragged from libgcc.

    Naked Code in .init Sections

    This feature is specfic to avr-gcc. The syntax is like

    __attribute__((__used__,__unused__,__naked__,__section__(".init8")))
    static void init8 (void)
    {
      __asm volatile ("; code");
    }
    
    • Only (inline) assembly is supported in naked functions.
    • If some .initN section contains more than one function, the order of execution is unspecified.

    The following sections have library resp. start-up code located / attached to to them:

    • .init0: Implements vector0: Set up __zero_reg__, SP, EIND, and RAMP* registers (from AVR-LibC).
    • .init4: Run __do_copy_data and __do_clear_bss as needed (from libgcc).
    • .init6: Run __do_global_ctors as needed (from libgcc).
    • .init9: Call main and exit (from AVR-LibC).

    Own Startup Code

    If you prefer own startup code altogether, then

    • Write that code as (inline) assembly.
    • Link with -nostartfiles.
    • Define the following symbols as empty: __do_copy_data, __do_clear_bss, __do_global_ctors.
    • The vector table is part of AVR-LibC's startup code, hence with -nostartfiles you'll have to provide your own vectab.