Trabaja con tarjeta SD a través de la interfaz SPI. Implementación de VHDL

Hola habr Una vez en el trabajo, tuve la tarea de evaluar la posibilidad de implementar el almacenamiento de datos en una tarjeta SD al conectarla a un FPGA. Se asumió el uso de SPI como una interfaz de interacción, ya que es más fácil de implementar. Me gustaría compartir la experiencia adquirida.



Dado que el espacio en la placa de circuito impreso siempre es limitado, se considerarán las tarjetas SD en el ejemplo de las tarjetas en el factor de forma microSD.

Contenido


1. Especificación de lectura
1.1 Información general
1.2 Inicialización
1.3 Borrar información
1.4 Leer información
1.4.1 Leer un bloque de datos
1.4.2 Leer muchos bloques de datos
1.5 Escribir información
1.5.1 Escribir un bloque de datos
1.5.2 Escribir muchos bloques de datos
2. Implementar el algoritmo en hardware
2.1 Componente de la capa física
2.2 Componente del nivel de comando
2.3 Componente de comunicación con el mundo exterior
3. Verificación en hardware
4. Resultados

1. Especificaciones de lectura


1.1 General


Una lectura rápida de la especificación nos dice las siguientes opciones de tarjeta SD:

  • la transferencia de datos a la tarjeta SD se realiza en una línea;
  • la lectura de datos de una tarjeta SD se realiza en una línea;
  • en modo SPI, la potencia puede ser solo + 3.3V;
  • frecuencia de reloj en modo de inicialización en el rango de 100-400 kHz;
  • frecuencia de reloj después de la inicialización - 25 MHz.

Esto implica inmediatamente el punto en el ancho de banda máximo teórico: 25 MHz * 1 bit = 25 Mb / s, que es algo pequeño. El segundo menos el uso de tarjetas SD, potencia + 3.3V. En la placa de circuito impreso en la que se planeó instalar la tarjeta SD, no existe ese voltaje.

Las tarjetas de factor de forma MicroSD se pueden dividir en 3 categorías por capacidad:

  • SDSC Capacidad de tarjeta de hasta 2 GB inclusive. La dirección dentro de la tarjeta es byte.
  • SDHC. La capacidad de la tarjeta es de más de 2 GB y hasta 32 GB inclusive. La dirección dentro de la tarjeta indica un bloqueo de 512 bytes.
  • SDXC. La capacidad de la tarjeta es de más de 32 GB y hasta 128 TB inclusive. La dirección dentro de la tarjeta indica un bloqueo de 512 bytes.

La vista general del mapa se muestra en la figura a continuación.


Número de contactoNombreUn tipoDescripción
1RSV-No utilizado
2CSentradaSelección de chips
3DIentradaLínea de datos del dispositivo maestro (MOSI)
4 4VddNutriciónTensión de alimentación
5 5SCLKentradaSeñal de reloj
6 6VssNutriciónTierra
7 7HACERSalidaLínea de datos al dispositivo maestro (MISO)
8RSV-No utilizado

La conexión se lleva a cabo de acuerdo con el siguiente diagrama: las


resistencias deben ser de 50 kOhm.

Después de encender la alimentación, la tarjeta SD está en modo SDIO. Para cambiar al modo SPI, debe realizar la inicialización. El protocolo para trabajar con la tarjeta implica el uso de un esquema de control para la transferencia correcta de datos y comandos en forma de algoritmo CRC. Cuando se opera en modo SPI, la verificación CRC está deshabilitada de manera predeterminada. Por lo tanto, el primer comando enviado a la tarjeta para cambiar la tarjeta al modo SPI debe contener el valor CRC correcto.

Los comandos transmitidos a través de la interfaz SPI tienen un tamaño de 48 bits. Formato de comando:

  • El bit 47 (más a la izquierda) siempre contiene el valor 0.
  • El bit 46 siempre contiene el valor 1.
  • Los bits 45..40 contienen el índice de comando.
  • Los bits 39..8 contienen los argumentos del comando.
  • Los bits 7..1 contienen CRC de bits anteriores.
  • El bit 0 siempre contiene el valor 1.

Los bits 47 y 46 le dan a la tarjeta la capacidad de rastrear sin ambigüedades el inicio de una transacción, ya que el bus MOSI en reposo es igual a uno.



Los comandos utilizados al trabajar con la tarjeta SD recibirán respuestas como R1, R3, R7.


Una respuesta de tipo R1, tamaño 8 bits. Tipo de respuesta R3, tamaño 40 bits. Tipo de respuesta R7, tamaño 40 bits. Todos los comandos y sus respuestas se detallan en la Especificación simplificada de la capa física.









1.2 Inicialización


Algoritmo de inicialización:

  1. Después de encender la alimentación, espere al menos 1 ms.
  2. Genere un mínimo de 74 cambios de reloj para la tarjeta. Las líneas CS y MOSI deben estar en estado de unidad lógica.
  3. Generar comando CMD0. El comando CMD0 restablece la tarjeta 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. Esperando una respuesta al comando CMD58. La respuesta es una respuesta de tipo R3. Si se establece un bit en la respuesta de que la tarjeta funciona con direcciones de bloque de 512 bytes, vaya al paso 16, de lo contrario al paso 14.

Una vez completada la inicialización, la tarjeta puede funcionar en bloques de 512 bytes con una frecuencia de reloj de 25 MHz. Esta es la versión completa del algoritmo de inicialización, que cubre todo tipo de tarjetas. En mi caso, cuando usaba una tarjeta de 16 GB, el algoritmo de inicialización consistía en los pasos 1-6, 17-22, 16.

Algoritmo Gráfico

1.3 Borrar información


Las tarjetas de factor de forma Micro SD admiten comandos de borrado. Después del comando de borrado, el valor de las direcciones de borrado especificadas se completará con el valor 0xFF o 0x00, dependiendo de la tarjeta.

Algoritmo de borrado de información

  1. CMD32. .
  2. CMD32. R1. 0x00 ( - ), 3, 4.
  3. . , .
  4. CMD33. . , CMD32.
  5. CMD33. R1. 0x00 ( - ), 3, 6
  6. Envío del comando CMD38. El comando para borrar información de los bloques seleccionados. Cualquier 4 bytes debe enviarse como argumento, excepto los valores 0x00000001, 0x00000002.
  7. Esperando una respuesta al comando CMD38. La respuesta es una respuesta de tipo R1b. Esta es una versión extendida de la respuesta cuando la tarjeta genera una respuesta R1 y luego dibuja la línea MISO a cero, lo que indica que el chip está ocupado. Es necesario esperar hasta que el valor de la unidad aparezca en la línea MISO. Si la respuesta no es 0x00 (hubo algún error al ejecutar el comando), vaya al paso 3, de lo contrario al paso 8
  8. Finalización del algoritmo de borrado.

Algoritmo Gráfico

1.4 Información de lectura


La lectura de información de una tarjeta SD a través de SPI es posible de dos maneras.

1.4.1 Leer un solo bloque de datos


Al leer un bloque de datos, el dispositivo Maestro genera un comando para que la tarjeta SD lea un bloque de datos, espera una respuesta de que el comando ha sido procesado y está esperando un paquete con datos de la tarjeta. Después de recibir un paquete con datos de la tarjeta, finaliza la transacción de lectura.


Vista general de una transacción que lee un bloque de datos.

Inicialmente, se implementó dicha opción, pero la velocidad resultante estaba muy alterada (las comparaciones de velocidad serán menores).

1.4.2 Lectura de múltiples bloques de datos


Al leer múltiples bloques de datos, el dispositivo Maestro genera un comando para que la tarjeta SD lea múltiples bloques de datos, espera una respuesta de que el comando ha sido procesado y espera un paquete de datos de la tarjeta. Después de enviar un paquete de datos, la tarjeta envía el siguiente paquete de datos. Esto continuará hasta que se reciba un comando del dispositivo maestro para completar la lectura.


Vista general de una transacción que lee muchos bloques de datos.


Estructura del paquete de datos

donde:

  • Token de datos El comando de lectura usa el valor 0xFE.
  • Bloque de datos Contiene datos leídos de la tarjeta.
  • CRC Contiene la suma de verificación de los campos anteriores.

Si se produjo un error durante la lectura, la tarjeta en lugar del token de datos devuelve un token de error. El tamaño del token de error es de 1 byte. Los bits 7..5 contienen un valor de cero, los bits 4..0 codifican el tipo de error.

Algoritmo para leer múltiples bloques de datos:

  1. Envío del comando CMD18. El comando le dice a la tarjeta que se leerán varios bloques.
  2. Esperando una respuesta al comando CMD18. La respuesta es una respuesta de tipo R1. Si la respuesta no es 0x00 (hubo algún error al ejecutar el comando), vaya al paso 3, de lo contrario al paso 4.
  3. Estado de error Lectura fallida, saliendo del algoritmo de lectura.
  4. Esperando una ficha de la tarjeta. Si se recibe un token de error de la tarjeta, vaya al paso 3; de lo contrario, vaya al paso 5.
  5. Reciba desde una tarjeta de bloque de datos de 512 bytes de tamaño.
  6. Recibir de la tarjeta CRC tamaño de campo de 2 bytes.
  7. . , 8, 4.
  8. CMD12. . , Data Packet, .
  9. CMD12. R1b. R1, MISO , . MISO , . 0x00 ( - ), 3, 10.
  10. .

Hay un ligero matiz en el algoritmo de lectura. La señal de selección de chip (CS) debe establecerse en cero lógico antes de generar el comando CMD18 y establecerse en uno lógico después de recibir una respuesta al comando CMD12.

Algoritmo Gráfico

1.5 Registro de información


Escribir información en la tarjeta SD a través de la interfaz SPI es posible en dos versiones.

1.5.1 Escribir un solo bloque de datos


Al grabar un bloque de datos, el dispositivo Maestro genera un comando para que la tarjeta SD escriba un bloque de datos, espera una respuesta de la tarjeta de que el comando ha sido procesado, transmite un paquete con datos para grabar en la tarjeta, espera una respuesta de la tarjeta de que los datos están escritos, completa la transacción.


Vista general de una transacción de escritura de un bloque de datos.

Al igual que con la lectura, originalmente se implementó un registro de un bloque de datos. Los resultados de la velocidad fueron insatisfactorios.

1.5.2 Escribir múltiples bloques de datos


Al grabar múltiples bloques de datos, el dispositivo Maestro genera un comando para grabar múltiples bloques de datos, espera una respuesta de la tarjeta de que el comando ha sido procesado, transmite un paquete con datos para grabar en la tarjeta, espera una respuesta de la tarjeta de que los datos están grabados. Después de recibir una respuesta maestra, el dispositivo transmite un paquete con los siguientes datos para grabar en la tarjeta. Esto continuará hasta que el dispositivo maestro envíe un token de datos de detención.


Vista general de una transacción de escritura para múltiples bloques de datos.

La estructura del paquete de datos es similar a la estructura del paquete de datos al leer datos.

Formato:

  • Token de datos Para el comando de escritura, se utiliza el valor 0xFC.
  • Bloque de datos Contiene datos escritos en la tarjeta.
  • CRC Contiene la suma de verificación de los campos anteriores.

El token Stop Tran utilizado para completar el comando de escritura tiene un tamaño de 1 byte e igual a 0xFD.

Después de que el último bit del paquete de datos se ha introducido en la tarjeta, la tarjeta responde al siguiente reloj con el estado del registro de datos: Respuesta de datos. La respuesta de datos tiene un tamaño de 1 byte, los bits 7..5 pueden ser cualquiera, el bit 4 siempre es cero, el bit 0 siempre es igual a uno, los bits 3..1 codifican el estado del registro de datos. Después de que la tarjeta ha devuelto el Paquete de datos, la tarjeta dibuja la línea MISO a cero, lo que indica que la tarjeta está ocupada. Una vez que el nivel de la unidad lógica está en la línea MISO, puede transferir el siguiente paquete de datos a la tarjeta.

El algoritmo para grabar múltiples bloques de datos:

  • Envío del comando CMD25. El comando le dice a la tarjeta que se escribirán varios bloques.
  • CMD25. R1. 0x00 ( - ), 3, 4.
  • . , .
  • .
  • 512 .
  • CRC 2 .
  • Data Response . , 3, 8.
  • . , 9, 4.
  • Stop Tran Token. , .
  • Esperando una respuesta de la tarjeta. La tarjeta en Stop Tran Token dibuja la línea MISO a cero, lo que indica que la tarjeta está ocupada. Es necesario esperar en la línea MISO el valor de la unidad, que indicará el final del comando
  • La finalización del algoritmo de grabación.

También hay un pequeño matiz en el algoritmo de grabación. La señal de selección de chip (CS) debe establecerse en cero lógico antes de generar el comando CMD25 y establecerse en uno lógico después de recibir una respuesta a Stop Tran Token

Algoritmo Gráfico

2. Implementación del algoritmo en hardware.


Como resultado de leer la especificación, obtenemos algunas características del algoritmo que deben implementarse en el hardware.

Posibles modos de funcionamiento:

  • Formación de frecuencia inicial. Las líneas CS y MOSI deben estar en estado de unidad lógica.
  • Transfiere datos a una tarjeta SD.
  • Recibir datos de una tarjeta SD.
  • A la espera de la finalización del equipo. Se utiliza cuando, después de generar una respuesta, la tarjeta SD dibuja la línea MISO a cero para esperar la aparición de una unidad.
  • Lea la respuesta al escribir datos.
  • Esperando un token mientras lee datos.

Posibles modos de reloj:

  • Señal de reloj para inicializar.
  • Señal de reloj para el trabajo.

Desde mi punto de vista, el algoritmo se implementa de manera óptima utilizando tres componentes:

  • El componente de la capa física, que está conectada directamente a la tarjeta SD, genera señales SCLK, CS, DI, lee con DO.
  • Un componente de nivel de comando que prepara todos los datos para un componente en la capa física.
  • Un componente de comunicación con el mundo exterior que oculta todo el dispositivo interno y proporciona una interfaz para comandos (lectura, escritura, borrado) y datos.

2.1 Componente de capa física


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;

Dónde:

  • 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 , .
  • primera señal de reinicio, nivel uno activo.

En los FPGA, existen unidades especiales para trabajar con una señal de reloj (PLL, MMCM), sin embargo, recibir una señal de reloj a menos de 5 MHz de su salida es problemático. Como resultado, la capa física opera a una frecuencia de 50 MHz. Junto con cada dato en la señal iPhyMode, se recibe un bit que indica a qué frecuencia estos datos deben transferirse a la tarjeta SD (o recibirse de ella). Dependiendo del bit de velocidad, se generan señales de activación del reloj.

Se implementan dos autómatas en el componente de la capa física, para transferir datos a una tarjeta SD y para recibir datos de ella.

Código de máquina para la transferencia de datos: github .

  • El estado SDummy proporciona conformación de frecuencia inicial, 128 conmutaciones.
  • El estado de STxBits proporciona transferencia de datos a la tarjeta SD.

El código de la máquina para recibir datos: github .

  • El estado sRxBits proporciona recepción de datos desde la tarjeta SD.
  • El estado sBusy asegura que la tarjeta SD esté lista (la tarjeta libera la línea MISO al nivel de la unidad).
  • El estado sResp implementa la lectura de la respuesta al escribir datos.
  • El estado sToken implementa una espera de token mientras lee datos.

2.2 Componente a nivel de comando


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

Dónde:

  • oSdInitComp firma la finalización de la inicialización de la tarjeta SD.
  • oSdInitFail signo de error de inicialización.
  • Dirección de iSdAddress en la tarjeta SD para ejecutar el comando.
  • iSdStartErase iniciar la ejecución del comando de borrado.
  • iSdStartRead comienza a leer la ejecución del comando.
  • iSdStartWrite iniciar la ejecución del comando de escritura.
  • oSdCmd: Finaliza el estado de finalización del equipo. El bit cero es igual a uno, el comando se completó con éxito. El primer bit es uno, el comando se completó con un error.
  • oSdhc Indicador actual de detección de tarjeta SDHC / SDXC.
  • oSdReadData Leer datos para escribir en la tarjeta SD.
  • Datos iSdDataR para escribir en la tarjeta SD.
  • Indicador oSdWriteData para escribir datos leídos de la tarjeta SD.
  • Datos de oSdDataW leídos de una tarjeta SD.

Las señales restantes coinciden con las señales de la capa física.

El componente tiene 5 máquinas automáticas.

  • smSdInit ( github ): inicialización de la tarjeta SD.
  • smSdErase ( github ): borra datos de una tarjeta SD.
  • smSdRead ( github ): lee datos de una tarjeta SD.
  • smSdWrite ( github ): escribe datos en una tarjeta SD.
  • smSdCommand ( github ): sobre la base de las características generadas, prepara los datos para la capa física de todas las máquinas anteriores.

2.3 Componente de comunicación con el mundo exterior.


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

Dónde:

  • Código de comando de iSdCommand para ejecutar.
  • iSdAddress es la dirección para ejecutar el comando.
  • Ejecución del comando de inicio iSdStart.
  • oSdStatus estado de finalización del equipo. El bit cero es igual a uno: se completa el comando. El primer bit es uno: el comando se completó con un error.
  • oSdInitFail signo de error de inicialización.
  • iSdTxData. Interfaz Axi-Stream para escribir datos en una tarjeta SD. Puerto con datos.
  • iSdTxValid. Interfaz Axi-Stream para escribir datos en una tarjeta SD. Puerto con señal de escritura.
  • iSdTxLast. Interfaz Axi-Stream para escribir datos en una tarjeta SD. Puerto con un signo de la última dw en los datos.
  • oSdTxReady. Interfaz Axi-Stream para escribir datos en una tarjeta SD. Puerto con un signo de disponibilidad para recibir datos.
  • oSdRxData. Interfaz Axi-Stream para leer datos de una tarjeta SD. Puerto con datos.
  • oSdRxValid. Interfaz Axi-Stream para leer datos de una tarjeta SD. Puerto con señal de escritura.
  • oSdRxLast. Interfaz Axi-Stream para leer datos de una tarjeta SD. Puerto con un signo de la última dw en los datos.
  • iSdRxReady. Interfaz Axi-Stream para leer datos de una tarjeta SD. Puerto con un signo de disponibilidad para recibir datos.

Las señales restantes coinciden con las señales de la capa física.

El componente implementa una máquina smSdControl ( github ).

  • Estado de reposo. Esperando la inicialización y el comando para completar.
  • El estado de sWaitCmd. Comprobando el tipo de comando.
  • sReadCmd. FIFO, , SD- .
  • sWriteCmd. , FIFO SD-, .
  • sEraseCmd. .
  • sWaitEnd. .
  • sFinish. , .

3.


El algoritmo está escrito, verificado en el simulador. Es necesario verificar ahora en hierro. De lo que estaba disponible, surgió la placa Zybo de Digilent . Tiene terminales FPGA gratuitas en un banco con un voltaje de + 3.3V, al que puede conectar fácilmente un dispositivo externo. Sí, y el tipo de FPGA utilizado es Zynq-7000, lo que significa que hay un núcleo de procesador. Puede escribir una prueba en C, lo que simplificará la tarea de prueba. Entonces, conectamos el algoritmo implementado al núcleo del procesador a través del puerto GP (es posible la operación de 4 bytes, similar a PIO ). No nos molestaremos con las interrupciones; implementamos una encuesta de temporizador. Cuando trabaje en el módulo del procesador, el algoritmo de grabación de datos será el siguiente:









  • Establecer dirección en la tarjeta SD.
  • Establecer el código de comando 2.
  • Escribir datos en un búfer ubicado en lógica programable.
  • Ejecute el comando
  • Espere hasta que se complete el comando.
  • Restablecer el estado de finalización del equipo.

Prueba implementada:

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

A la pregunta de por qué se usa el límite exterior de 1024 en el bucle, el algoritmo establece el número de bloques igual a 8. El tamaño de un bloque es de 512 bytes. El tamaño total de 8 bloques de datos es 8 * 512 bytes = 4096 bytes. El bus entre el módulo procesador y la lógica programable tiene un tamaño de 4 bytes. Resulta que para enviar 4096 bytes de 4 bytes desde el módulo del procesador a la lógica programable, es necesario realizar 4096/4 = 1024 operaciones de escritura.

Cuando trabaje en el módulo del procesador, el algoritmo de lectura de datos será el siguiente:

  • Establecer dirección en la tarjeta SD.
  • Establecer código de comando 1.
  • Ejecute el comando
  • Espere hasta que se complete el comando.
  • Restablecer el estado de finalización del equipo.
  • Leer datos del búfer en lógica programable.

Prueba implementada:

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

Al trabajar en el módulo del procesador, el algoritmo de borrado de datos será el siguiente:

  • Establecer dirección en la tarjeta SD.
  • Establecer el código de comando 4.
  • Ejecute el comando
  • Espere hasta que se complete el comando.
  • Restablecer el estado de finalización del equipo.

Prueba implementada:

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

Prueba completamente en github.

4. Resultados


La cantidad de datosLeyendoGrabarBorrar
1 bloque (512 bytes)4.7 Mbps1.36 Mbps0,58 Mbps
8 bloques (4096 bytes)15,4 Mbps6,38 Mbps4.66 Mbps
16 bloques (8192 bytes)18,82 Mbps11,26 Mbps9,79 Mbps

Se utilizó una tarjeta de 16 GB. Durante las pruebas, se registraron 2 GB de datos, se leyeron 2 GB de datos y se borraron 2 GB de datos.

Las conclusiones son decepcionantes. Cuando se usa FPGA, no tiene sentido usar la tarjeta SD en modo SPI, excepto en el caso de que sea muy necesario almacenar grandes cantidades de datos sin presentar requisitos de velocidad.

All Articles