Gestión del bus spi desde C

Enviado por Javi y clasificado en Informática

Escrito el en español con un tamaño de 9,49 KB

INTRODUCCIÓN:

El Bus SPI (Serial Peripheral Interface) es un estándar de comunicaciones, usado principalmente para la transferencia de información entre circuitos integrados en equipos electrónicos. Es un bus serie, síncrono y trabaja en modo full dúplex. Incluye una línea de reloj, dato entrante, dato saliente y un pin de chip select, que conecta o desconecta la operación del dispositivo con el que uno desea comunicarse.

GESTIÓN DEL BUS SPI DESDE C:

Existen 4 funciones en lenguaje C asociadas con el módulo SPI, pero todas ellas son utilizables únicamente si el microcontrolador seleccionado dispone de módulo hardware SSP. No existe implementación software del módulo SPI. Las funciones mencionadas son las siguientes:

-       setup_SPI():

void setup_SPI(const modos);

Esta función sirve para inicializar y configurar el Interfaz de Puerto Serie (SPI) ya que define el modo de trabajo de esta comunicación.

En el fichero de cabeceras del dispositivo microcontrolador (.h) están definidas una serie de etiquetas que están asociadas a los modos de funcionamiento y que se separan en 3 grupos:

a) Modo:

  • SPI_MASTER: configura el dispositivo como maestro.
  • SPI_SLAVE: configure el dispositivo como esclavo.
  • SPI_SS_DISABLED: desactiva el pin de selección SS.

b) Flanco: configura los modos de transmisión sobre SPI según las siguientes combinaciones:

  • SPI_L_TO_H: flanco de bajo a alto (flanco de subida).
  • SPI_H_TO_L: flanco de alto a bajo (flanco de bajada).

//  MOTOROLA    |        MICROCHIP      |           CCS 
//-----------------------------------------------------------------------------------------------------
//   SPI Mode 0,0  |   CKP = 0, CKE = 1  |  SPI_L_TO_H | SPI_XMIT_L_TO_H 
//   SPI Mode 0,1  |   CKP = 0, CKE = 0  |  SPI_L_TO_H 
//   SPI Mode 1,0  |   CKP = 1, CKE = 1  |  SPI_H_TO_L 
//   SPI Mode 1,1  |   CKP = 1, CKE = 0  |  SPI_H_TO_L | SPI_XMIT_L_TO_H

CKP=Clock Polarity Select bit

CKE=Clock Edge Select bit


c) Frecuencia: define la frecuencia a la que oscilará el reloj. Solo se utiliza si el dispositivo se configura como maestro ya que es quien genera la señal de reloj.

SPI_CLK_DIV_4

SPI_CLK_DIV_16

SPI_CLK_DIV_64

SPI_CLK_T2

Las etiquetas anteriores se enlazan mediante el operador OR (|). Veamos algunos ejemplos:

  • configurando el dispositivo como maestro, modo B (0,1) y con una velocidad de reloj:

setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_16);

  • configurando el dispositivo como esclavo, modo C (1,0) y con el pin de selección desactivado:

setup_spi(SPI_SLAVE | SPI_H_TO_L | SPI_SS_DISABLED);

-       spi_write():

void spi_write(char c);

Esta función selecciona el siguiente carácter a escribir en el puerto SPI. Si el dispositivo es maestro genera una señal de reloj y se envía el valor inmediatamente. Si el dispositivo es esclavo, el valor no se envía hasta que el maestro se lo indica con una señal de reloj.

-       spi_read():

char spi_read([char c]);

Esta función tiene distinto efecto en función de que el dispositivo sea Maestro o Esclavo. La función devuelve un dato leído a través del SPI y puede llevar un dato como parámetro o no.

Si el dispositivo es Maestro SPI, la función envía el valor c cuando un nuevo valor se ha recibido (d=spi_read(c)). Si no hay datos para enviar pero hay que hacer una operación de lectura, se le pasa cero a la función (d=spi_read(0)). Si se ha utilizado previamente la función spi_write() y queremos leer un dato durante la escritura utilizaremos esta función sin pasarle ningún parámetro (d=spi_read()).

Si el dispositivo es Esclavo, la función spi_read() espera a que el dispositivo maestro envíe la señal de reloj y el dato por el puerto SPI. Mientras el nuevo dato se recibe, se envía el dato c al otro dispositivo. Para saber si hemos recibido un dato por el puerto SPI utilizamos la función spi_data_is_in().

-       spi_data_is_in():

char spi_data_is_in();

Esta función devuelve TRUE si se ha recibido un dato a través del  puerto SPI.

Veamos un ejemplo de utilización de las funciones explicadas. El ejemplo consiste en la comunicación de un maestro por un lado, y de un esclavo por otro. Para compilar el maestro, descomentar “#define MASTER_DEVICE”.

#include <16f877.h>

#fuses HS,NOWDT                        //un Microchip pic16f877

#use delay(clock=10000000)

#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)

#use standard_IO(D)

// #define MASTER_DEVICE

#ifdef MASTER_DEVICE

//          (maestro)

void main()

{

            int8 c,d;

            setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_16);

            printf(“Presiona una tecla para empezar: “);

            while(1)

            {

                        c=getchar();

                        output_D(0xFF ^ c);  //enciende los LED’s correspondientes del

  // portD

                        //las siguientes dos líneas representan un método

                        spi_write(c);              //datos enviados usando write

                        d=spi_read();            //datos leídos usando read

                        //método alternativo a las dos líneas anteriores

                        //d=spi_read(c);    //escribe y lee datos usando read

                        putchar(c);

            }

}

#else

//          (esclavo)

void main()

{

            int8 c;

            setup_spi(SPI_SLAVE | SPI_L_TO_H | SPI_CLK_DIV_16);

            while(1)

            {

                        //flash C2 para mostrar cuando se activen

                        output_low(PIN_C2);

                        delay_ms(100);                    //retardo de 100 ms

                        output_high(PIN_C2);

                        delay_ms(100);

                        //un metodo – comprueba que los datos están listos antes de

                        //hacer la lectura

                        if(spi_data_is_in())

                        {

                                   c=spi_read();                        //lee los datos

                                   output_D(0xFF ^ c);            //enciende los LED’s correspondientes

                                                                       //del port D

                                   spi_write(c);              //espera la señal del maestro para

                                                                       //enviar y escribe los datos

                        }

                        // método alternativo:

                        // c=spi_read(c);          //escribe los datos antiguos y lee los nuevos

                        //output_D(0xFF ^ c); //enciende los LED’s del port D

                                                              //correspondientes

            }

}

#endif

Existen numerosas librerías más complejas que permiten la utilización de funciones más específicas para la gestión del bus SPI.

Entradas relacionadas: