Arbeiten Sie mit der SD-Karte über die SPI-Schnittstelle. VHDL-Implementierung

Hallo Habr! Bei der Arbeit hatte ich die Aufgabe, die Möglichkeit der Implementierung der Datenspeicherung auf einer SD-Karte beim Anschluss an ein FPGA zu prüfen. Die Verwendung von SPI wurde als Interaktionsschnittstelle angenommen, da es einfacher zu implementieren ist. Ich möchte die gesammelten Erfahrungen teilen.



Da der Platz auf der Leiterplatte immer begrenzt ist, werden SD-Karten am Beispiel von Karten im microSD-Formfaktor berücksichtigt.

Inhalt


1. Lesen der Spezifikation
1.1 Allgemeine Informationen
1.2 Initialisierung
1.3 Löschen von Informationen
1.4 Lesen von Informationen
1.4.1 Lesen eines Datenblocks
1.4.2 Lesen vieler Datenblöcke
1.5 Schreiben von Informationen
1.5.1 Schreiben eines Datenblocks
1.5.2 Schreiben vieler Datenblöcke
2. Implementieren des Algorithmus in Hardware
2.1 Komponente der physischen Schicht
2.2 Komponente der Befehlsebene
2.3 Komponente der Kommunikation mit der Außenwelt
3. Überprüfung in Hardware
4. Ergebnisse

1. Lesen der Spezifikationen


1.1 Allgemeines


Ein kurzes Lesen der Spezifikation zeigt uns die folgenden SD-Kartenoptionen:

  • Die Datenübertragung auf die SD-Karte erfolgt in einer Zeile.
  • Das Lesen von Daten von einer SD-Karte erfolgt in einer Zeile.
  • im SPI-Modus kann die Leistung nur +3,3 V betragen;
  • Taktfrequenz im Initialisierungsmodus im Bereich von 100-400 kHz;
  • Taktfrequenz nach der Initialisierung - 25 MHz.

Dies impliziert sofort den Punkt auf der theoretischen Spitzenbandbreite: 25 MHz * 1 Bit = 25 Mb / s, was etwas klein ist. Die zweite abzüglich der Verwendung von SD-Karten, Strom + 3,3V. Auf der Leiterplatte, auf der die SD-Karte installiert werden sollte, liegt keine solche Spannung an.

MicroSD-Formfaktorkarten können nach Kapazität in drei Kategorien unterteilt werden:

  • SDSC Kartenkapazität bis zu 2 GB inklusive. Die Adresse auf der Karte ist Byte.
  • SDHC. Die Kartenkapazität beträgt mehr als 2 GB und bis zu 32 GB inklusive. Die Adresse auf der Karte gibt einen 512-Byte-Block an.
  • SDXC. Die Kartenkapazität beträgt mehr als 32 GB und bis zu 128 TB inklusive. Die Adresse auf der Karte gibt einen 512-Byte-Block an.

Die allgemeine Ansicht der Karte ist in der folgenden Abbildung dargestellt.


Kontakt NummerNameEine ArtBeschreibung
1RSV- -Wird nicht benutzt
2CSEingangChipauswahl
3DIEingangDatenleitung vom Master-Gerät (MOSI)
4VddErnährungVersorgungsspannung
5SCLKEingangTaktsignal
6VssErnährungLand
7TUNAusgabeDatenleitung zum Master-Gerät (MISO)
8RSV- -Wird nicht benutzt

Der Anschluss erfolgt gemäß folgendem Diagramm:


Der Widerstand muss 50 kOhm betragen.

Nach dem Einschalten befindet sich die SD-Karte im SDIO-Modus. Um in den SPI-Modus zu wechseln, müssen Sie die Initialisierung durchführen. Das Protokoll für die Arbeit mit der Karte beinhaltet die Verwendung eines Steuerschemas für die korrekte Übertragung von Daten und Befehlen in Form eines CRC-Algorithmus. Im SPI-Modus ist die CRC-Überprüfung standardmäßig deaktiviert. Daher muss der erste an die Karte gesendete Befehl zum Umschalten der Karte in den SPI-Modus den richtigen CRC-Wert enthalten.

Über die SPI-Schnittstelle übertragene Befehle sind 48 Bit groß. Befehlsformat:

  • Bit 47 (ganz links) enthält immer den Wert 0.
  • Bit 46 enthält immer den Wert 1.
  • Die Bits 45..40 enthalten den Befehlsindex.
  • Die Bits 39..8 enthalten die Argumente des Befehls.
  • Die Bits 7..1 enthalten CRC aus vorherigen Bits.
  • Bit 0 enthält immer den Wert 1.

Die Bits 47 und 46 geben der Karte die Möglichkeit, den Beginn einer Transaktion eindeutig zu verfolgen, da der MOSI-Bus in Ruhe einer ist.



Die Befehle, die beim Arbeiten mit der SD-Karte verwendet werden, erhalten Antworten wie R1, R3, R7.


Eine Antwort vom Typ R1, Größe 8 Bit. Antworttyp R3, Größe 40 Bit. Antworttyp R7, Größe 40 Bit. Alle Befehle und ihre Antworten sind in der vereinfachten Spezifikation der physischen Schicht aufgeführt.









1.2 Initialisierung


Initialisierungsalgorithmus:

  1. Warten Sie nach dem Einschalten mindestens 1 ms.
  2. Generieren Sie mindestens 74 Taktschaltungen für die Karte. CS- und MOSI-Leitungen müssen sich im Status der logischen Einheit befinden.
  3. Generieren Sie den Befehl CMD0. Der Befehl CMD0 setzt die SD-Karte zurück.
  4. CMD0. R1. , R1 16 , 3. R1 , 0x01 ( ), 3, 5.
  5. CMD8. .
  6. CMD8. R7. , , , 7, , , 17, 13.
  7. CMD55. CMD55 , .
  8. CMD55. R1. 0x01 ( ), 7, 9.
  9. ACMD41. ACMD41 , SDSC ( 0x00000000) .
  10. ACMD41. R1. , , 11. , 0x00 ( ) 14, 7.
  11. CMD1. CMD1 ACMD41.
  12. CMD1. R1. , , 13, , 0x00 ( ), 14, 11.
  13. . , . .
  14. CMD16. , 512 .
  15. CMD16. R1. , 0x00 ( ) 16, 13.
  16. . . .
  17. CMD55. CMD55 , .
  18. CMD55. R1. 0x01 ( ), 17, 19.
  19. ACMD41. ACMD41. ACMD41 , SDHC ( 0x40000000) .
  20. ACMD41. R1. , , 13. , 0x00 ( ) 21, 17.
  21. CMD58. .
  22. Warten auf eine Antwort auf den Befehl CMD58. Die Antwort ist eine Antwort vom Typ R3. Wenn in der Antwort, dass die Karte mit Blockadressen von 512 Bytes arbeitet, ein Bit gesetzt ist, fahren Sie mit Schritt 16 fort, andernfalls mit Schritt 14.

Nach Abschluss der Initialisierung kann die Karte in Blöcken von 512 Bytes mit einer Taktfrequenz von 25 MHz betrieben werden. Dies ist die Vollversion des Initialisierungsalgorithmus, der alle Arten von Karten abdeckt. In meinem Fall bestand der Initialisierungsalgorithmus bei Verwendung einer 16-GB-Karte aus den Schritten 1-6, 17-22, 16.

Grafischer Algorithmus

1.3 Informationen löschen


Micro SD-Formfaktorkarten unterstützen Löschbefehle. Nach dem Löschbefehl wird der Wert der angegebenen Löschadressen je nach Karte mit dem Wert 0xFF oder 0x00 gefüllt.

Algorithmus zum Löschen von Informationen

  1. CMD32. .
  2. CMD32. R1. 0x00 ( - ), 3, 4.
  3. . , .
  4. CMD33. . , CMD32.
  5. CMD33. R1. 0x00 ( - ), 3, 6
  6. CMD38-Befehl senden. Der Befehl zum Löschen von Informationen aus den ausgewählten Blöcken. Alle 4 Bytes sollten als Argument gesendet werden, mit Ausnahme der Werte 0x00000001, 0x00000002.
  7. Warten auf eine Antwort auf den CMD38-Befehl. Die Antwort ist eine Antwort vom Typ R1b. Dies ist eine erweiterte Version der Antwort, wenn die Karte eine R1-Antwort generiert und dann die MISO-Linie auf Null zieht, was anzeigt, dass der Chip beschäftigt ist. Es muss gewartet werden, bis der Einheitswert in der MISO-Zeile angezeigt wird. Wenn die Antwort nicht 0x00 lautet (beim Ausführen des Befehls ist ein Fehler aufgetreten), fahren Sie mit Schritt 3 fort, andernfalls mit Schritt 8
  8. Vervollständigung des Löschalgorithmus.

Grafischer Algorithmus

1.4 Informationen lesen


Das Lesen von Informationen von einer SD-Karte über SPI ist auf zwei Arten möglich.

1.4.1 Einen einzelnen Datenblock lesen


Beim Lesen eines Datenblocks generiert das Master-Gerät einen Befehl für die SD-Karte zum Lesen eines Datenblocks, wartet auf eine Antwort, dass der Befehl verarbeitet wurde, und wartet auf ein Paket mit Daten von der Karte. Nach dem Empfang eines Pakets mit Daten von der Karte endet die Lesetransaktion.


Gesamtansicht einer Transaktion, die einen Datenblock liest.

Ursprünglich wurde eine solche Option implementiert, aber die resultierende Geschwindigkeit war sehr verärgert (Geschwindigkeitsvergleiche werden niedriger sein).

1.4.2 Mehrere Datenblöcke lesen


Beim Lesen mehrerer Datenblöcke generiert das Master-Gerät einen Befehl für die SD-Karte zum Lesen mehrerer Datenblöcke, wartet auf eine Antwort, dass der Befehl verarbeitet wurde, und erwartet ein Datenpaket von der Karte. Nach dem Senden eines Datenpakets sendet die Karte das nächste Datenpaket. Dies wird fortgesetzt, bis ein Befehl vom Master-Gerät empfangen wird, um das Lesen abzuschließen.


Gesamtansicht einer Transaktion, die viele Datenblöcke liest.


Datenpaketstruktur

Wo:

  • Daten-Token Der Lesebefehl verwendet den Wert 0xFE.
  • Datenblock. Enthält von der Karte gelesene Daten.
  • CRC Enthält die Prüfsumme aus den vorherigen Feldern.

Wenn beim Lesen ein Fehler aufgetreten ist, gibt die Karte anstelle des Daten-Tokens ein Fehler-Token zurück. Die Fehler-Token-Größe beträgt 1 Byte. Die Bits 7..5 enthalten den Wert Null, die Bits 4..0 codieren den Fehlertyp.

Algorithmus zum Lesen mehrerer Datenblöcke:

  1. CMD18-Befehl senden. Der Befehl teilt der Karte mit, dass mehrere Blöcke gelesen werden.
  2. Warten auf eine Antwort auf den CMD18-Befehl. Die Antwort ist eine Antwort vom Typ R1. Wenn die Antwort nicht 0x00 lautet (beim Ausführen des Befehls ist ein Fehler aufgetreten), fahren Sie mit Schritt 3 fort, andernfalls mit Schritt 4.
  3. Fehlerstatus. Lesen fehlgeschlagen, Beenden des Lesealgorithmus.
  4. Warten auf einen Token von der Karte. Wenn ein Fehler-Token von der Karte empfangen wird, fahren Sie mit Schritt 3 fort, andernfalls fahren Sie mit Schritt 5 fort.
  5. Empfangen von einer Datenblockkarte mit einer Größe von 512 Bytes.
  6. Empfangen Sie von der Karte eine CRC-Feldgröße von 2 Bytes.
  7. . , 8, 4.
  8. CMD12. . , Data Packet, .
  9. CMD12. R1b. R1, MISO , . MISO , . 0x00 ( - ), 3, 10.
  10. .

Der Lesealgorithmus weist eine leichte Nuance auf. Das Chipauswahlsignal (CS) muss vor dem Erzeugen des CMD18-Befehls auf logisch Null und nach dem Empfang einer Antwort auf den CMD12-Befehl auf logisch Eins gesetzt werden.

Grafischer Algorithmus

1.5 Informationen aufzeichnen


Das Schreiben von Informationen auf die SD-Karte über die SPI-Schnittstelle ist in zwei Versionen möglich.

1.5.1 Einen einzelnen Datenblock schreiben


Beim Aufzeichnen eines Datenblocks generiert das Master-Gerät einen Befehl für die SD-Karte zum Schreiben eines Datenblocks, wartet auf eine Antwort von der Karte, dass der Befehl verarbeitet wurde, sendet ein Paket mit Daten zum Aufzeichnen auf die Karte, erwartet eine Antwort von der Karte, dass die Daten geschrieben werden, schließt die Transaktion ab.


Gesamtansicht einer Schreibtransaktion eines Datenblocks.

Wie beim Lesen wurde ursprünglich ein Datensatz eines Datenblocks implementiert. Die Geschwindigkeitsergebnisse waren unbefriedigend.

1.5.2 Mehrere Datenblöcke schreiben


Beim Aufzeichnen mehrerer Datenblöcke generiert das Master-Gerät einen Befehl zum Aufzeichnen mehrerer Datenblöcke, wartet auf eine Antwort von der Karte, dass der Befehl verarbeitet wurde, sendet ein Paket mit Daten zur Aufzeichnung auf die Karte und erwartet eine Antwort von der Karte, dass die Daten aufgezeichnet werden. Nach dem Empfang einer Master-Antwort sendet das Gerät ein Paket mit den folgenden Daten zur Aufzeichnung auf die Karte. Dies wird fortgesetzt, bis das Master-Gerät ein Stop Data Token sendet.


Allgemeine Ansicht einer Schreibtransaktion für mehrere Datenblöcke.

Die Struktur des Datenpakets ähnelt der Struktur des Datenpakets beim Lesen von Daten.

Format:

  • Daten-Token Für den Schreibbefehl wird der Wert 0xFC verwendet.
  • Datenblock. Enthält auf die Karte geschriebene Daten.
  • CRC Enthält die Prüfsumme aus den vorherigen Feldern.

Das zum Ausführen des Schreibbefehls verwendete Stop-Tran-Token ist 1 Byte groß und entspricht 0xFD.

Nachdem das letzte Bit des Datenpakets in die Karte verschoben wurde, antwortet die Karte auf die nächste Uhr mit dem Status des Datensatzes - Datenantwort. Die Datenantwort hat eine Größe von 1 Byte, die Bits 7..5 können beliebig sein, Bit 4 ist immer Null, Bit 0 ist immer gleich Eins, Bits 3..1 codieren den Status des Datensatzes. Nachdem die Karte das Datenpaket zurückgegeben hat, zieht die Karte die MISO-Linie auf Null, um anzuzeigen, dass die Karte belegt ist. Nachdem sich die Ebene der logischen Einheit auf der MISO-Leitung befindet, können Sie das nächste Datenpaket auf die Karte übertragen.

Der Algorithmus zum Aufzeichnen mehrerer Datenblöcke:

  • CMD25-Befehl senden. Der Befehl teilt der Karte mit, dass mehrere Blöcke geschrieben werden.
  • CMD25. R1. 0x00 ( - ), 3, 4.
  • . , .
  • .
  • 512 .
  • CRC 2 .
  • Data Response . , 3, 8.
  • . , 9, 4.
  • Stop Tran Token. , .
  • Warten auf eine Antwort von der Karte. Die Karte auf Stop Tran Token zieht die MISO-Linie auf Null, was anzeigt, dass die Karte besetzt ist. Es ist notwendig, in der MISO-Zeile auf den Einheitswert zu warten, der das Ende des Befehls anzeigt
  • Der Abschluss des Aufzeichnungsalgorithmus.

Es gibt auch eine kleine Nuance im Aufzeichnungsalgorithmus. Das Chipauswahlsignal (CS) muss vor dem Generieren des CMD25-Befehls auf logisch Null und nach dem Empfang einer Antwort auf Stop Tran Token auf logisch Eins gesetzt werden

Grafischer Algorithmus

2. Implementierung des Algorithmus in Hardware


Durch das Lesen der Spezifikation erhalten wir einige Eigenschaften des Algorithmus, die in der Hardware implementiert werden müssen.

Mögliche Betriebsarten:

  • Anfängliche Frequenzbildung. CS- und MOSI-Leitungen müssen sich im Status der logischen Einheit befinden.
  • Daten auf eine SD-Karte übertragen.
  • Empfangen Sie Daten von einer SD-Karte.
  • Warten auf die Fertigstellung des Teams. Es wird verwendet, wenn die SD-Karte nach dem Generieren einer Antwort die MISO-Linie auf Null zieht, um auf das Erscheinen einer Einheit zu warten.
  • Antwort beim Schreiben von Daten lesen.
  • Warten auf ein Token beim Lesen von Daten.

Mögliche Uhrmodi:

  • Taktsignal zum Initialisieren.
  • Taktsignal für die Arbeit.

Aus meiner Sicht wird der Algorithmus mit drei Komponenten optimal implementiert:

  • Die Komponente der physikalischen Schicht, die direkt mit der SD-Karte verbunden ist, erzeugt SCLK-, CS-, DI-Signale und liest mit DO.
  • Eine Komponente auf Befehlsebene, die alle Daten für eine Komponente in der physischen Schicht vorbereitet.
  • Eine Komponente der Kommunikation mit der Außenwelt, die das gesamte interne Gerät verbirgt und eine Schnittstelle für Befehle (Lesen, Schreiben, Löschen) und Daten bietet.

2.1 Komponente der physikalischen Schicht


entity SDPhy is
	generic	(	gTCQ		: time := 2 ns );
	port	(	-- Control bus
			iPhyTxData	: in	std_logic_vector( 9 downto 0);
			iPhyMode	: in	std_logic_vector( 4 downto 0);
			iPhyTxWrite	: in	std_logic;
			oPhyTxReady	: out	std_logic; 
			-- Out Data
			oPhyRxData	: out	std_logic_vector( 7 downto 0); 
			oPhyRxWrite	: out	std_logic;
			oPhyCmdEnd	: out	std_logic;
			-- Spi
			oSdCS		: out	std_logic;
			oSdClk		: out	std_logic;
			oSdMosi		: out	std_logic;
			oSdMosiT	: out	std_logic;
			iSdMiso		: in	std_logic;
			-- system
			sclk		: in	std_logic;
			pclk		: in	std_logic;
			rst		: in	std_logic ); 
end SDPhy;

Wo:

  • iPhyTxData , iPhyMode , .
  • iPhyTxWrite , iPhyTxData iPhyMode .
  • oPhyTxReady , . FULL FIFO, .
  • oPhyRxData , SD-.
  • oPhyRxWrite , oPhyRxData .
  • oPhyCmdEnd , .
  • oSdCS (CS) SD-.
  • oSdClk SD-.
  • oSdMosi SD-.
  • oSdMosiT SD-.
  • iSdMiso SD-.
  • sclk SD- (50 ).
  • pclk , .
  • Erstes Rücksetzsignal, aktive Stufe eins.

In FPGAs gibt es spezielle Einheiten für die Arbeit mit einem Taktsignal (PLL, MMCM). Das Empfangen eines Taktsignals von weniger als 5 MHz von ihrem Ausgang ist jedoch problematisch. Infolgedessen arbeitet die physikalische Schicht mit einer Frequenz von 50 MHz. Zusammen mit allen Daten im iPhyMode-Signal wird ein Bit empfangen, das angibt, mit welcher Frequenz diese Daten auf die SD-Karte übertragen (oder von dieser empfangen) werden sollen. Abhängig vom Geschwindigkeitsbit werden Taktfreigabesignale erzeugt.

In der Komponente der physischen Schicht sind zwei Automaten implementiert, um Daten auf eine SD-Karte zu übertragen und Daten von dieser zu empfangen.

Maschinencode für die Datenübertragung: Github .

  • Der SDummy-Zustand bietet eine anfängliche Frequenzformung und 128 Umschaltung.
  • Der STxBits-Status ermöglicht die Datenübertragung auf die SD-Karte.

Der Code der Maschine zum Empfangen von Daten: github .

  • Der Status sRxBits ermöglicht den Datenempfang von der SD-Karte.
  • Der Status sBusy stellt sicher, dass die SD-Karte bereit ist (die Karte gibt die MISO-Leitung auf Einheitenebene frei).
  • Der sResp-Status implementiert das Lesen der Antwort beim Schreiben von Daten.
  • Der sToken-Status implementiert eine Token-Wartezeit beim Lesen von Daten.

2.2 Komponente auf Befehlsebene


entity SdCommand is
	generic	(	gTCQ		: time := 2 ns );
	port	(	-- Command from host
			oSdInitComp	: out	std_logic;
			oSdInitFail	: out	std_logic;
			iSdAddress	: in	std_logic_vector(31 downto 0);
			iSdStartErase	: in	std_logic;
			iSdStartRead	: in	std_logic;
			iSdStartWrite	: in	std_logic;
			oSdCmdFinish	: out	std_logic_vector( 1 downto 0);
			oSdhcPresent	: out	std_logic;
			-- Data
			oSdReadData	: out	std_logic;
			iSdDataR	: in	std_logic_vector(31 downto 0);
			oSdWriteData	: out	std_logic;
			oSdDataW	: out	std_logic_vector(32 downto 0);
			-- Spi
			oSdCS		: out	std_logic;
			oSdClk		: out	std_logic;
			oSdMosi		: out	std_logic;
			oSdMosiT	: out	std_logic;
			iSdMiso		: in	std_logic;
			-- system
			pclk		: in	std_logic;
			sclk		: in	std_logic;
			rst		: in	std_logic );

Wo:

  • oSdInitComp signiert Abschluss der Initialisierung der SD-Karte.
  • oSdInitFail Zeichen eines Initialisierungsfehlers.
  • iSdAddress-Adresse auf der SD-Karte, um den Befehl auszuführen.
  • iSdStartErase Start Löschbefehlsausführung.
  • iSdStartRead beginnt mit dem Lesen der Befehlsausführung.
  • iSdStartWrite startet die Ausführung des Schreibbefehls.
  • Abschlussstatus des oSdCmdFinish-Teams. Das Nullbit ist gleich Eins, der Befehl wurde erfolgreich ausgeführt. Das erste Bit ist eins, der Befehl wurde mit einem Fehler abgeschlossen.
  • oSdhcPresent SDHC / SDXC-Kartenerkennungsflag.
  • oSdReadData Liest Daten, um auf die SD-Karte zu schreiben.
  • iSdDataR-Daten zum Schreiben auf die SD-Karte.
  • oSdWriteData-Flag zum Schreiben von Daten, die von der SD-Karte gelesen wurden.
  • oSdDataW-Daten, die von einer SD-Karte gelesen wurden.

Die verbleibenden Signale stimmen mit den Signalen der physikalischen Schicht überein.

Die Komponente verfügt über 5 Automaten.

  • smSdInit ( github ) - Initialisierung der SD-Karte.
  • smSdErase ( github ) - löscht Daten von einer SD-Karte.
  • smSdRead ( github ) - liest Daten von einer SD-Karte.
  • smSdWrite ( github ) - Daten auf eine SD-Karte schreiben.
  • smSdCommand ( github ) - bereitet auf der Grundlage der generierten Features Daten für die physische Schicht aller vorherigen Maschinen auf.

2.3 Bestandteil der Kommunikation mit der Außenwelt


entity SdHost is
	generic	(	gTCQ		: time := 2 ns );
	port	(	-- Sd Host command
			iSdCommand	: in	std_logic_vector( 2 downto 0);
			iSdAddress	: in	std_logic_vector(31 downto 0);
			iSdStart	: in	std_logic;
			oSdStatus	: out	std_logic_vector( 1 downto 0);
			oSdInitFail	: out	std_logic;
			-- Write data to card
			iSdTxData	: in	std_logic_vector(31 downto 0);
			iSdTxValid	: in	std_logic;
			iSdTxLast	: in	std_logic;
			oSdTxReady	: out	std_logic;
			-- Read data from card
			oSdRxData	: out	std_logic_vector(31 downto 0);
			oSdRxValid	: out	std_logic;
			oSdRxLast	: out	std_logic;
			iSdRxReady	: in	std_logic;
			-- Spi
			oSdCS		: out	std_logic;
			oSdClk		: out	std_logic;
			oSdMosi		: out	std_logic;
			oSdMosiT	: out	std_logic;
			iSdMiso		: in	std_logic;
			-- system
			pclk		: in	std_logic;
			sclk		: in	std_logic;
			rst		: in	std_logic );

Wo:

  • auszuführender iSdCommand-Befehlscode.
  • iSdAddress ist die Adresse, an der der Befehl ausgeführt werden soll.
  • iSdStart Startbefehlsausführung.
  • Abschlussstatus des oSdStatus-Teams. Das Nullbit ist gleich Eins - der Befehl ist abgeschlossen. Das erste Bit ist eins - der Befehl wurde mit einem Fehler abgeschlossen.
  • oSdInitFail Zeichen eines Initialisierungsfehlers.
  • iSdTxData. Axi-Stream-Schnittstelle zum Schreiben von Daten auf eine SD-Karte. Port mit Daten.
  • iSdTxValid. Axi-Stream-Schnittstelle zum Schreiben von Daten auf eine SD-Karte. Port mit einem Schreibsignal.
  • iSdTxLast. Axi-Stream-Schnittstelle zum Schreiben von Daten auf eine SD-Karte. Port mit einem Zeichen des letzten Dw in den Daten.
  • oSdTxReady. Axi-Stream-Schnittstelle zum Schreiben von Daten auf eine SD-Karte. Port mit einem Zeichen der Bereitschaft zum Empfang von Daten.
  • oSdRxData. Axi-Stream-Schnittstelle zum Lesen von Daten von einer SD-Karte. Port mit Daten.
  • oSdRxValid. Axi-Stream-Schnittstelle zum Lesen von Daten von einer SD-Karte. Port mit einem Schreibsignal.
  • oSdRxLast. Axi-Stream-Schnittstelle zum Lesen von Daten von einer SD-Karte. Port mit einem Zeichen des letzten Dw in den Daten.
  • iSdRxReady. Axi-Stream-Schnittstelle zum Lesen von Daten von einer SD-Karte. Port mit einem Zeichen der Bereitschaft zum Empfang von Daten.

Die verbleibenden Signale stimmen mit den Signalen der physikalischen Schicht überein.

Die Komponente implementiert eine smSdControl-Maschine ( Github ).

  • Einzelzustand. Warten auf die Initialisierung und den Abschluss des Befehls.
  • Der Status von sWaitCmd. Überprüfen des Befehlstyps.
  • sReadCmd. FIFO, , SD- .
  • sWriteCmd. , FIFO SD-, .
  • sEraseCmd. .
  • sWaitEnd. .
  • sFinish. , .

3.


Der Algorithmus wird im Simulator geschrieben und verifiziert. Es ist notwendig, jetzt in Eisen einzuchecken. Von dem, was verfügbar war, kam das Zybo- Board von Digilent auf den Markt . Es verfügt über freie FPGA-Anschlüsse in einer Bank mit einer Spannung von +3,3 V, an die Sie problemlos ein externes Gerät anschließen können. Ja, und der verwendete FPGA-Typ ist Zynq-7000, was bedeutet, dass ein Prozessorkern vorhanden ist. Sie können einen Test in C schreiben, wodurch die Testaufgabe vereinfacht wird. Daher verbinden wir den implementierten Algorithmus über den GP-Port mit dem Prozessorkern (4-Byte-Betrieb ist ähnlich wie bei PIO möglich ). Wir werden uns nicht um Unterbrechungen kümmern, sondern eine Timer-Umfrage durchführen. Bei der Arbeit am Prozessormodul lautet der Datenaufzeichnungsalgorithmus wie folgt:









  • Adresse auf SD-Karte einstellen.
  • Befehlscode 2 einstellen.
  • Schreiben Sie Daten in einen Puffer in der programmierbaren Logik.
  • Führen Sie den Befehl aus.
  • Warten Sie, bis der Befehl abgeschlossen ist.
  • Teamabschlussstatus zurücksetzen.

Implementierter Test:

for (SectorAddress = 0; SectorAddress < 1048576; SectorAddress ++)
{
	if ((SectorAddress % 1024) == 0)
	{
		xil_printf("Data write to %d sector \n\r", SectorAddress);
	}

	/** Set address */
	Xil_Out32(0x43c00008, SectorAddress);

	/** Set command */
	Xil_Out32(0x43c00004, 2);

	/** Write data to PL */
	for (int32_t i = 0; i < 1024; i++)
	{
		Xil_Out32(0x43c00014, cntrData);
		cntrData++;
	}

	/** Start */
	Xil_Out32(0x43c00000, 1);

	/** Wait end of operation */
	for (;;)
	{
		status = Xil_In32(0x43c0000c);
		if (status == 0x01 || status == 0x03)
		{
			if (status == 0x03)
			{
				xil_printf("Error in write \n\r");
			}
			break;
		}
		else
		{
			cntrDuration++;
			usleep(100);
		}
	}

	/** Duration operation */
	durationWrite += cntrDuration;

	if (cntrDuration > MaxWrite )
	{
		MaxWrite = cntrDuration;
	}

	cntrDuration = 0x00;

	/** Clear start */
	Xil_Out32(0x43c00000, 0);

	SectorAddress += 7;
}

Auf die Frage, warum die äußere Grenze von 1024 in der Schleife verwendet wird, setzt der Algorithmus die Anzahl der Blöcke auf 8. Die Größe eines Blocks beträgt 512 Bytes. Die Gesamtgröße von 8 Datenblöcken beträgt 8 * 512 Bytes = 4096 Bytes. Der Bus zwischen dem Prozessormodul und der programmierbaren Logik ist 4 Byte groß. Es stellt sich heraus, dass zum Senden von 4096 Bytes von 4 Bytes vom Prozessormodul an die programmierbare Logik 4096/4 = 1024 Schreiboperationen ausgeführt werden müssen.

Bei der Arbeit am Prozessormodul lautet der Datenlesealgorithmus wie folgt:

  • Adresse auf SD-Karte einstellen.
  • Befehlscode 1 einstellen.
  • Führen Sie den Befehl aus.
  • Warten Sie, bis der Befehl abgeschlossen ist.
  • Teamabschlussstatus zurücksetzen.
  • Lesen Sie Daten aus dem Puffer in programmierbarer Logik.

Implementierter Test:

for (SectorAddress = 0; SectorAddress < 1048576; SectorAddress++)
{
	if ((SectorAddress % 1024) == 0)
	{
		xil_printf("Data read from %d sector \n\r", SectorAddress);
	}

	/** Set address */
	Xil_Out32(0x43c00008, SectorAddress);

	/** Set command */
	Xil_Out32(0x43c00004, 1);

	/** Start */
	Xil_Out32(0x43c00000, 1);

	/** Wait end of operation */
	for (;;)
	{
		status = Xil_In32(0x43c0000c);
		if (status == 0x01 || status == 0x03)
		{
			 if (status == 0x03)
			{
				xil_printf("Error in read \n\r");
			}
			break;
		}
		else
		{
			cntrDuration++;
			usleep(100);
		}
	}

	 /** Duration operation */
	 durationRead += cntrDuration;

	 if (cntrDuration > MaxRead )
	 {
		 MaxRead = cntrDuration;
	 }

	cntrDuration = 0x00;

	/** Clear start */
	Xil_Out32(0x43c00000, 0);

	/** Read data from PL */
	for (int32_t i = 0; i < 1024; i++)
	{
		DataR = Xil_In32(0x43c0001c);
		if (DataR != cntrData)
		{
			xil_printf("Data corrupt! \n\r");
		}
		DataR = Xil_In32(0x43c00020);
		cntrData++;
	}

	SectorAddress += 7;
}

Bei der Arbeit am Prozessormodul lautet der Datenlöschalgorithmus wie folgt:

  • Adresse auf SD-Karte einstellen.
  • Befehlscode einstellen 4.
  • Führen Sie den Befehl aus.
  • Warten Sie, bis der Befehl abgeschlossen ist.
  • Teamabschlussstatus zurücksetzen.

Implementierter Test:

for (SectorAddress = 0; SectorAddress < 1048576; SectorAddress++)
{
	if ((SectorAddress % 1024) == 0)
	{
		xil_printf("Data erase from %d sector \n\r", SectorAddress);
	}

	/** Set address */
	Xil_Out32(0x43c00008, SectorAddress);

	/** Set command */
	Xil_Out32(0x43c00004, 4);

	/** Start */
	Xil_Out32(0x43c00000, 1);

	/** Wait end of operation */
	for (;;)
	{
		status = Xil_In32(0x43c0000c);
		if (status == 0x01 || status == 0x03)
		{
			if (status == 0x03)
			{
				xil_printf("Error in write! \n\r");
			}
			break;
		}
		else
		{
			cntrDuration++;
			usleep(100);
		}
	}

	/** Duration operation */
	durationErase += cntrDuration;

	if (cntrDuration > MaxErase )
	{
		MaxErase = cntrDuration;
	}

	cntrDuration = 0x00;

	/** Clear start */
	Xil_Out32(0x43c00000, 0);

	SectorAddress += 7;
}

Vollständig auf Github testen.

4. Ergebnisse


DatenmengelesenAufzeichnungLöschen
1 Block (512 Bytes)4,7 Mbit / s1,36 Mbit / s0,58 Mbit / s
8 Blöcke (4096 Bytes)15,4 Mbit / s6,38 Mbit / s4,66 Mbit / s
16 Blöcke (8192 Bytes)18,82 Mbit / s11,26 Mbit / s9,79 Mbit / s

Eine 16 GB Karte wurde verwendet. Während des Tests wurden 2 GB Daten aufgezeichnet, 2 GB Daten wurden gelesen, 2 GB Daten wurden gelöscht.

Die Schlussfolgerungen sind enttäuschend. Bei Verwendung von FPGA ist es nicht sinnvoll, die SD-Karte im SPI-Modus zu verwenden, es sei denn, es ist sehr wichtig, große Datenmengen ohne Geschwindigkeitsanforderungen zu speichern.

All Articles