Fonctionne avec la carte SD via l'interface SPI. Implémentation VHDL

Salut Habr! Une fois au travail, j'ai eu la tâche d'évaluer la possibilité d'implémenter le stockage de données sur une carte SD lors de sa connexion à un FPGA. L'utilisation de SPI a été supposée comme interface d'interaction, car elle est plus facile à mettre en œuvre. Je voudrais partager l'expérience acquise.



Étant donné que l'espace sur la carte de circuit imprimé est toujours limité, la prise en compte des cartes SD sera effectuée sur l'exemple des cartes au format microSD.

Contenu


1. Spécifications de lecture
1.1 Informations générales
1.2 Initialisation
1.3 Effacement des informations
1.4 Lecture des informations
1.4.1 Lecture d'un bloc de données
1.4.2 Lecture de plusieurs blocs de données
1.5 Écriture d'informations
1.5.1 Écriture d'un bloc de données
1.5.2 Écriture de plusieurs blocs de données
2. Mise en œuvre de l'algorithme en matériel
2.1 Composante de la couche physique
2.2 Composante du niveau de commande
2.3 Composante de communication avec le monde extérieur
3. Vérification matérielle
4. Résultats

1. Spécifications de lecture


1.1 Général


Une lecture rapide de la spécification nous indique les options de carte SD suivantes:

  • le transfert de données vers la carte SD s'effectue sur une seule ligne;
  • la lecture des données d'une carte SD s'effectue sur une seule ligne;
  • en mode SPI, la puissance ne peut être que de + 3,3 V;
  • fréquence d'horloge en mode d'initialisation dans la plage de 100 à 400 kHz;
  • fréquence d'horloge après l'initialisation - 25 MHz.

Cela implique immédiatement le point sur la bande passante de crête théorique: 25 MHz * 1 bit = 25 Mb / s, ce qui est un peu petit. La seconde moins l'utilisation de cartes SD, puissance + 3,3V. Sur la carte de circuit imprimé sur laquelle il était prévu d'installer la carte SD, il n'y a pas une telle tension.

Les cartes au format MicroSD peuvent être divisées en 3 catégories par capacité:

  • SDSC Capacité de la carte jusqu'à 2 Go inclus. L'adresse à l'intérieur de la carte est un octet.
  • SDHC. La capacité de la carte est supérieure à 2 Go et jusqu'à 32 Go inclus. L'adresse à l'intérieur de la carte indique un bloc de 512 octets.
  • SDXC. La capacité de la carte est supérieure à 32 Go et jusqu'à 128 To inclus. L'adresse à l'intérieur de la carte indique un bloc de 512 octets.

La vue générale de la carte est illustrée dans la figure ci-dessous.


Numéro de contactNomUn typeLa description
1RSV-Non utilisé
2CScontributionSélection de jetons
3DIcontributionLigne de données de l'appareil maître (MOSI)
4VddNutritionTension d'alimentation
5SCLKcontributionSignal d'horloge
6VssNutritionTerre
7FAIREProductionLigne de données vers le périphérique maître (MISO)
8RSV-Non utilisé

La connexion s'effectue selon le schéma ci-dessous:


Les résistances doivent être calibrées à 50 kOhm

Après la mise sous tension, la carte SD est en mode SDIO. Pour passer en mode SPI, vous devez effectuer l'initialisation. Le protocole pour travailler avec la carte implique l'utilisation d'un schéma de contrôle pour le transfert correct des données et des commandes sous la forme d'un algorithme CRC. En fonctionnement en mode SPI, la vérification CRC est désactivée par défaut. Ainsi, la première commande envoyée à la carte pour faire passer la carte en mode SPI doit contenir la valeur CRC correcte.

Les commandes transmises via l'interface SPI ont une taille de 48 bits. Format de commande:

  • Le bit 47 (le plus à gauche) contient toujours la valeur 0.
  • Le bit 46 contient toujours la valeur 1.
  • Les bits 45 à 40 contiennent l'index de commande.
  • Les bits 39..8 contiennent les arguments de la commande.
  • Les bits 7..1 contiennent le CRC des bits précédents.
  • Le bit 0 contient toujours la valeur 1.

Les bits 47 et 46 donnent à la carte la possibilité de suivre sans ambiguïté le début d'une transaction, car le bus MOSI au repos est égal à un.



Les commandes utilisées lors de l'utilisation de la carte SD recevront des réponses telles que R1, R3, R7.


Une réponse de type R1, taille 8 bits. Type de réponse R3, taille 40 bits. Type de réponse R7, taille 40 bits. Toutes les commandes et leurs réponses sont détaillées dans la spécification simplifiée de la couche physique.









1.2 Initialisation


Algorithme d'initialisation:

  1. Après la mise sous tension, attendez au moins 1 ms.
  2. Générez un minimum de 74 commutations d'horloge pour la carte. Les lignes CS et MOSI doivent être à l'état d'unité logique.
  3. Générez la commande CMD0. La commande CMD0 réinitialise la carte SD.
  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. En attente d'une réponse à la commande CMD58. La réponse est une réponse de type R3. Si un bit est défini dans la réponse que la carte fonctionne avec des adresses de bloc de 512 octets, passez à l'étape 16, sinon à l'étape 14.

Une fois l'initialisation terminée, la carte peut être exploitée par blocs de 512 octets avec une fréquence d'horloge de 25 MHz. Il s'agit de la version complète de l'algorithme d'initialisation, qui couvre tous les types de cartes. Dans mon cas, lors de l'utilisation d'une carte de 16 Go, l'algorithme d'initialisation consistait en les étapes 1-6, 17-22, 16.

Algorithme graphique

1.3 Effacement des informations


Les cartes micro SD format prennent en charge les commandes d'effacement. Après la commande d'effacement, la valeur des adresses d'effacement spécifiées sera remplie par la valeur 0xFF ou 0x00, selon la carte.

Algorithme d'effacement des informations

  1. CMD32. .
  2. CMD32. R1. 0x00 ( - ), 3, 4.
  3. . , .
  4. CMD33. . , CMD32.
  5. CMD33. R1. 0x00 ( - ), 3, 6
  6. Envoi de la commande CMD38. La commande pour effacer les informations des blocs sélectionnés. 4 octets doivent être envoyés comme argument, à l'exception des valeurs 0x00000001, 0x00000002.
  7. En attente d'une réponse à la commande CMD38. La réponse est une réponse de type R1b. Il s'agit d'une version étendue de la réponse lorsque la carte génère une réponse R1, puis dessine la ligne MISO à zéro, indiquant que la puce est occupée. Il faut attendre que la valeur unitaire apparaisse sur la ligne MISO. Si la réponse n'est pas 0x00 (il y a eu une erreur lors de l'exécution de la commande), passez à l'étape 3, sinon à l'étape 8
  8. Achèvement de l'algorithme d'effacement.

Algorithme graphique

1.4 Lecture des informations


La lecture des informations d'une carte SD via SPI est possible de deux manières.

1.4.1 Lecture d'un seul bloc de données


Lors de la lecture d'un bloc de données, le dispositif maître génère une commande pour que la carte SD lise un bloc de données, attend une réponse indiquant que la commande a été traitée et attend un paquet contenant des données de la carte. Après avoir reçu un paquet contenant des données de la carte, la transaction de lecture se termine.


Vue générale d'une transaction lisant un bloc de données.

Initialement, une telle option a été mise en œuvre, mais la vitesse résultante a été très contrariée (les comparaisons de vitesse seront plus faibles).

1.4.2 Lecture de plusieurs blocs de données


Lors de la lecture de plusieurs blocs de données, le périphérique maître génère une commande pour que la carte SD lise plusieurs blocs de données, attend une réponse indiquant que la commande a été traitée et attend un paquet de données de la carte. Après avoir envoyé un paquet de données, la carte envoie le prochain paquet de données. Cela continuera jusqu'à ce qu'une commande soit reçue du périphérique maître pour terminer la lecture.


Vue générale d'une transaction lisant de nombreux blocs de données.


Structure des paquets de données

Où:

  • Jeton de données La commande de lecture utilise la valeur 0xFE.
  • Bloc de données. Contient des données lues sur la carte.
  • CRC Contient la somme de contrôle des champs précédents.

Si une erreur s'est produite lors de la lecture, la carte au lieu du jeton de données renvoie un jeton d'erreur. Erreur La taille du jeton est de 1 octet. Les bits 7..5 contiennent une valeur de zéro, les bits 4..0 codent le type d'erreur.

Algorithme de lecture de plusieurs blocs de données:

  1. Envoi de la commande CMD18. La commande indique à la carte que plusieurs blocs seront lus.
  2. En attente d'une réponse à la commande CMD18. La réponse est une réponse de type R1. Si la réponse n'est pas 0x00 (il y a eu une erreur lors de l'exécution de la commande), passez à l'étape 3, sinon à l'étape 4.
  3. Statut d'erreur. La lecture a échoué, en quittant l'algorithme de lecture.
  4. En attente d'un jeton de la carte. Si un jeton d'erreur est reçu de la carte, passez à l'étape 3, sinon passez à l'étape 5.
  5. Recevez d'une carte de bloc de données une taille de 512 octets.
  6. Recevez de la carte un champ CRC de 2 octets.
  7. . , 8, 4.
  8. CMD12. . , Data Packet, .
  9. CMD12. R1b. R1, MISO , . MISO , . 0x00 ( - ), 3, 10.
  10. .

Il y a une légère nuance dans l'algorithme de lecture. Le signal de sélection de puce (CS) doit être mis à zéro logique avant de générer la commande CMD18 et mis à un logique après avoir reçu une réponse à la commande CMD12.

Algorithme graphique

1.5 Enregistrement des informations


L'écriture d'informations sur la carte SD via l'interface SPI est possible en deux versions.

1.5.1 Écriture d'un seul bloc de données


Lors de l'enregistrement d'un bloc de données, l'appareil maître génère une commande pour que la carte SD écrive un bloc de données, attend une réponse de la carte indiquant que la commande a été traitée, transmet un paquet de données à enregistrer sur la carte, attend une réponse de la carte que les données sont écrites, termine la transaction.


Vue générale d'une transaction d'écriture d'un bloc de données.

Comme pour la lecture, un enregistrement d'un bloc de données a été initialement mis en œuvre. Les résultats de vitesse n'étaient pas satisfaisants.

1.5.2 Écriture de plusieurs blocs de données


Lors de l'enregistrement de plusieurs blocs de données, le dispositif maître génère une commande pour enregistrer plusieurs blocs de données, attend une réponse de la carte indiquant que la commande a été traitée, transmet un paquet de données à enregistrer sur la carte, attend une réponse de la carte que les données sont enregistrées. Après avoir reçu une réponse principale, l'appareil transmet un paquet avec les données suivantes pour l'enregistrement sur la carte. Cela continuera jusqu'à ce que l'appareil maître envoie un jeton de données d'arrêt.


Vue générale d'une transaction d'écriture pour plusieurs blocs de données.

La structure du paquet de données est similaire à la structure du paquet de données lors de la lecture des données.

Format:

  • Jeton de données Pour la commande d'écriture, la valeur 0xFC est utilisée.
  • Bloc de données. Contient des données écrites sur la carte.
  • CRC Contient la somme de contrôle des champs précédents.

Le jeton Stop Tran utilisé pour exécuter la commande d'écriture a une taille de 1 octet et est égal à 0xFD.

Après que le dernier bit du paquet de données a été inséré dans la carte, la carte répond à l'horloge suivante avec l'état de l'enregistrement de données - Réponse de données. La réponse des données a une taille de 1 octet, les bits 7..5 peuvent être quelconques, le bit 4 est toujours nul, le bit 0 est toujours égal à un, les bits 3..1 codent l'état de l'enregistrement de données. Une fois que la carte a renvoyé le paquet de données, la carte trace la ligne MISO à zéro, indiquant que la carte est occupée. Une fois que le niveau d'unité logique est sur la ligne MISO, vous pouvez transférer le prochain paquet de données sur la carte.

L'algorithme d'enregistrement de plusieurs blocs de données:

  • Envoi de la commande CMD25. La commande indique à la carte que plusieurs blocs seront écrits.
  • CMD25. R1. 0x00 ( - ), 3, 4.
  • . , .
  • .
  • 512 .
  • CRC 2 .
  • Data Response . , 3, 8.
  • . , 9, 4.
  • Stop Tran Token. , .
  • En attente d'une réponse de la carte. La carte sur le jeton Stop Tran trace la ligne MISO à zéro, indiquant que la carte est occupée. Il faut attendre sur la ligne MISO la valeur unitaire qui indiquera la fin de la commande
  • L'achèvement de l'algorithme d'enregistrement.

Il y a aussi une petite nuance dans l'algorithme d'enregistrement. Le signal de sélection de puce (CS) doit être mis à zéro logique avant de générer la commande CMD25 et mis à un logique après avoir reçu une réponse au jeton Stop Tran

Algorithme graphique

2. Implémentation de l'algorithme dans le matériel


À la suite de la lecture de la spécification, nous obtenons certaines caractéristiques de l'algorithme qui doivent être implémentées dans le matériel.

Modes de fonctionnement possibles:

  • Formation de fréquence initiale. Les lignes CS et MOSI doivent être à l'état d'unité logique.
  • Transférez les données sur une carte SD.
  • Recevez des données d'une carte SD.
  • En attente de l'achèvement de l'équipe. Il est utilisé lorsque, après avoir généré une réponse, la carte SD ramène la ligne MISO à zéro afin d'attendre l'apparition d'une unité.
  • Lisez la réponse lors de l'écriture des données.
  • Attendre un jeton lors de la lecture des données.

Modes d'horloge possibles:

  • Signal d'horloge à initialiser.
  • Signal d'horloge pour le travail.

De mon point de vue, l'algorithme est implémenté de manière optimale en utilisant trois composants:

  • Le composant de la couche physique, qui est connecté directement à la carte SD, génère des signaux SCLK, CS, DI, lit avec DO.
  • Un composant de niveau commande qui prépare toutes les données pour un composant de la couche physique.
  • Un composant de communication avec le monde extérieur qui cache tout le dispositif interne et fournit une interface pour les commandes (lecture, écriture, effacement) et les données.

2.1 Composante de la couche physique


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;

Où:

  • 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 , .
  • premier signal de réinitialisation, niveau un actif.

Dans les FPGA, il existe des unités spéciales pour travailler avec un signal d'horloge (PLL, MMCM), cependant, la réception d'un signal d'horloge inférieur à 5 MHz de leur sortie est problématique. En conséquence, la couche physique fonctionne à une fréquence de 50 MHz. Avec chaque donnée du signal iPhyMode, un bit est reçu qui indique à quelle fréquence ces données doivent être transférées sur la carte SD (ou reçues de celle-ci). Selon le bit de vitesse, des signaux d'activation d'horloge sont générés.

Deux automates sont implémentés dans le composant de la couche physique, pour transférer des données vers une carte SD et recevoir des données de celle-ci.

Code machine pour le transfert de données: github .

  • L'état SDummy fournit une mise en forme de fréquence initiale, 128 commutations.
  • Le statut STxBits permet le transfert de données vers la carte SD.

Le code de la machine pour recevoir des données: github .

  • L'état sRxBits assure la réception des données de la carte SD.
  • L'état sBusy garantit que la carte SD est prête (la carte libère la ligne MISO au niveau de l'unité).
  • L'état sResp implémente la lecture de la réponse lors de l'écriture de données.
  • L'état sToken implémente une attente de jeton lors de la lecture des données.

2.2 Composant de niveau commande


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

Où:

  • oSdInitComp signe la fin de l'initialisation de la carte SD.
  • Signe oSdInitFail de l'échec de l'initialisation.
  • Adresse iSdAddress sur la carte SD pour exécuter la commande.
  • iSdStartErase démarre l'exécution de la commande d'effacement.
  • iSdStartRead démarre la lecture de l'exécution de la commande.
  • iSdStartWrite démarre l'exécution de la commande d'écriture.
  • Statut d'achèvement de l'équipe oSdCmdFinish. Le bit zéro est égal à un, la commande s'est terminée avec succès. Le premier bit est un, la commande s'est terminée avec une erreur.
  • Indicateur de détection de carte SDHC / SDXC oSdhcPresent.
  • oSdReadData Lire les données à écrire sur la carte SD.
  • Données iSdDataR pour l'écriture sur la carte SD.
  • Drapeau oSdWriteData pour écrire les données lues sur la carte SD.
  • Données oSdDataW lues sur une carte SD.

Les signaux restants coïncident avec les signaux de la couche physique.

Le composant dispose de 5 machines automatiques.

  • smSdInit ( github ) - initialisation de la carte SD.
  • smSdErase ( github ) - efface les données d'une carte SD.
  • smSdRead ( github ) - lire les données d'une carte SD.
  • smSdWrite ( github ) - écrire des données sur une carte SD.
  • smSdCommand ( github ) - sur la base des fonctionnalités générées prépare les données pour la couche physique de toutes les machines précédentes.

2.3 Composante de communication avec le monde extérieur


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

Où:

  • Code de commande iSdCommand à exécuter.
  • iSdAddress est l'adresse pour exécuter la commande.
  • Exécution de la commande de démarrage iSdStart.
  • Statut d'achèvement de l'équipe oSdStatus. Le bit zéro est égal à un - la commande est terminée. Le premier bit est un - la commande s'est terminée avec une erreur.
  • Signe oSdInitFail de l'échec de l'initialisation.
  • iSdTxData. Interface Axi-Stream pour écrire des données sur une carte SD. Port avec données.
  • iSdTxValid. Interface Axi-Stream pour écrire des données sur une carte SD. Port avec un signal d'écriture.
  • iSdTxLast. Interface Axi-Stream pour écrire des données sur une carte SD. Port avec un signe du dernier dw dans les données.
  • oSdTxReady. Interface Axi-Stream pour écrire des données sur une carte SD. Port avec un signe de disponibilité pour recevoir des données.
  • oSdRxData. Interface Axi-Stream pour lire les données d'une carte SD. Port avec données.
  • oSdRxValid. Interface Axi-Stream pour lire les données d'une carte SD. Port avec un signal d'écriture.
  • oSdRxLast. Interface Axi-Stream pour lire les données d'une carte SD. Port avec un signe du dernier dw dans les données.
  • iSdRxReady. Interface Axi-Stream pour lire les données d'une carte SD. Port avec un signe de disponibilité pour recevoir des données.

Les signaux restants coïncident avec les signaux de la couche physique.

Le composant implémente une machine smSdControl ( github ).

  • État ralenti. En attente d'initialisation et de fin de commande.
  • L'état de sWaitCmd. Vérification du type de commande.
  • sReadCmd. FIFO, , SD- .
  • sWriteCmd. , FIFO SD-, .
  • sEraseCmd. .
  • sWaitEnd. .
  • sFinish. , .

3.


L'algorithme est écrit, vérifié dans le simulateur. Il faut vérifier maintenant en fer. A partir de ce qui était disponible, la carte Zybo de Digilent est arrivée, elle dispose de bornes FPGA gratuites dans une banque avec une tension de + 3,3V, à laquelle vous pouvez facilement connecter un appareil externe. Oui, et le type de FPGA utilisé est le Zynq-7000, ce qui signifie qu'il y a un cœur de processeur. Vous pouvez écrire un test en C, ce qui simplifiera la tâche de test. Ainsi, nous connectons l'algorithme implémenté au cœur du processeur via le port GP (un fonctionnement sur 4 octets est possible, similaire à PIO ). Nous ne nous soucierons pas des interruptions; nous mettons en œuvre un sondage temporisé. Lorsque vous travaillez sur le module processeur, l'algorithme d'enregistrement des données sera le suivant:









  • Définissez l'adresse sur la carte SD.
  • Définissez le code de commande 2.
  • Écrivez les données dans un tampon situé en logique programmable.
  • Exécutez la commande.
  • Attendez la fin de la commande.
  • Réinitialiser l'état d'achèvement de l'équipe.

Test implémenté:

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;
}

À la question de savoir pourquoi la limite extérieure de 1024 est utilisée dans la boucle. Le nombre de blocs est fixé à 8. La taille d'un bloc est de 512 octets. La taille totale de 8 blocs de données est de 8 * 512 octets = 4096 octets. Le bus entre le module processeur et la logique programmable a une taille de 4 octets. Il s'avère que pour envoyer 4096 octets de 4 octets du module processeur à la logique programmable, il est nécessaire d'effectuer 4096/4 = 1024 opérations d'écriture.

Lorsque vous travaillez sur le module processeur, l'algorithme de lecture des données sera le suivant:

  • Définissez l'adresse sur la carte SD.
  • Définissez le code de commande 1.
  • Exécutez la commande.
  • Attendez la fin de la commande.
  • Réinitialiser l'état d'achèvement de l'équipe.
  • Lire les données du tampon en logique programmable.

Test implémenté:

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;
}

Lorsque vous travaillez sur le module processeur, l'algorithme d'effacement des données sera le suivant:

  • Définissez l'adresse sur la carte SD.
  • Définissez le code de commande 4.
  • Exécutez la commande.
  • Attendez la fin de la commande.
  • Réinitialiser l'état d'achèvement de l'équipe.

Test implémenté:

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;
}

Testez complètement sur github.

4. Résultats


Quantité de donnéesEn train de lireRecordEffacer
1 bloc (512 octets)4,7 Mbps1,36 Mbps0,58 Mbps
8 blocs (4096 octets)15,4 Mbps6,38 Mbps4,66 Mbps
16 blocs (8192 octets)18,82 Mbps11,26 Mbps9,79 Mbps

Une carte de 16 Go a été utilisée. Pendant le test, 2 Go de données ont été enregistrés, 2 Go de données ont été lus et 2 Go de données ont été effacés.

Les conclusions sont décevantes. Lorsque vous utilisez FPGA, cela n'a aucun sens d'utiliser la carte SD en mode SPI, sauf dans le cas où il est très nécessaire de stocker de grandes quantités de données sans présenter de contraintes de vitesse.

All Articles