Hi Leute, Ich verwende einen ATmega128, der mit dem externen Speicherinterface zwei SRAM-Bausteine a 512kB anspricht. Dazu verwende ich drei weitere Port Pins als Adressleitungen und zwei Port Pins um die SRAM-Bausteine mittels Chip Enable zu de- / aktivieren. Um den Speicher zu testen, habe ich ein kleines Testprogramm geschrieben, das unten dargestellt ist. Das ganze klappt auch wunderbar und ist soweit alles in Ordnung, ich habe nun eine Frage zu der Initialisierung des externen Speicherinterface. Im speziellen habe habe ich ne Frage zu dieser Codezeile <c> void xram(void) _attribute_ ((naked)) _attribute_ ((section (".init1"))); </c> So wie ich es verstanden habe sorgt man somit dafür, dass das Speicherinterface frühzeitig initialisiert wird. Somit wird dem Compiler? oder Linker? mitgeteilt, das er den externen Speicher nutzen kann. Oder sehe ich das falsch? Ich habe das ganze auch mal ohne diese vorzeitige Initialisierung gemacht, sondern die Funktion void xram(void) ganz normal in der main()aufgerufen. Das Ergebnis war, dass es auch so funktionierte. Deshalb meine weitere Frage, wozu macht man es dann und was kann passieren, wenn mann es nicht macht? Mir geht es darum, den Hintergrund zu verstehen, da ich es für eine Ausarbeitung gebrauche und den Quellcode begründen soll. Vielleicht hat der werte Herr Jörg Wunsch Zeit und Möglichkeit mir darauf zu antworten, da ich diesen Code bzw. diese Befehlszeile in einen Beitrag von ihn gefunden habe. Hier nun mein kleines nicht sehr anspruchvolles, aber funktionierendes Testprogramm <c> #include"lcd_i2c.h" #include"i2cmaster.h" #include "define.h" #include <avr/io.h> #include <stdio.h> #define OFFSET 0x1100 #define SET_SRAM1 {PORTF |= (1<<PF1); PORTF &= ~(1<<PF0);} #define SET_SRAM2 {PORTF |= (1<<PF0); PORTF &= ~(1<<PF1);} #define BANK_0 {PORTF &= ~(1<<PF4); PORTF &= ~(1<<PF3); PORTF &= ~(1<<PF2);} #define BANK_1 {PORTF &= ~(1<<PF4); PORTF &= ~(1<<PF3); PORTF |= (1<<PF2);} #define BANK_2 {PORTF &= ~(1<<PF4); PORTF |= (1<<PF3); PORTF &= ~(1<<PF2);} #define BANK_3 {PORTF &= ~(1<<PF4); PORTF |= (1<<PF3); PORTF |= (1<<PF2);} #define BANK_4 {PORTF |= (1<<PF4); PORTF &= ~(1<<PF3); PORTF &= ~(1<<PF2);} #define BANK_5 {PORTF |= (1<<PF4); PORTF &= ~(1<<PF3); PORTF |= (1<<PF2);} #define BANK_6 {PORTF |= (1<<PF4); PORTF |= (1<<PF3); PORTF &= ~(1<<PF2);} #define BANK_7 {PORTF |= (1<<PF4); PORTF |= (1<<PF3); PORTF |= (1<<PF2);} void xram(void) _attribute_ ((naked)) _attribute_ ((section (".init1"))); void xram(void) { MCUCR |= (1<<SRE)|(1<<SRW10); // The SRE Bit will activate the memory interface of the ATmega128 // The SRW11 and SRW10 bits control XMCRA |= (1<<SRW11); // the number of wait-states XMCRB |= (1<<XMBK); // Enable the buskeeper, witch ensure a definied logic level // on the lines AD7:0, otherwise they will be tri-stated // Remember: if you disable the memory Interface, don´t forget // to disable the buskeeper too. } //********************************************************************** ******************************************** //The function memwrite fills up a memorybank of the selected SRAM //alternate with 0x55 and 0xaa //********************************************************************** ******************************************** void memwrite(void) { unsigned char *pwrite = (unsigned char *) (OFFSET + 0); // Pointer to a unsigned char with the adress 0x1100 unsigned int count = 0; for(count=0; count<= (0xFFFF-OFFSET); count++) // until the end of the memory { if(count%2) // odd memorycells pwrite[count]=0x55; else // even memorycells pwrite[count]=0xaa; } } //********************************************************************** ******************************************** //The function memread checks a memorybank of the selected SRAM //if the cells has alternate values of 0x55 and 0xaa //********************************************************************** ******************************************** unsigned int memread(void) { unsigned char *pread = (unsigned char *) (OFFSET + 0); // Pointer to a unsigned char with the adress 0x1100 unsigned int count = 0; unsigned char error = 0; do { if(count%2) // odd memorycells { if(pread[count]!=0x55) // Memorycell dosen´t contain the desired value error = 1; } else // even memorycells { if(pread[count]!=0xaa) // Memorycell dosen´t contain the desired value error = 1; } count++; }while((count<=(0xFFFF-OFFSET))&&(error == 0)); // Ends with error or the last memorycell if(error) { return(count); // Memorycell "count" has a wrong value // 1 <= count <= 0xef00 } else { return(0); // no problems at all } } //********************************************************************** ******************************************** //The function memtest uses the functions memwrite and memread. //If the cells has a wrong value, it returns the number of the cell //If there is no problem it returns a Zero //********************************************************************** ******************************************** unsigned int memtest(void) { unsigned int i = 0; memwrite(); i = memread(); return(i); } //********************************************************************** ******************************************** //The function error_diplay only shows the memorycell with the wrong value inside //********************************************************************** ******************************************** void error_display(unsigned char SRAM, unsigned char BANK, unsigned int MEMORYCELL) { lcdi2c_ausgabexy("SRAM -> Bank ",0,0); lcdi2c_ausgabenummer(SRAM, 5, 0); lcdi2c_ausgabenummer(BANK, 15, 0); lcdi2c_ausgabexy("Fehler beim Auslesen",0,1); lcdi2c_ausgabexy("Speicherzelle: ",0,2); lcdi2c_ausgabenummer(MEMORYCELL, 20, 2); } int main(void) { UCHAR x = 0; unsigned int MEMORYCELL = 0; i2c_init(); // initialitze the I2C-Bus x = lcdi2c_init(); // checks the display PORTF |= (0<<PF7)|(0<<PF6)|(0<<PF5)|(0<<PF4)|(0<<PF3)|(0<<PF2)|(1<<PF1)|(1<<PF0); DDRF |= (0<<PF7)|(0<<PF6)|(0<<PF5)|(1<<PF4)|(1<<PF3)|(1<<PF2)|(1<<PF1)|(1<<PF0); // Belegung PORTF // // PF0: /CE SRAM 1 // PF1: /CE SRAM 2 // PF2: Adressleitung 16 // PF3: Adressleitung 17 // PF4: Adressleitung 18 // PF5: Frei // PF6: Frei // PF7: Frei SET_SRAM1 BANK_0 MEMORYCELL = memtest(); if(MEMORYCELL) error_display( 1,0 , MEMORYCELL); else { BANK_1 MEMORYCELL = memtest(); if(MEMORYCELL) error_display( 1,1 , MEMORYCELL); else { BANK_2 MEMORYCELL = memtest(); if(MEMORYCELL) error_display( 1,2 , MEMORYCELL); else { BANK_3 MEMORYCELL = memtest(); if(MEMORYCELL) error_display( 1,3 , MEMORYCELL); else { BANK_4 MEMORYCELL = memtest(); if(MEMORYCELL) error_display( 1,4 , MEMORYCELL); else { BANK_5 MEMORYCELL = memtest(); if(MEMORYCELL) error_display( 1,5 , MEMORYCELL); else { BANK_6 MEMORYCELL = memtest(); if(MEMORYCELL) error_display( 1,6 , MEMORYCELL); else { BANK_7 MEMORYCELL = memtest(); if(MEMORYCELL) error_display( 1,7 , MEMORYCELL); else { SET_SRAM2 BANK_0 MEMORYCELL = memtest(); if(MEMORYCELL) error_display( 2,0 , MEMORYCELL); else { BANK_1 MEMORYCELL = memtest(); if(MEMORYCELL) error_display( 2,1 , MEMORYCELL); else { BANK_2 MEMORYCELL = memtest(); if(MEMORYCELL) error_display( 2,2 , MEMORYCELL); else { BANK_3 MEMORYCELL = memtest(); if(MEMORYCELL) error_display( 2,3 , MEMORYCELL); else { BANK_4 MEMORYCELL = memtest(); if(MEMORYCELL) error_display( 2,4 , MEMORYCELL); else { BANK_5 MEMORYCELL = memtest(); if(MEMORYCELL) error_display( 2,5 , MEMORYCELL); else { BANK_6 MEMORYCELL = memtest(); if(MEMORYCELL) error_display( 2,6 , MEMORYCELL); else { BANK_7 MEMORYCELL = memtest(); if(MEMORYCELL) error_display( 2,7 , MEMORYCELL); else { lcdi2c_ausgabexy("Speicherzellen OK!",0,0); //Output on display } } } } } } } } } } } } } } } } while(1) { } } </c>
Schade, das das mit den Tags nicht so will, aber ich habe den C-Code als Dateianhang beigefügt. Gruß und Freude Thomas
Die Tags stehen in eckigen Klammern, außerdem wird das C groß geschrieben. Zur Hälfte hast du dir das schon richtig gedacht: das frühzeitige Aktivieren des XRAM-Interfaces in .init3 ist notwendig, damit dort normaler Variablenspeicher untergebracht werden kann. In .init4 erfolgt dann die Initialisierung der Variablen (Kopieren der ROM-Daten für .data, Ausnullen von .bss), wenn man also Variablen in den externen RAM legen möchte, muss man selbigen vorher aktiviert haben. Zur Hälfte nur deshalb: das schafft die Voraussetzung, dass man das überhaupt machen kann, aber es aktiviert diesen Bereich noch lange nicht für Variablen. Das erfolgt durch entsprechende Linker-Anweisungen. Damit sollte auch klar sein dass, wenn man dort keine Variablen unterbringen möchte, die Aktivierung und Deaktivierung des XRAM zu beliebigen Zeitpunkten erfolgen kann.
Gmh, die gleiche Anfrage in zwei verschiedenen Threads zu starten ist keine gute Idee! Hab Dir in deinem 2. Thread geantwortet: http://www.mikrocontroller.net/forum/read-1-380742.html#380761 Stefan
@Jörg Verstehe ich dich richtig? Wenn ich später den externen Speicher, nur per Zeigeroperationen anspreche um so Daten abzulegen, ich die (.init) Anweisung garnicht gebrauchen muss?? Weil, dann kann diese Anweisung ja raus und braucht nicht von mir erklärt werden. Oder kann da etwas passieren?
> Gmh, die gleiche Anfrage in zwei verschiedenen Threads zu > starten ist keine gute Idee! Um nicht zu sagen: es ist hochgradig unhöflich.
@Forum Sorry für den Doppelpost!! @Jörg Deine Antworten (seien sie auch sehr kurz) bringen mich gerade echt weiter. Dann habe ich aber noch eine Frage an dich. Leider kommt die aus dem anderen Beitrag, möchte sie aber nun hier gerne haben. Es passt thematisch auch besser hier rein. Im Makefile habe ich folgende Anweisung, die so wie ich es verstanden habe, für den Linker gedacht ist. EXMEMOPTS = -wl,--defsym=__heap_start=0x801100,--defsym=__heap_end=0x80ffff damit befindet sich der Heap im externen Speicher. Der Stack müsste sich immer noch im internen Speicher befinden. So wie alles andere auch, ist jedenfalls so in der avrlib zu sehen. Verwende ich die andere im Makefile gegebene Option EXMEMOPTS = -wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff dann schmiert mir der Prozessor komplett ab. Die erste Option ist für die Möglichkeit des dynamischen Speichers angedacht. Welcher dann per malloc() reserviert wird. Wenn ich aber wiederrum nur per Zeigeroperationen im exteren Speicher arbeite, benutze ich nunmal kein malloc(). Muss ich dann trotzdem diese Linkeranweisung machen? Und warum schmiert mir der µC bei der zweiten Option ab??
> Deine Antworten (seien sie auch sehr kurz)... :-) 's ist ja meine Arbeitszeit, da kann ich keine Romane schreiben. > Verwende ich die andere im Makefile gegebene Option > EXTMEMOPTS = -wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff > dann schmiert mir der Prozessor komplett ab. Der Haken ist, dass beim ATmega128 (und bei allen anderen AVRs, bei denen die IO-Register länger als bis 0x60 gehen) sowohl die GCC-Specs als auch die Kommandozeile eine -Tdata-Option haben, die dann an den Linker weitergereicht wird. Früher funktionierte das, da der Linker die zweite auftauchende (die aus der Kommandozeile) benutzt hat. Mit binutils 2.16 hat sich dieses Verhalten geändert, damit wird dein -Tdata ignoriert und nur das -Tdata=0x800100 aus den GCC-Specs genommen. Workaround: -Wl,--section-start=.data=0x801100 > Muss ich dann trotzdem diese Linkeranweisung machen? Nein. Sie definiert ausschließlich Symbole für die Steuerung des Heaps. Wenn du den nicht benutzt, interessieren diese Symbole keine Sau.
Guten morgen!! Ich merke immer wieder, das in meinem Studium als Nachrichtentechniker viel zu wenig auf Mikrokontrollertechnik im allgemeinen eingegangen worden ist. Es ist für mich immernoch recht komplex und schwierig zu verstehen, besonders die Sachen mit Linker und seinen ganzen Optionen, aber bislang konnte ich mir immer gut helfen. @Jörg Ok, wenn man also im Makefile deinen Workaround benutzt, ich denke mal in folgender Form: EXTMEMOPTS = -Wl,--section-start=.data=0x801100,--defsym=__heap_end=0x80ffff dann befinden sich also auch die Variablen im externen Speicher. Falls dann globale Variablen genutzt werden, muss das XMEM Interface mit der (.init) Anweisung frühzeitig initialisiert werden. Ansonsten können die globalen Variablen beim Start-Up des Kontrollers nicht deklariert und definiert werden. Ich hoffe so habe ich es richtig beschrieben. Gruß und Freude Thomas
> Ich hoffe so habe ich es richtig beschrieben.
Hast du.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.