2012-05-06 16 views
14

Sto creando codice per un ARM Cortex-M3 (LCP17xx di NXP). Fino ad ora ho utilizzato la memoria statica e tutto ha funzionato bene. Ho provato ad aggiungere il supporto per la memoria dinamica, ma una volta chiamo malloc, il sistema si blocca.Utilizzo di malloc di newlib in un ARM Cortex-M3

Sto compilando con gcc per arm bare metal e utilizzando newlib. Versione: gcc-arm-none-eabi-4_6-2012q1

Per aggiungere il supporto per malloc, ho implementato una semplice funzione _sbrk e modificato il mio script linker per creare spazio per l'heap (ho letto molti tutorial su questo parte, ma nessuno copre il problema che ho incontrato dopo).

Con l'aiuto di alcuni LED, posso essere certo che il codice viene eseguito fino al punto che chiama malloc, quindi non va avanti. Non raggiunge nemmeno la mia funzione _sbrk. Inoltre, si bloccherà in una chiamata a sizeof, se includo una chiamata a malloc più avanti nel codice.

Quindi, cosa posso fare di sbagliato che quando si chiama malloc il codice si blocca senza mai raggiungere _sbrk o di ritorno?

Dopo aver fissato per un po 'la mappa di memoria generata quando è inclusa la chiamata malloc e quando non lo è, ho il sospetto che sia correlata alle strutture utilizzate da malloc.

Questa è la parte dello script ld che definisce la memoria ram:

.bss : 
{ 
    _start_bss = .; 
    *(.bss) 
    *(COMMON) 
    _ebss = .; 
    . = ALIGN (8); 
    _end = .; 
} >sram 
. = ALIGN(4); 
_end_bss = .; 
. = ALIGN(256); 
_start_heap = .; 
PROVIDE(__cs3_heap_start = _start_heap) 

_end_stack = 0x10008000; 

_end_stack viene impostato nella tabella vettore di interrupt.

E ora un confronto tra le diverse mappe. Senza usare malloc nel codice:

*(COMMON) 
      0x1000000c    _ebss = . 
      0x10000010    . = ALIGN (0x8) 
*fill*  0x1000000c  0x4 00 
      0x10000010    _end = . 
      0x10000010    . = ALIGN (0x4) 
      0x10000010    _end_bss = . 
      0x10000100    . = ALIGN (0x100) 
      0x10000100    _start_heap = . 

mappa di memoria utilizzando malloc nel codice:

*(COMMON) 
COMMON  0x10000848  0x4 ...arm-none-eabi/lib/armv7-m/libc.a(lib_a-reent.o) 
      0x10000848    errno 
      0x1000084c    _ebss = . 
      0x10000850    . = ALIGN (0x8) 
*fill*  0x1000084c  0x4 00 
      0x10000850    _end = . 

.bss.__malloc_max_total_mem 
      0x10000850  0x4 
.bss.__malloc_max_total_mem 
      0x10000850  0x4 ...arm-none-eabi/lib/armv7-m/libc.a(lib_a-mallocr.o) 
      0x10000850    __malloc_max_total_mem 

(...) It goes on (...) 
      0x1000085c    __malloc_current_mallinfo 
      0x10000884    . = ALIGN (0x4) 
      0x10000884    _end_bss = . 
      0x10000900    . = ALIGN (0x100) 
      0x10000900    _start_heap = . 
+0

Sei sicuro di voler richiamare correttamente il codice di avvio, che inizializzerà le strutture dell'heap? –

+0

Ovviamente sto facendo qualcosa di sbagliato, il problema è che non so COSA sto sbagliando. Ho aggiunto ulteriori informazioni sulle mappe di memoria, speriamo che possa aiutare a trovare l'errore. –

+0

Un problema molto simile si verifica quando si utilizza sprintf. Quindi non è solo un problema Malloc. Ha a che fare con tutta la roba newlib. Probabilmente ha bisogno di un cambiamento nello script di collegamento, anche se non riesco a capire cosa. –

risposta

16

Così, dopo circa 10 ore passate debug questo, ho finalmente fatto il lavoro. Il problema era nello script del linker. Tuttavia, non era nella sezione bss che avevo pubblicato, ma nella sezione di testo e dati. Ecco la sceneggiatura che funziona.

OUTPUT_FORMAT("elf32-littlearm") 
OUTPUT_ARCH(arm) 
ENTRY(_startup) 

MEMORY 
{ 
    rom (rx) : ORIGIN = 0x00000000, LENGTH = 512K 
    ram (rwx) : ORIGIN = 0x10000000, LENGTH = 32K 
} 

/* Define the top our stack at the end of SRAM */ 
_end_stack = 0x10008000; 

EXTERN(__interrupt_vector_table); 

SECTIONS 
{ 
    .text : 
    { 
     /* Insert the interrupt vector table first */ 
     __interrupt_vector_table = .; 
     *(.interrupt_vector_table) 
     /* Startup assembly */ 
     *(.startup) 
     /* Rest of the code (C) */ 
     *(.text) *(.text.*) *(.glue_7) *(.glue_7t) 
     *(.vfp11_veneer) 
     *(.ARM.extab* .gnu.linkonce.armextab.*) 
     *(.rodata) *(.rodata.*) 
     . = ALIGN(8); 
     _end_text = .; 
     _start_datai = .; 
    } >rom 

    .data : 
    { 
     _start_data = .; 
     *(vtable) 
     *(.data) *(.data.*) 
     . = ALIGN (8); 
     _end_data = .; 
    } >ram AT >rom 

    .data_init : { _end_datai = .; } >rom 

    __exidx_start = .; 
    .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } > rom 
    __exidx_end = .; 

    .bss : 
    { 
     _start_bss = .; 
     *(.bss) 
     *(COMMON) 
    } >ram 

    . = ALIGN(4); 
    _end_bss = .; 
    . = ALIGN(256); 

    _start_heap = .; 
    PROVIDE(__cs3_heap_start = _start_heap); 

    /* Linker wants .eh_frame section defined because of gcc 4.4.X bug, 
    * just discard it here. */ 
    /DISCARD/ : { *(.eh_*) } 
} 

_end = .; 
PROVIDE(end = .); 

ho anche dovuto aggiungere un po 'di inizializzazione variabile per il mio codice di inizializzazione:

extern unsigned int _start_data; 
extern unsigned int _end_data; 
extern unsigned int _start_datai; 
extern unsigned int _end_datai; 

void init(void) { 

    // (...) Other stuff 

    // Initialize Global Variables 
    uint32_t* data_begin = (uint32_t*) &_start_data; 
    uint32_t* data_end = (uint32_t*) &_end_data; 
    uint32_t* datai_begin = (uint32_t*) &_start_datai; 
    uint32_t* datai_end = (uint32_t*) &_end_datai; 
    while(data_begin < data_end) 
    { 
     *data_begin = *datai_begin; 
     data_begin++; 
     datai_begin++; 
    } 

Queste due pagine erano molto utile, anche se ancora mi c'è voluto molto per capire cosa stava succedendo: http://fun-tech.se/stm32/linker/index.php e http://e2e.ti.com/support/microcontrollers/stellaris_arm_cortex-m3_microcontroller/f/473/t/44452.aspx?pi23648=1

Spero che questo possa essere utile a qualcun altro che ha riscontrato gli stessi problemi che stavo vivendo.

+6

È inoltre necessario azzerare la sezione .bss: 'for (uint32_t * p = & _start_bss; p <&_ebss; ++ p) * p = 0;' –

+0

@Marga, grazie per aver capito tutto questo. Lo userò! – nic

-15

Se è nel tuo budget, considera l'acquisto di una licenza per un compilatore ARM. Keil e IAR sono entrambi ottimi compilatori ARM che si prenderanno cura della stragrande maggioranza dei problemi relativi alla toolchain e hanno entrambi un supporto decente.

+15

Non dire a qualcuno di usare i soldi per smettere di imparare. I risultati che ha trovato sono ottimi nell'istruire quali lavori di terra hanno fatto Keil e IAR. Alla fine, lei sarà un programmatore più potente dal momento che ora capisce cosa c'è sotto il cofano. – nic