Forum: Mikrocontroller und Digitale Elektronik Verständnisproblem mit SDRAM


von Moe E. (moe_espunkt)


Lesenswert?

Hallo zusammen,

ich hoffe, dass ich nicht verbal gesteinigt werde, falls ich die ein 
oder andere dumme Frage stelle. Aber falls doch, dann bin ich mental 
bereit :D

Ich weiß nicht ob ich ein grundsätzliches Verständnisproblem habe was 
die Ansteuerung von SDRAMs betrifft. Ich verwende den SDRAM ISSI 
IS42S81600F-7TLI und den µC STM32H753ZIT. Der SDRAM ist an der 
SDRAM-Bank#1 des µC angeschlossen. Die FMC-Schnittstelle des µC habe ich 
auch bereits erfolgreich konfiguriert und ich kann auch bereits auf den 
SDRAM lesen und schreiben. Zum Lesen und Schreiben nutze ich die 
HAL-Funktionen.

Frage: Laut Datenblatt hat der SDRAM vier interne Bänke mit jeweils 
32Mbit und ich verstehe noch nicht ganz, wie ich mit den HAL-Funktionen 
zwischen den Bänken wechseln kann. Mit den Pins BA0 und BA1 kann man 
wohl die jeweilige Bank auswählen aber wie mache ich das aus den 
HAL-Funktionen heraus? Kann es sein, dass ich da mit der Funktion 
"HAL_SDRAM_SendCommand(...)" irgendwie hantieren muss? Also ich sehe 
einfach nicht die Möglichkeit die Pins BA0 und BA1 anzusteuern über HAL.


Danke für eure Hilfe und einen schönen Start in die Woche!

von Harry L. (mysth)


Lesenswert?

Moe E. schrieb:
> Zum Lesen und Schreiben nutze ich die
> HAL-Funktionen.

Warum?
Du kannst den Speicher ganz normal wie jedes andere RAM ansprechen.
Allerdings musst du im Linker-Scruipt eine Region dafür anlegen, und via 
"__attrbute__" deine gewünschten Variablen auch in diesen Bereich legen.
Mit HAL hat das rein gar nichts zu tun.

Moe E. schrieb:
> Mit den Pins BA0 und BA1 kann man
> wohl die jeweilige Bank auswählen

Die legt man einfach auf die oberen Adressleitungen.

Moe E. schrieb:
> aber wie mache ich das aus den
> HAL-Funktionen heraus?

s.o.: das hat absolut nichts mit HAL zu tun.

: Bearbeitet durch User
von Rüdiger B. (rbruns)


Lesenswert?

Harry L. schrieb:
> Die legt man einfach auf die oberen Adressleitungen.

von Falk B. (falk)


Lesenswert?

Moe E. schrieb:
> Kann es sein, dass ich da mit der Funktion
> "HAL_SDRAM_SendCommand(...)" irgendwie hantieren muss? Also ich sehe
> einfach nicht die Möglichkeit die Pins BA0 und BA1 anzusteuern über HAL.

Nö. BA0 und BA1 steuert der FMC komplett automatisch an, da hat die 
Software rein gar nichts zu tun.

von Falk B. (falk)


Lesenswert?

Harry L. schrieb:
> Moe E. schrieb:
>> Mit den Pins BA0 und BA1 kann man
>> wohl die jeweilige Bank auswählen
>
> Die legt man einfach auf die oberen Adressleitungen.

Unsinn. Das ist SDRAM und kein Bastler-SRAM. BA0 und BA1 kommen, 
Surprise, Surprise, an die genau gleichnamigen Pins am Controller!

von Harry L. (mysth)


Lesenswert?

Falk B. schrieb:
> Unsinn. Das ist SDRAM und kein Bastler-SRAM. BA0 und BA1 kommen,
> Surprise, Surprise, an die genau gleichnamigen Pins am Controller!

Hast recht!
Sorry, war ein Schnellschuss...

von Moe E. (moe_espunkt)


Lesenswert?

Falk B. schrieb:
> Moe E. schrieb:
>> Kann es sein, dass ich da mit der Funktion
>> "HAL_SDRAM_SendCommand(...)" irgendwie hantieren muss? Also ich sehe
>> einfach nicht die Möglichkeit die Pins BA0 und BA1 anzusteuern über HAL.
>
> Nö. BA0 und BA1 steuert der FMC komplett automatisch an, da hat die
> Software rein gar nichts zu tun.

Ich glaube da ist mein Denkfehler. Woher weiß der FMC welche Bank er 
ansteuern muss? Oder übergebe ich dem µC die Daten und er kümmert sich 
vollkommen alleine darum in welche Bank er die Daten ablegt? Das habe 
ich nämlich aus dem Datenblatt irgendwie anders verstanden.

: Bearbeitet durch User
von Harry L. (mysth)


Lesenswert?

Moe E. schrieb:
> Ich glaube da ist mein Denkfehler. Woher weiß der FMC welche Bank er
> ansteuern muss?

Aufgrund der Zieladresse.

Moe E. schrieb:
> Oder übergebe ich dem µC die Daten und er kümmert sich
> vollkommen alleine darum in welche Bank er die Daten ablegt?

Genau so.

von Moe E. (moe_espunkt)


Lesenswert?

Harry L. schrieb:
> Moe E. schrieb:
>> Oder übergebe ich dem µC die Daten und er kümmert sich
>> vollkommen alleine darum in welche Bank er die Daten ablegt?
>
> Genau so.

Okay, dann macht alles wieder Sinn. Danke dir und auch danke an Falk für 
die selbe Antwort.

Der SDRAM, den ich verwende, hat eine Kapazität von 128Mbit. Die 
Startadresse der SDRAM Bank#1 am µC ist 0xC0000000. Demnach wäre also 
der Adressbereich von 0xC000000 bis 0xC8000000 der Bereich in dem ich 
die 128Mbit beschreiben kann.
Habe ich einen Denkfehler? Denn bei dem Versuch auf die Speicherzelle 
0xC100000 zu schreiben wird der HardFault_Handler() ausgelöst.

Der Zugriff sieht folgendermaßen aus:
1
void FMC_Test()
2
{
3
  uint32_t i;
4
  uint32_t* SDRAM_START_ADDRESS = (uint32_t*)0xC1000000;
5
  uint8_t SDRAM_DATA[]  = {0xFF,0xFF,0xFF,0xFF};
6
  uint8_t SDRAM_ERASE[] = {0x00,0x00,0x00,0x00};
7
8
  for( i=0; i<256; i++)
9
  {
10
      HAL_SDRAM_Write_8b(&hsdram1,SDRAM_START_ADDRESS, &SDRAM_DATA, sizeof(SDRAM_DATA));
11
      SDRAM_START_ADDRESS++;
12
  }
13
  HAL_Delay(50);
14
}

von MaWin O. (mawin_original)


Lesenswert?

Moe E. schrieb:
> HAL_SDRAM_Write_8b

Warum jetzt wieder HAL?

von Falk B. (falk)


Lesenswert?

Moe E. schrieb:
> Der SDRAM, den ich verwende, hat eine Kapazität von 128Mbit.

Naja, traditionell wwerden Speicher in Bit angegeben, so ganz praktisch 
ist das aber nicht. Das sind 16 MByte, aufgeteilt auf 4 Bänke a 4 MByte.

> Die
> Startadresse der SDRAM Bank#1 am µC ist 0xC0000000.

Wenn das pasend konfiguriert ist.

> Demnach wäre also
> der Adressbereich von 0xC000000 bis 0xC8000000 der Bereich in dem ich
> die 128Mbit beschreiben kann.

Nö. 16 MByte sind 0x0100 0000, macht bei Startadresse 0xC000 0000 eine 
obere Adresse von 0xC0FF FFFF. Du würfelst Bits und Bytes durcheinander! 
Außerdem endet so ein Speicherbereich immer mit FFFF auf den unteren 
Adressen!

> Habe ich einen Denkfehler?

JA!!

> Denn bei dem Versuch auf die Speicherzelle
> 0xC100000 zu schreiben wird der HardFault_Handler() ausgelöst.

Warum in aller Welt Fängst du deinen Test nicht bei der Startadresse an?

> Der Zugriff sieht folgendermaßen aus:
> void FMC_Test()
> {
>   uint32_t i;
>   uint32_t* SDRAM_START_ADDRESS = (uint32_t*)0xC1000000;
>   uint8_t SDRAM_DATA[]  = {0xFF,0xFF,0xFF,0xFF};
>   uint8_t SDRAM_ERASE[] = {0x00,0x00,0x00,0x00};
>   for( i=0; i<256; i++)
>   {
>       HAL_SDRAM_Write_8b(&hsdram1,SDRAM_START_ADDRESS, &SDRAM_DATA,
> sizeof(SDRAM_DATA));
>       SDRAM_START_ADDRESS++;
>   }
>   HAL_Delay(50);
> }

Was soll der Käse? Du hast IMMMER noch nicht verstanden, wie externer 
SDRAM funktioniert! Aus Sicht des C-Programmierers genau so wie interner 
RAM! Da braucht es keine Spezialfunktion! Du kannst einfach mit einem 
Pointer drauf zugreifen! So wie das oben mit SDRAM_START_ADDRESS gemacht 
wird. Aber im Normalfall schreibt man Variablen mit Kleinbuchstaben. 
Alles in Großbuchstaben sind #defines. Das ist eine recht weit 
verbreitete Regel.

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Falk B. schrieb:
> Was soll der Käse? Du hast IMMMER noch nicht verstanden, wie externer
> SDRAM funktioniert! Aus Sicht des C-Programmierers genau so wie interner
> RAM! Da braucht es keine Spezialfunktion!

Es ist nicht sinnvoll, den TE dafür zu beschimpfen, dass er sich 
offenbar strikt an die Dokumentation des HAL hält. Demnach sollen 
tatsächlich alle Zugriffe über die besagten Funktionen HAL_SDRAM_* 
erfolgen, weil darin auch eine Zustandsvariable und eine Verriegelung 
konkurrierender Zugriffe enthalten sind. Der eigentliche Kopiervorgang 
ist ein memcpy() für Arme. Es ist sogar ein "Speicherschutz" vorgesehen, 
der aber keineswegs einen Zugriff auf ein entsprechendes FMC-Register 
beinhaltet, sondern nur über die o.a. Zustandsvariable realisiert wird.

Vermutlich versucht ST damit, ein einheitliches Interface für alle 
möglichen externen Speicher zu schaffen, d.h. auch serielle Flashes 
usw.. Bei parallel angebundenem SDRAM ist das natürlich völlig sinnfrei. 
Es gibt durchaus manche Softwarearchitekten, denen besonders 
einheitliche und schicke Diagramme wichtiger sind als die technische 
Funktionalität; ich kann mir sehr gut vorstellen, dass solche 
elektronischen Hochglanzfolien dann als Implementierungsgrundlage 
dienten. Natürlich sieht das zunächst schön einheitlich und stimmig aus, 
so dass man damit ab einer gewisser Entscheiderebene punkten kann. Und 
man kann auch in den Werbeprospekt reinschreiben, dass es einheitliche 
APIs für alle externen Speicher gibt, unabhängig von ihren 
physikalischen Eigenschaften. Und so etwas finden auch manche 
Entscheider auf Kundenseite hochgradig attraktiv.

Ggf. war sogar mal in der technischen Beschreibung ein Hinweis auf die 
direkte Adressierbarkeit des SDRAM-Bereich enthalten, aber bei 
irgendeiner QS-Runde wurde dann festgestellt, dass hierdurch von der 
definierten Softwarearchitektur abgewichen würde. Zwecks Einheitlichkeit 
dürften dann solche dreisten Umgehungen nicht mehr Kunden gegenüber 
beschrieben werden. Außerdem wird dadurch ja der o.a. "Speicherschutz" 
umgangen.

Ein winziges Fünkchen Sinn könnte ich noch erkennen, wenn die Adresse im 
SDRAM relativ zur Startadresse angegeben würde. Hier ist ST aber 
inkonsequent und verlangt tatsächlich einen Pointer im gesamten 
Adressraum.

> Du kannst einfach mit einem Pointer drauf zugreifen!

Exakt. Man konfiguriert das SDRAM ja auch nicht ständig um.

> So wie das oben mit SDRAM_START_ADDRESS gemacht
> wird. Aber im Normalfall schreibt man Variablen mit Kleinbuchstaben.
> Alles in Großbuchstaben sind #defines. Das ist eine recht weit
> verbreitete Regel.

Volle Zustimmung. Ggf. wäre es sinnvoll, einen Pointer 
(kleingeschrieben) mit einer Konstanten (z.B. großgeschrieben) zu 
initialisieren, sofern man z.B. einen Pufferbereich referenzieren will. 
Dennoch ist es WESENTLICH sinnvoller, nicht direkt mit den Adressen zu 
hantieren, sondern über den Linker die Platzierung der entsprechenden 
Variable im SDRAM zu steuern.

Eine ähnliche Diskussion hatte ich vor ca. 26 Jahren mit einem 
Hardwareentwickler, der auch nicht einsehen wollte, dass ich in meinem 
Programmcode keine expliziten Zugriffsfunktionen für den Speicher 
definieren muss, sondern dass der Programmcode direkt aus dem Speicher 
ausgeführt wird und ich auch für Datenzugriffe nicht explizit an den 
Steuerleitungen (/CS, /WR, /RD, o.ä.) wackeln muss.

: Bearbeitet durch User
von -gb- (Gast)


Lesenswert?

Andreas S. schrieb:
> sondern dass der Programmcode direkt aus dem Speicher
> ausgeführt wird und ich auch für Datenzugriffe nicht explizit an den
> Steuerleitungen (/CS, /WR, /RD, o.ä.) wackeln muss.

... was irgendwo der Inhalt des Begriffs HAL ist. Wenn sich der 
Programmierer auf der Ebene noch mit einzelnen Leitungen befassen 
müsste, deren Bedienung Aufgabe des beteiligten Controllers ist, dann 
gäbe es an jedem I2C und SPI-Baustein einiges zu zuppeln.

Maximmal um eine geeigente Einstellung des CS sollte man sich kümmern 
(müssen).

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Georg B. schrieb:
> Andreas S. schrieb:
>> sondern dass der Programmcode direkt aus dem Speicher
>> ausgeführt wird und ich auch für Datenzugriffe nicht explizit an den
>> Steuerleitungen (/CS, /WR, /RD, o.ä.) wackeln muss.
>
> ... was irgendwo der Inhalt des Begriffs HAL ist.

Nein, das ist etwas ganz anderes, da ja der Programmcode des HAL 
ebenfalls nicht ausgeführt werden könnte. Es ging um das grundsätzliche 
Verständnisproblem des damaligen Hardwareentwicklers, der in seiner 
Karriere noch niemals auch nur ein Stück Programmcode, insbesondere 
Assembler- oder Maschinencode gesehen hatte und einen Mikroprozessor nur 
aus der Sicht seiner externen Pins kannte..

> Wenn sich der
> Programmierer auf der Ebene noch mit einzelnen Leitungen befassen
> müsste, deren Bedienung Aufgabe des beteiligten Controllers ist, dann
> gäbe es an jedem I2C und SPI-Baustein einiges zu zuppeln.

Dann fühlt man sich gleich wieder wie auf dem Atmel AT91RM9200, dessen 
Peripherieblöcke so fehlerhaft waren, dass man I2C lieber per Bitbanging 
betrieb. Hierfür gibt es im Linux-Kernel zu auch explizit die 
Umschaltmöglichkeit. Die USARTs waren im ISO7816-Modus ähnlich 
katastrophal. Erst bei den AT91SAM9 wurden dann etliche Fehler behoben.

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.