Jugando con las tarjetas SD
Hola a todos. Después de mucho renegar y leer decenas de hojas de datos
pude por fin comunicarme con la tarjeta SD. Si bien lo había echo
enseguida en el simulador, este emula una tarjeta MMC y no una SD,
ademas que tiene todo simplificado con lo que al pasar a la realidad las
cosas pueden cambiar y si bien eso lo sabia no me desalentó sino mas
bien me sirvió porque al probar de todo para hacer andar la tarjeta aprendí mucho mas que si hubiese salido a la primera.
Así que acá las cosas que aprendí y si bien no es una guía completa sirve de muy buen ejemplo de lo que no hay que hacer.
En el mercado hay muchas tarjetas de memoria, entre ellas las MMC y las SD que, aunque son compatibles, son diferentes en el manejo de las mismas.
Así que acá las cosas que aprendí y si bien no es una guía completa sirve de muy buen ejemplo de lo que no hay que hacer.
En el mercado hay muchas tarjetas de memoria, entre ellas las MMC y las SD que, aunque son compatibles, son diferentes en el manejo de las mismas.
El otro protocolo es el SPI. El cual uso ya que ademas de requerir menos pines es mas fácil de implementar ya que esta mas documentado.
En un principio iba a montar todo en un protoboard, pero luego me decidi crear una pequeña placa ya que me ahorraria varios problemas.
Los valores de los componentes están en un TXT dentro del archivo adjunto al final del post.
En el esquema faltan las conexiones de alimentación del integrado
MAX232. No se porque el Eagle no me las pone, pero son: PIN 16 Vcc... y
PIN 15 GND.
Como se puede observar incluí el archiconocido MAX232 para tener una conexión RS232 ya que en un primer momento el PIC solamente iba a hacer de puente entre la tarjeta y la PC. Pero luego de que se me complicara programar la PC y siendo que eso sumaria otra fuente de problemas decidí usar el PIC y prescindir de la comunicación con la PC. Para depurar usaba la EEPROM del PIC.
Los conectores que se aprecian están porque puedo usar la placa con el MAX232 en otros proyectos y por eso la inclusión del conector JP1. El conector JP4, junto con un jumper, me permite seleccionar entre una salida hacia el LED para indicar cualquier problema en las pruebas o usar el pin para la comunicación RS232.
La placa quedo así:
Como se puede observar incluí el archiconocido MAX232 para tener una conexión RS232 ya que en un primer momento el PIC solamente iba a hacer de puente entre la tarjeta y la PC. Pero luego de que se me complicara programar la PC y siendo que eso sumaria otra fuente de problemas decidí usar el PIC y prescindir de la comunicación con la PC. Para depurar usaba la EEPROM del PIC.
Los conectores que se aprecian están porque puedo usar la placa con el MAX232 en otros proyectos y por eso la inclusión del conector JP1. El conector JP4, junto con un jumper, me permite seleccionar entre una salida hacia el LED para indicar cualquier problema en las pruebas o usar el pin para la comunicación RS232.
La placa quedo así:
Como la tarjeta es una Micro SD uso un adaptador. El conector de esta
ultima fue fabricado artesanalmente y la idea fue sacada de acá: Cheap DIY SD card breadboard socket
Quedando asi:
Ahora venia la parte dura de proyecto: Hacerlo andar XD.
Este tipo de tarjetas, al alimentarlas, quedan en el protocolo propietario debiendo pasarles ciertos comandos para que cambien al protocolo SPI. Las secuencias y los comandos que habrá que enviarles difieren si se usa una memoria MMC o una SD y dentro de estas ultimas hay variaciones si son V1 o V2.
Los pasos son los siguientes:
--> Se alimenta la tarjeta y luego se le envían mas de 74 pulsos de reloj teniendo la precaución de que el pin CS este a un nivel alto.
--> Se pone el CS a 0 para seleccionar la tarjeta y se le envía el comando 0 (CMD0) Lo que resetea la tarjeta y la deja en estado de espera.
--> Se envía el comando 8 (CMD8) Si la tarjeta responde que es un comando ilegal puede deberse a que sea una SD v1 o una MMC.
En mi caso era una V2 así que prosigue de esta forma:
--> Se envía el comando 58 (CMD58) para saber en que rango de tensión trabaja.
--> Por ultimo se envía repetidamente el comando especial 41 (ACMD41) hasta que la tarjeta responda con el dato 0x00 (tarjeta lista).
Con esto la tarjeta queda en modo SPI y la espera de comandos de lectura, escritura, borrado, etc.
En mi caso y el programa que esta a continuación lo que hace es inicializar la tarjeta en modo SPI y luego lee los primeros 128bytes (máxima capacidad de la EEPROM) para proceder a grabarlos en la EEPROM del PIC.
El único problema al que me enfrente es que por error soldé una resistencia equivocada en el regulador de 3.3V con lo que en realidad solo alimentaba la tarjeta a 2.7v. Al tratar de inicializarla me aceptaba todos los comandos con la excepción del comando ACM41. Al enviar este comando la tarjeta se moría y no contestaba mas a nada. Al parecer en los primeros comandos el consumo de energía es muy pequeño pero al iniciarse en el otro protocolo el consumo crece con lo que me bajaba la tensión del regulador y quedaba fuera de la tensión mínima de trabajo.
El regulador de 3.3v esta echo con zener y transistor por el simple echo de que no tenia ganas de ir a la casa de electrónica solo por un regulador.
Comandos CMD0, CMD8 y ACMD41
Las tarjetas SD poseen diversos comandos. Muchos de estos comandos son unicamente validos cuando las tarjetas trabajan en el modo SD propietario pero inválidos en el modo SPI.
Aquí pondré los mas usados (al menos por mi hasta el momento XD). Como se forman, con que parámetros y cual es la respuesta que debemos esperar.
Todos los comandos poseen la misma longitud de 6 bytes, pero no a todos latarjeta responde de la misma forma, a algunos comandos respondera con un byte, a otros con 2, otros con 4, etc.
El modo de crear un comando esta representado en la imagen superior.
Se puede apreciar que los dos primeros bits siempre son iguales 01, luego vendrán los siguientes 6 bits que forman el comando en si. Con esto ya tenemos un byte usado.
Los siguientes 4 bytes indican el parámetro. Por ejemplo la dirección a la cual leer.
Por ultimo el sexto byte es el que contiene el CRC (cyclic redundancy check) de 7 bits de longitud. El octavo bit siempre es 1.
Cuando se dice que se le envía el comando CMD1 por ejemplo, el primer byte del comando en realidad posee el valor 0x41(65 en decimal). Veamos porque:
Dijimos que los primeros dígitos valen 01. Y que los siguientes 6 representan el comando:
01 + 000001 = 01000001 (0x41).
Si lo programamos en C quedaría:
spi_write(comando | 0x40); // Xor 0x40 proque 0x40 = 01000000
Los siguientes 4 bytes no necesitan ser modificados porque son enviados tal cual son.
Por ultimo queda los 7 bit del CRC. El CRC es valor que sirve para comprobar que los 5 bytes enviados antes no sufrieron modificaciones en la comunicación. El octavo bit siempre es 1.
El CRC no es necesario en el protocolo SPI ya que por defecto esta deshabilitado con la excepción del comando CMD0 y del CMD8. Estos últimos comandos son utilizados en la inicializacion y poseen siempre el mismo CRC por lo que no hace falta calcularlos (en realidad el CMD8 si puede variar pero veremos porque digo que siempre tiene el mismo CRC).
La mayoría de los comandos responden con 1 byte que indica los posibles errores o no después de recibir un comando:
Traducido quedaría así:
Bit 8: Siempre en 0.
Bit 7: Error en el parámetro pasado.
Bit 6: Error en la dirección seleccionada.
Bit 5: Error en la secuencia de borrado.
Bit 4: Error en la comprobación del CRC.
Bit 3: El comando enviado es ilegal.
Bit 2: Erase Reset. ¿?
Bit 1: En estado de espera.
Comandos usados en la inicializacion de la tarjeta en modo SPI:
Antes que nada hay que aclarar que mientras dura la inicializacion la velocidad del puerto SPI no debe superar los 400Khz una vez la tarjeta se encuentre lista para trabajar se puede incrementar la velocidad sin problemas.
El primer comando que se envía es el CMD0. No posee parámetros, siempre son 0´s y por eso el CRC siempre es el mismo 0x95. Este comando le dice a la tarjeta que se resetee y quede en estado de espera:
spi_write(0x40); // 0x00 | 0x40 = 0x40.
spi_write(0x00);
spi_write(0x00);
spi_write(0x00);
spi_write(0x00);
spi_write(0x95);
Debido a que cada comando escrito así quedaría un poco confuso es mejor usar una función que aglomere todo quedando así:
send_cmd(0, 0x00, 0x00, 0x00, 0x00, 0x95);
Se aprecia que se envía el valor 0 y no el 0x40 ya que la función ya calcula el valor haciendo un XOR con 0x40.
Una vez enviado el CMD0 si todo estuvo bien la memoria nos responderá con 0x01. Si miramos el gráfico anterior 00000001 significa: Tarjeta en estado de espera. Que es precisamente lo que le dijimos que haga con el CMD0.
Un punto a aclarar es que la tarjeta no responde inmediatamente a un comando sino que puede tardar de 1 a 8 bytes en enviar la respuesta. Mientras si leemos el valor que obtendremos es 0xFF. Así que tendremos que leer los bytes siguientes al comando hasta que encontremos un valor diferente a 0xFF. Si después de 8 bytes seguimos sin respuesta es que hubo algún error en el proceso que impide a la tarjeta comunicarse.
El comando que le enviaremos a continuación es el CMD8(sen Interface Conection). Con este sabremos si es una SD v1, SD v2 o una MMC. Una tarjeta SDv1 o una MMC responderá con 0x04 (comando ilegal). En el caso de una SDv2 nos dará el rango de tensión en la que trabaja.
send_cmd(8, 0x00, 0x00, 0x01, 0xAA, 0x87);
El byte 4 (0x01) le pregunta a la tarjeta si puede trabajar entre el rango de 2.7v a 3.6v.
El byte 5 (0xAA) es un byte de chequeo, en la respuesta la tarjeta nos debe devolver el mismo valor. Este valor puede ser cualquiera pero se aconseja el 0xAA (por lo que el valor de CRC siempre es el mismo de usarse este valor).
La respuesta es como muestra la imagen:
Bit 8: Siempre en 0.
Bit 7: Error en el parámetro pasado.
Bit 6: Error en la dirección seleccionada.
Bit 5: Error en la secuencia de borrado.
Bit 4: Error en la comprobación del CRC.
Bit 3: El comando enviado es ilegal.
Bit 2: Erase Reset. ¿?
Bit 1: En estado de espera.
Comandos usados en la inicializacion de la tarjeta en modo SPI:
Antes que nada hay que aclarar que mientras dura la inicializacion la velocidad del puerto SPI no debe superar los 400Khz una vez la tarjeta se encuentre lista para trabajar se puede incrementar la velocidad sin problemas.
El primer comando que se envía es el CMD0. No posee parámetros, siempre son 0´s y por eso el CRC siempre es el mismo 0x95. Este comando le dice a la tarjeta que se resetee y quede en estado de espera:
spi_write(0x40); // 0x00 | 0x40 = 0x40.
spi_write(0x00);
spi_write(0x00);
spi_write(0x00);
spi_write(0x00);
spi_write(0x95);
Debido a que cada comando escrito así quedaría un poco confuso es mejor usar una función que aglomere todo quedando así:
send_cmd(0, 0x00, 0x00, 0x00, 0x00, 0x95);
Se aprecia que se envía el valor 0 y no el 0x40 ya que la función ya calcula el valor haciendo un XOR con 0x40.
Una vez enviado el CMD0 si todo estuvo bien la memoria nos responderá con 0x01. Si miramos el gráfico anterior 00000001 significa: Tarjeta en estado de espera. Que es precisamente lo que le dijimos que haga con el CMD0.
Un punto a aclarar es que la tarjeta no responde inmediatamente a un comando sino que puede tardar de 1 a 8 bytes en enviar la respuesta. Mientras si leemos el valor que obtendremos es 0xFF. Así que tendremos que leer los bytes siguientes al comando hasta que encontremos un valor diferente a 0xFF. Si después de 8 bytes seguimos sin respuesta es que hubo algún error en el proceso que impide a la tarjeta comunicarse.
El comando que le enviaremos a continuación es el CMD8(sen Interface Conection). Con este sabremos si es una SD v1, SD v2 o una MMC. Una tarjeta SDv1 o una MMC responderá con 0x04 (comando ilegal). En el caso de una SDv2 nos dará el rango de tensión en la que trabaja.
send_cmd(8, 0x00, 0x00, 0x01, 0xAA, 0x87);
El byte 4 (0x01) le pregunta a la tarjeta si puede trabajar entre el rango de 2.7v a 3.6v.
El byte 5 (0xAA) es un byte de chequeo, en la respuesta la tarjeta nos debe devolver el mismo valor. Este valor puede ser cualquiera pero se aconseja el 0xAA (por lo que el valor de CRC siempre es el mismo de usarse este valor).
La respuesta es como muestra la imagen:
Para finalizar la inicializacion de la tarjeta se envía el comando
especial ACMD41. Este comando en realidad son dos en uno. Primero se envía el CMD55 y luego el CMD41.
CMD55 le indica a la tarjeta que el siguiente comando es del tipo ACMD. y el CMD41 es el comando en si:
send_cmd(55, 0x00, 0x00, 0x00, 0x00, 0xFF);
send_cmd(41, 0x40, 0x00, 0x00, 0x00, 0xFF);
Si bien el CMD55 posee respuesta habrá que ignorarla. Pero no así la respuesta del CMD41.
Mientras la tarjeta se encuentra inicializandose responderá al ACMD41 con 0x01 (tarjeta ocupada) por lo que debemos seguir enviado el ACMD41 hasta que nos devuelva el valor 0x00 (tarjeta inicializada y lista para operar). A partir de acá ya podremos leer y escribir en ella.
¿ Cuantas veces debemos enviar el ACMD41 ? La tarjeta demorara un tiempo variable, se aconseja entonces enviar el ACMD41 un determinado tiempo, de no recibir respuesta algo habrá salido mal.
Cabe aclarar que una vez la tarjeta este en modo SPI para pasarla al protocolo SD propietario habrá que quitarle la alimentación para que se resetee. No hay comando para ello.
Acá esta el archivo con la placa, esquema, software, etc: SD.zip
CMD55 le indica a la tarjeta que el siguiente comando es del tipo ACMD. y el CMD41 es el comando en si:
send_cmd(55, 0x00, 0x00, 0x00, 0x00, 0xFF);
send_cmd(41, 0x40, 0x00, 0x00, 0x00, 0xFF);
Si bien el CMD55 posee respuesta habrá que ignorarla. Pero no así la respuesta del CMD41.
Mientras la tarjeta se encuentra inicializandose responderá al ACMD41 con 0x01 (tarjeta ocupada) por lo que debemos seguir enviado el ACMD41 hasta que nos devuelva el valor 0x00 (tarjeta inicializada y lista para operar). A partir de acá ya podremos leer y escribir en ella.
¿ Cuantas veces debemos enviar el ACMD41 ? La tarjeta demorara un tiempo variable, se aconseja entonces enviar el ACMD41 un determinado tiempo, de no recibir respuesta algo habrá salido mal.
Cabe aclarar que una vez la tarjeta este en modo SPI para pasarla al protocolo SD propietario habrá que quitarle la alimentación para que se resetee. No hay comando para ello.
Acá esta el archivo con la placa, esquema, software, etc: SD.zip
HOLA AMIGO COMO ESTA FALTA UN ARCHIVO
ResponderEliminarHola.
EliminarNo veo que archivo falta. Aclaro que el software solo lee los primeros 128 bits de la tarjeta y los graba en la EEPROM del pic. Esta "anulado" sino también enviaría los datos por RS232.
El programa esta compilado con el compilador de HITECH. Quizás lo que te pida sea la librería de ese compilador, si es que usas otro por lo que lo deberás adaptar a la librería del compilador que uses.
Hola, muy buena doc. Tienes una simulacion para proteus. Gracias.
ResponderEliminarHard Rock Hotel Casino & Spa - MapyRO
ResponderEliminarFind 춘천 출장안마 out the easiest way to get from 밀양 출장샵 Hard Rock Hotel 전라북도 출장샵 Casino & Spa to Hard Rock Hotel Casino 화성 출장안마 & Spa in Las 남원 출장마사지 Vegas. Make an online booking and use