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


von Sauger (Gast)


Lesenswert?

Nabend,

48KB SDRam für gcc mit 64MHz auf einem Atmel Xplain :
1
/*************************************************************************
2
 *
3
 *  Name         : .init3
4
 *
5
 *  Beschreibung : EBI und SysClock initialisieren
6
 *
7
 *                 Aufruf vor main durch den StartUp Code
8
 *                 Stack-Pointer ist hier schon initialisiert.
9
 *                 SDRam ab Adresse 0x4000 mit einer Länge von 8MB
10
 *                 einblenden.Der Speicher wird für globale Variablen
11
 *                 (static) und malloc()/free() verwendet. Für diese
12
 *                 Funktionen stehen 48K zur Verfügung, da gcc und die
13
 *                 libc von einem 16-Bit Adressraum ausgehen.
14
 *
15
 *                 Initialwerte werden im Anschluss durch den StartUp Code
16
 *                 aus dem Flash ins SDRam kopiert.
17
 *                 Die Linkeroptionen
18
 *                 "-Wl,-section-start=.data=0x804000" und
19
 *                 "-Wl,-defsym=__heap_end=0x80ffff"
20
 *                 sind Pflicht!
21
 *                 avr-size berücksichtigt den dazubekommenen Speicher 
22
 *                 nicht! 
23
 *
24
 *                 32KHz/32MHz RC-OSC Starten
25
 *                 PLL mit 64MHz Starten
26
 *                 ClkCpu auf 32MHz; ClkPer2 auf 64MHz setzen
27
 *
28
 *  Parameter    : keine
29
 *
30
 *  Rückgabe     : keine
31
 *
32
 *************************************************************************/
33
#define LED0_ON             (PORTE_OUTCLR=PIN0_bm)
34
#define LED1_ON             (PORTE_OUTCLR=PIN1_bm)
35
#define LED0_OFF            (PORTE_OUTSET=PIN0_bm)
36
#define LED1_OFF            (PORTE_OUTSET=PIN1_bm)
37
38
void __attribute__ ((naked, section(".init3"))) XplainMemAndClk(void)
39
{
40
 uint8_t temp = (WDT.CTRL & ~WDT_ENABLE_bm) | WDT_CEN_bm;
41
 CCP = CCP_IOREG_gc;
42
 WDT.CTRL = temp;                       // Watchdog abschalten
43
44
 PORTE.DIR      = 0xff;                 // LEDs auf Ausgang
45
 PORTE.OUT      = 0xff;                 // LEDs aus
46
 LED0_ON;                               // Konfiguration beginnt...
47
48
// EBI Initialisieren;  stammt aus der Atmel AppNote AVR1312.PDF,
49
// der TechNote AVR1312.ZIP und dem Micron MT48LC16M4A2TG DataSheed
50
51
 PORTH.OUT = 0x0F;                      // EBI PORTs richten
52
 PORTH.DIR = 0xFF;
53
 PORTK.DIR = 0xFF;
54
 PORTJ.DIR = 0xF0;
55
56
 EBI.CTRL       = EBI_SDDATAW_4BIT_gc | EBI_IFMODE_3PORT_gc;
57
 EBI.SDRAMCTRLA = (EBI.SDRAMCTRLA & ~(EBI_SDCAS_bm | EBI_SDROW_bm | EBI_SDCOL_gm)) |
58
                  EBI_SDCOL_10BIT_gc | EBI_SDROW_bm;
59
 EBI.SDRAMCTRLB = EBI_MRDLY_0CLK_gc | EBI_ROWCYCDLY_1CLK_gc | EBI_RPDLY_0CLK_gc;
60
 EBI.SDRAMCTRLC = EBI_WRDLY_0CLK_gc | EBI_ESRDLY_0CLK_gc    | EBI_ROWCOLDLY_0CLK_gc;
61
 EBI.REFRESH    = 0xff00;
62
 EBI.INITDLY    = 0x0100;
63
 EBI.CS3.CTRLB  = (EBI.CS3.CTRLB & ~(EBI_CS_SDSREN_bm | EBI_CS_SDMODE_gm)) |
64
                  EBI_CS_SDMODE_NORMAL_gc;
65
 EBI.CS3.BASEADDR = (((uint32_t) SDRAM_ADDR)>>8) & (0xFFFF<<(EBI_CS_ASPACE_8MB_gc>>2));
66
 EBI.CS3.CTRLA  = (EBI.CS3.CTRLA & ~(EBI_CS_ASPACE_gm | EBI_CS_MODE_gm)) |
67
                  EBI_CS_ASPACE_8MB_gc | EBI_CS_MODE_SDRAM_gc;
68
69
 while(!(EBI.CS3.CTRLB & EBI_CS_SDINITDONE_bm)); // warten bis fertig
70
71
 // System Clock initialisieren
72
 OSC.PLLCTRL    = OSC_PLLSRC_RC32M_gc | OSC_PLLFAC3_bm;// 32MHz/4 * 8 = 64MHz
73
 OSC.DFLLCTRL   = OSC_RC32MCREF_bm;      // 32MHz Rc kalibrieren
74
 DFLLRC32M.CTRL = DFLL_ENABLE_bm;        // Kalibrierung ein
75
76
 OSC.CTRL      |= OSC_RC32MEN_bm | OSC_RC32KEN_bm; // 32M+32K OSC einschalten
77
 while(!(OSC.STATUS & OSC_RC32KRDY_bm)); // warten bis stabil
78
 while(!(OSC.STATUS & OSC_RC32MRDY_bm)); // warten bis stabil
79
80
 OSC.CTRL      |= OSC_PLLEN_bm ;         // PLL mit 64Mhz ein
81
 uint8_t CTRLn  = (CLK.PSCTRL & (~(CLK_PSADIV_gm | CLK_PSBCDIV1_bm))) |
82
                  CLK_PSADIV_1_gc | CLK_PSBCDIV_1_2_gc;
83
 CCP            = CCP_IOREG_gc;          // ClkCPU = 32Mhz; ClkPer2 = 64 MHz
84
 CLK.PSCTRL     = CTRLn;                 // Prescaler setzen
85
 while(!(OSC.STATUS & OSC_PLLRDY_bm));   // warten bis PLL stabil
86
 CCP            = CCP_IOREG_gc;
87
 CLK.CTRL       = CLK_SCLKSEL_PLL_gc;    // Sysclock über PLL
88
89
 // SDRAM testen
90
 uint16_t Crc1  = 0xDEAD;
91
 uint16_t Crc2  = 0xDEAD;
92
 uint16_t i;
93
 uint8_t  Val   = 0;
94
95
 for(i=SDRAM_ADDR; i < 0xffff - SDRAM_ADDR; i++)
96
  {
97
   *(uint8_t*) i = Val;                  // Speicher beschreiben
98
   Crc1 = _crc_ccitt_update(Crc1 ,Val++);// CRC bilden
99
  }
100
101
 // *(uint16_t*) 0x7654 = 0xBEAF;         // Fehler erzwingen
102
103
 for(i=SDRAM_ADDR; i < 0xffff - SDRAM_ADDR; i++)
104
  {
105
   Val  = *(uint8_t*) i;                // Speicher lesen
106
   Crc2 = _crc_ccitt_update(Crc2 ,Val); // CRC bilden
107
  }
108
109
 if(Crc1 == Crc2)                       // passt?
110
  LED0_OFF;                             // Speicherfehler!
111
112
 LED1_ON;                               // ... geschafft
113
}

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

von Sauger (Gast)


Lesenswert?

nachtrag,

#define   SDRAM_ADDR (0x4000)

von Reader (Gast)


Lesenswert?

wozu sollen die 48k gut sein ? Das Xplain hat 8MB SDRAM !

von Sauger (Gast)


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

von Werner B. (werner-b)


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

von Sauger (Gast)


Lesenswert?

Nabend nochmal,

hier mal eine Testschleife:
1
int __attribute__((OS_main)) main(void)
2
{
3
4
 PORTD.DIR = 0xff;
5
 PORTD.OUT = 0x00;      // für Geschwindigkeitsmessungen
6
7
 sei();
8
/*************************************************************************
9
 *  main Loop
10
 *************************************************************************/
11
 while(1)
12
 {
13
  PORTD_OUTTGL=PIN0_bm;
14
  wdt_reset();
15
  
16
  #define BLK_LEN     0x9000
17
18
    uint8_t *p = malloc(BLK_LEN);
19
    if(!p)
20
     {
21
      LED0_ON;
22
      continue;
23
     }
24
25
    memset(p, 0xaa, BLK_LEN);
26
    *(p+BLK_LEN) = 0x0;
27
28
    uint16_t Len = strlen((char*)p);
29
30
    if(Len != BLK_LEN )  // länge passt nicht
31
     LED0_ON;
32
33
    free(p);
34
    PORTD_OUTSET=PIN0_bm;
35
  }
36
}

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

von Reader (Gast)


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.

von Werner B. (werner-b)


Lesenswert?

Vorsicht!

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

von Sauger (Gast)


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

von Simon K. (simon) Benutzerseite


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

von Sauger (Gast)


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

von Dominik (Gast)


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=0CCYQFjAC&url=http%3A%2F%2Fdownload.micron.com%2Fpdf%2Fdatasheets%2Fdram%2Fsdram%2F64MSDRAM.pdf&rct=j&q=MT48LC16M4A2P-75%3AG&ei=_78pTIziOtuhsQaN4aDEBA&usg=AFQjCNFjW7otmsW78p97ayW8QdJcFaasQg

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

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

von Sauger (Gast)


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

von Dominik (Gast)


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

von Sauger (Gast)


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

von Hagen R. (hagen)


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:
1
    EBI.SDRAMCTRLA = EBI_SDROW_bm | EBI_SDCOL_10BIT_gc;
2
    EBI.SDRAMCTRLB = EBI_MRDLY_2CLK_gc | EBI_ROWCYCDLY_1CLK_gc | EBI_RPDLY_3CLK_gc;
3
    EBI.SDRAMCTRLC = EBI_WRDLY_2CLK_gc | EBI_ESRDLY_5CLK_gc | EBI_ROWCOLDLY_1CLK_gc;
4
    EBI.REFRESH = 1000; // max. 1023, max. 15.625us, 1/64MHz*1000=15.625us * 4096 = 64ms
5
    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.

von Sebastian (Gast)


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

von Sebastian (Gast)


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

von Werner B. (werner-b)


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__sections.html

von Auch was sagen wollen (Gast)


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.

von Sebastian (Gast)


Lesenswert?

Vielen Dank für eure Hilfe. Es hat funktioniert.

von Sebastian (Gast)


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

von Sebastian (Gast)


Angehängte Dateien:

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

von Werner B. (werner-b)


Lesenswert?

@ Sebastian,

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

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
Noch kein Account? Hier anmelden.