2012-05-06 12 views
14

Ich erstelle Code für ein ARM Cortex-M3 (NXP LCP17xx). Ich habe bisher statischen Speicher verwendet und alles hat gut funktioniert. Ich habe versucht, dynamische Speicherunterstützung hinzuzufügen, aber sobald ich malloc anrufe, bleibt das System stecken.Verwenden von Newlib Malloc in einem ARM Cortex-M3

Ich kompiliere mit gcc für arm bare metal, und mit newlib. Version: gcc-arm-none-eabi-4_6-2012q1

Um malloc-Unterstützung hinzuzufügen, habe ich eine einfache _sbrk-Funktion implementiert und mein Linker-Skript geändert, um Platz für den Heap zu schaffen (ich habe viele verschiedene Tutorials dazu gelesen Teil, aber keiner deckt das Problem, das ich als nächstes antraf).

Mit Hilfe einiger LEDs kann ich sicher sein, dass der Code bis zu dem Punkt läuft, an dem er malloc aufruft, dann geht es nicht weiter. Es erreicht nicht einmal meine _sbrk Funktion. Außerdem wird es in einem Anruf zu sizeof stecken bleiben, wenn ich einen Anruf zu malloc später im Code einschließe.

Also, was kann ich falsch machen, dass beim Aufruf malloc der Code stecken bleibt, ohne jemals erreicht _sbrk oder zurück?

Nach dem starren für die Speicherkarte, die erstellt, wenn der malloc Aufruf enthalten ist, und wenn es nicht ist, vermute ich, dass es zu den Strukturen verwandt wird, die von malloc verwendet werden.

Dies ist der Teil des LD-Skript, das den RAM-Speicher definiert:

.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 dann in der Unterbrechungsvektortabelle eingestellt ist.

Und jetzt ein Vergleich der verschiedenen Karten.

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

Speicherkarte unter malloc im Code: malloc im Code ohne Verwendung

*(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

Sind Sie sicher, dass Sie den Startup-Code richtig aufrufen, wodurch die Heap-Strukturen initialisiert werden? –

+0

Ich mache offensichtlich etwas falsch, das Problem ist, dass ich nicht weiß, was ich falsch mache. Ich habe zusätzliche Informationen über die Speicherkarten hinzugefügt, die hoffentlich helfen werden, den Fehler zu finden. –

+0

Ein sehr ähnliches Problem tritt auf, wenn sprintf verwendet wird. Es ist also nicht nur ein Malloc-Problem. Es hat mit dem ganzen newlib Zeug zu tun. Es muss wahrscheinlich eine Änderung im Verknüpfungsskript vorgenommen werden, obwohl ich nicht weiß was. –

Antwort

16

So, nachdem einige 10 Stunden Debuggen dies verbrachte, habe ich es endlich arbeiten. Das Problem lag im Linker-Skript. Allerdings war es nicht in der bss-Sektion, die ich gepostet hatte, sondern im Text- und Datenteil. Hier ist das Skript, das funktioniert.

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 = .); 

Ich hatte auch einige Variableninitialisierung meinen init-Code hinzufügen:

waren
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++; 
    } 

Diese beiden Seiten sehr hilfreich, auch wenn es mir noch viel nahm, um zu verstehen, was los war: http://fun-tech.se/stm32/linker/index.php und http://e2e.ti.com/support/microcontrollers/stellaris_arm_cortex-m3_microcontroller/f/473/t/44452.aspx?pi23648=1

Ich hoffe, dass dies für jemand anderen nützlich sein könnte, der die gleichen Probleme erlebt, die ich erlebte.

+6

Sie müssen auch die .bss-Sektion auf Null setzen: 'für (uint32_t * p = & _start_bss; p <&_ebss; ++ p) * p = 0;' –

+0

@Marga, vielen Dank, dass Sie das alles herausgefunden haben. Ich werde es benutzen! – nic

-15

Wenn es in Ihrem Budget ist, erwägen Sie den Kauf einer Lizenz für einen ARM-Compiler. Keil und IAR sind großartige ARM-Compiler, die sich um den Großteil Ihrer Toolchain-Probleme kümmern werden und beide über eine ordentliche Unterstützung verfügen.

+15

Sagen Sie niemandem, Geld zu verwenden, um mit dem Lernen aufzuhören. Die Ergebnisse, die sie gefunden hat, sind großartig, um zu erklären, welche Bodenarbeit Keil und IAR gemacht haben. Am Ende wird sie ein leistungsfähigerer Programmierer sein, da sie jetzt versteht, was unter der Haube ist. – nic