2017-06-01 3 views
0

Ich habe einen sehr kleinen Bootloader vor der Hauptfirmware, der auf einer speziell entwickelten Platine läuft, die auf dem STM32F405VGT-Chip basiert. Es hat eine minimal modifizierte Startup.s und Linker-Dateien für beide Anwendungen. Die primäre Anwendung läuft ordnungsgemäß, wenn sie in den Stamm des FLASH-Speichers geladen wird, startet jedoch nicht vom Bootloader aus.Bootloader für STM32F405 Nicht zur Anwendung springen

Beim Durchlaufen des Codes, sobald es versucht, die App zu starten, endet das Programm in der WWDG_IRQHandler, die auf den Default_Handler Alias ​​ist und sitzt und dreht sich in der Endlosschleife (WWDG ist für den Bootloader deaktiviert)).

Urladercodes:

uint32_t addr = 0x08010000; 

    /* Get the application stack pointer (First entry in the application vector table) */ 
    uint32_t appStack = (uint32_t) *((__IO uint32_t*) addr); 

    /* Get the application entry point (Second entry in the application vector table) */ 
    ApplicationEntryPoint entryPoint = (ApplicationEntryPoint)*((__IO uint32_t*)(addr + sizeof(uint32_t))); 

    /* would expect the value of entryPoint to be 0x802bc9c based on the values in the .map file as well as the actual values downloaded from the image using openocd. Instead, it comes back as 0x802bc9d, not sure if this is related to THUMB code */ 

    /* Reconfigure vector table offset register to match the application location */ 
    SCB->VTOR = addr; 

    /* Set the application stack pointer */ 
    __set_MSP(appStack); 

    /* Start the application */ 
    entryPoint(); 

Hier ist die .LD Datei für die Anwendung:

/* Include memory map */ 
/* Uncomment this section to use the real memory map */ 
MEMORY 
{ 
    BOOTLOADER (rx) : ORIGIN = 0x08000000, LENGTH = 32K 
    USER_PROPS (rw) : ORIGIN = 0x08008000, LENGTH = 16K 
    SYS_PROPS (r)  : ORIGIN = 0x0800C000, LENGTH = 16K 
    APP_CODE  (rx) : ORIGIN = 0x08010000, LENGTH = 448K 
    SWAP   (rx) : ORIGIN = 0x08070000, LENGTH = 384K 

    RAM   (xrw) : ORIGIN = 0x20000000, LENGTH = 128K 
    BOOT_RAM  (xrw) : ORIGIN = 0x2001E000, LENGTH = 8K 
    CCMRAM  (rw) : ORIGIN = 0x10000000, LENGTH = 64K 
} 

/* Uncomment this section to load directly into root memory */ 
/* 
MEMORY 
{ 
    APP_CODE (rx)  : ORIGIN = 0x08000000, LENGTH = 1024K 
    RAM (xrw)  : ORIGIN = 0x20000000, LENGTH = 128K 
    MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K 
    CCMRAM (rw)  : ORIGIN = 0x10000000, LENGTH = 64K 
} 
*/ 

/* Highest address of the user mode stack */ 
_estack = 0x20020000; /* end of 128K RAM */ 

/* Entry Point */ 
ENTRY(Reset_Handler) 



/* Generate a link error if heap and stack don't fit into RAM */ 
_Min_Heap_Size = 0x000;  /* required amount of heap (none) */ 
_Min_Stack_Size = 0x400;  /* required amount of stack */ 

SECTIONS 
{ 


    /* The startup code goes first into EEPROM */ 
    .isr_vector : 
    { 
    . = ALIGN(4); 
    KEEP(*(.isr_vector)) /* Startup code */ 
    . = ALIGN(4); 
    } >APP_CODE 


    /* The program code and other data goes into EEPROM */ 
    .text : 
    { 
    . = ALIGN(4); 
    *(.text)   /* .text sections (code) */ 
    *(.text*)   /* .text* sections (code) */ 
    *(.glue_7)   /* glue arm to thumb code */ 
    *(.glue_7t)  /* glue thumb to arm code */ 
    *(.eh_frame) 

    KEEP (*(.init)) 
    KEEP (*(.fini)) 

    . = ALIGN(4); 
    _etext = .;  /* define a global symbols at end of code */ 
    } >APP_CODE 

    /* Constant data goes into EEPROM */ 
    .rodata : 
    { 
    . = ALIGN(4); 
    *(.rodata)   /* .rodata sections (constants, strings, etc.) */ 
    *(.rodata*)  /* .rodata* sections (constants, strings, etc.) */ 
    . = ALIGN(4); 
    } >APP_CODE 

    .preinit_array  : 
    { 
    PROVIDE_HIDDEN (__preinit_array_start = .); 
    KEEP (*(.preinit_array*)) 
    PROVIDE_HIDDEN (__preinit_array_end = .); 
    } >APP_CODE 
    .init_array : 
    { 
    PROVIDE_HIDDEN (__init_array_start = .); 
    KEEP (*(SORT(.init_array.*))) 
    KEEP (*(.init_array*)) 
    PROVIDE_HIDDEN (__init_array_end = .); 
    } >APP_CODE 
    .fini_array : 
    { 
    PROVIDE_HIDDEN (__fini_array_start = .); 
    KEEP (*(SORT(.fini_array.*))) 
    KEEP (*(.fini_array*)) 
    PROVIDE_HIDDEN (__fini_array_end = .); 
    } >APP_CODE 


    /* used by the startup to initialize data */ 
    _sidata = LOADADDR(.data); 

    /* Initialized data sections goes into RAM, load LMA copy after code */ 
    .data : 
    { 
    . = ALIGN(4); 
    _sdata = .;  /* create a global symbol at data start */ 
    *(.data)   /* .data sections */ 
    *(.data*)   /* .data* sections */ 

    . = ALIGN(4); 
    _edata = .;  /* define a global symbol at data end */ 
    } >RAM AT> APP_CODE 

    /* Uninitialized data section */ 
    . = ALIGN(4); 
    .bss : 
    { 
    /* This is used by the startup in order to initialize the .bss secion */ 
    _sbss = .;   /* define a global symbol at bss start */ 
    __bss_start__ = _sbss; 
    *(.bss) 
    *(.bss*) 
    *(COMMON) 

    . = ALIGN(4); 
    _ebss = .;   /* define a global symbol at bss end */ 
    __bss_end__ = _ebss; 
    } >RAM 

    /* User_heap_stack section, used to check that there is enough RAM left */ 
    ._user_heap_stack : 
    { 
    . = ALIGN(8); 
    PROVIDE (end = .); 
    PROVIDE (_end = .); 
    . = . + _Min_Heap_Size; 
    . = . + _Min_Stack_Size; 
    . = ALIGN(8); 
    } >RAM 

    /* Remove information from the standard libraries */ 
    /DISCARD/ : 
    { 
    libc.a (*) 
    libm.a (*) 
    libgcc.a (*) 
    } 

    .ARM.attributes 0 : { *(.ARM.attributes) } 
} 

Der Bootloader .LD ist identisch, mit der Ausnahme alle Verweise auf APP_CODE mit Bootloader ersetzt werden

Hier ist die Datei startup.s für den Bootloader. Die startup.s Datei für die Anwendung ist identisch, mit der Ausnahme Boot_Reset_Handler Reset_Handler stattdessen aufgerufen wird:

.syntax unified 
    .cpu cortex-m4 
    .fpu softvfp 
    .thumb 

.global g_pfnVectors 
.global Default_Handler 

/* start address for the initialization values of the .data section. 
defined in linker script */ 
.word _sidata 
/* start address for the .data section. defined in linker script */ 
.word _sdata 
/* end address for the .data section. defined in linker script */ 
.word _edata 
/* start address for the .bss section. defined in linker script */ 
.word _sbss 
/* end address for the .bss section. defined in linker script */ 
.word _ebss 
/* stack used for SystemInit_ExtMemCtl; always internal RAM used */ 

/** 
* @brief This is the code that gets called when the processor first 
*   starts execution following a reset event. Only the absolutely 
*   necessary set is performed, after which the application 
*   supplied main() routine is called. 
* @param None 
* @retval : None 
*/ 

    .section .text.Boot_Reset_Handler 
    .weak Boot_Reset_Handler 
    .type Boot_Reset_Handler, %function 
Boot_Reset_Handler: 
    ldr sp, =_estack  /* set stack pointer */ 

/* Copy the data segment initializers from flash to SRAM */ 
    movs r1, #0 
    b LoopCopyDataInit 

CopyDataInit: 
    ldr r3, =_sidata 
    ldr r3, [r3, r1] 
    str r3, [r0, r1] 
    adds r1, r1, #4 

LoopCopyDataInit: 
    ldr r0, =_sdata 
    ldr r3, =_edata 
    adds r2, r0, r1 
    cmp r2, r3 
    bcc CopyDataInit 
    ldr r2, =_sbss 
    b LoopFillZerobss 
/* Zero fill the bss segment. */ 
FillZerobss: 
    movs r3, #0 
    str r3, [r2], #4 

LoopFillZerobss: 
    ldr r3, = _ebss 
    cmp r2, r3 
    bcc FillZerobss 

/* Call the clock system intitialization function.*/ 
    bl SystemInit 
/* Call static constructors */ 
    bl __libc_init_array 
/* Call the application's entry point.*/ 
    bl main 
    bx lr  
.size Boot_Reset_Handler, .-Boot_Reset_Handler 

/** 
* @brief This is the code that gets called when the processor receives an 
*   unexpected interrupt. This simply enters an infinite loop, preserving 
*   the system state for examination by a debugger. 
* @param None  
* @retval None  
*/ 
    .section .text.Default_Handler,"ax",%progbits 
Default_Handler: 
Infinite_Loop: 
    b Infinite_Loop 
    .size Default_Handler, .-Default_Handler 

    .section .isr_vector,"a",%progbits 
    .type g_pfnVectors, %object 
    .size g_pfnVectors, .-g_pfnVectors 



g_pfnVectors: 
    .word _estack 
    .word Boot_Reset_Handler 

    .word NMI_Handler 
    .word HardFault_Handler 
    .word MemManage_Handler 
    .word BusFault_Handler 
    .word UsageFault_Handler 
    .word 0 
    .word 0 
    .word 0 
    .word 0 
    .word SVC_Handler 
    .word DebugMon_Handler 
    .word 0 
    .word PendSV_Handler 
    .word SysTick_Handler 
    ... 

Ich möchte darauf hinweisen, dass dies nicht ein Duplikat Bootloader for Cortex M4 - Jump to loaded Application obwohl das Problem scheint ähnlich, der Autor, dass Beitrag hat nicht angemessen erklärt, wie das Problem gelöst wurde.

Alles wird mit Standard-GCC-Tools für Embedded-Entwicklung gebaut.

+0

Wie sieht die Zerlegung um den eigentlichen Sprung/Aufruf aus? –

+0

und die Demontage der Vektortabelle für die Anwendung. –

+1

Verknüpfen Sie mit CMSIS und/oder einer Datei namens "system_stm32f4xx.c"? Diese Datei hat möglicherweise eine Funktion namens 'SystemInit()', die 'SCB-> VTOR' auf einen anderen Wert als erwartet setzt. Möglicherweise müssen Sie diese Datei bearbeiten und den Wert von 'VECT_TAB_OFFSET' für Ihre Erwartungen festlegen. – kkrambo

Antwort

0

Ich habe folgenden Ansatz auf verschiedene STM32 Cortex-M3 und M4 Teilen verwendet:

die folgende in-line Montagefunktion gegeben:

__asm void boot_jump(uint32_t address) 
{ 
    LDR SP, [R0]  ;Load new stack pointer address 
    LDR PC, [R0, #4] ;Load new program counter address 
} 

der Bootloader-Schalter zur Anwendung Bild so:

// Switch off core clock before switching vector table 
SysTick->CTRL = 0 ; 

// Switch off any other enabled interrupts too 
... 

// Switch vector table 
SCB->VTOR = APPLICATION_START_ADDR ; 

//Jump to start address 
boot_jump(APPLICATION_START_ADDR) ; 

Wo APPLICATION_START_ADDR die Adresse des Anwendungsbereiches Basis (addr in Ihrem Beispiel); Diese Adresse ist der Beginn der Vektortabelle der Anwendung, die mit dem anfänglichen Stapelzeiger und dem Rücksetzvektor beginnt. Die Funktion boot_jump() lädt diese in die SP- und PC-Register, um die Anwendung zu starten, als wäre sie beim Zurücksetzen gestartet worden. Der Rücksetzvektor der Anwendung enthält die Ausführungsstartadresse der Anwendung.

Der offensichtliche Unterschied zwischen dieser und Ihrer Lösung besteht in der Deaktivierung aller Interrupt-Generatoren vor dem Umschalten der Vektortabelle. Sie dürfen natürlich keine Interrupts im Bootloader verwenden.

Verwandte Themen