miércoles, 8 de mayo de 2013

Protocolo SPI

Protocolo SPI


Por ahí leí algo así: El protocolo SPI es aquel que uno diseñaría si le dieran solo 10 minutos para ello. Y sinceramente, sin desmerecer el protocolo, concuerdo en que es bastante sencillo.

Es un protocolo serial y sincrónico en el que un maestro puede comunicarse con uno o mas esclavos.
Posee 3 lineas para la comunicación (MOSI, MISO, CLK) mas 1 para la selección de la tarjeta con la que se comunicara(CS).
Por ultimo existen 4 modos en los que cada uno especifica solamente en que polaridad y flanco se leen o envían los datos.

Detalle de las lineas:

MOSI: Siglas que significan Salida del Maestro - Entrada del esclavo (Master Output - Slave Input). Por esta linea el Maestro (en mi caso el microcontrolador) envia los datos hacia el esclavo (tarjeta SD).

MISO: Entrada del Maestro - Salida del Esclavo (Master Input - Slave Output). Es la linea por donde el maestro recibe los datos que le envia el esclavo.

CLK: Linea de reloj. Es la encargada de generar los pulsos de reloj que indicaran cuando un dato (bit) es valido. Osea cuando tiene que ser leído un bit o cuando hay que preparar otro para su lectura. Esta linea es manejada exclusivamente por el maestro.

CS: Selección del Esclavo (Chip Select). Por medio de esta linea el maestro habilita uno de los esclavos presentes (Si es que hay mas de 1). Es esencial para evitar que dos esclavos, por ejemplo, transmitan los datos al mismo tiempo creando colisiones (errores en la linea) con lo que se corromperían los datos.

Tanto las lineas MISO y MOSI son llamadas también DO (Data Out) y DI(Data In). En lo personal prefiero MISO y MOSI ya que a mi me crea menos confusiones.

La comunicación se establece cuando la linea CS se hace baja (!CS). A partir de acá, como dijimos hay 4 modos que son los siguientes:

Modo 0: (Y el usado por las tarjetas SD).


Datos se leen en el flanco de subida del pulso de reloj.
El micro mantiene el CLK en bajo. Pone el bit a transmitir, sube la linea CLK en alto y luego lee los datos.


Modo 1:
 
Datos se leen en el flanco de bajada del pulso de reloj.
El micro mantiene el CLK en bajo. Sube la linea de CLK, pone el bit a transmitir, baja la linea CLK y luego lee los datos.


Modo 2:
Datos se leen en el flanco de bajada del pulso de reloj.
El micro mantiene el CLK en alto. Pone el bit a transmitir, baja la linea CLK y luego lee los datos.


Modo 3:
Datos se leen en el flanco de subida del pulso de reloj.
El micro mantiene el CLK en alto. Baja la linea de CLK, pone el bit a transmitir, sube la linea CLK y luego lee los datos.


  Básicamente el modo 0 y el 2, como así también el 1 y el 3, son similares. La única diferencia es en que nivel esta la linea de CLK al mandar el primer bit para hacer el desplazamiento de los datos. Por ejemplo, en el modo 0, el primer bit a transmitir se carga antes de subir la linea de CLK.
Como se puede apreciar en las imágenes los datos se envían empezando por el bit mas significativo (MSB).

La función en C seria así (para el Modo 0):

unsigned char spi_write(unsigned char byte)
{
      unsigned char i, SPI_Valor = 0;

      for (i = 0; i < 8; i++) { // 8 bit a transmitir
                                         SCK = 0;
                                         MOSI = (byte & 128) >> 7;
                                         SCK = 1;
                                         SPI_Valor = SPI_Valor << 1;
                                         SPI_Valor = SPI_Valor | MISO;
                                         byte = byte << 1;
                                      }
      MOSI = 1;
      return SPI_Valor;
}


1) Linea de CLK en bajo. Recuerden que el primer bit se lee en el pulso de subida.

SCK = 0;

2) Preparo el bit MSB a ser transmitido y lo pongo en la linea de salida.

MOSI = (byte & 128) >> 7;

3) Subo la linea de CLK para validar los datos.

SCK = 1;

4) Las dos siguientes lineas leen el bit transmitido por la tarjeta SD y lo desplazan.

SPI_Valor = SPI_Valor << 1;
SPI_Valor = SPI_Valor | MISO;


5) Desplazo el byte a transmitir para comenzar otro ciclo en el paso 1.

byte = byte << 1;

Ojala que con las imágenes quede mas claro.

Como se aprecia, la función de escritura también lee el dato enviado por la SD. Con lo que la función debería llamarse spi_RW(). A mi me quedo mas claro llamarla como spi_write por lo que explicare a continuación.

Una cosa importante es que la linea MOSI nunca debe quedar en bajo cuando se lee los datos de la tarjeta. Cuando se leen datos de la tarjeta se le envía continuamente 1´s.
dato = spi_write(0xFF);

Para no confundirse, en C uno puede decirle que la función spi_read() sea igual que spi_write(0xFF) de la siguiente forma:

#define spi_read() spi_write(0xFF)

Con lo que al compilador al encontrarse con spi_read() lo reemplazara con spi_write(0xFF).

Otro punto a aclarar es que si bien parece que el protocolo SPI es full duplex (se transmite y recibe al mismo tiempo) es mas bien half duplex (los datos van en solo sentido a la vez, osea o se transmite o se recibe, pero no los dos a la vez). Por eso hay que enviarle el valor 0xFF para que la memoria nos devuelva el dato que necesitamos.

Espero que con esto me haya podido explicar bien como es la transmisión entre el micro y la SD en el protocolo SPI emulado en software. Tengan presente que si el micro a usar tiene ya un modulo SPI integrado la cosa se simplifica bastante.

Saludos.


5 comentarios:

  1. Genial, pero lo que necesito es en assemply. Igual gracias por el aporte

    ResponderEliminar
  2. Genial, pero lo que necesito es en assemply. Igual gracias por el aporte

    ResponderEliminar
  3. Respuestas
    1. Hola.

      El código para la comunicación SPI es el que esta publicado. Lo único que le falta es definir los pines que usaras del micro para cada linea de transmisión (SCK, MOSI; MISO) ya que la comunicación es por software dado que el micro no tiene SPI por hardware.

      Si lo que buscas es el código para comunicarse con una tarjeta SD, lo único que tengo es el publicado en un post sobre la tarjeta: http://mini12f.blogspot.com.ar/2013/05/jugando-con-las-tarjetas-sd-hola-todos.html

      Al final esta el código que es este: http://www.mediafire.com/download/13l9x3zi6mmkjdw/SD.zip

      Revisando, lo que hace es, inicializa la tarjeta y la pone en modo SPI, luego lee los primeros 128 bytes y los graba en la EEPROM del PIC. Como la placa que hice tiene para comunicarse por RS232 también esta la función para enviar estos 128 bytes a la pc (en el código esta bloqueada, solo hay que remover los "//").

      Para verlos no cree ningún programa en la PC sino que usaba el hyperterminal de windows.

      Lamentablemente quedo todo ahí, no le he dedicado mas tiempo.

      Saludos.

      Eliminar