| Disclaimer | Visitante # |
Estadísticas |
El
presente trabajo trata sobre la tecnología SD (Secure Digital) Card en memorias
flash y el diseño de un dispositivo basado en un microcontrolador que pueda
realizar operaciones de lectura y escritura sobre ellas. Se presenta primero un
panorama sobre el funcionamiento y características de la tarjeta, de la que
destaca el hecho que comparte características con un disco duro tradicional,
pero que adicionalmente incorpora tecnologías para la encriptación en el
almacenamiento de datos, lo que ha dado gran auge a esta tecnología. Por otro
lado, su interfaz es muy sencilla ya que la comunicación se lleva por medio de
solo 9 pines, pero que en este proyecto solo se usaran 2, ya que se
implementara el protocolo SPI estándar de transmisión serial, que basa la
comunicación en el envío de comandos y la obtención de la respuesta a la
petición realizada con el comando. Por ultimo, mediante el uso de un
microcontrolador 8051 se implementa un sistema para realizar operaciones de
lectura y escritura de archivos de texto a tarjetas SD de diferentes
capacidades (8MB, 16MB y 64MB).Además se realizan la lectura de otros registros
de la tarjeta para poner al alcance del usuario del sistema características
particulares de cada una de las tarjetas de tal forma que se puede acceder
tanto el área de almacenamiento de la misma como los registros proporcionados
por el fabricante para la descripción de cada producto.
Hace
algunos años el mercado dio a conocer las tarjetas Flash SD Card como una
opción de almacenamiento para cámaras digitales, PDAs, pocket PCs, etc. El
avance que han tenido ha sido asombroso y actualmente se pueden conseguir
capacidades de almacenamiento de hasta 1 GB, lo cual las hace candidatas a
convertirse dentro de unos años en una fuerte tecnología para almacenamiento de
cualquier tipo de datos, no solo en dispositivos pequeños, sino inclusive
incorporarlas en otras aplicaciones mas complejas como una computadora portátil
para reducir aún más el tamaño de éstas.
El
estándar SD es reservado y propietario, es decir la información acerca del
mismo posee un costo, de tal manera que para fines sólo académicos resulta
bastante difícil conseguirla. A lo largo de este informe, describiremos
características acerca de esta tecnología. Se dividirá esta información en 4
etapas: características físicas y eléctricas de la tarjeta, diseño del sistema
con el host (“slot” de la tarjeta), protocolo de comunicación y la estructura
interna de la misma.
Finalmente,
ya que el propósito perseguido es mostrar como acceder a la información de una
tarjeta con tecnología SD utilizando un microcontrolador programado en lenguaje
ensamblador; en cada sección de esta última parte se irá citando el código y la
lógica programada relacionada. Misma que incluye una aplicación de ejemplo que
permite dispositivo capaz de realizar operaciones de acceso a la tarjeta, más
específicamente de la lectura y escritura de archivos a la tarjeta, a través de
cualquier aplicación de comunicación serial de de la computadora.
Características
generales
La
comunicación de las tarjeta SD esta basada en una interfase de 9 pines: una
línea de reloj (CLK), una de comandos (COMMAND), 4 líneas de datos y 3 líneas
mas de alimentación. Esta diseñada para operar en rangos bajos de voltaje.
El protocolo de comunicación fue
definido como parte de su especificación, pero también soporta operaciones
MultiMediaCard. Además, también ofrece la posibilidad de usar el protocolo
estándar SPI, lo cual la hace compatible con controladores ya existentes.
La
tarjeta contiene chips de memoria flash diseñados especialmente para su uso
como medio de almacenamiento. Además de esto, las tarjetas incluyen un
controlador inteligente que administra diferentes protocolos de comunicación,
algoritmos de seguridad para la protección contra copia no autorizada de la
información almacenada, algoritmos de corrección de errores de código, manejo de
defectos, diagnósticos, y administración de potencia.
Características
físicas
Las tarjetas son muy ligeras y
pequeñas pesan cerca de 20g y miden cerca de 32mm de largo, 24mm de ancho y 2.1mm de grosor. Lo que las
hace excelentes medios de almacenamiento para dispositivos móviles.

Figura 1. Características físicas de la tarjeta
Características
eléctricas
Las
tarjetas trabajan en un rango de voltaje de 2.7 a 3.6 V y el consumo de
corriente (Ta=25C@ 3V) varía dependiendo del estado en que se encuentren y
tiene como máximos los siguientes:
|
Estado Valor Unidades |

La
interfase de comunicación es a través de
9 pines, de los cuales 6 necesitan resistencias de pull-up: línea de
habilitación de la tarjeta (CS), línea de envío de comandos (CMD) y las 4 línea
de datos(DAT3-0).

Figura 2.
Características eléctricas de la tarjeta
Modos de operación
Las
tarjetas con tecnología SD Card tienen dos modos de operación, el modo SPI y el
modo SD. Las diferencias entre los modos involucran principalmente la función
de cada uno de los pines, el protocolo usado y los comandos que son específicos
de cada modo. A continuación se detalla las características principales de
ambos modos.
Modo SD
Este
modo permite que se utilicen las terminales de datos (D0 - D3) en forma
bidireccional, lo cual da mayor ancho de banda durante las transmisiones. Por
otro lado, los comandos se transmiten por la línea CMD en forma serial, y por
ultimo la respuesta de la tarjeta al comando se transmite por la línea
CMD. La principal ventaja de este modo
Al inicio de la transferencia solo se envían datos por D0, ya después se pueden
ampliar el ancho de banda de los datos hasta D3. La aplicación de cada uno de
estos pines es la siguiente:

Modo SPI
En
este modo la tarjeta solo permite la entrada de datos por DATA IN
(2) y la salida de datos por la terminal DATA OUT(7). Los comandos se mandan
también por la terminal DATA IN. La habilitación de la tarjeta se hace por la
terminal CS(1). La señal de CLK que se envía desde el host o controlador es la
que establece la velocidad de la comunicación, es por esto que el diseño del
host se facilita ya que no se tienen problemas de desincronización cuando el
host es más lento que la tarjeta. Sin embargo, como sólo se envían los datos
por una terminal se tiene menor utilización del potencial de la memoria. Ya que el protocolo SPI es un estándar muy
conocido, se decidió implementar este protocolo de comunicación con la tarjeta.

Sistema de
desarrollo
Para
la implementación del dispositivo fue usado como host, un slot de inserción
para la tarjeta, el cual permite acceder físicamente más fácil a las 9 líneas
de comunicación de la tarjeta, además agrega otras 2 líneas al sistema que no
pertenecen propiamente a la tarjeta sino al host usado (slot de inserción de la
tarjeta) las cuales nos permiten saber si la tarjeta ha sido insertada en el host y/o si está
protegida contra escritura. Ambas señales son activas en estado bajo y
funcionan mediante un sencillo mecanismo físico, como se indica a continuación:

No habilitada Habilitada
Este
“host” está conectado a un sistema de desarrollo basado en un microcontrolador
8051 el cual había sido previamente construido para la clase de
Microprocesadores I. Dicho sistema tiene las siguientes características:
El diagrama esquemático del sistema de desarrollo, así como los
componentes necesarios para dicho sistema se muestran a continuación:

Figura 3. Sistema de desarrollo
Resistencias Capacitores Circuitos integrados Otros componentes
(1/4 watt, 5%) C1,C2 — 20 pF Microcontrolador
8051 SW1 Interruptor NA
R1 — 8.2 KW C3 — 10 µF GAL
20V8 SW2 —
Push button
R2 — 100 W C4-7 — 22 µF Latch
74LS373 Conector DB9 macho
R3 — 10 KW RAM 6264
Cristal ROM 2716
XTAL1 12 MHz MAX232
Para
la interfase de este sistema con la tarjeta se utilizó el puerto P1 del sistema
de desarrollo. Las conexiones que se realizaron a este sistema se muestran a
continuación donde se observan las resistencias de pull-up (DIN, CS) y las
líneas extras que son parte del host (CARD INSERT y WRITE ENABLE). Para obtener
el voltaje en un rango de voltaje entre 2.7 y 3 V, se uso una resistencia y un
diodo Zener.

Figura 4. Interfase de la tarjeta
con el sistema de desarrollo
Protocolo de comunicación
El
protocolo de comunicación esta basado en comandos, los cuales son enviados
serialmente a través de DOUT y la respuesta al comando es recibida a través de
DIN.

Los comandos de la tarjeta tienen un
tamaño fijo (6 bytes). Donde la convención es que primero se envía el bit más
significativo del byte más significativo del comando. El formato de los
comandos es el siguiente:

Donde el primer byte contiene el
bit de inicio, el host y el identificador del comando a enviar, los siguientes
4 bytes contienen el argumento para dicho comando y el ultimo byte representa
el CRC7 1 que es calculado por la tarjeta de la siguiente forma:

Existen muchos comandos para la
tarjeta en modo SPI, los cuales se dividen en distintas clases dependiendo de
las funcionalidades del comando.

Figura 5. Tabla de clasificación del
los comandos en modo SPI
[1] Ver mayor descripción del CRC7 en SanDisk Manual v1.9 pág 3-13
A continuación se presenta una
tabla con los comandos, indicando el numero de comando, si es aplicable en el
modo SPI, el argumento del comando y el tipo de respuesta que tiene, además de
la abreviación del nombre del comando y una pequeña descripción del mismo.



Sin embargo, para este proyecto
solo se usaron los siguientes comandos:
CMD0 400000000095H Coloca
la tarjeta en inactividad
CMD1 410000000001H Activa la tarjeta
CMD9 490000000001H Responde con el contenido del CSD
CMD10 4A0000000001H Responde con el contenido del CID
CMD17 510000000001H Permite leer un sector de la
tarjeta
CMD24 580000000001H Permite escribir un sector en
la tarjeta
La respuesta a un comando tiene tamaño estándar de
3 bytes que indica si el comando enviado tuvo éxito o no. Si el comando
enviado a la
tarjeta SD indica lectura a algún sector o registro, esta regresa el contenido
del registro (23 bytes) o el contenido del sector (512 bytes). En este último
caso existe antes del bloque de 512 bytes un token que indica la correcta
recepción del comando.
COMANDO RESPUESTA INDICA
CMD0 FF01FFH En espera
CMD1 FF00FFH Activo (Lista)
CMD9 (23 bytes) Contenido CSD
CMD10 (23 bytes) Contenido CID
CMD17 Token + (512 bytes) Leer un sector de la tarjeta
CMD24 Token (Espera bloque) Escribir un sector a la tarjeta
Token
(Recepción correcta)
Figura
6. Respuestas para los comandos usados
Lectura y
escritura de bloques
Para la transferencia de bloques
este protocolo de comando-respuesta varía un poco.

Figura
7. Lectura de un bloque de la tarjeta
En el caso de la lectura por
ejemplo, al enviar el comando de lectura de un bloque (CMD 17) este debe llevar
como argumento la dirección del bloque de 512 bytes que se desea. Es decir, que
por ejemplo para leer el sector 2 de la tarjeta, el comando 17 debe ser
modificado de la siguiente forma:
CMD17 5100 0002 0001H
Una vez que el comando sea
recibido por la tarjeta, esta regresa una respuesta de 3 bytes y un token de
inicio, seguidos del bloque de 512 bytes y el CRC del mismo. Este token es de
la forma
FF FF 00 FF FE
Aunque en la práctica se
encontraron algunas diferencias en las distintas tarjetas.
Por otro lado, en el caso de la
escritura, primero se envía el comando que de igual forma que en el caso de la
lectura lleva como argumento la dirección del sector que se escribirá. Sin
embargo, a diferencia de la lectura después de recibir la respuesta estándar de
3 bytes que indica que el comando se acepta, el host enviara un token de inicio
seguido del bloque de 512 bytes de datos y dos token de fin de datos. Por
último, una vez que la transmisión del bloque termina la tarjeta envía una
respuesta que incluye si hubo error y/o si la tarjeta esta ocupada.

Figura
8. Escritura de un bloque a la tarjeta
Implementación
de la comunicación
La
comunicación bidireccional con la tarjeta para el protocolo anteriormente
descrito se implementó de forma modular, primero a bajo nivel (envío y
recepción de bytes) y luego a nivel comando (envío de 3 bytes), nivel respuesta
(recepción de 3, 23 o 56 bytes) y nivel bloque (envío / recepción de bloques de
512 bytes).
Tanto en la transmisión como en
la recepción de bytes, el dato debe ser valido durante la transición positiva
de la señal de reloj, esto se implementó mediante el uso de constantes para
reducir el código, así una constante contenía valor del dato y el bit de CLK en
bajo y posteriormente el bit de CLK en alto, con lo que se lograba el dato
valido al mismo tiempo que la transición positiva, sin necesidad de
instrucciones adicionales que reducirían la frecuencia de transmisión.
; CLK
| CS
| DI | DO
; 3F 0 0
1 1 >>
RECIBIR (CLK EN BAJO)
; BF 1 0
1 1 >>
RECIBIR (CLK EN ALTO)
; 3F 0 0
1 1 >>
ENVIAR 1
; BF 1 0
1 1
; 0F 0 0
0 0 >>
ENVIAR 0
; 8F 1
0 0
0
Figura
9. Definición de constantes del programa
A continuación se muestran las
rutinas de bajo nivel que sirven para el envió y recepción de un byte y mas
adelante se presentaran y explicaran las de alto nivel.
Como se puede ver en ambas
rutinas, la velocidad de la transferencia al final se dejo variable pues esta
dada por directamente por la duración de la rutina WAIT, la cual en la
implementación final se dejo con duración de 2 microsegundos, lo cual da una señal
de reloj con frecuencia máxima de 0.25 MHz.
;
---------------------------------------------------------------------------------------------------------------------
; RUTINA QUE ENVIA 1 BYTE A LA
TARJETA( El byte este contenido en el Acumulador)
; ---------------------------------------------------------------------------------------------------------------------
SNDBYTE
MOV
R6, #8D ; SE ENVIARAN 8 bits
ACAS: RLC A ; MAS
SIGNIFICATIVO >> MENOS SIGNIFICATIVO
JNC ZERO
ONE: MOV P1, #ENVIA1_B ; 0011
LCALL WAIT
MOV P1, #ENVIA1_A ; 1011 Cambia el CLK y el DOUT = 1
LCALL WAIT
SJMP SEW
ZERO: MOV P1,
#ENVIA0_B ; 0001
LCALL WAIT
MOV P1, #ENVIA0_A ; 1001 Cambia el CLK y el DOUT = 1
LCALL
WAIT
SEW: DJNZ R6, ACAS
RET
; ---------------------------------------------------------------------------
; RECIBE UN BYTE ( Regresa el
byte en el Acumulador)
;
---------------------------------------------------------------------------
LEE_BYTE:
MOV R7, #8D ; 8 BITS POR BYTE
BBIT MOV P1, #RECIBE_B ; 3F 0
011
LCALL WAIT
MOV C, P1.5 ; BIT RECIBIDO
RLC A ; MAS
SIGNIFICATIVOàMENOS
SIGNIFICATIVO
MOV P1,
#RECIBE_A
LCALL WAIT
DJNZ R7, BBIT
RET
Figura
10. Rutinas de comunicación
bidireccional a bajo nivel
Por otro lado, las rutinas de
transmisión de comandos y obtención de la respuesta se optimizaron basadas en
lo anterior y quedan como se presentara a continuación.
;
---------------------------------------------------------------------------------------
; ENVIA EL COMANDO
APUNTADO POR DPTR
; Se envian 6 bytes bit
por bit / Se usan R7 #bytes, R6 # bits
;
---------------------------------------------------------------------------------------
SNDCMD:
MOV R7, #6D ;
SE ENVIARAN 6 BYTES
CLR A ; A = 0
MOVC A,@A+DPTR ; Tomo primer
byte
LCALL SNDBYTE
INC DPTR ; Apunto a siguiente byte
DJNZ
R7, BYTE ; Si es cero ya termine
RET
Figura
11. Rutina de transmisión de comando
Como puede observarse se hace
uso del DPTR, esto último debido a todo el código reside en la memoria RAM, la
cual en este sistema es tratada como memoria externa por el microcontrolador.
;
---------------------------------------------------------------------------
; OBTENER RESPUESTA (R0)
; NBYTES para numero de
bytes de transferencia
; DPTR apunta a donde se
va a guardar la respuesta
; B = 8 BITS
;
---------------------------------------------------------------------------
GTRESP:
MOV R7, #8D ;
8 BITS POR BYTE
RESPU:MOV P1, #RECIBE_B
LCALL WAIT
MOV C, P1.5 ;
BIT RECIBIDO
RLC A ;
MSB à LSB
MOV P1, #RECIBE_A
LCALL WAIT
JNZ R7, RESPU
MOVX @DPTR, A
INC DPTR
DJNZ NBYTES, GTRESP
RET
;
---------------------------------------------------------------------------
; RUTINA READ BLOCK
;
---------------------------------------------------------------------------
READBLK
CLR F0 ;
Primeros dos bytes del comando
MOV A, #51H
LCALL SNDBYTE
MOV A, #00H
LCALL SNDBYTE
MOV R1, #ADDR ; Enviar la dirección que
accesa el comando
MOV A, @R1
LCALL SNDBYTE
INC R1
MOV A, @R1
LCALL SNDBYTE
MOV A, #00H ; Dos ultimos bytes
LCALL SNDBYTE
MOV A, #01H
LCALL SNDBYTE
LCALL WAIT40 ; Espero 40 ms
LCALL SUPER_TOKEN
NADA MOV DPTR, #RESP ; Ahora si 512 bytes
MOV NBYTES, #255D
LCALL GTRESP
MOV NBYTES,
#255D
LCALL GTRESP
MOV NBYTES, #2
LCALL GTRESP
LCALL WAIT40
JB F0,READBLK ; Si fue buena respuesta seguir
RET
; -----------------------------------------------------------------------------------------------------------
; RECIBE Y CHECA EL TOKEN DE
COMANDOS DE LECTURA DE BLOQUE
;
-----------------------------------------------------------------------------------------------------------
SUPER_TOKEN
MOV DPTR, #RESP ;
Voy a recibir el token. No se guarda
MOV NBYTES, #5D ;
así que
después se sobrescribirá
LCALL GTRESP
MOV DPTR, #RESP ; Se compara si el token es
correcto
MOVX A, @DPTR
CJNE A, #0FFH,
NOES
INC DPTR
MOVX A, @DPTR
CJNE A, #0FFH,
NOES
INC DPTR
MOVX A, @DPTR
CJNE A, #00H,
NOES
INC DPTR
MOVX A, @DPTR
CJNE A, #0FFH,
NOES
INC DPTR
MOVX A, @DPTR
CJNE A, #0FEH,
NOES
CLR F0
SJMP FINI
NOES SETB F0
FINI RET
; -------------------------------------------------------------------------------------
; LA VARIABLE RESP TIENE LOS DATOS A ESCRIBIR
;
-------------------------------------------------------------------------------------
WRITEBLK
MOV A, #58H
LCALL SNDBYTE
MOV A,
#00H
LCALL SNDBYTE
MOV R1, #ADDR ;
Enviar la direccion del bloque
MOV A, @R1 ;
que accesa el comando
LCALL SNDBYTE
INC R1
MOV A, @R1
LCALL SNDBYTE
MOV A, #00H ; Dos ultimos bytes
LCALL SNDBYTE
MOV A, #01H
LCALL SNDBYTE
LCALL WAIT40 ; Espero 40 MS
;
RECIBIR LA RESPUESTA
MOV DPTR, #R_CORTA ; Voy a recibir la respuesta al comando
MOV NBYTES, #3D ;
no me importa asi que lo voy a desechar
LCALL GTRESP
MOV DPTR, #R_CORTA ; Checa los primeros 3 bytes para confirmar
MOVX A,@DPTR ;
que el envio del comando fue exitoso
CJNE A,#0FFH,OTRAVEZ ; FF00FF
INC DPTR
MOVX A,@DPTR
CJNE A,#00H,OTRAVEZ
INC DPTR
MOVX A,@DPTR
CJNE A,#0FFH,OTRAVEZ
CLR F0 ; Indico que hubo exito
SJMP YA_ ; Salto al fin de la rutina
OTRAVEZ SETB F0 ; Indico que fallo, para intentar otra vez
YA_ JB F0,WRITEBLK ; Si fracaso intentar de nuevo
MOV A, #0FEH ;
Tokens de inicio
LCALL SNDBYTE
MOV DPTR, #RESP ;
Apunto al bloque a enviar
MOV B, #255D ;
Primeros 255 bytes
ESCR1 MOVX A, @DPTR
LCALL SNDBYTE
DJNZ B, ESCR1 ;
Hasta que termine el ciclo1
MOV B, #255D
ESCR2 MOVX A,
@DPTR
LCALL SNDBYTE
DJNZ B, ESCR2
MOV B, #2D
ESCR3 MOVX A,
@DPTR
LCALL SNDBYTE
DJNZ B, ESCR3
MOV A, #0FEH ;
Tokens de fin de envio escritura
LCALL SNDBYTE
MOV A, #0FEH
LCALL SNDBYTE
MOV DPTR, #R_CORTA ; Voy a recibir la respuesta del write block
MOV NBYTES, #3D
LCALL GTRESP
MOV DPTR, #R_CORTA ; Voy a recibir el token
MOV NBYTES, #3D ;
no me importa asi que lo voy a desechar
LCALL PRINT_RESP
RET
Figura
12. Rutinas de comunicación a alto nivel
La
organización interna de la tarjeta esta constituida por un área de
almacenamiento, una zona de registros de configuración/información acerca de la
misma como se puede apreciar en la Figura 13. A su vez, el área de
almacenamiento se subdivide en 2 partes independientes: el área protegida, la
cual no se puede acceder a menos que el dispositivo se identifique, y en el
área de almacenamiento común. Además,
posee 5 registros de información, el CID, CSD, OCR, SCR y RCA1. Para
los objetivos de este proyecto se desplegaron sólo los registros CID y CSD.
[1] Ver información sobre los registros en SanDisk Manual v1.9 pág 3-13
Figura
13. Organización física interna de la
tarjeta
El registro CID (Card
Identification Information) posee una longitud de 16 bytes y almacena un número
único de identificación de la tarjeta. La figura 14 muestra el CID desplegado
en desde la consola a través del microcontrolador. Obsérvese que se reciben en
total 20 bytes de los cuales, los primeros 4 corresponden a la respuesta del
comando de la cual se hablará más tarde.

Figura 14:
Impresión de CID en formato bruto e interpretado
Para acceder a la información de
este registro es necesario enviar a la tarjeta en comando 10. Las siguientes
líneas de código son empleadas para llevar a cabo esta lectura:
………………
CMD10 DB 4AH,00H,00H,00H,00H,01H
………………
MOV
DPTR, #CMD10
LCALL
SNDCMD ;
Enviar el comando
MOV DPTR, #RESP
MOV
NBYTES, #20D ; Se esperan 20 bytes
LCALL
GTRESP ;
Leer la respuesta
MOV DPTR,
#RESP ;apuntar a la variable
que contiene la respuesta
MOV NBYTES, #20D
LCALL PRINT_RESP ;
imprimir respuesta en formato bruto
LCALL
WAIT40 ;
Esperar 40 mseg para asegurar finalizacion exitosa
La figura 14 muestra adicionalmente
la misma información interpretada, ver anexo 1 para obtener detalles acerca de
la decodificación de la repuesta.[1]
De igual forma, la tarjeta regresa
su CSD con formato de 16 bytes más 4 adicionales de respuesta al comando. El
CSD contiene información de configuración necesaria para poder acceder a la
tarjeta y es posible obtenerlo enviando el comando 9 a la tarjeta. El código en
ensamblador requerido para accesarlo es el siguiente:
CMD9 DB 49H,00H,00H,00H,00H,01H
...
MOV
DPTR, #CMD9
LCALL
SNDCMD ;
Enviar el comando
MOV DPTR, #RESP
MOV
NBYTES, #20D ; Se esperan 20 bytes
ACALL
GTRESP ;
Leer la respuesta
MOV DPTR, #RESP ;
imprimir respuesta.
MOV NBYTES, #20D
LCALL PRINT_RESP
LCALL WAIT40
![]()
Figura
15: Impresión de CSD en formato bruto
El envío de este comando proveyó de
varias características importantes acerca de una tarjeta en particular: la
capacidad del dispositivo, y el formato mediante el cual son almacenados los
datos en el mismo. La figura 3 muestra un trozo de la tabla de decodificación
del CSD. Consideramos que esta información es muy relevante ya que nos muestra
que tipo de sistema de archivos posee la tarjeta a leer. En nuestra prueba, el
bit correspondiente al FILE_FORMAT_GRP es el 15, el cual se encuentra en cero y los bits asociados al FILE_FORMAT son el 10 y
11 los cuales tienen un valor de cero. Esto nos permite aseverar que la tarjeta
posee una organización de almacenamiento para área de datos similar a la de un
disco duro, de la cual se hablará más adelante.

Figura
16: Tipos de formato
Las tarjetas SD poseen un
mecanismo de protección de Copyright que les permite identificarse cuando son
accesadas a través de una PDA, o cualquier otro dispositivo. Dicha información
es almacenada en una partición de la tarjeta; ésta zona es conocida como Write
Protecction Group (WP Group). Como se mencionó se encuentra en una partición
aislada del área de almacenamiento y posee su propia tabla de particiones, así
como comandos especiales para su acceso. Esta partición es de tamaño variable y
viene especificada por el CSD de la tarjeta.
El área de almacenamiento común
ofrece la posibilidad de guardar cualquier tipo de información. Como se
mencionó líneas más arriba, el esquema de organización de archivos es semejante
al de un disco duro, el cual se mostrará a continuación.
La unidad básica de lectura de
una tarjeta SD es un bloque de 512 bytes llamado sector. La estructura interna
de la tarjeta está decidida en el sector cero de la misma el cual contiene el
master boot record and partition table, la cual provee el bloque en el cual se
encuentra la única partición de datos simples[2].
La figura 18 describe la ubicación de cada uno de los diferentes elementos que conforman
un área de almacenamiento y la figura 19 nos muestra una tabla de particiones,
es decir nos sitúa en la dirección 0000h. El código necesario para leer[3] el
sector 0 viene dado de la siguiente manera:
MOV R0,
#ADDR ; Apuntar a la direccion 0000H
MOV @R0,
#00H ; Master Boot Record
INC R0
MOV @R0,
#00H
LCALL READBLK

Figura 17. Organización lógica
interna de la tarjeta

Figura 18. Organización del mapa de
memoria de la tarjeta
La primera entrada de la tabla
de particiones corresponde a la única partición del sistema y en la cual
tenemos almacenados todos los datos que hemos ido guardando en nuestra SD.
|
Dirección |
Contenido |
Tipo |
|
+ 000h |
Código de la partición |
|
|
+ 1BEh |
1ª entrada en la tabla de partición |
16 bytes |
|
+ 1CEh |
2ª entrada en la tabla de partición |
16 bytes |
|
+ 1DEh |
3ª entrada en la tabla de partición |
16 bytes |
|
+ 1EEh |
4ª entrada en la tabla de partición |
16 bytes |
|
+ 1FEh |
Identificación AA55H |
2 bytes |
Figura 19: Contenido del Master Boot Record
Dentro de la primera entrada de
la tabla de particiones, encontramos un formato como el siguiente (figura 20).
El desplazamiento 8 apunta al sector de arranque de la partición. Cabe
mencionar que un disco duro convencional destina 4 bytes para calcular esta
dirección de lboque; sin embargo, una SD Card solo utiliza 2 bytes ya que la
capacidad que posee es muy pequeña para compararse con un disco duro
tradicional. De cualquier forma, las tarjetas SD respetan este formato y
destinan 4 bytes para poder almacenar su sector de arranque. El fragmento de
código mostrado a continuación realiza el cálculo del relative sector de una
tarjeta:
MOV R0,
#RELATIVE_SECTOR ; = RESP[454] + 256 *
RESP[455]
MOV DPTR, #RESP ;
Apunto a RESP
MOV A,#255 ;
454 no cabe en una variable de 8 bits
CICLOPS
INC DPTR
DJNZ A,
CICLOPS
MOV A,#199
PARTE2
INC DPTR
DJNZ A,PARTE2
MOVX A, @DPTR ;
Posiciono byte bajo de la dirección
MOV @R0, A ;
Guardo byte bajo
INC R0
INC DPTR
MOVX A, @DPTR ;
Posiciono byte alto
MOV @R0, A ;
Guardo parte alta de la dirección

Figura 20: Contenido de una entrada de la tabla de particiones
MOV R0, #RELATIVE_SECTOR ; = RESP[454] + 256 * RESP[455]
MOV DPTR,
#RESP ; Apunto a RESP
MOV A,#255
CICLOPS INC DPTR
DJNZ A,
CICLOPS
MOV A,#199
PARTE2 INC DPTR
DJNZ A,PARTE2
MOVX A, @DPTR ;
Posiciono byte 1
MOV @R0, A ;
Guardo
INC R0
INC DPTR
MOVX A, @DPTR ;
Posiciono byte alto
MOV @R0, A ;
Guardo
Es necesario multiplicar este
relative sector por 2 para obtener el partition boot sector. Esta
multiplicación es una exigencia del estándar de la tarjeta y se mantiene
inalterable de una capacidad a otra; es decir, cada vez que se calcule una
dirección, es necesario multiplicarla por 2 para obtener la dirección correcta.
El partition boot sector es un bloque de 512 bytes que contiene la
información referente a la estructura de la tabla 1. La jerarquía ya mencionada
es que el master boot record sector
nos da la información necesaria para localizar el partition boot sector y éste último nos aporta las direcciones y
datos para localizar y describir a las estructuras restantes FAT, root directory y data area.La tabla
2 muestra la información y los desplazamientos requeridos para calcular esta
información. El código referente a esta operación se localiza en la rutina
CALCULA localizada en el anexo 1.

Figura 21:
Partition Boot Sector
El programa realizado calcula y
despliega algunas variables importantes del partition bootsector (tabla 2).

Figura 22:
Datos obtenidos del Partition boot sector
Uva vez calculadas y almacenadas
estas variables es posible acceder al FAT y al directorio raíz y al área de
datos. El FAT1 y FAT2 son los siguientes escalones en la tabla número 1. El
FAT1 contiene toda la información de apuntadores a archivos contenidos en una tarjeta dada, el FAT2 es
una copia de seguridad del FAT1. En un inicio, la tecnología SD implementó FAT
12 como sistema de archivos; en la actualidad, las tarjetas SD del mercado
manejan capacidades desde los 32 MB en adelante utilizando el sistema de
archivos FAT16.
El FAT 16 almacena en 2 bytes la
dirección a un cluster del área de datos en la cual un archivo se encuentra
localizado. Los primeros 4 bytes del FAT están reservados para indicar el tipo
de File System (Cluster 0) FFF8h para
FAT 16 y el cluster 1 es un cluster reservado, indicado por FFFFh. Esto
significa que desde el cluster 2 podemos almacenar direcciones de archivos
(figura 23).

Figura 23: FAT
16
Supongamos que un archivo tiene
como cluster inicial el 0003h; el archivo posee 3 clusters. Al ir al cluster
0003h en el FAT, encontramos que aparece la dirección 0005h; esta dirección
significa que el siguiente cluster esta en la 0005h. ahora bien, leyendo ese
cluster del FAT encontramos que su contenido es FFFFh lo cual significa que
este es el fin de archivo y ya no hay otra liga. En pocas palabras, el FAT es
una lista encadenada de apuntadores al área de datos ya que no solo contiene el
cluster en el área de datos, sino también la liga al siguiente cluster.
El formato de lectura para un
cluster en el FAT es little endian; primero se lee la parte baja de la
dirección y posteriormente la alta. Observe que el código mostrado en el anexo
1 mantiene el mismo formato para una lógica más sencilla:
MOV DPTR,
#RESP ; Apunto a
RESP
MOV R0,#RELATIVE_SECTOR ; Apunto a var en la que voy a salvar
…
MOVX A, @DPTR ;
Posiciono byte 1
MOV @R0, A ;
Guardo parte baja de la dirección
INC R0
INC DPTR
MOVX A, @DPTR ;
Posiciono byte alto
MOV @R0, A ;
Guardo parte alta de la dirección
…
Utilizando el formato de FAT16
se tiene que cada bloque leído de FAT contiene hasta 256 direcciones de
cluster. La implementación llevada a cabo, solo mantiene en memoria 1 sector de
FAT, por lo que es necesario, una vez leída la dirección del siguiente cluster,
calcular en qué sector del FAT se encuentra. Para ello se realiza una operación
de división y residuo, de tal forma que se obtienen dos datos: el sector en el
cual está ese cluster y el desplazamiento relativo que hay que hacer dentro de
éste cluster.
Por ejemplo, supongamos que
tengo el cluster 0A33h. Deseo saber el sector del FAT en el que se encuentra.
Al llevar a cabo la división entre 256, encontramos que directamente, la parte
alta del cluster se convierte en el sector y la baja en el residuo. Es decir,
se leerá el sector 000Ah y una vez leído se avanzarán 0033h palabras para
quedar localizado en el nuevo cluster.
Para calcular la dirección del
FAT se proporciona la siguiente fórmula:
FAT1_ADDR
= Partition Boot Sector Address +
Partition Boot Sector [14] + Partition Boot
Sector [15]*256
La dirección de la copia del FAT
viene dada por la siguiente fórmula
FAT2_ADDR =
FAT1_ADDR +
Partition Boot Sector [22] + Partition Boot
Sector [22]*256
Se mencionó que el FAT contiene
las direcciones de cluster en las cuales está almacenado un archivo. Ahora
bien, si embargo, no se mencionó el origen del primer cluster del archivo.
Dicha dirección se obtiene del directorio raíz o cualquier otro directorio.
Hablemos del directorio raíz.
El área del directorio raíz está
conformada por 512 entradas, divididas en
32 sectores. En cada sector del directorio raíz hay contenidas 16
entradas (una entrada ocupa 32 bytes). La primera entrada del directorio raíz
contiene la etiqueta de Volumen. Las entradas subsecuentes pueden ser desde
archivos, carpetas, archivos ocultos, de sistema, etc (figura 25)

Figura 24: Contenido de una entrada
del directorio raíz
La figura 24 muestra el orden de
campos contenidos en una entrada del DR. Observe que el nombre del archivo
ocupa 8 caracteres mientras que la extensión ocupa solo 3, los nombres y
extensiones se escriben en mayúsculas y en caso de que los nombres sean mayores
a 8 caracteres, se truncan hasta el sexto carácter y se les agrega el símbolo ~
seguido de un número; este tipo de formato se conoce como 8.3 y se utilizó en
las versiones de MS DOS. Windows empieza a implementar la política de long file
names lo cual permite escribir nombres largos desperdiciando campos del
directorio para almacenar el nombre. Las tarjetas SD permiten ambas opciones y
para fines prácticos solo se validó que los archivos cumplan con el formato
8.3.

Figura 24: Atributos de la entrada
Para validar si una entrada del
directorio raíz es válida, se deben verificar 2 casos: que esté vacía o que
esta borrada. La validación mencionada se muestra a continuación:
NEXT MOVX A, @DPTR ; LEO EL PRIMER CARACTER
CJNE A, #0FFH, POS1 ; verifico si es una entrada válida
SJMP NO ;
esta entrada esta vacía....
POS1 CJNE A, #00H, POS2 ; esta entrada esta vacía....
SJMP NO
POS2 CJNE A, #0E5H, YEAH ; esta entrada esta borrada....
LJMP NO
YEAH MOV R7, A ; ENTRADA VALIDA
Notamos que según el dispositivo
que le de formato a la tarjeta, una entrada vacía puede ser representada por
FFh o 00h. Una entrada borrada se representa con el caracter E0h.
Para calcular la dirección del Directorio raíz se
proporciona la siguiente fórmula:
RD_ADDR =
FAT2_ADDR +
Partition Boot
Sector [22] + Partition Boot Sector [22]*256
SDCARD . 0000 00000000
SARA . TXT 0002 00000003
PABLO . TXT 0003 00000004
PRUEBA . DOC 0004 0000001A
Figura 25: Directorio raíz
Ya se mencionó que para tener
información acerca de un archivo es necesario localizarlo en el directorio raíz
para obtener su cluster de inicio y posteriormente ir al FAT y leer cada
cluster hasta encontrar uno que diga fin de archivo (FFFFh). Ahora hablemos que
hacer con estas direcciones de cluster que obtenemos en el FAT.
Cada vez que se obtiene una
dirección de cluster, es necesario ir al área de datos y acceder a ese cluster
en particular. Definamos la fórmula de dirección del área de datos:
DTA_ADDR =
DR_ADDR + 20h
El valor de 20h se obtiene de
dividir las entradas
Recordemos que las tarjetas SD
solo pueden hacer accesos de tamaño bloque y que la dirección que nos proporcionan
tanto el FAT como el Directorio raíz son cluster. Es necesario aplicar una
conversión de cluster a sector para poder hacer el acceso. El sector lógico del
cluster X esta dado como sigue:
SLCx =
DTA_ADD + (cluster - 2) * partition boot sector [13];
Se decrementa el cluster en 2 ya
que como se mencionó en páginas anteriores, los 2 primeros clusters del área de
datos están reservados.
Además, hay que tener en mente que un
cluster esta formado de varios sectores (definidos en la variable sectores por cluster,
del Partition Boot Sector) y que cuando se hace una lectura de
bloque a un cluster, es necesario terminar de leer el cluster en su totalidad;
para esto basta con incrementar la dirección de sector en 2 y mantener un
contador que alcance la cuenta de sectores por cluster. Esto se aprecia más fácilmente en el
siguiente segmento de código:
MOV R3, SECTOR_CLUSTER ;variable sectores por cluster
OTRO_SECTOR_CLUSTER
LCALL READBLK ;
Lee el sector indicado por ADDR
MOV DPTR, #RESP ;
Apunto al bloque leído en memoria
…
MOV R0, #ADDR ;
Calculo la dir del siguiente sector lógico
INC R0 ;
dentro de este mismo cluster
MOV A, @R0
CLR C
ADD A, #02 ;
sólo incremento 2
MOV @R0, A ;
actualizo la variable que apunta al sig. sector
DJNZ R3, OTRO_SECTOR_CLUSTER
Para salir de idle state, es
responsabilidad del bus master (microcontrolador) aplicar una secuencia de
ciclos de reloj para asegurar que el voltaje es llevado hasta el máximo punto
de operación (ya que pueden estar conectadas varias SD). Para esto se requieren
64 ciclos de reloj. Se agregan 10 ciclos más para eliminar problemas de
sincronización de voltaje.
El segmento de código que describe esta operación se
muestra en seguida:
OPEN:
MOV
B, #74D ; 74 ciclos de reloj
CLK74: MOV P1, #7FH ;
Pulso de reloj (senal bajo)
LCALL WAIT
MOV P1, #FFH ;
Pulso de reloj (senal alto)
LCALL WAIT
DJNZ B, CLK74 ;
Hasta que termine
Cuando la tarjeta SD despierta,
se encuentra en modo SD. Entrará en modo SPI siempre y cuando la señal de CS se
ponga en bajo durante la recepción del comando cero (CMD0). Una vez en este
modo, la tarjeta responde para indicar que entró al modo de forma exitosa. El
comando cero, (40 00 00 00 00 95) se envía a la tarjeta posteriormente de la
secuencia de pulsos de reloj y su codificación en ensamblador es la siguiente:
SEND0:
MOV DPTR, #CMD0 ; Apuntar al comando 0
LCALL SNDCMD ;
Enviar el comando
MOV DPTR,
#RESP ; Lugar donde se va a
guardar la resp
MOV NBYTES,
#3D ; Se esperan 3 bytes de
respuesta
ACALL GTRESP ;
LEER LA RESPUESTA
MOV DPTR,
#RESP ; IMPRIME RESPUESTA
MOV NBYTES,
#3D ; se recibe una
respuesta de 3 bytes
LCALL PRINT_RESP ; imprime respuesta en la
pantalla
MOV DPTR,
#RESP ; CHECA RESPUESTA
MOVX A,
@DPTR ; verificar que
la respuesta sea correcta
CJNE A,
#FFH, SEND0 ; FF
INC DPTR
MOVX A,
@DPTR
CJNE A,
#01H, SEND0 ; 01
INC DPTR
MOVX A,
@DPTR
CJNE A,
#FFH, SEND0 ; FF
La respuesta al comando cero es FF
01 FF; si esta respuesta no se recibe correctamente es necesario reenviar el
comando cero tantas veces sea necesario hasta obtener una respuesta exitosa.
Una vez en modo SPI, es necesario inicial el proceso de inicialización de
la tarjeta mediante en comando 1; en este caso, se envía 2 veces, para asegurar
un correcto reset de la misma. El segmento de código que define el envío del
comando 1 es el que sigue:
SEND11:
MOV DPTR, #CMD1 ;
Apuntar el Comando 1
LCALL SNDCMD ; Enviar el comando
MOV DPTR, #RESP
MOV NBYTES, #3D ;
Se esperan 3 bytes
LCALL GTRESP ; Leer la respuesta
MOV DPTR, #RESP ;
IMPRIME RESPUESTA
MOV NBYTES, #3D
LCALL PRINT_RESP
MOV DPTR, #RESP ;
Comparo respuesta con FF01FF
MOVX A, @DPTR
CJNE A, #FFH, SEND11
INC DPTR
MOVX A, @DPTR
CJNE A, #01H, SEND11
INC DPTR
MOVX A, @DPTR
CJNE A, #FFH, SEND11
LCALL
WAIT40
SEND12:
MOV DPTR, #CMD1 ;
Apuntar el comando 1
ACALL SNDCMD ;
Enviar el comando
MOV DPTR, #RESP
MOV NBYTES, #3D ;
Se esperan 3 bytes
ACALL GTRESP ;
Leer la respuesta
MOV DPTR, #RESP ;
IMPRIME RESPUESTA
MOV NBYTES, #3D
LCALL PRINT_RESP
MOV DPTR, #RESP
MOVX A, @DPTR
CJNE A, #FFH, SEND12
INC DPTR
MOVX A, @DPTR
CJNE A, #00H, SEND12
INC DPTR
MOVX A, @DPTR
CJNE A, #FFH, SEND12
LCALL WAIT40
En el primer envío, la tarjeta responde indicando que
esta en el modo SPI (recepción de comando correcta), en el segundo envío, la
respuesta generada por la SD es reset exitoso (FF 00 FF). (figura 26)

Figura 26. Respuestas a los
comandos de inicialización
A partir de este momento, la tarjeta
se encuentra lista para recibir comandos. El diagrama de flujo mostrado en la
figura 27 muestra la secuencia de pasos llevados a cabo:

Figura 27. Algoritmo de
inicialización
Pag
3-8 dice lo de las resistencias
Bus
timing 32-113
