Skip to content

S6: Comunicaciones

Juan Gonzalez-Gomez edited this page Nov 21, 2022 · 95 revisions

Sesión 6: Comunicaciones

  • Tiempo: 2h
  • Fecha: Lunes, 21 de Noviembre de 2022
  • Objetivos de la sesión:
    • Conocer las formas de comunicación de datos entre circuitos
    • Aprender a comunicar el Arduino con la FPGA
    • Comunicar la FPGA con el PC por puerto serie

Contenido

Introducción

Nuestros circuitos tiene que comunicarse con otros circuitos, para enviarles datos o recibir información de ellos. Estos circuitos pueden estar dentro de la propia FPGA, o bien en chip diferentes. En esta sesión veremos cómo se realiza el intercambio de información y veremos ejemplos de dos mecanismos muy usados: El SPI y el puerto serie. Aprenderemos a comunicar nuestro Arduino con la FPGA, y la FPGA con nuestro PC

Este es nuestro esquema general, que iremos refinando. Queremos que dos circuitos digitales intercambien información. ¿Cómo lo hacemos?

En cualquier sistema de comunicación tenemos dos aspectos:

  • El dato a transmitir. Tiene un tamaño. Y una forma de transmitirse
  • Evento de transmisión: Cuándo transmitir el dato
  • Sentido de la transmisión: Los datos van de un origen a un destino

Comunicaciones en paralelo

Empezaremos por lo que ocurre en el interior de los chips. En nuestro caso, en el interior de la FPGA. Los datos se transmiten en paralelo, usándose un cable para cada bit

En esta figura se muestra un ejemplo de transmisión de un dato de 8 bits desde un circuito origen (el transmisor) a otro destino (el receptor). Todos los bits se transmite a la vez, por 8 cables independientes

En los esquemas de estos circuitos NO se dibujan todos los cables, para que sean legibles. En su lugar se dibuja un cable con una barra cruzada que indica el número de bits que se transmiten en paralelo. Además, se pueden añadir etiquetas para no tener que dibujar el bus completo desde el extremo inicial al final

En este esquema de ejemplo se han conectado dos circuitos a través de un cable de bus de 64 bits. Aunque no se dibujen todos los cables... ¡En realidad hay 64 cables que transportan los bits!

Transmisión Síncrona con reloj del sistema

Para indicar cuando se transmite un dato se utiliza una señal que solemos denominar señal de reloj. Cada flanco de subida de esta señal indica que hay datos disponibles que se deben capturar. Estos datos están sincronizados con esta señal de reloj, por lo que se dice que trata de una comunicación síncrona

Las transmisiones más rápidas son las que se realizan en paralelo y a la velocidad del reloj sistema: Comunicaciones síncronas en paralelo. Cada transferencia dura 1 ciclo de reloj

En esta figura se muestra un ejemplo del funcionamiento. Hay 3 registros de 16 bits conectados en cadena, inicializados a 0000. En cada ciclo de reloj los datos pasan del registro de la izquierda al de la derecha. En el estado inicial hay un DATO disponible a la entrada del registro 1

En el momento inicial, los tres registros están a 0. Cuando llega el prier flanco, el DATO se captura en el registro 1. En el siguiente ciclo pasa al registro 2. Y en el tercer ciclo al registro 3. Así, el DATO tarda 1 ciclo en pasar de un registro a otro. Ha tardado 3 ciclos en llegar al registro 3

Transmisión síncrona con señal de validación

La transmisión no tiene por qué hacerse de manera continua, en cada ciclo de reloj, sino que nos puede interesar controlar cuándo queremos que haya transferencia y cuando no. Para ello utilizamos la señal de validación (Strobe). Es una señal de control que indica que hay un dato disponible para que el receptor capture

En este ejemplo el circuito 1 envía un dato de 8 bits al registro, que se captura cuando se activa la señal de validación (strobe)

Este es el cronograma. Inicialmente la señal de validación está desactivada. Por la salida del circuito 1 sale un valor cualquiera. Al llegar el primer ciclo el circuito 1 envía el DATO. Pero todavía no lo captura el registro. En el siguiente ciclo el circuito 1 activa la señal de validación, para indicar que el registro ya sí que puede capturar el dato. En el siguiente flanco se captura, por lo que en el tercer ciclo ya está el dato en el registro

Ahora el flujo de información se controla con la señal de validación. Hasta que no se activa no hay transferencia de información

Transmisión síncrona con señales de validación y ocupado

En los circuitos receptores que hemos usado en los ejemplos anteriores (un registro) el dato se captura en un ciclo, pero podría ocurrir que el circuito tarde tiempo en realizar esta escritura, de manera que no se le puede enviar información en cualquier momento, sino sólo cuando está disponible

En estos casos el circuito emisor tiene que tener en cuenta el estado del receptor: si está ocupado (busy) o disponible (ready). Para eso se utiliza la señal de busy (o su negada, ready)

En este cronograma se muestra el funcionamiento. El dato sólo se transfiere cuando el receptor está diponible (busy = 1). Al realizar la escritura, el receptor pone busy a 1. Cuando ha finalizado la operación se vuelve a poner a 0 y se puede realizar otra transferencia

Comunicaciones serie

Las comunicaciones en paralelo son muy rápidas, pero consumen muchos cables. Esto cobra especial importancia fuera del chip, cuando estamos conectando dos elementos. Si uno le tiene que enviar a otro un valor de 32 bits, ¡habría que tirar 32 cables externos!

Para reducir el número de cables entre chips, usamos las comunciaciones serie. Para transmitir un dato del emisor al receptor ahora necesitamos sólo 1 cable. Los bits se envían secuencialmente uno detrás de otro por ese cable

En este ejemplo el chip 1 le ha transitido el valor 0x55 al chip 2 a través de un único cable, mediante comunicación serie. Por el cable se han enviado secuencialmente los 8 bits del dato: 01010101

Ahorramos muchos cables, y los diseños son más limpios, PERO las comunicaciones serie son MUCHO MÁS LENTAS. En el ejemplo anterior, necesitamos al menos 8 ciclos de reloj para transmitir todos los bits, mientras que en el caso paralelo lo hacíamos sólo en 1 cicloj

Para que la comunicación serie funcione, los dos extremos tienen que seguir las mismas reglas. El diseñador debe decir el orden de envío de los bits: empezar por el de menor peso o por el mayor. También se debe determinar qué evento usar para indicar que ha llegado un bit. Se puede usar una señal de reloj adicional para validar cada bit, o bien cada chip usa su propio reloj interno. Esto nos divide las comunicaciones serie en dos tipos: Síncronas y Asíncronas

Comunicaciones serie síncronas

En las comunicaciones serie síncronas se utilizan dos cables: uno para el envío de los bits en serie y otro con la señal de reloj que indica cuándo se puede capturar cada bit

La señal de reloj se suele denominar SCK y define el tiempo que transcurre entre cada bit. En este cronograma se muestra la transferencia de un dato de 8 bits. Se envía primero el bit más significativo

Algunos ejemplos de comunicaciones serie síncronas son los buses SPI e I2C

Bus SPI

En el Bus SPI hay un circuito, el maestro que lleva la voz cantante de la comunicación. Es el que genera la señal de reloj SCLK. Se puede comunicar con uno o varios circuitos, que se llaman esclavos

Este es el esquema de comunicación punto-punto, entre un maestro y un esclavo

Se utilizan 4 cables en total:

  • MOSI (Master-Out, Slave-IN): Datos en el sentido maestro-esclavo
  • MISO (Master-In, Slave-Out): Datos en el sentido esclavo-maestro
  • SCLK: Señal de reloj para cada bit, generada por el maestro
  • SS: (Slave Select): Selección del esclavo

Este es el esquema de comunicación multipunto, en el que el maestro se comunica con varios esclavos. Sólo el esclavo seleccionado mediante la correspondiente señal ss es el que recibe los datos de MOSI y envía las respuestas por MISO

Bus I2C

El Bus I2C también es de tipo Maestro-esclavo. Está pensando para conectar fácilmente muchos esclavos, usando sólo 2 cables, uno de datos y otro de reloj, que se denominan SDA y SCL respectivamente

Este es el esquema de conexión punto-punto entre el maestro y un esclavo. El cable de datos SDA es bidireccional

En esta figura se muestra la conexión de un maestro con dos esclavos. Cada uno de los esclavos tiene asignada una dirección.

Comunicaciones serie asíncronas

En las comunicaciones serie asíncronas cada uno de los circuitos tiene su propio reloj para detectar la llegada de los bits, por eso NO hay cable con la señal de reloj. En esta figura se muestra la conexión entre dos circuitos, utilizando comunicaciones asíncronas. Sólo se necesitan 2 cables de datos, cada uno para un sentido de la transmisión

La comunicación es punto-punto entre dos iguales, y full-duplex. No hay maestros ni esclavos. La señal del emisor al receptor se llama TX. La del receptor al emisor se llama RX

En este cronograma se muestra cómo se realiza la transmisión del dato 0x53. En total se transmite los 8 bits más un bit de comienzo (start) a 0 y un bit de stop a 1

La velocidad de la transmisión debe ser conocida a priori tanto por el emisor como por el receptor. Se utiliza en baudios (que son bits por segundo). Dos velocidades muy típicas son 9600 y 115200 baudios

Cuando utilizamos este tipo de comunicación desde el PC lo denominamos comunicación por puerto serie

Comunicación Arduino-FPGA

En la FPGA hemos aprendido a diseñar controladores hardware para nuestros robots: unidades de PWM, procesamiento de sensores, control de servos... Desde Arduino hacemos programas (software) para implementar comportamientos en el robot. Para comunicarnos con los controladores hardware en la FPGA utilizaremos el bus SPI

Este es el esquema de conexionado entre Arduino y la FPGA

Estos son los pines que vamos a utilizar:

Pin Arduino Pin Alhambra Descripción
D13 D13 SCLK. Señal de reloj
D12 D12 MISO. Datos desde la FPGA al Arduino
D11 D11 MOSI. Datos desde el Arduino a la FPGA
D10 D10 SS. Selección de la FPGA

Veremos dos ejemplos, uno para escribir información de Arduino a la FPGA y para leer datos de la FPGA en Arduino

Escritura en la FPGA

El circuito en la FPGA está formado por un registro de desplazamiento hacia la izquierda, que captura los 8 bits que llegan en serie. Se captura un bit por cada flanco de subida del reloj SCLK. Cuando termina de enviarse el dato la señal SS se pone a 1, capturándose el dato en un registro de 8 bits, cuya salida está conectada a los LEDs

(01-Arduino-FPGA-write.ice)

Este mismo ejemplo se puede implementar utilizando el bloque spi esclavo, que encapsula todo lo necesario. Así es más facil integrar las comunicaciones en nuestros circuitos

Este es el programa que se carga en Arduino. Desde el bucle principal se envían los valores 0x55 y 0xAA a la FPGA cada medio segundo

#include <SPI.h>

//-- Pin usado para la seleccion del esclavo
#define SS 10

void setup() {

  //-- Inicializar SPI
  SPI.begin();
  SPI.beginTransaction (SPISettings (4000000, MSBFIRST, SPI_MODE0));

}

//-- Enviar un valor por el SPI para
//-- sacarlo por los LEDs de la FPGA
void write_LEDs(uint8_t value)
{
  digitalWrite(SS, LOW);
  SPI.transfer(value); 
  digitalWrite(SS, HIGH);
}

void loop() {

  //-- Sacar valor 0xAA por los LEDs
  write_LEDs(0xAA);
  delay(500);

  //-- Sacar valor 0x55 por los LEDs
  write_LEDs(0x55);
  delay(500);
}

Bienvenidos al mundo del codiseño Hardware-Software!!. Una parte se hace en software y la otra en Hardware

Lectura de la FPGA

Para leer información de la FPGA se utiliza también un registro de desplazamiento hacia la izquierda. Se usa la señal SS para realizar la carga del dato a enviar al maestro en el registro. La señal del reloj (SCLK) realiza el desplazamiento de los bits, que se van enviando por la salida del esclavo (MOSI)

En este ejemplo se envían al maestro (Arduino) el estado de los dos pulsadores SW1 y SW2

Este es el mismo ejemplo, pero usando el bloque SPI esclavo

Este es el programa que se carga en el arduino. Realiza una lectura por el SPI cada 300ms. El valor recibido se muestra en dos leds conectados a arduino (LED1 y LED2) y se envía por el puerto serie al PC para verlo en el monitor serie

#include <SPI.h>

//-- Pin usado para la seleccion del esclavo
#define SS 10

//-- Pin de los LEDs
#define LED1 7
#define LED2 6

void setup() {

//-- Configurar los LEDs
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);

  //-- Inicializar SPI
  SPI.begin();
  SPI.beginTransaction (SPISettings (2000000, MSBFIRST, SPI_MODE0));
 
  Serial.begin(9600);
}

//-- Leer los pulsadores de la FPGA,
//-- a través del SPI
uint8_t leer_pulsadores()
{
  //-- Activar el esclavo
  digitalWrite(SS, LOW);

  //-- Leer el valor. A la vez hay que enviar
  //-- otro dato. Mandamos un 0 (basura)
  uint8_t value = SPI.transfer(0x00); 

  //-- Desactivar el esclavo
  digitalWrite(SS, HIGH);

  return value;
}


void loop() 
{

  //-- Leer los pulsadores
  uint8_t estado = leer_pulsadores();

  //-- Encender el LED1 si el pulsador SW1 está apretado
  digitalWrite(LED1, estado & 0x01);

  //-- Encender el LED2 si el puslador SW2 está apretado
  digitalWrite(LED2, estado & 0x02);

  //-- Mostrar el valor leido por puerto serie
  Serial.write(estado+'0');
  Serial.write("\n");
  
  delay(300);
}

Comunicación FPGA-PC: Puerto serie

Desde la FPGA podemos enviar información al PC, y recibirla de él, a través del puerto Serie. Para ello necesitamos utilizar los bloques serial-tx y serial-rx disponibles en la colección stdio

Ejemplo de transmisión de un carácter

Este circuito envía el carácter 'A' cada vez que se aprieta el pulsador SW1

A través del Monitor serie de Icestudio podemos ver los caracteres recibidos:

Ejemplo de recepción de un carácter

En este ejemplo se utiliza el receptor serie para mostrar por los LEDs los caracteres enviados desde el PC a través del terminal serie

Componentes virtuales en la FPGA

La comunicación por puerto serie nos permite implementar interfaces gráficos en el PC con componentes virtuales. Los componentes virtuales más básicos son los pulsadores y los LEDs. Al apretar un pulsador en la interfaz gráfica se envía el evento por el puerto serie a la FPGA y un componente obtiene una señal de estado, que se puede utilizar igual que si viniese de un componente real

Este es un ejemplo de un panel con 4 interruptores, 4 pulsadores y 8 LEDs virtuales

Está accesible desde esta página web: PANEL DE PRUEBA. Es necesario utilizar un navegador que soporte WebSerial, como Chrome o Chromium

En este ejemplo se llevan las 8 entradas virtuales (4 pulsadores y 4 interruptores) a los LEDs reales, para verlos. Y los dos pulsadores reales se muestran por los LEDs etiquetados como a y b

Autor

Licencia

Créditos

Enlaces

Clone this wiki locally