Translate

martes, 9 de abril de 2013

Tarjetas SDSC/SDHC (inicialización y lectura de registros)


Como un ejemplo un poco más complicado (pero muy útil) del uso del protocolo SPI veremos en más detalle el uso de tarjetas de memoria flash en su formato SD (SecureDigital). Entre las posibilidades de comunicación que ofrecen dichas tarjetas está un modo SPI. Este modo, aunque más lento que el modo SD nativo, es más sencillo de implementar.

En este tutorial nos centraremos en las conexiones hardware, la inicialización de la tarjeta (tanto para tarjetas SD standard como para las SDHC de alta capacidad), y la obtención de las características de la tarjeta (capacidad, número de sectores, número de serie, etc.) a través de sus registros CSD y CID.

El objetivo es conseguir el volcado de información que aparece a la derecha



En una entrada posterior veremos como leer/escribir datos en la tarjeta, considerando como optimizar dicha transferencia de datos. 


Código asociado a esta entrada: SPI_sdhc.c



--------------------------------------------------------------------


Hardware:

Las imágenes muestran el pin-out de una tarjeta SD. No todos los pines mostrados se usan en la interfaz SPI.  La siguiente tabla especifica los pines usados y su función:





PIN
Name
Tipe
Description
1
CS
In
Chip Select (asserted low)
2
SDI
In
Serial Data input
3
Vss
Gnd
Ground
4
Vdd
V+
Power (3.3V usually)
5
SCL
In
Clock
6
Vss
Gnd
Ground
7
SDO
Out
Serial Data out



Otros formatos (como por ejemplo microSD, a la derecha) tendrán la misma funcionalidad, aunque su pinout puede variar.

Necesitaremos también el socket para la tarjeta elegida (SD o microSD). En Ebay, sparkfun (https://www.sparkfun.com/products/204) o Mikroelektronika (http://www.mikroe.com/add-on-boards/storage/) podéis adquirir diversas tarjetas con un socket SD o microSD y alguna electrónica adicional. Yo estoy usando un simple socket ($5-10 sin electrónica) como el mostrado a la izquierda.  Obviamente tendremos el mismo problema de antes: la diferencia de voltaje entre los 5V del PIC y los 3.3V de la tarjeta. Lo he resuelto de la misma forma cutre de antes (ver entrada de memoria flash): un regulador para obtener 3.3V a partir de los 5V del PIC, con divisores de tensión en las lineas micro à tarjeta y conexión directa de la tarjeta (3.3V) al micro (5V). 

 


Algunas de las tarjetas que se pueden adquirir (como la de Mikroe mostrada a la derecha $20),  incorporan un regulador de 5 a 3.3V y conversores de niveles que serían más fiables. En este caso es sólo una cuestión de
conectar los pines correspondientes.

Recalcar de nuevo la necesidad de resistencias pull-up en las líneas MISO y MOSI que mantengan alta la línea en ausencia de actividad por parte del micro o tarjeta. De nuevo, algunas de las opciones comentadas incluyen estas resistencias pull-up.


Configuración del módulo SPI

Antes de hacer nada debemos elegir el modo SPI (CPOL,CPHA), velocidad, etc. para inicializar el módulo SPI del PIC.

El modo SPI (0,0)  con SMP=0  es una combinación que me ha funcionado con todas las tarjetas usadas. Obviamente el micro (PIC) será el master SPI. Solo nos hace falta decidir la velocidad del reloj.

En algunos referencias se advierte que es preciso una conexión inicial a baja velocidad (se cita un máximo de 400Khz) y solo cuando la tarjeta ha sido convenientemente inicializada y ha habido una negociación pasaremos a la velocidad máxima soportada. En otros lugares se indica que dicha restricción es sólo para tarjetas MMC. Con las tarjetas que yo he probado (SD todas ellas) la inicialización ha sido satisfactoria arrancando a la máxima velocidad, pero no cuesta nada realizar el primer intercambio a velocidad baja y pasar a velocidad alta tras la inicialización.

En nuestro caso usaremos Fosc/64 como velocidad inicial y Fosc/4 como velocidad final.

En este proyecto usaremos un cristal de 8 MHz y la opción HSPLL en la configuración. Con esta opción un PLL multiplica por 4 la frecuencia del cristal, por lo que el PIC está trabajando a 32 Mhz. Para habilitar esta opción basta hacer al principio del programa:

#pragma config OSC=HSPLL  // PLL x 4

 Con un cristal "efectivo" de 32 MHz, la velocidad más lenta (Fosc/64) corresponde a un reloj del SPI inicial de 500 Khz y una velocidad final (Fosc/4) de 8 Mhz. La velocidad inicial se sale un poco del máximo recomendado, pero me ha funcionado con las tarjetas probadas.

Usando las rutinas conocidas podemos inicializar el módulo SPI con la siguiente función:



// CS line
#define SD_CS     LATCbits.LATC2
#define SD_CS_dir TRISCbits.TRISC2
#define select_SD   SD_CS=0
#define deselect_SD SD_CS=1

void SD_spi_init(byte clock)
{
 SD_CS_dir=0; deselect_SD; // Configure CS line as output and set it low.
 spi_master(clock);  // Configure SPI as master and set clock
 spi_mode(0,0,0);    // SPI mode (0,0). Sample incoming bits at mid period   
 spi_enable();       // Enable SPI
}


Como hicimos en el caso de la memoria flash, previamente definimos SD_CS y SD_CS_dir para informar al resto de las rutinas de que pin estamos usando como ChipSelect (CS) y su correspondiente bit de dirección TRIS.


Especificación del protocolo SPI para tarjetas SD

En el documento SanDisk Secure Digital Card (Product Manual)   podéis encontrar unas especificaciones bastante completas del protocolo para comunicarse con tarjetas SD. En particular hay que leer el capítulo 5 que contiene la definición del protocolo SPI.  

Nota:  todo lo que viene a continuación es una versión muy reducida del protocolo completo. Sigo muchos atajos (confiando por ejemplo que se que tipo de tarjeta tengo, o que voltaje acepta) y como siempre existe la posibilidad de que tenga errores. El protocolo completo es complejo y es posible que si no se respeta estrictamente tengamos un código que funcione en muchos casos pero falle para cierto tipo de tarjetas que exigen una adherencia más estricta al protocolo.  En caso de duda o problemas no hay nada como leerse las especificaciones.
De hecho, si alguien desea realmente enterarse de los detalles debería estar leyendo dicho capítulo 5 en lugar de este documento.

Además de en una somera lectura de las especificaciones, el código presentado está basado en varias fuentes entre las que caben destacar:


Algunos de estos códigos son para otros micros, pero la base del protocolo de comunicación es esencialmente la misma. En general los programas citados anteriormente son mucho más completos que el que presento aquí, considerando más tipos de comandos, etc.

Una muy buena referencia del proceso de inicialización de una tarjeta SD puede encontrarse en 

     http://elm-chan.org/docs/mmc/mmc_e.html



Envío de comandos a la tarjeta SD:

El protocolo de comunicación entre PIC y tarjeta SD se basa en el envío de comandos desde el PIC y la recepción de respuestas de la tarjeta. La secuencia standard es:
  1. Comando de PIC a SD (un total de 6 bytes)
  2. Respuesta de SD a PIC (normalmente 1 o 2 bytes, casi siempre 1, a veces más dependiendo del comando usado). La tarjeta siempre responde, aunque podemos llegar a necesitar hasta 8 "peticiones" de bytes hasta que llegue las respuesta.
  3. Opcionalmente un bloque de datos (en uno u otro sentido) si el comando era de escritura/lectura de datos.
En este apartado presentaremos el intercambio más sencillo consistente en Envio de Comando/Respuesta sin datos. La figura siguiente ilustra este tipo de intercambios.

 En ocasiones (2º ejemplo de la figura) el comando exige un cierto trabajo a la tarjeta. Para indicar que está ocupada mantendrá la línea MISO a 0.  Como dicha línea debería tener una resistencia de pull-up que la mantenga a nivel alto por defecto si está a 0 indica que la tarjeta la está manteniendo abajo y que debemos esperar a que termine.

El comando enviado es simplemente un código (1 byte) seguido de un argumento de 4 bytes y de un CRC de un byte, para un total de 6 bytes. El uso de un CRC correcto es opcional en el protocolo SPI y generalmente se ignora su valor (aunque hay que seguir mandando dicho byte).  La única excepción es en los primeros comandos  enviados para pasar al modo SPI. Como la tarjeta no está todavía en modo SPI si que es preciso enviar un CRC valido.

El código de comando es un valor de 6 bits (de 0 a 63). Antes de mandarlo se añade 01 en los dos bits más significativos. Para ello haremos un OR  con el valor 0b01000000=0x40. La tabla siguiente refleja algunos de los comandos usados en el código:



#define CMD_GO_IDLE_STATE       0x00        // CMD00: R1
#define CMD_SEND_CSD            0x09        // CMD09: R1
#define CMD_SEND_CID            0x0A        // CMD10: R1
#define CMD_SET_BLOCKLEN        0x10        // CMD16: R1 arg=BLOCKLEN
#define CMD_READ_SECTOR         0x11        // CMD17: R1 arg=data address
#define CMD_READ_MULT           0x12        // CMD18: R1 arg=data address
#define CMD_WRITE_SECTOR        0x18        // CMD24: R1 arg=data address
#define CMD_WRITE_MULT          0x19        // CMD25: R1 arg=data address
#define CMD_APP                 0x37        // CMD55: R1
#define ACMD_SEND_OP_COND       0x29        // ACMD41 R1 (after CMD_APP_CMD)

// SDHC addemdum
#define CMD_SEND_OP_COND     0x01
#define CMD_SEND_IF_COND     0x08



Tras la recepción de un comando (aunque puede que no inmediatamente) la tarjeta responderá. Hay varios formatos de respuesta, dependiendo del comando, pero el más común es el tipo R1, de tamaño 1 byte:




El bit más significativo debe ser 0. Un 1 en esa posición indica que el byte recibido no es una respuesta válida. De nuevo, la idea es que el pull-up en está línea la mantendrá alta en ausencia de actividad por parte de la tarjeta. Exigir que el 1er bit sea un 0 permite saber si la tarjeta está activa. El resto de los bits indican distintos tipos de errores cuando están a 1. La excepción es el bit 0 que indica que la tarjeta esta en IDLE_STATE y corriendo el proceso de inicialización. En el código usamos los siguientes defines para identificar estos estados:

#define R1_IDLE                 0x01    //  Idle_State
#define R1_BAD                  0x80    //  MSbit no nulo


Las respuestas de tipo R2 consisten en un byte adicional con información adicional (el 1er byte es identico a R1). Hay también respuestas con un mayor número de bytes. En el código de este tutorial solo trabajaremos con respuestas del tipo R1.

Vamos a escribir una función que mande un comando, reciba la respuesta y compruebe que todo va bien para poder proseguir. La función usada para mandar un comando de tipo R1 es la siguiente (habría que escribir distintas funciones para enviar comandos tipo R2, etc.:

/// send a R1 type command and wait for an answer
byte send_command_R1(byte cmd, unsigned long arg)
{
 byte* ptr = (byte*)&arg; // Pointer to individual bytes of argument
 byte k,res,crc=0xFF;

 if (cmd==CMD_GO_IDLE_STATE) crc=0x95; //  CMD00 --> crc needed = 0x95
 if (cmd==CMD_SEND_IF_COND)  crc=0x87; //  CMD08 --> crc needed = 0x87

 cmd = (cmd & 0x3F) | 0x40; // Makes sure cmd is 6 bit and OR it with 0x40

 // Wait up to 10 x 8 clocks until line is idle (0xFF)
 k=10; res=0; while ( (res!=0xFF) && (k--) ) {res=spi_rx();  Delay10TCYx(1); }

 //  Send command, argument and CRC (only needed for CMD00 and CMD08)
 spi_tx(cmd); // Command
 for(k=0;k<4;k++) spi_tx(ptr[3-k]); // Argument bytes: Most Significant Byte first
 spi_tx(crc);  //// CRC (fake in all cases except for CMD00 or CMD08)

// Wait up to 10 bytes to get a R1 answer with a clear MSbit
 res=0xFF; k=10; while ( (res&R1_BAD) && (k--) ) res=spi_rx();
  
 return res;
}



Algunos comentarios sobre el código anterior:
  • Antes de enviar el comando se verifica que la línea esta libre (alta). Se detecta al recibir 0xFF.
  • Se manda el COMANDO + 4 bytes de argumento + CRC.
  • El CRC enviado solo es correcto para dos comandos CMD00 y CMD08  que se mandan al principio. En todos los demás casos se usa un CRC=0xFF.
  • Se espera hasta recibir una respuesta tipo R1, con el primer bit igual a 0. LLegamos a esperar hasta 10 peticiones de respuesta antes de desistir.


Inicialización de la tarjeta en modo SPI

Una vez que ya sabemos la configuración necesaria para el puerto SPI y como mandar comandos básicos a la tarjeta, estamos en condiciones de inicializar una tarjeta SD.  Pasamos a describir los pasos para conseguirlo.

Nota: la inicialización completa de una tarjeta SD es un proceso complicado si queremos cubrir todas las posibilidades. En http://elm-chan.org/docs/mmc/sdinit.png podéis encontrar un diagrama de flujo de los pasos a seguir. El proceso que presento aquí es una simplificación de ese gráfico que me funciona para todas las SD que he probado (SDSC v1.0, SDSC v2.0 y SDHC v2.0). Si estáis seguros de la tarjeta que váis a usar podríais simplificar aún más el código presentado. Si debemos manejar cualquier tarjeta que a la gente se le ocurra meter en la ranura, deberíamos implementar el protocolo completo.


Tras un power-up una tarjeta SD despierta en modo SDbus. Lo primero que hay que hacer es pasarla a modo SPI.  El proceso que uso en mi código es el siguiente:



  1. Dejar un delay inicial de algunos ms para estar seguros de que se ha estabilizado la alimentación
  2. Inicializar SPI a la velocidad más lenta (Fosc/64)
  3. Con CS=1 (deselect_SD), mandar al menos 74 clocks a la tarjeta. Lo conseguiremos mandando 8 bytes (8x10=80) cualesquiera usando spi_clock().
  4. Mandarle el comando CMD00 que pone a la tarjeta en modo SPI, dejándola en IDLE_STATE mientras corre una especie de self-test. Comprobar que se recibe una respuesta tipo R1 (1 bytes) con valor 0x01 (idle state).  Este comando requiere un CRC correcto (00x95). 
  5. Si este comando funciona correctamente tratar de enviar un comando CMD_08 a la tarjeta con argumento 0x1AA y CRC = 0x87.  Este paso es fundamental si se tiene una tarjeta SDHC y se puede obviar con otras tarjetas.  En comandos sucesivos ya no es necesario enviar CRCs correctos.
  6. La especificación indica que ahora deberíamos preguntar sobre un cierto registro (OCR) y determinar el voltaje aceptado por la tarjeta y actuar en consecuencia. También hay una serie de pasos que permiten distinguir entre las antiguas tarjetas MMC y las más modernas SD. Si estamos seguros de que no hay problemas de voltaje y de que nuestra tarjeta es una SD y no una MMC, podemos saltarnos dichas comprobaciones y pasar directamente al siguiente paso.
  7. Si el comando CMD08 no fue aceptado,   se envía el comando CMD_0x37 seguido del comando CMD_0x29. El comando CMD_0x37 (APP_CMD) es un "prefijo" que indica que el siguiente comando es un comando especifico de aplicación  (APPLICATION COMMAND) en vez de un comando usual. El CMD_0x29 (ACMD_SEND_OP_COND) activa el proceso de inicialización de la tarjeta en modo SPI. Ambos comandos no precisan argumento (aunque siempre hay que mandar 4 bytes, p.e. 0x00 00 00 00) ni CRCs correctos. 
  8. Si el comando CMD08 fue aceptado se envia el comando CMD_0x01 (CMD_SEND_OP_COND), de nuevo con argumento 0 y CRC cualquiera.
  9. Si 7 u 8 funcionaron la tarjeta está inicializada y lista para aceptar todo tipo de comandos en modo SPI. Como el proceso de auto-test puede llegar a tardar hasta 1 segundo es conveniente reintentar el envio de estos comando durante cierto tiempo antes de declarar un TIMEOUT.
  10. Trás la inicialización podemos usar el comando SET_BLOCKLEN (CMD16) para fijar el tamaño del bloque de datos (que se pasa como argumento). El tamaño "nativo" de las tarjetas SD es de 512 bytes. En operaciones de lectura se puede especificar un tamaño de bloque entre 1 y 512 bytes. Las operaciones de escritura deben hacerse en bloques de 512. Lo normal es usar el BLOCKLEN nativo de 512.

Una vez inicializada la tarjeta, volvemos a  poner la máxima velocidad posible (Fosc/4) en el reloj del módulo SPI (si es que empezamos con una velocidad lenta) para agilizar las transferencias de información.  El código completo de la inicialización queda:



#define N_trials 10
byte init_SD(void)
{
  byte k,res;

  SD_spi_init(2);   // Slow SPI clock (Fosc/64)

  deselect_SD; for (k=0;k<10;k++) spi_clock(); //80 clocks with CS=1 to start up card

  select_SD; 

  for(k=0;k<N_trials;k++)  //Try with CMD_0x00 a few times
   {
    res=send_command_R1(CMD_GO_IDLE_STATE,0x00); 
    if (res==R1_IDLE) break; // Great, card went into IDLE_STATE
    Delay10KTCYx(25); //delay
   }
  if (res!=R1_IDLE) {deselect_SD; return 4;}  // Didn't reach IDLE_STATE

  // Check a few times for SDHC with CMD_0x08
  for(k=0;k<N_trials;k++)
   {
    res=send_command_R1(CMD_SEND_IF_COND,0x1AA);   
    if (res==R1_IDLE) // Great, CMD_08 accepted
      {
       spi_clock(); spi_clock(); spi_clock(); spi_clock();  // Shift 4 trailing bytes
       break; //
      }
    Delay10KTCYx(25); //delay_ms
   }

  // According to answer to CMD08 try CMD_SEND_OP, ACMD_SEND_OP, or return with error
  switch (res)
   {
    case 1:  //SDHC card --> send CMD_01
     res=1; k=0;  // Try with CMD_SEND_OP a few times.
     while(res & (k<100))
      {
       res=send_command_R1(0x01,0x40000000); if (res&R1_BAD) continue
       k++; Delay10KTCYx(10); //delay_ms(20);
      }
     if (res) {deselect_SD; return 2;}  // Card failed when sending CMD_SEND_OP_COND after CMD08
     break;

    case 5:  // CMD08 declared illegal command, maybe it is a normal SD card

     res=1; k=0;  // Try with CMD_APP+ACMD_SEND_OP a few times.
     while(res & (k<100))
      {
       res=send_command_R1(CMD_APP,0); if (res&R1_BAD) continue
       res=send_command_R1(ACMD_SEND_OP_COND,0);
       k++; Delay10KTCYx(10); //delay_ms(20);
      }
     if (res) { deselect_SD; return 1; } // Card failed when sending ACMD_SEND_OP_COND
     break;
   
     otherwise:  deselect_SD; return 3;  break // Failed CMD08
   }

  res=send_command_R1(CMD_SET_BLOCKLEN,512L);  // Set block length = 512

  deselect_SD;

  SD_spi_init(0); // Fastest SPI clock (Fosc/4)

  return (0);
}


Lectura de registros CSD/CID de la tarjeta: 


Si todo ha ido bien, la rutina init_SD devuelve un valor 0 (no error), indicando que la tarjeta está lista para aceptar todo tipo de comandos válidos y para enviar/recibir datos. A continuación veremos como leer nuestros primeros datos de la tarjeta, los registros CID (Card ID Data) y CSD (Card Specific Data), conteniendo interesante información de la tarjeta, como su velocidad de transferencia, capacidad, tamaño de sector, consumo eléctrico, fecha de fabricación, número de serie, etc.


Proceso de lectura de datos:

Para proceder a leer el registro CSD es preciso implementar nuestro primer comando de lectura de datos. Veremos en primer lugar como es un típico intercambio de lectura.

Un comando de lectura se inicia con el mismo intercambio CMD/Respuesta presentado antes. La diferencia es que si el comando tiene éxito, la tarjeta transferirá un cierto bloque de datos a su buffer de salida y procederá a enviarlos (cuando el master se lo pida). El número de datos depende del comando, pero el primer dato enviado es siempre un Data Token (que en la mayoría de los casos corresponde a 0xFE) indicando que los datos pedidos vienen a continuación.  En vez del Data Token (0xFE) también podría recibirse un Error Token (0b 000xxxxx) donde los 5 bits menos significativos corresponden a banderas para diferentes errores. Por ejemplo podríamos haber pedido leer un sector fuera del rango de la tarjeta. Si se recibe un Error Token  no se continua con la transmisión de datos esperada.

Un típico comando de lectura de datos tiene el siguiente diagrama:


Al intercambio CMD/R le sigue la recepción de un bloque de datos. Dicho bloque está delimitado por un Data Token con valor 0xFE y terminado por un CRC de 16 bits (que puede ignorarse en modo SPI).

Como el intercambio Command/Response ya esta cubierto en nuestra función send_command() basta escribir una función que reciba los datos enviados y los guarde en un buffer indicado por el usuario:

uint8 read_data_block(uint8* buf, uint16 n)   // Read data block
{
 uint16 k;
 uint8 res,crc;

 res=0xFF; while(res==0xFF) res=spi_rx();   // Wait for first data
 if (res!=0xFE) return res;  // Data token not found, return Error Token

 for(k=0;k<n;k++) buf[k]=spi_rx(); // read n bytes
 crc=spi_rx(); crc=spi_rx();   // Read CRC (16 bits) and ignore it

 return(0);
}


Lectura del registro CSD:

Veamos como usar la rutina anterior para leer los registros CSD y CID. Ambos registros tienen 16 bytes y basta mandar el comando correspondiente para iniciar el proceso de transferencia de esos 16 bytes:


byte read_CSD(unsigned char* buf)
{
 byte res;

 select_SD;
 res=send_command_R1(CMD_SEND_CSD,0); 
 if(res==0) res=read_data_block(buf,16);
 deselect_SD;

 return res;
}

byte read_CID(unsigned char* buf)
{
 byte res;

 select_SD;
 res=send_command_R1(CMD_SEND_CID,0); 
 if(res==0) res=read_data_block(buf,16);
 deselect_SD;

 return res;
}


Los datos de ambos registros se guardan en el buffer suministrado por el usuario (con un espacio de al menos 16 bytes).

Para la interpretación de ambos registros debemos dirigirnos a las especificaciones citadas anteriormente (en particular el apartado 3.5.3). 
Usando dichas especificaciones he escrito un par de funciones show_CID_data y show_CSD_data que vuelcan por el puerto serie algunos de los campos más interesantes de ambos registros. El registro CID contiene información sobre el fabricante, producto, número de serie y fecha de fabricación. El registro CSD lleva info muy importante sobre tamaño y número de sectores, capacidad de la tarjeta, limitaciones y forma de acceso, etc.

Veamos la salida para un par de tarjetas SD. La primera es una vieja tarjeta de 32 Mb de Panasonic. La segunda, una tarjeta más reciente de 8 Gbytes de SanDisk:

Panasonic 32 Mbytes:



SanDisk Ultra 8 Gbytes:




La información más interesante está en el CSD, a partir de la cual podemos saber el tamaño del sector (típicamente 512 bytes) y el número de sectores o capacidad de la tarjeta. La discrepancia entre los datos del fabricante (32 Mb y 8 Gb frente a los 29 Mb y 7580 Mb obtenidos) es que yo estoy usando 1Mbyte = 1024 Kb y no 1 Mbyte = 1000 Kb).

Otra diferencia muy importante es que la segunda tarjeta (como todas las SD mayores de 2 Gb) es de alta capacidad (SDHC). Esto será importante de cara a la lectura de datos. Las tarjetas más pequeñas admiten lecturas/escrituras parciales de datos (esto es, por debajo del amaño del sector). Esto nos permite mantener un buffer más pequeño en el PIC donde acumular los datos hasta que llega el momento de volcarlos a la tarjeta. Por el contrario en las tarjetas SDHC la lectura/escritura es sólo por bloques de 512 bytes.

De hecho, como veremos en el siguiente tutorial, cuando usemos los comandos para escribir/leer datos, veremos que en el caso de las tarjetas SDSC (Standard Capacity) cuando especifiquemos la dirección u offset a partir del cual se van a escribir los datos, se dan en unidades de bytes. Por el contrario, en tarjetas SDHC (High Capacity) la dirección de lectura/escritura se da en unidades de bloques.  

19 comentarios:

  1. hola antonio, estoy trabajando en el tema de las micro sd y según yo queda inicializada en modo SPI pero no puedo leer ni escribir en ella.. nunca me llega el token FE para comenzar la lectura.tienes algún correo para enviar mi codigo?
    espero tu respuesta saludos

    ResponderEliminar
    Respuestas
    1. ¿Has probado mi código con tu sistema? Eso podría valer para determinar si hay un problema en tu código o si podría haber un problema de hardware (aunque por lo que dices si que parece que funciona durante la inicialización).

      Si que es verdad que, como comento, la implementación presentada es una versión simplificada del protocolo, pero a mi me ha funcionado en todas (5 o 6) tipos de tarjetas que he probado.

      Es cierto que no lo he probado en una microSD, aunque eso no debería influir ya que tienen la misma funcionalidad (de ahí que usen adaptadores microSD-SD sin electronica adicional).

      Un saludo, Antonio

      Eliminar
  2. No es necesario usar el contacto cs de la sd simplemente colocandolo a masa funciona ahorrando un bit del port. gauna sergio antonio ing Freescale

    ResponderEliminar
  3. http://www.youtube.com/watch?v=6ust10hCjf0

    ResponderEliminar
  4. Hola Antonio, sera que tu has trabajado con la tarjeta de desarrollo TM4C123G con este mismo tipo de proyectos, es claro resaltar que es de sistemas embebidos, o algun contacto que sepa de ello, por otro lado que si tienes el codigo completo perdon por la pedirlo pero es que quiero trabajar sobre la realizacion de poder leer datos MP3 desde una SD con el protocolo SPI, gracias por su atencion.

    Att. Fernando

    ResponderEliminar
    Respuestas
    1. No conozco la tarjeta de desarrollo que mencionas. Respecto al código del proyecto lo tienes enlazado al inicio de la entrada. Lo que ocurre es que de cara a tu aplicación lo presentado aquí es sólo una parte. Tu proyecto constaría de 3 partes:
      1. Código de bajo nivel para leer sectores de una tarjeta SD usando SPI (esta entrada)
      2. Ser capaz de usar un sistema de ficheros (algo simple como FAT16 o FAT32) para poder leer ficheros MP3 de una tarjeta SD. En una próxima entrada pensaba describir como manejar un FAT16 con un PIC.
      3. Código para decodificar el formato comprimido MP3 y enviarlo al DAC correspondiente.

      Un saludo, Antonio.

      Eliminar
  5. Buenas, estaba interesado en cambiar PERM_WRITE_PROTECT en el bit 13, porque mi memoria esta bloqueda en escritura y me gustaria arreglarlo. ¿Como se haría?

    ResponderEliminar
  6. Buenas tardes, estoy con una SD Sandisk 1Gb, en lamisma puedo escribir, pero a la hora de leer y almacenar los datos en el buffer solo leo basura, esto lo corroboro leyendo, grabando en el burffer y luego reescribiendo la info en otra parte d ela memoria, hay alguna manera de ir descartando que problema tengo al leer, ya que sigo al pie de la letra la secuencia, envio CMD leer , corroboro que recibo el TOKEN 0XFE, y luego con un for de 512 repeticiendo voy guardando todo en una variable vector char, trabajo con el pic4550, no se si sera problema de ruido o me estoy saltando algun paso del protocolo

    ResponderEliminar
  7. https://www.youtube.com/watch?v=UajDN5dpW3I

    ResponderEliminar
  8. Hola Antonio,

    Tengo un problema con mi tarjeta SD que creo es distinto a todo lo que explicas pero podrías ayudar.

    Mi tarjeta se le ha activado PERM_WRITE_PROTECT (Se colocó en 1) y no he podido cambiar ese valor, quisiera saber si hay alguna forma electrónica o en software de cambiarlo, ya que pues es la tercera que le sucede lo mismo y no deseo invertir más dinero.

    Agradecería una respuesta.

    ResponderEliminar
    Respuestas
    1. No se muy bien cual es el problema que mencionas pero el programa WinHex te permite acceder a toda la información de la tarjeta y puedes modificar cualquier dato de ella, creo que la dificultad seria identificar cual es ese valor, ¿ya probaste formateando la tarjeta?

      Eliminar
  9. Para nada es la forma cutre partir de regulador a 5v reducir con regulador 3,3v mientras el primer regulador este elegido para aguantar todo el consumo, para cutre están los montajes basados en divisores de resistencias y voltaje de 5v para todo, eso sí es cutre ya que toda la estabilidad general de los 3,3 de la tarjeta depende del consumo general e influye en la estabilidad de los divisores

    ResponderEliminar
  10. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  11. hola estoy tratando de iniciar una SDHC todo va bien hasta envio el cmd 0x08 y me devuelve 0x01 0x00 0x00 0x01 0xAA pero al enviar el cmd 0x01 y el resto de comandos la sd solo me responde 0x01 y no se que hace por favor necesito una mano con eso

    ResponderEliminar
  12. Hola!, tengo una duda... para usar SPI Y USART en el pic18f4550 como le hiciste? Ya que ambas comunicaciones utilizan el pin C7 para SDO y RX respectivamente???

    ResponderEliminar
  13. Hola que Tal... estoy intentando consultar la guia que dejaste en este link "SanDisk Secure Digital Card (Product Manual)" pero la pagina no se encuentra. por casualidad tienes el documento u otro link en donde lo pueda consultar??

    ResponderEliminar
  14. Hola, que tal?.
    Un favor, estoy confuso sobre lá funcion: spi_clock(), no veo el código de ella. Podrias darme mas detalhes?.

    Desde ya agradezco por lá ayuda.

    ResponderEliminar
  15. Muy interesante, me gustaría saber como direccionar la memoria para escribir y leer datos

    ResponderEliminar