www.mikrocontroller.net

Forum: Projekte & Code 48KB SDRam für gcc auf xplain


Autor: Sauger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nabend,

48KB SDRam für gcc mit 64MHz auf einem Atmel Xplain :
/*************************************************************************
 *
 *  Name         : .init3
 *
 *  Beschreibung : EBI und SysClock initialisieren
 *
 *                 Aufruf vor main durch den StartUp Code
 *                 Stack-Pointer ist hier schon initialisiert.
 *                 SDRam ab Adresse 0x4000 mit einer Länge von 8MB
 *                 einblenden.Der Speicher wird für globale Variablen
 *                 (static) und malloc()/free() verwendet. Für diese
 *                 Funktionen stehen 48K zur Verfügung, da gcc und die
 *                 libc von einem 16-Bit Adressraum ausgehen.
 *
 *                 Initialwerte werden im Anschluss durch den StartUp Code
 *                 aus dem Flash ins SDRam kopiert.
 *                 Die Linkeroptionen
 *                 "-Wl,-section-start=.data=0x804000" und
 *                 "-Wl,-defsym=__heap_end=0x80ffff"
 *                 sind Pflicht!
 *                 avr-size berücksichtigt den dazubekommenen Speicher 
 *                 nicht! 
 *
 *                 32KHz/32MHz RC-OSC Starten
 *                 PLL mit 64MHz Starten
 *                 ClkCpu auf 32MHz; ClkPer2 auf 64MHz setzen
 *
 *  Parameter    : keine
 *
 *  Rückgabe     : keine
 *
 *************************************************************************/
#define LED0_ON             (PORTE_OUTCLR=PIN0_bm)
#define LED1_ON             (PORTE_OUTCLR=PIN1_bm)
#define LED0_OFF            (PORTE_OUTSET=PIN0_bm)
#define LED1_OFF            (PORTE_OUTSET=PIN1_bm)

void __attribute__ ((naked, section(".init3"))) XplainMemAndClk(void)
{
 uint8_t temp = (WDT.CTRL & ~WDT_ENABLE_bm) | WDT_CEN_bm;
 CCP = CCP_IOREG_gc;
 WDT.CTRL = temp;                       // Watchdog abschalten

 PORTE.DIR      = 0xff;                 // LEDs auf Ausgang
 PORTE.OUT      = 0xff;                 // LEDs aus
 LED0_ON;                               // Konfiguration beginnt...

// EBI Initialisieren;  stammt aus der Atmel AppNote AVR1312.PDF,
// der TechNote AVR1312.ZIP und dem Micron MT48LC16M4A2TG DataSheed

 PORTH.OUT = 0x0F;                      // EBI PORTs richten
 PORTH.DIR = 0xFF;
 PORTK.DIR = 0xFF;
 PORTJ.DIR = 0xF0;

 EBI.CTRL       = EBI_SDDATAW_4BIT_gc | EBI_IFMODE_3PORT_gc;
 EBI.SDRAMCTRLA = (EBI.SDRAMCTRLA & ~(EBI_SDCAS_bm | EBI_SDROW_bm | EBI_SDCOL_gm)) |
                  EBI_SDCOL_10BIT_gc | EBI_SDROW_bm;
 EBI.SDRAMCTRLB = EBI_MRDLY_0CLK_gc | EBI_ROWCYCDLY_1CLK_gc | EBI_RPDLY_0CLK_gc;
 EBI.SDRAMCTRLC = EBI_WRDLY_0CLK_gc | EBI_ESRDLY_0CLK_gc    | EBI_ROWCOLDLY_0CLK_gc;
 EBI.REFRESH    = 0xff00;
 EBI.INITDLY    = 0x0100;
 EBI.CS3.CTRLB  = (EBI.CS3.CTRLB & ~(EBI_CS_SDSREN_bm | EBI_CS_SDMODE_gm)) |
                  EBI_CS_SDMODE_NORMAL_gc;
 EBI.CS3.BASEADDR = (((uint32_t) SDRAM_ADDR)>>8) & (0xFFFF<<(EBI_CS_ASPACE_8MB_gc>>2));
 EBI.CS3.CTRLA  = (EBI.CS3.CTRLA & ~(EBI_CS_ASPACE_gm | EBI_CS_MODE_gm)) |
                  EBI_CS_ASPACE_8MB_gc | EBI_CS_MODE_SDRAM_gc;

 while(!(EBI.CS3.CTRLB & EBI_CS_SDINITDONE_bm)); // warten bis fertig

 // System Clock initialisieren
 OSC.PLLCTRL    = OSC_PLLSRC_RC32M_gc | OSC_PLLFAC3_bm;// 32MHz/4 * 8 = 64MHz
 OSC.DFLLCTRL   = OSC_RC32MCREF_bm;      // 32MHz Rc kalibrieren
 DFLLRC32M.CTRL = DFLL_ENABLE_bm;        // Kalibrierung ein

 OSC.CTRL      |= OSC_RC32MEN_bm | OSC_RC32KEN_bm; // 32M+32K OSC einschalten
 while(!(OSC.STATUS & OSC_RC32KRDY_bm)); // warten bis stabil
 while(!(OSC.STATUS & OSC_RC32MRDY_bm)); // warten bis stabil

 OSC.CTRL      |= OSC_PLLEN_bm ;         // PLL mit 64Mhz ein
 uint8_t CTRLn  = (CLK.PSCTRL & (~(CLK_PSADIV_gm | CLK_PSBCDIV1_bm))) |
                  CLK_PSADIV_1_gc | CLK_PSBCDIV_1_2_gc;
 CCP            = CCP_IOREG_gc;          // ClkCPU = 32Mhz; ClkPer2 = 64 MHz
 CLK.PSCTRL     = CTRLn;                 // Prescaler setzen
 while(!(OSC.STATUS & OSC_PLLRDY_bm));   // warten bis PLL stabil
 CCP            = CCP_IOREG_gc;
 CLK.CTRL       = CLK_SCLKSEL_PLL_gc;    // Sysclock über PLL

 // SDRAM testen
 uint16_t Crc1  = 0xDEAD;
 uint16_t Crc2  = 0xDEAD;
 uint16_t i;
 uint8_t  Val   = 0;

 for(i=SDRAM_ADDR; i < 0xffff - SDRAM_ADDR; i++)
  {
   *(uint8_t*) i = Val;                  // Speicher beschreiben
   Crc1 = _crc_ccitt_update(Crc1 ,Val++);// CRC bilden
  }

 // *(uint16_t*) 0x7654 = 0xBEAF;         // Fehler erzwingen

 for(i=SDRAM_ADDR; i < 0xffff - SDRAM_ADDR; i++)
  {
   Val  = *(uint8_t*) i;                // Speicher lesen
   Crc2 = _crc_ccitt_update(Crc2 ,Val); // CRC bilden
  }

 if(Crc1 == Crc2)                       // passt?
  LED0_OFF;                             // Speicherfehler!

 LED1_ON;                               // ... geschafft
}

Würde mich über Rückmeldungen freuen.  Wer Lust und Zeit hat könnte auch 
mal einige Performancemessungen machen z.B.
10k per malloc() anfordern, diese mit memset() füllen, zurücklesen und 
mit free() wieder freigeben, um den unterscheid zwischen 32/64MHz 
ClkPer2 zu sehen. Ich habe leider keine Messtechnik.

MfG

Autor: Sauger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
nachtrag,

#define   SDRAM_ADDR (0x4000)

Autor: Reader (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wozu sollen die 48k gut sein ? Das Xplain hat 8MB SDRAM !

Autor: Sauger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nabend,

Reader schrieb:
>  * Für diese Funktionen stehen 48K zur Verfügung, da gcc und die
>  * libc von einem 16-Bit Adressraum ausgehen.

dann jubel dem AVR-gcc und der libc mal 8M unter die er für dich 
verwaltet.

MfG

Autor: Werner B. (werner-b)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Reader schrieb:
> wozu sollen die 48k gut sein ? Das Xplain hat 8MB SDRAM !

Das ist schon richtig. Nur leider lassen sich die 8 MB mit AVR-GCC nicht 
so einfach, elegant ansprechen.
Als "Anleitung" wie man generell (und in einer hoffentlich erträglichen 
Geschwindigkeit) mit dem DRAM des XPlain arbeiten kann, ist das 
Codefragment eine "Offenbarung".

Dank an Sauger.

Werner

Autor: Sauger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nabend nochmal,

hier mal eine Testschleife:
int __attribute__((OS_main)) main(void)
{

 PORTD.DIR = 0xff;
 PORTD.OUT = 0x00;      // für Geschwindigkeitsmessungen

 sei();
/*************************************************************************
 *  main Loop
 *************************************************************************/
 while(1)
 {
  PORTD_OUTTGL=PIN0_bm;
  wdt_reset();
  
  #define BLK_LEN     0x9000

    uint8_t *p = malloc(BLK_LEN);
    if(!p)
     {
      LED0_ON;
      continue;
     }

    memset(p, 0xaa, BLK_LEN);
    *(p+BLK_LEN) = 0x0;

    uint16_t Len = strlen((char*)p);

    if(Len != BLK_LEN )  // länge passt nicht
     LED0_ON;

    free(p);
    PORTD_OUTSET=PIN0_bm;
  }
}

durch rumspielen mit den Prescalern
CLK_PSADIV_1_gc | CLK_PSBCDIV_1_2_gc
ist zwischen 32/64MHz ClkPer2 ein Faktor 2 erkennbar. Wenn jemand das 
ganze mal an einen Oskar hängen könnte um reelle Zeiten (ms) zu 
ermitteln wäre ich dankbar.

MfG

Autor: Reader (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Sauger

>dann jubel dem AVR-gcc und der libc mal 8M unter die er für dich
>verwaltet.

Aus diesem Grund nutze ich Assembler, damit lassen sich die 8MB 
ansprechen.

@Werner B:

>Als "Anleitung" wie man generell (und in einer hoffentlich erträglichen
>Geschwindigkeit) mit dem DRAM des XPlain arbeiten kann, ist das
>Codefragment eine "Offenbarung".

Meine Meinung: Ganz oder gar nicht.
Hat meiner Meinung nach in der Codesammlung nichts zu suchen, da völlig 
unbrauchbar.

Autor: Werner B. (werner-b)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vorsicht!

Offenbar durch den Vulkan aus ihrer Isländischen Heimat vertieben 
tummeln sich jetzt hier die Trolle.

Autor: Sauger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin,

Reader schrieb:
> Aus diesem Grund nutze ich Assembler, damit lassen sich die 8MB
> ansprechen.

Ja, und deswegen auch:
"48KB SDRam für gcc mit 64MHz auf einem Atmel Xplain"

Das Beispiel zeigt wie man das EBI das xMega128A1 auf dem Xplain 
initialisiert und den System Takt über die PLL auf 32/64MHz setzen kann.
Durch die Linkeroptionen:
"-Wl,-section-start=.data=0x804000" und 
"-Wl,-defsym=__heap_end=0x80ffff"
werden dann 48K der 8M dem gcc zugeschlagen. Der Rest lässt sich auch 
weiterhin nutzen egal ob C oder Assembler, man muss ihn nur selber 
verwalten.

MfG

P.S.
0x9000 Byte füllen und zurücklesen (mit obiger Testschleife) dauern bei 
64MHz ClkPer2 20ms bei 32Mhz 27ms

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Reader schrieb:
> @Sauger
>
>>dann jubel dem AVR-gcc und der libc mal 8M unter die er für dich
>>verwaltet.
>
> Aus diesem Grund nutze ich Assembler, damit lassen sich die 8MB
> ansprechen.

Wo ist der Sinn? Auch mit dem AVR-GCC lassen sich 8MB ansprechen. Nur 
kann der Linker wegen der 16Bit Pointer unter C nicht die ganzen 8MB 
verwalten.

In Assembler kann man den Speicher gar nicht verwalten lassen, also ist 
die hier gezeigte Lösung der Mittelweg zwischen "gar keine automatische 
Verwaltung" (Assembler) und "vollautomatische Verwaltung" (mit einem 
gepimpten C Compiler, der das unterstützt, wozu AVR-GCC aber nicht 
gehört.).

Autor: Sauger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin,

mal ein Selbstgespräch:

mit:
"-Wl,-section-start=.noinit=0x804000" und
"-Wl,--defsym=__heap_end=0x80ffff

bleiben statische Variablen im internen SRam, malloc()/free() gehen ins 
SDRam.

MfG

Autor: Dominik (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Sauger,

danke für das Code-Beispiel. Allerdings verstehe ich nicht, wie du auf 
die Delay-Werte (EBI.SDRAMCTRLB / EBI.SDRAMCTRLC) kommst. Ich hab ein 
Xplain Revision 4 Board. Als SDRAM-Speicher wird der Baustein 
MT48LC16M4A2P-75:G verwendet. Laut dem Datenblatt des Speichers schafft 
der das von dir verwendete Timing nicht.

MT48LC16M4A2P-75:G (Datenblatt Seite 48/49)
  ACTIVE-to-READ or WRITE delay: 20 ns
  PRECHARGE command period: 20 ns
  WRITE recovery time: 1 CLK + 7.5 ns / 15 ns
  Exit SELF REFRESH-to-ACTIVE command: 75 ns
  LOAD MODE REGISTER command to ACTIVE or REFRESH command: 2 CLK

Da das SDRAM maximal mit 64 MHz getaktet werden kann, ergibt sich eine 
Takt-Zykluszeit von mindestens 15.625 ns. Daher wäre ich auf folgende 
Delay-Werte gekommen:

CLK_PER2 = 64 MHz
  MRDLY: 2
  ROWCYCDLY: Nicht im Datenblatt gefunden -> 7?
  WRDLY: 2
  RPDLY: 2
  ESRDLY: 5
  ROWCOLDLY: 2


Hab ich da was falsch verstanden oder gelesen?


lg,
Dominik


MT48LC16M4A2P-75:G Datenblatt (Rev. N 12/08 EN):
http://www.google.at/url?sa=t&source=web&cd=3&ved=...

AVR XMEGA A Datenblatt (Revision H, updated 12/09):
http://www.atmel.com/dyn/resources/prod_documents/...

Xplain (Revision 4) User Guide (Revision D, updated 4/10)
http://www.atmel.com/dyn/resources/prod_documents/...

Autor: Sauger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Malzeit,

Dominik,
lasse dich nicht von "EBI_MRDLY_0CLK_gc" blenden. "_0CLK" ist schon 
CLK_PR2 / 2

... das ganze aus dem Kopf, werde es mir aber nochmal (beim nächsten 
Sauwetter) anschauen.

MfG

Autor: Dominik (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sauger schrieb:
> lasse dich nicht von "EBI_MRDLY_0CLK_gc" blenden. "_0CLK" ist schon
> CLK_PR2 / 2


Hallo Sauger,


Warum ist das schon CLK_PER2 / 2? Hängt das mit dem CAS = 2 zusammen 
(kenn mich mit SDRAM [noch] nicht so gut aus? Bei den 
Registerbeschreibungen steht im AVR XMEGA A Datenblatt immer
    ... in number of Peripheral 2x clock (CLK_PER2) cycles ...

Daher bin ich davon ausgegangen, dass sich die Registerwerte auf 
CLK_PER2 beziehen. Auch in Abbildung "Figure 33-44. Single write" sieht 
man NOPs die nur einen CLK_PER2-Zyklus lang sind. Die Anzahl der NOPs 
entspricht dem Wert in Register ??DLY . EBI_??DLY_0CLK_gc ist als 0 
definiert. Allerdings steht in den Fußnoten zu den diversen 
Timing-Diagrammen immer
    ... The number of NOPs is equal to WRDLY[1:0] + 1 ...

Also dürfte für WRDLY eine Ausnahme gelten...


Soll ich eventuell einen regulären Beitrag im µC Forum öffnen?


lg,
Dominik


PS: Ich will dich jetzt aber nicht von diversen Freizeitaktivitäten bei 
idealem Sommerwetter abhalten ;-)

Autor: Sauger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nabend,

Dominik schrieb:
> ... in number of Peripheral 2x clock (CLK_PER2) cycles ...

der xMega braucht 2 Takte für sich (besser das EBI)
... aus dem Kopf,

habe hier als Betreuer jede Menge kleine (WUKIS) rumlaufen, die sich 
nicht entscheiden können wer lieber Cowboy / Indianer ist. Nach der 
Fütterung liegen fast alle in ihren Zelten / Tipis, aber die Nacht ist 
noch nicht zu Ende.

MfG

Autor: Hagen Re (hagen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Dominik:

Meiner Meinuing nach siehst du das schon richtig so. Ich benutze den 
selben SDRAM (nicht XPLAIN) und nutze folgende Werte laut Datenblatt für 
64MHz CLK_PER2:
    EBI.SDRAMCTRLA = EBI_SDROW_bm | EBI_SDCOL_10BIT_gc;
    EBI.SDRAMCTRLB = EBI_MRDLY_2CLK_gc | EBI_ROWCYCDLY_1CLK_gc | EBI_RPDLY_3CLK_gc;
    EBI.SDRAMCTRLC = EBI_WRDLY_2CLK_gc | EBI_ESRDLY_5CLK_gc | EBI_ROWCOLDLY_1CLK_gc;
    EBI.REFRESH = 1000; // max. 1023, max. 15.625us, 1/64MHz*1000=15.625us * 4096 = 64ms
    EBI.INITDLY = 6400; // max. 16383, min. 100us, 1/64MHz*6400=100us

Auch beim Refresh und Initdelay sehe ich hier im Forum immer wieder 
inkorrekte Einstellungen. Zb. REFRESH = 0xFF00; was soll das bringen 
wenn Refresh nur 10Bit breit ist, also bis 1023 gehen kann.

Die Row/ColCycDly findet man auch im Datenblatt des SDRAMs, als Tabelle 
in Angabe EBI Takte. Andere Angaben sind wieder in Zeit gemacht und man 
muß das in Takte umrechnen, wie Zb. Refresh und InitDelay.

Gruß Hagen

PS: allerdings läuft es auch mit Angabe von ???_0CLK_gc in allen Felder 
bis auf EBI_ROWCYCDLY_1CLK_gc.

Autor: Sebastian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

danke für den Code, glaube das wird mir sehr weiterhelfen.
Habe bisher noch nie Linker-Optionen verwendet. Kannst du mir sagen, wo 
ich

"-Wl,-section-start=.data=0x804000" und
"-Wl,-defsym=__heap_end=0x80ffff"

eintragen soll?

Verwende einen ATXMEGA128128A1.

MfG
Sebastian

Autor: Sebastian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo noch mal,

habe nun herausgefunden, dass man die Linker-Optionen in AVR Studio 
direkt eintragen kann.
Aber wohin mit dem Code? Er soll ja vor der main aufgerufen werden.

Würde mich freuen, wenn ihr mir weiterhelft.

MfG
Sebastian

Autor: Werner B. (werner-b)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sebastian schrieb:
> Hallo noch mal,
>
> habe nun herausgefunden, dass man die Linker-Optionen in AVR Studio
> direkt eintragen kann.
> Aber wohin mit dem Code? Er soll ja vor der main aufgerufen werden.
>
> Würde mich freuen, wenn ihr mir weiterhelft.
>
> MfG
> Sebastian

Möglicherweise in Section .init3

Siehe
http://www.nongnu.org/avr-libc/user-manual/mem__se...

Autor: Auch was sagen wollen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Janz einfach. Den obigen Code setzt Du z.B. in die Datei die Deine 
main() enthält. Anhand dieser Zeile

void _attribute_ ((naked, section(".init3"))) XplainMemAndClk(void)

erkennt der Compiler was Sache ist und setzt diesen Teil im compilierten 
Code an die richtige Stelle.

Autor: Sebastian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank für eure Hilfe. Es hat funktioniert.

Autor: Sebastian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo nochmal,

leider klappt das alles doch nicht so ganz wie erhofft. Das obige 
Beispiel funktioniert.
Nun habe ich mit den Linkeroptionen 
"-Wl,-Tdata=0x804000,--defsym=__heap_end=0x80ffff" .data, .bss und den 
heap in den externen RAM gelegt. Die main() sieht so aus:

int main (void)
{
  unsigned int i;
  static unsigned int c [15000];
  initSerialPortE0(9600);
  sei();

  for (i = 0; i < 15000; i++)
  {
    c[i] = i;
  }

  for (i = 0; i < 15000; i++)
  {
    usartSendE0(c[i] >> 8);
    usartSendE0(c[i]);
  }

  for (;;)
  {}
}

Das Programm scheint immer wieder neu zu starten und gibt manchmal ca 
1500 Bytes aus, manchmal auch nicht.

Wäre nett, wenn ihr mir noch mal weiterhelfen könntet.

MfG
Sebastian

Autor: Sebastian (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

das Problem war wohl die Initialisierung des EBI, das bei meiner 
Hardware so nicht funktioniert hat. Habe nun aus der Atmel Appnote 
AVR1312 die Initialisierung übernommen. Musste sie nur umbauen, sodass 
es keine Funktionsaufrufe gibt (der Stackpointer ist ja noch nicht 
initialisiert).
Das Ergebnis findet sich im Anhang.

MfG
Sebastian

Autor: Werner B. (werner-b)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Sebastian,

ich vermisse in deinem  XplainMemAndClk(void) nur das "Clk" ?

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.