Forum: Mikrocontroller und Digitale Elektronik xmega128a1 EBI SDRAM


von Markus C. (ljmarkus)


Lesenswert?

Hallo,

Ich habe das ALVIDI Board (V1.3) mit dem SDRAM MT48LC16M4A2.

nun lege zb.
1
volatile uint8_ data_00[512];
2
volatile uint8_ data_01[512];
3
volatile uint8_ data_02[512];
4
volatile uint8_ data_03[512];
5
volatile uint8_ data_04[512];
6
volatile uint8_ data_05[512];
7
volatile uint8_ data_06[512];
8
volatile uint8_ data_07[512];
9
volatile uint8_ data_08[512];
10
volatile uint8_ data_09[512];
11
volatile uint8_ data_10[512];
12
volatile uint8_ data_11[512];
13
volatile uint8_ data_12[512];
14
volatile uint8_ data_13[512];
15
volatile uint8_ data_14[512];
16
volatile uint8_ data_15[512];
17
volatile uint8_ data_16[512];
18
volatile uint8_ data_17[512];
19
volatile uint8_ data_18[512];
20
volatile uint8_ data_19[512];
21
volatile uint8_ data_20[512];

an und befülle die Arrays zb: data_00[i] = 'a' usw.
wenn ich die dann auslese und über Uart aus gebe habe ich immer an der 
gleichen Stelle mehrere Byte Fehler.

Den EBI starte ich so:
1
void initExternalRam(void){
2
/*--------------------------------------------------------------------------------------*/
3
  //SRAM einbinden mittels EBI (External Bus Interface)
4
  //RAM an Port H:(Ctrl), 
5
  //            J:D0..D3, A8..A11
6
  //            K:A0..A7
7
  /*! \brief Address where we want SDRAM to be accessed. */
8
  #define SDRAM_ADDR 0x4000
9
10
  /*! \brief Macro to access SDRAM. */
11
  #define SDRAM(addr) ((uint8_t *) SDRAM_ADDR)[addr]
12
13
  /*! \brief Number of test bytes to store to SDRAM */
14
  #define VECTOR_SIZE 40000L
15
  /*
16
   *  Hardware setup for 3-port SDRAM interface:
17
   *
18
   *  PORTK[7:0] - A[7:0]
19
   *
20
   *  PORTJ[7:0] - {A[11:8],D[3:0]}
21
   *
22
   *  PORTH[7:0] - {WE,CAS,RAS,DQM,BA0,BA1,CKE,CLK}
23
   *
24
   */
25
26
  /* Set signals which are active-low to high value */
27
  PORTH.OUT = 0x0F;
28
29
30
  /* Configure bus pins as outputs(except for data lines). */
31
  PORTH.DIR = 0xFF;
32
  PORTK.DIR = 0xFF;
33
  PORTJ.DIR = 0xF0;
34
35
  /* Set direction and output value of Chip Select line (C0). */
36
  PORTC.DIR = 0x01;
37
  PORTC.OUT = 0x00;
38
39
40
41
42
43
  // Initialize EBI. 
44
  EBI_Enable( EBI_SDDATAW_4BIT_gc,
45
              EBI_LPCMODE_ALE1_gc,
46
              EBI_SRMODE_ALE12_gc,
47
              EBI_IFMODE_3PORT_gc );
48
49
  // Initialize SDRAM 
50
  EBI_EnableSDRAM( EBI_CS_ASPACE_2MB_gc, //EBI_CS_ASPACE_8KB_gc,   // 8 KB address space. 
51
                   (void *) SDRAM_ADDR,    // Base address. 
52
                   false,                  // 2 cycle CAS Latency.
53
                   false,                  // 11 Row bits. 
54
                   EBI_SDCOL_8BIT_gc,      // 8 Column bits.
55
                   EBI_MRDLY_1CLK_gc,      // 1 cycle Mode Register Delay. 
56
                   EBI_ROWCYCDLY_1CLK_gc,  // 1 cycle Row Cycle Delay. 
57
                   EBI_RPDLY_1CLK_gc,      // 1 cycle Row to Pre-charge Delay. 
58
                   EBI_WRDLY_1CLK_gc,      // 1 cycle Write Recovery Delay. 
59
                   EBI_ESRDLY_1CLK_gc,     // 1 cycle Exit Self Refresh to Active Delay. 
60
                   EBI_ROWCOLDLY_1CLK_gc,  // 1 cycle Row to Column Delay. 
61
                   0x03FF,                 // 1023 cycle Refresh Period (32.8 ms @ 2MHz). 
62
                   0x0100 );               // 256 cycle Initialization Delay (128 us @ 2MHz). 
63
64
65
}

Stimmt meine EBI nicht oder woran kann es liegen?


Danke,
Markus

von Jens (Gast)


Lesenswert?

Du schreibst nicht in das externe RAM sondern in das interne.
Das hier:
#define SDRAM_ADDR 0x4000

/*! \brief Macro to access SDRAM. */
  #define SDRAM(addr) ((uint8_t *) SDRAM_ADDR)[addr]

ist die Startadresse (0x4000) für deinen externen RAM-Bereich. Deine 
Arrays müssen ab diesem RAM-Bereich im Speicher liegen. Bei den 
Test-Sourcen, die ich gefunden habe, schreiben die immer "zu Fuß" ins 
RAM. Ist für mich unlogisch, aber anscheinend geht das nicht besser.

Grüße, Jens

von Markus C. (ljmarkus)


Lesenswert?

Hallo Jens,

hmm, wie lege ich denn die arrays in den SDRAM und beschreibe und lese 
die?

danke, markus

von Jens (Gast)


Lesenswert?

Ich schau mal wo ich die Sachen habe. Vielleicht kann ich die Sachen 
hochladen.
Dauert aber ein bisschen. Vielleicht heute Abend.
Bei mir habe ich das externe RAM auf dem XPLAIN Board in Betrieb 
genommen und das läuft ganz gut.
Was ich aber nicht verstehe wou das Ganze gut sein soll. Wenn ich die 
Werte "zu Fuß" reinschreiben muss, ist das mit jedem beliebigen 
Controller möglich, oder?
Ich hatte gehofft, dass der Compiler merkt dass ich mehr Speicher habe 
und kann dann das RAM dementsprechend aufteilen. Vielleicht weißß hier 
ja noch jemand etwas mehr als ich.
Gruß, Jens

von Markus C. (ljmarkus)


Lesenswert?

Also mein Wunsch wäre ja das man frei wählen kann wo man was rein 
schreibt.

uint8_t xyz[100];          // liegt im internem SRAM
uint8_t abc[100] extern;   // liegt im externen SRAM

somit nutzt man die schnelleren 8Kb internen SRAM
und da GCC dezeit ja nur max. 64Kb unterstützt, hat man 56Kb externen 
SDRAM.

lg, markus

von Jens (Gast)


Lesenswert?

Im Tutorial kann ich die maximale Größe grad nicht sehen. Wo steht, dass 
der Speicher begrenzt ist?
Kann man vielleicht mehr nehmen, wenn man malloc() verwendet? Ich werde 
das heute Abend auf dem XPLAIN versuchen. Mit dem JTAG-Debugger müsste 
ich die Werte ja sehen können. Oder ich schreibe die 8Mbyte voll und 
lese die wieder aus. Ich lass mir was einfallen.
Ich hab auch im Netz noch keine vernünftigen Sourcen zum EBI gefunden.
Wie gesagt, bei mir hab ich ein Funktion, die den externen Speicher 
beschreibt. Effektiv ist das nicht!

Gruß

von Jens (Gast)


Lesenswert?

Wie gesagt, bei mir dauert das immer ein bisschen, da ich nicht so viel 
Zeit habe. Schau immer mal wieder hier rein. Ich werde die Ergebnisse 
hochladen! :-)

von Markus C. (ljmarkus)


Lesenswert?

Hallo Jens,

habe diese diese Funktion:
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
#define LED0_GREEN            (PORTE_OUTSET=PIN0_bm) && (PORTE_OUTCLR=PIN1_bm)
39
#define LED0_RED              (PORTE_OUTSET=PIN1_bm) && (PORTE_OUTCLR=PIN0_bm)
40
#define LED0_OFF              (PORTE_OUTCLR=PIN0_bm) && (PORTE_OUTCLR=PIN1_bm)
41
42
void __attribute__ ((naked, section(".init3"))) XplainMemAndClk(void)
43
{
44
  uint8_t temp = (WDT.CTRL & ~WDT_ENABLE_bm) | WDT_CEN_bm;
45
  CCP = CCP_IOREG_gc;
46
  WDT.CTRL = temp;                       // Watchdog abschalten
47
  
48
  PORTE.DIR      = 0xff;                 // LEDs auf Ausgang
49
  PORTE.OUT      = 0xff;                 // LEDs aus
50
  LED0_OFF;
51
  //LED0_ON;                               // Konfiguration beginnt...
52
  
53
  // EBI Initialisieren;  stammt aus der Atmel AppNote AVR1312.PDF,
54
  // der TechNote AVR1312.ZIP und dem Micron MT48LC16M4A2TG DataSheed
55
56
  PORTH.OUT = 0x0F;                      // EBI PORTs richten
57
  PORTH.DIR = 0xFF;
58
  PORTK.DIR = 0xFF;
59
  PORTJ.DIR = 0xF0;
60
61
  EBI.CTRL       = EBI_SDDATAW_4BIT_gc | EBI_IFMODE_3PORT_gc;
62
  EBI.SDRAMCTRLA = (EBI.SDRAMCTRLA & ~(EBI_SDCAS_bm | EBI_SDROW_bm | EBI_SDCOL_gm)) |
63
                    EBI_SDCOL_10BIT_gc | EBI_SDROW_bm;
64
  EBI.SDRAMCTRLB = EBI_MRDLY_0CLK_gc | EBI_ROWCYCDLY_1CLK_gc | EBI_RPDLY_0CLK_gc;
65
  EBI.SDRAMCTRLC = EBI_WRDLY_0CLK_gc | EBI_ESRDLY_0CLK_gc    | EBI_ROWCOLDLY_0CLK_gc;
66
  EBI.REFRESH    = 0xff00;
67
  EBI.INITDLY    = 0x0100;
68
  EBI.CS3.CTRLB  = (EBI.CS3.CTRLB & ~(EBI_CS_SDSREN_bm | EBI_CS_SDMODE_gm)) |
69
                    EBI_CS_SDMODE_NORMAL_gc;
70
  EBI.CS3.BASEADDR = (((uint32_t) SDRAM_ADDR)>>8) & (0xFFFF<<(EBI_CS_ASPACE_8MB_gc>>2));
71
  EBI.CS3.CTRLA  = (EBI.CS3.CTRLA & ~(EBI_CS_ASPACE_gm | EBI_CS_MODE_gm)) |
72
                    EBI_CS_ASPACE_8MB_gc | EBI_CS_MODE_SDRAM_gc;
73
74
  while(!(EBI.CS3.CTRLB & EBI_CS_SDINITDONE_bm)); // warten bis fertig
75
76
  // System Clock initialisieren
77
  OSC.PLLCTRL    = OSC_PLLSRC_RC32M_gc | OSC_PLLFAC3_bm;// 32MHz/4 * 8 = 64MHz
78
  OSC.DFLLCTRL   = OSC_RC32MCREF_bm;      // 32MHz Rc kalibrieren
79
  DFLLRC32M.CTRL = DFLL_ENABLE_bm;        // Kalibrierung ein
80
81
  OSC.CTRL      |= OSC_RC32MEN_bm | OSC_RC32KEN_bm; // 32M+32K OSC einschalten
82
  while(!(OSC.STATUS & OSC_RC32KRDY_bm)); // warten bis stabil
83
  while(!(OSC.STATUS & OSC_RC32MRDY_bm)); // warten bis stabil
84
85
  OSC.CTRL      |= OSC_PLLEN_bm ;         // PLL mit 64Mhz ein
86
  uint8_t CTRLn  = (CLK.PSCTRL & (~(CLK_PSADIV_gm | CLK_PSBCDIV1_bm))) |
87
                    CLK_PSADIV_1_gc | CLK_PSBCDIV_1_2_gc;
88
  CCP            = CCP_IOREG_gc;          // ClkCPU = 32Mhz; ClkPer2 = 64 MHz
89
  CLK.PSCTRL     = CTRLn;                 // Prescaler setzen
90
  while(!(OSC.STATUS & OSC_PLLRDY_bm));   // warten bis PLL stabil
91
  CCP            = CCP_IOREG_gc;
92
  CLK.CTRL       = CLK_SCLKSEL_PLL_gc;    // Sysclock über PLL
93
94
  // SDRAM testen
95
  uint16_t Crc1  = 0xDEAD;
96
  uint16_t Crc2  = 0xDEAD;
97
  uint16_t i;
98
  uint8_t  Val   = 0;
99
  
100
  
101
  for(i=SDRAM_ADDR; i < 0xffff - SDRAM_ADDR; i++)
102
  {
103
    *(uint8_t*) i = Val;                  // Speicher beschreiben
104
    Crc1 = _crc_ccitt_update(Crc1 ,Val++);// CRC bilden
105
  }
106
107
 // *(uint16_t*) 0x7654 = 0xBEAF;         // Fehler erzwingen
108
 
109
 
110
  for(i=SDRAM_ADDR; i < 0xffff - SDRAM_ADDR; i++)
111
  {
112
    Val  = *(uint8_t*) i;                // Speicher lesen
113
    Crc2 = _crc_ccitt_update(Crc2 ,Val); // CRC bilden
114
  }
115
116
  if (Crc1 == Crc2) {  LED0_GREEN; }  // passt?
117
  else { LED0_RED; }                // Speicherfehler
118
119
//  if(Crc1 == Crc2) LED0_OFF;                     // passt? 
120
//  else LED0_ON;                             // Speicherfehler!
121
//  LED1_ON;                               // ... geschafft
122
}

im makefile:
1
#---------------- Linker Options ----------------
2
#  -Wl,...:     tell GCC to pass this to linker.
3
#    -Map:      create map file
4
#    --cref:    add cross reference to  map file
5
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
6
LDFLAGS += $(EXTMEMOPTS)
7
LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS))
8
LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
9
#LDFLAGS += -T linker_script.x
10
LDFLAGS += -Wl,-section-start=.data=0x804000
11
LDFLAGS += -Wl,-defsym=__heap_end=0x80ffff

lg, markus

von Jens (Gast)


Lesenswert?

Der Speicher auf deinem Board ist genauso groß wie auf dem XPLAIN Board. 
Daher müssten die Sourcen kompatibel sein. Ab 18 Uhr bin ich zu Hause 
und kann das bei mir mal testen. Die Ergebnisse werde ich dann hier 
hochladen. Ich bin mir sicher, dass das nicht nur für uns zwei 
interessant ist!

von Markus C. (ljmarkus)


Lesenswert?

Wenn ich mir das jetzt so durchrechne, externer SDRAM fängt bei 0x4000 
an.
0xFFFF - 0x4000 = 49kB die man nutzen kann.

Bis heute abend. markus

von Jens (Gast)


Angehängte Dateien:

Lesenswert?

Also ich bin einen Schritt weiter:
Ich habe das exteren SDRAM am Laufen, aber du hast Recht: Man kann nur 
49kByte benutzen. Dafür kannst du aber das Ram so einbinden wie du das 
wolltest. Du kannst einfach in das Array schreiben und es wird 
automatisch im externen RAM angelegt. Schau dir das mal an. Vielleicht 
kannst du das direkt laufen lassen.
Jetzt muss man nur noch rausbekommen, warum die Größe limitiert ist. Das 
ist sehr unschön! Ich brauche mehr Platz.
Wenn man mit einer Funktion ins RAM schreibt geht mehr. Das habe ich 
schon getestet. Da gehen wirklich die 8MByte. Aber halt langsamer.
Ich hänge das Projekt an!

von Markus C. (ljmarkus)


Lesenswert?

Hallo Jens,

ja nur das was ich nicht verstehe ist warum nur 49kB nutzbar sind?
da fehlen 16kB (8kB vom internen) und 8kB vom externen.

lg, markus

von Jens (Gast)


Lesenswert?

Ich hab es:
Im Datenblatt auf Seite 22 steht, das das interne SRAM auf Adresse 
0x2000 los geht.
Enn man mehr als 64kByte haben will, muss man die Adressierung selber 
machen und einen 32bit Pointer anlegen. In den Tutorials von Atmel ist 
da was drin. Aber wie gut das geht weiss ich noch nicht.
Ich habe hier im Forum eine Bibliothek gefunden (himem.h). Die macht 
genau das. Die verwendet nicht nur die RAMPX und RAMPY Pointer, sondern 
auch den RAMPZ Pointer. Ich hab die noch nicht implementiert. Aber 
vielleicht hast du heute noch Muse das zu tun. Ich schaff das heute 
wahrscheinlich nicht mehr.
Ansonsten ab morgen mehr. Ob ich am Wochenende dazu komme weiss ich 
nicht. Du müsstest genau sagen, was du brauchst. Dann kann ich morgen 
vielleicht mal einen Studenten in der Firma dran setzten!

Grüße und schönen Abend, Jens

von Markus C. (ljmarkus)


Lesenswert?

Hallo Jens,

das es "normal" mit dem GCC nur bis 64kB geht ist mir klar.

Dem Linker sage ich folgendes:
1
#---------------- Linker Options ----------------
2
#  -Wl,...:     tell GCC to pass this to linker.
3
#    -Map:      create map file
4
#    --cref:    add cross reference to  map file
5
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
6
LDFLAGS += $(EXTMEMOPTS)
7
LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS))
8
LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
9
#LDFLAGS += -T linker_script.x
10
LDFLAGS += -Wl,-section-start=.data=0x804000
11
LDFLAGS += -Wl,-defsym=__heap_end=0x80ffff

Bei dieser Einstellung habe ich ja 49kB zuverfügung.


der interne geht bei 0x2000 los, der externe bei 0x4000


0xFFFF - 0x2000 = 57kB. Da fehlen doch aber noch 8kB

lg, markus

von Jens (Gast)


Lesenswert?

Schau mal ins Datenblatt rein!
Von 0x0000 - 0x1FFF sind die ganzen Register
    0x2000 - 0x3FFF internes SRAM
    0x4000 - 0xFFFFFF externes RAM
Der Atmel hat eine durchgehende Adressmap für alle Speicher und 
Register.
Mit den 49kB geht das genau auf.
Deine Linker Optionen muss ich zugeben, die sagen mir überhaut nichts. 
Damit hatte ich bis jetzt noch nichts zu tun.
Ich lade morgen nochmal den anderen Code hoch, der den Speicher bis 
8MByte unterstützt. Da müssten wir uns mal Gedanken machen, ob man den 
inline einfügt und wir müssten testen, ob das die Performance steigert. 
Der Mittelweg ist dann der Richtige. Nämlich Laufzeit und 
Speicherbelastung.

Gruß, Jens

von Markus C. (ljmarkus)


Lesenswert?

Ich habe nochmal etwas getestet, ziehe ich meinen CS Jumper für den 
externen RAM, dann wird kein Array mehr angelegt was bedeutet das der 
interne Speicher nicht angesprochen wird.

lg, markus

von Jens (Gast)


Lesenswert?

Das glaube ich nicht. Kannst du den Code mal posten?
Das CS geht doch nur auf den externen SRAM. Du könntest auch mal 
beschreiben, was du vor hast. Dann kann man die SOurcen gleich so 
trimmen, das das passt.

Gruß, Jens

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.