Ir al contenido

Bus SPI en el PLC Raspberry de Industrial Shields

Uso del bus de interfaz periférica serie (SPI)
2 de noviembre de 2023 por
Bus SPI en el PLC Raspberry de Industrial Shields
Boot & Work Corp. S.L, Joan Vilardaga Castro

Índice


Introducción


En este post conoceremos el bus SPI, una de las comunicaciones disponibles en toda nuestra familia de Raspberry PLC.

El bus SPI es interesante porque una gran variedad de sensores y dispositivos comerciales tienen una interfaz SPI como medio de comunicación. Por ejemplo, muchas pantallas TFT utilizan el protocolo SPI, así como una amplia gama de sensores, como termopares, sensores de temperatura o sensores de humedad. 

Requisitos


En el ejemplo del sketch hemos usado un Raspberry 58 PLC y un M-Duino 21+ PLC. Pero sirve cualquier Raspberry PLC y/o M-Duino PLC, siempre que haya uno de cada.

PLC Raspberry industrial >>>

Fuente de alimentación >>>

También necesitarás las bibliotecas SPI y Adafruit-Blinka en el Raspberry PLC. Puedes instalarlas con estos comandos:

sudo apt-get install -y python3-pip
pip3 install spidev adafruit-blinka

El protocolo SPI


El bus SPI (Serial Peripheral Interface) fue desarrollado por Motorola en 1980. Actualmente es un estándar en el mundo de la electrónica y la automatización.

El bus SPI tiene una arquitectura maestro-esclavo.

El dispositivo maestro puede iniciar la comunicación con uno o varios dispositivos esclavos, y enviarles o recibir datos de ellos. Los dispositivos esclavos no pueden iniciar la comunicación ni intercambiar datos directamente entre sí. 

La comunicación de datos entre maestros y esclavos se realiza en dos líneas independientes, una del maestro a los esclavos y otra de los esclavos al maestro. Por tanto, la comunicación es full duplex, es decir, el maestro puede enviar y recibir datos simultáneamente.

Otra característica de SPI es que es un bus síncrono. El dispositivo maestro proporciona una señal de reloj que mantiene sincronizados todos los dispositivos. Esto reduce la complejidad del sistema en comparación con los sistemas asíncronos. 

Por tanto, necesitamos un mínimo de 3 señales para la transmisión de datos por SPI: una de las líneas para enviar datos a los esclavos, otra línea para recibir datos de los distintos esclavos y la señal de reloj para sincronizar todo el bus. Además, se necesita una línea SS (Slave Select) adicional por cada dispositivo esclavo conectado, para seleccionar el dispositivo con el que se quiere comunicar:

  • MOSI (Master-out, slave-in): comunicación del maestro al esclavo
  • MISO (Master-in, slave-out): comunicación del esclavo al maestro.
  • SCK (Clock): señal de reloj generada por el maestro.
  • SS (Slave Select): selecciona el dispositivo con el que se quiere comunicar.

Ventajas y desventajas


Ventajas:

  • Comunicación full duplex.
  • Mayor velocidad de transmisión que con I²C o SMBus.
  • Protocolo flexible en el que se tiene control absoluto sobre los bits transmitidos.
  • No está limitado a transferencias en bloques de 8 bits.
  • La implementación hardware es extremadamente sencilla.
  • Consume menos energía que I²C o SMBus porque tiene un circuito más simple y reducido, y no necesita resistencias pull-up. 
  • No es necesario ningún mecanismo de arbitraje ni de respuesta ante fallos.
  • Los dispositivos esclavos usan el reloj enviado, por lo que no necesitan reloj propio.
  • No es obligatorio implementar un transceptor (transmisor y receptor): un dispositivo conectado puede configurarse para solo enviar, solo recibir, o ambas opciones a la vez.
  • Usa muchos menos terminales en cada chip/conector que una interfaz paralela equivalente.
  • Como máximo, se necesita una única señal específica por cada usuario (señal SS); el resto de señales pueden compartirse.

Desventajas:

  • Usa más pines por chip que I²C, incluso en la variante de 3 hilos.
  • El direccionamiento se hace mediante líneas específicas (señalización fuera de banda), a diferencia de I²C, donde cada chip se selecciona con una dirección de 7 bits que se envía por las mismas líneas del bus.
  • No hay control de flujo por hardware.
  • No permite fácilmente tener varios maestros conectados al bus.
  • Solo funciona a distancias cortas, a diferencia, por ejemplo, de RS-232 o RS-485.

Conexiones SPI típicas


Opción 1) Si es una conexión en la que hay que conectar pocos esclavos, se debe usar el esquema de conexión en paralelo:

Diagrama de conexión SPI en paralelo

Se necesita una línea SS (Slave Select) adicional por cada dispositivo esclavo conectado, para seleccionar el dispositivo con el que se debe comunicar.

Opción 2) La conexión anterior tiene el inconveniente de requerir una línea por cada dispositivo esclavo. Si hay muchos esclavos, puede no ser práctica, por lo que se puede adoptar una conexión en cascada, en la que cada esclavo transmite los datos al siguiente:

Diagrama de conexión SPI en cascada

Por otro lado, en esta configuración la información debe llegar a todos los esclavos para que la comunicación termine, por eso, en general, la velocidad de respuesta del bus es menor que en la primera configuración.

Hardware


Todos los controladores lógicos programables de Industrial Shields tienen los pines SO, SI y SCK. Consulta el manual de usuario de tu versión de PLC industrial para ver dónde están estos pines. Consulta también el capítulo Pinout del manual de usuario para ver cuántos pines se pueden usar como SS (Slave Select). Aquí tienes el ejemplo del controlador Raspberry 58+ PLC, escogiendo el pin GPIO8 como SS:

Pinout SPI de los Raspberry PLC (placa de comunicación)

Software


Para usar el puerto SPI en la Raspberry podemos usar la biblioteca de Python Adafruit-Blinka, que contiene elementos de alto nivel y controladores de bajo nivel para interactuar con la interfaz SPI.

Funciones SPI básicas:

spi = board.SPI()       # Creates an SPI object to interact with the bus
spi.try_lock()          # Tries to get control of the SPI bus    
spi.write(write_buff)   # Sends the data through the bus
spi.readinto(read_buff) # If anything was received, it will put it in the read buffer
                        # if not, it will zero it.
# Both write_buff and read_buff must be of "byte" types.

Si quieres cambiar ajustes como la velocidad de reloj, la fase o la polaridad:

spi.configure(100000, 0, 0) # speed, phase and polarity
                            # By default, clock normally low-rising edge

Sin embargo, como cada dispositivo tiene una trama de datos específica,  normalmente no deberíamos usar estas funciones directamente, y el uso del bus SPI se hace de forma indirecta a través de la biblioteca del componente utilizado. Por suerte, existen muchas bibliotecas envoltorio (wrapper) para chips SPI compatibles con la biblioteca Adafruit-Blinka. Puedes encontrarlas buscando tu módulo concreto.

Ejemplo "Echo"


Un "echo" es básicamente un programa que recibe una entrada, la procesa de algún modo y devuelve esa misma entrada. Se usa habitualmente como programa de prueba básico para comprobar que la comunicación entre dos dispositivos funciona correctamente.

En este ejemplo, el Raspberry PLC será el maestro y el M-Duino será el esclavo:

Script de Python para la Raspberry:

import board
import digitalio
spi = board.SPI()  # uses SPI0 default pins
cs = digitalio.DigitalInOut(board.CE0) # select chip, GPIO8 by default

try:
    spi.unlock() # first unlock if SPI is being used by other programs
except ValueError:
    print("SPI not locked, proceeding to lock")
while not spi.try_lock():
    pass
spi.configure(100000) # change sclk frequency

try:
    write_buff = bytearray(b'0')
    while True:
        cs.value = False # select the chip
        read_buff = bytearray(1)
        spi.write(write_buff)
        spi.readinto(read_buff)
        if (read_buff != write_buff):
            print("Expected {}, but received {}" \
                  .format(write_buff, read_buff))
        else:
            print("Sent correctly")
        cs.value = True # de-select the chip
        time.sleep(1)

except KeyboardInterrupt:  # unlock the spi bus when ctrl-c'ing out of the loop
    print("Unlocking SPI bus and exiting...")
    spi.unlock()

Programa para el M-Duino:

#include  <SPI.h>

volatile boolean received;
volatile byte receivedData;
ISR (SPI_STC_vect) {     // Interrupt routine function
  receivedData = SPDR;   // Get the received data from SPDR register
  received = true;       // Sets received as True 
}

void setup() {
  Serial.begin(115200);
  pinMode(MISO,OUTPUT);   //Sets MISO as OUTPUT
  SPCR |= _BV(SPE);       //Turn on SPI in Slave Mode
  received = false;
  SPCR |= _BV(SPIE);
}

void loop() { 
  if(received) {                        
    SPDR = receivedData;    // send back the received data
    received = false;
    Serial.println((char) receivedData);
  }
}

Si ejecutamos estos dos programas, conectando ambos PLC como hemos visto en la opción 1, veremos que el Raspberry PLC siempre recibe el carácter '0'.

Buscar en nuestro blog

Bus SPI en el PLC Raspberry de Industrial Shields
Boot & Work Corp. S.L, Joan Vilardaga Castro 2 de noviembre de 2023
Compartir esta publicación

¿Estás buscando tu Controlador Lógico Programable ideal?

Echa un vistazo a esta comparativa de producto de varios controladores industriales basados en Arduino.

Comparamos entradas, salidas, comunicaciones y otras especificaciones con las de los equipos de otras marcas destacadas.

Comparativa de PLCs