- LiFePO4 Speicher Test         
Ergebnis 1 bis 4 von 4

Thema: AVR-XRAM vom C-Compiler verwalten lassen

  1. #1
    Erfahrener Benutzer Begeisterter Techniker Avatar von H.A.R.R.Y.
    Registriert seit
    15.09.2005
    Beiträge
    306

    AVR-XRAM vom C-Compiler verwalten lassen

    Anzeige

    Praxistest und DIY Projekte
    Hallo Gemeinde,

    seit einiger Zeit versuche ich einem ATmega162 externes RAM (XRAM-Interface, 32kB SRAM) anzuflanschen. Die Hardware funktioniert 100%. Das Problem ist die Software, genauer gcc-avr (winAVR).

    Also: das XRAM-Interface wird eingeschaltet (section .init1), dann wird per Zeiger direkt ein Bitmuster im externen RAM aufgebaut. Danach wird dieses Muster (wieder per Zeiger) aus dem RAM gelesen und in ein LCD kopiert - daher weiß ich auch, daß das alles sauber arbeitet. Der Quellcode dürfte daher uninteressant sein.

    Was nicht mitspielt - und ich habe nach tagelanger Recherche nichts hilfreiches zum Thema gefunden:
    Dem Compiler mitteilen, daß er jetzt über erheblich mehr Speicher herrschen darf.

    Laut Win-AVR Doku müßte es mit einem Eintrag im Makefile erledigt sein:
    avr-gcc ... -Wl,-Tdata=0x800500,--defsym=__heap_end=0x80ffff ...
    Leider ist es sowohl dem Compiler als auch dem Linker wurstegal, was ich da hineintippe. Auch ein zusätzliches:
    -minit-stack=0x800500
    (testweise auch mal auf 0x200) brachte nichts. Der Stacktop liegt grundsätzlich bei 0x4ff und wird durch jede größere Variablen-Deklaration nach unten verschoben. Das führt bei entsprechend vielen Variablen (oder großem Array!) dazu, daß der Stacktop auf 0x0000 oder kleiner (!!!) verbastelt wird et voilà die Maschine geht beim ersten RET in den Wald. Aber davon abgesehen liegt der Stacktop nicht wie erwartet und die anderen Code-Segmente auch nicht da, wo die Doku verspricht (siehe hier http://www.nongnu.org/avr-libc/user-...ml#faq_ext_ram und hier http://www.nongnu.org/avr-libc/user-...l#malloc_where).

    Zwei verschiedene Makefile-Templates habe ich jetzt auch durch, das gleiche schlechte Ergebnis.

    Also die Frage: Wie bekomme ich den AVR-GCC dazu dem Stack das komplette interne RAM zu geben und den Rest ins externe RAM zu verlagern und dieses damit vom Compiler verwalten lassen?

    Ich hoffe es liegt an mir und nicht an einem massiven Bug im winAvr, nur finde ich den Fehler nicht.

    Gruß H.A.R.R.Y.
    a) Es gibt keine dummen Fragen, nur dumme Antworten
    b) Fehler macht man um aus ihnen zu lernen
    c) Jeder IO-Port kennt drei mögliche Zustände: Input, Output, Kaputt

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Was sagt denn das map-file
    Code:
    ... -Wl,-Map=<file> ...
    Schon mal mit eigenem Linker-Script versucht?
    Disclaimer: none. Sue me.

  3. #3
    Erfahrener Benutzer Begeisterter Techniker Avatar von H.A.R.R.Y.
    Registriert seit
    15.09.2005
    Beiträge
    306
    Das Makefile beginnt mit diesen Zeilen:

    Code:
    PROJECT				= XRAMtest
    MCU_TARGET			= atmega162
    DEFINITIONS			= -DF_CPU=8000000UL
    LIBRARIES			= -lm
    EXTRA_CLEAN_FILES	= *.hex *.bin *.srec
    EXTRA_CLEAN_FILES	+= *.gch
    #OPTIMIZE			= -Os -mcall-prologues
    OPTIMIZE			= -O2
    
    
    COMPILER	= avr-gcc
    LINKER		= avr-gcc
    OBJCOPY		= avr-objcopy
    OBJDUMP		= avr-objdump
    
    
    TO_COMPILER	= -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFINITIONS)
    TO_LINKER	= $(TO_COMPILER) -Wl,--section-start=.data=0x800500,--defsym=__heap_start=0x806000,--defsym=__heap_end=0x807fff,-Map,$(PROJECT).map -o
    #TO_LINKER	= $(TO_COMPILER) -Wl,-Tdata=0x800500,--defsym=__heap_end=0x807fff,-Map,$(PROJECT).map -o
    #TO_LINKER	= $(TO_COMPILER) -Wl,-Map,$(PROJECT).map -o
    TO_OBJCOPY	= -j .text -j .data -O
    
    
    # Override is only needed by avr-lib build system.
    override CFLAGS	= $(TO_COMPILER)
    override LFLAGS	= $(TO_LINKER)
    Und daraus "zaubert" der Linker dann dieses hier:

    Code:
    Memory Configuration
    
    Name             Origin             Length             Attributes
    text             0x00000000         0x00020000         xr
    data             0x00800060         0x0000ffa0         rw !x
    eeprom           0x00810000         0x00010000         rw !x
    *default*        0x00000000         0xffffffff
    
    Linker script and memory map
    
    Address of section .data set to 0x800100
    LOAD c:/programme/atmel/winavr/bin/../lib/gcc/avr/4.1.1/../../../../avr/lib/avr5/crtm162.o
    Address of section .data set to 0x800500
                    0x00806000                __heap_start = 0x806000
                    0x00807fff                __heap_end = 0x807fff
    LOAD main.o
    LOAD c:/programme/atmel/winavr/bin/../lib/gcc/avr/4.1.1/../../../../avr/lib/avr5\libm.a
    LOAD c:/programme/atmel/winavr/bin/../lib/gcc/avr/4.1.1/avr5\libgcc.a
    LOAD c:/programme/atmel/winavr/bin/../lib/gcc/avr/4.1.1/../../../../avr/lib/avr5\libc.a
    LOAD c:/programme/atmel/winavr/bin/../lib/gcc/avr/4.1.1/avr5\libgcc.a
    ...[das Gemüse hier ist wohl uninteressant]...
                   0x00000294                _etext = .
    
    .data           0x00800500        0x0 load address 0x00000294
                    0x00800500                PROVIDE (__data_start, .)
     *(.data)
     .data          0x00800500        0x0 c:/programme/atmel/winavr/bin/../lib/gcc/avr/4.1.1/../../../../avr/lib/avr5/crtm162.o
     .data          0x00800500        0x0 main.o
     .data          0x00800500        0x0 c:/programme/atmel/winavr/bin/../lib/gcc/avr/4.1.1/avr5\libgcc.a(_copy_data.o)
     .data          0x00800500        0x0 c:/programme/atmel/winavr/bin/../lib/gcc/avr/4.1.1/avr5\libgcc.a(_clear_bss.o)
     *(.data*)
     *(.rodata)
     *(.rodata*)
     *(.gnu.linkonce.d*)
                    0x00800500                . = ALIGN (0x2)
                    0x00800500                _edata = .
                    0x00800500                PROVIDE (__data_end, .)
    
    .bss            0x00800500        0x0
                    0x00800500                PROVIDE (__bss_start, .)
     *(.bss)
     .bss           0x00800500        0x0 c:/programme/atmel/winavr/bin/../lib/gcc/avr/4.1.1/../../../../avr/lib/avr5/crtm162.o
     .bss           0x00800500        0x0 main.o
     .bss           0x00800500        0x0 c:/programme/atmel/winavr/bin/../lib/gcc/avr/4.1.1/avr5\libgcc.a(_copy_data.o)
     .bss           0x00800500        0x0 c:/programme/atmel/winavr/bin/../lib/gcc/avr/4.1.1/avr5\libgcc.a(_clear_bss.o)
     *(.bss*)
     *(COMMON)
                    0x00800500                PROVIDE (__bss_end, .)
                    0x00000294                __data_load_start = LOADADDR (.data)
                    0x00000294                __data_load_end = (__data_load_start + SIZEOF (.data))
    
    .noinit         0x00800500        0x0
                    0x00800500                PROVIDE (__noinit_start, .)
     *(.noinit*)
                    0x00800500                PROVIDE (__noinit_end, .)
                    0x00800500                _end = .
                    0x00800500                PROVIDE (__heap_start, .)
    Das sieht ja auch soweit gut aus. Mein Problem ist weniger der Linker sondern der Compiler! Der kommt ja bekanntlich vor dem Linker dran und weiß daher (noch) nix von den neuen Einstellungen für das RAM. Ergo nimmt er brav die Default-Werte des Controllers und manipuliert schön den Stackpointer (gekürzter Auszug aus dem Disassembler-Fenster des Simulators, verziert mit einigen Kommentaren meinerseits):

    Code:
    +00000000:   940C0038    JMP     0x00000038       Jump
    ...
    @00000038: early_XRAM_on
    ---- main.c ---------------------------------------------------------------------------------------
    34:       {
    +00000038:   E880        LDI     R24,0x80         Load immediate
    => das geht also schon mal
    
    +00000039:   BF85        OUT     0x35,R24         Out to I/O location
    +0000003A:   2411        CLR     R1               Clear Register
    +0000003B:   BE1F        OUT     0x3F,R1          Out to I/O location
    +0000003C:   EFCF        SER     R28              Set Register
    => mit diesem Vorgeplänkel geht es um SP
    +0000003D:   E0D4        LDI     R29,0x04         Load immediate
    +0000003E:   BFDE        OUT     0x3E,R29         Out to I/O location
    +0000003F:   BFCD        OUT     0x3D,R28         Out to I/O location
    => Aha, der steht jetzt auf 0x04ff - paßt also auch
    => bis hierher sieht es also tatsächlich gut aus
    
    => jetzt kommt ein ganzer Schwung mögliche Initialisierungen von Speicherbereichen, der eigentlich nicht weiter relevant ist....
    +00000040:   E015        LDI     R17,0x05         Load immediate
    +00000041:   E0A0        LDI     R26,0x00         Load immediate
    +00000042:   E0B5        LDI     R27,0x05         Load immediate
    +00000043:   E9E4        LDI     R30,0x94         Load immediate
    +00000044:   E0F2        LDI     R31,0x02         Load immediate
    +00000045:   C002        RJMP    PC+0x0003        Relative jump
    +00000046:   9005        LPM     R0,Z+            Load program memory and postincrement
    +00000047:   920D        ST      X+,R0            Store indirect and postincrement
    +00000048:   30A0        CPI     R26,0x00         Compare with immediate
    +00000049:   07B1        CPC     R27,R17          Compare with carry
    +0000004A:   F7D9        BRNE    PC-0x04          Branch if not equal
    +0000004B:   E015        LDI     R17,0x05         Load immediate
    +0000004C:   E0A0        LDI     R26,0x00         Load immediate
    +0000004D:   E0B5        LDI     R27,0x05         Load immediate
    +0000004E:   C001        RJMP    PC+0x0002        Relative jump
    +0000004F:   921D        ST      X+,R1            Store indirect and postincrement
    +00000050:   30A0        CPI     R26,0x00         Compare with immediate
    +00000051:   07B1        CPC     R27,R17          Compare with carry
    +00000052:   F7E1        BRNE    PC-0x03          Branch if not equal
    +00000053:   940C0098    JMP     0x00000098       Jump
    => und weiter gehts es
    @00000098: main
    ---- main.c ---------------------------------------------------------------------------------------
    41:       {
    +00000098:   930F        PUSH    R16              Push register on stack
    +00000099:   931F        PUSH    R17              Push register on stack
    +0000009A:   93CF        PUSH    R28              Push register on stack
    +0000009B:   93DF        PUSH    R29              Push register on stack
    
    => SP abholen
    +0000009C:   B7CD        IN      R28,0x3D         In from I/O location
    +0000009D:   B7DE        IN      R29,0x3E         In from I/O location
    
    => um 240Bytes verringern
    +0000009E:   5FC0        SUBI    R28,0xF0         Subtract immediate
    +0000009F:   40D0        SBCI    R29,0x00         Subtract immediate with carry
    
    => und den neuen Wert retour schreiben (unter optimierter IRQ-Sperre!)
    +000000A0:   B60F        IN      R0,0x3F          In from I/O location
    +000000A1:   94F8        CLI                      Global Interrupt Disable
    +000000A2:   BFDE        OUT     0x3E,R29         Out to I/O location
    +000000A3:   BE0F        OUT     0x3F,R0          Out to I/O location
    +000000A4:   BFCD        OUT     0x3D,R28         Out to I/O location
    => damit ist SP=0x040b
    Und damit auch klar ist, wieso der Compiler den SP um 240 runterdreht:
    Code:
    int main (void)
    {
    	unsigned char buffer[240];
    	char *storagePtr;			// ext. RAM is located RAMEND..0x7FFF
    	char check, temp;
    	unsigned char i;
    Dabei kommt mir so eine vage Vermutung: das Array ist bei dieser Deklaration eine private Variable von main() und wird deshalb im Stack platziert?!? - Natürlich !!!

    Die Deklaration als GLOBALES Array läßt den SP brav auf 0x04ff - AHA. Und wo liegt das globale Array nun? Im externen RAM ab 0x0500 - AHA.
    War das Ganze also - wie vermutet - ein Verständnisproblem meinerseits.

    Das heißt also nun, Stack und private Variablen (sofern nicht in Register passend) landen hier im internen RAM, alles GLOBALE im externen RAM => die großen (statischen) Arrays deklariere ich also erstmal global um den gewünschten Effekt zu erzielen.

    @SprinterSB:
    Danke für die Hilfsbereitschaft.

    Gruß René
    a) Es gibt keine dummen Fragen, nur dumme Antworten
    b) Fehler macht man um aus ihnen zu lernen
    c) Jeder IO-Port kennt drei mögliche Zustände: Input, Output, Kaputt

  4. #4
    Erfahrener Benutzer Begeisterter Techniker Avatar von H.A.R.R.Y.
    Registriert seit
    15.09.2005
    Beiträge
    306
    Nachtrag:

    Mit dieser Zeile im Makefile funktioniert das Verschieben von .data NICHT:
    Code:
    TO_LINKER	= $(TO_COMPILER) -Wl,-Tdata=0x800500,--defsym=__heap_end=0x807fff,-Map,$(PROJECT).map -o
    Auch diese Syntax will nicht (wobei ich das Komma anstelle Gleichzeichen für einen Tipfehler halte):
    Code:
    TO_LINKER	= $(TO_COMPILER) -Wl,-Tdata,0x800500,--defsym=__heap_end=0x807fff,-Map,$(PROJECT).map -o
    Mit dieser Zeile arbeitet das Verschieben von .data wie gewünscht:
    Code:
    TO_LINKER	= $(TO_COMPILER) -Wl,--section-start=.data=0x800500,--defsym=__heap_end=0x807fff,-Map,$(PROJECT).map -o
    Woran das wohl wieder liegt?
    a) Es gibt keine dummen Fragen, nur dumme Antworten
    b) Fehler macht man um aus ihnen zu lernen
    c) Jeder IO-Port kennt drei mögliche Zustände: Input, Output, Kaputt

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

LiFePO4 Speicher Test