Descarga la aplicación para disfrutar aún más
Vista previa del material en texto
,, Equation Chapter 1 Section 1 Proyecto Fin de Grado Ingeniería Eléctronica, Robótica y Mecatrónica Diseño VHDL de un driver I3C Autor: Pablo Ramírez Pons Tutores: Fernando Muñoz Chavero, Jóse María Hinojo Montero Dpto. Electrónica Escuela Técnica Superior de Ingeniería Universidad de Sevilla Sevilla, 2022 iii Proyecto Fin de Grado Ingeniería Electrónica, Robótica y Mecatrónica Diseño VHDL de un driver I3C Autor: Pablo Ramírez Pons Tutores: Fernando Muñoz Chavero Catedrático de Universidad Jóse María Hinojo Investigador Postdoctoral Talento Dpto. de Ingeniería Electrónica Escuela Técnica Superior de Ingeniería Universidad de Sevilla Sevilla, 2022 v Proyecto Fin de Grado: Diseño VHDL de un driver I3C Autor: Pablo Ramírez Pons Tutores: Fernando Muñoz Chavero, José María Hinojo Montero El tribunal nombrado para juzgar el Proyecto arriba indicado, compuesto por los siguientes miembros: Presidente: Vocales: Secretario: Acuerdan otorgarle la calificación de: Sevilla, 2022 El Secretario del Tribunal vii Página intencionalmente en blanco. ix Agradecimientos Este proyecto ha sido desarrollado como un proyecto colaborativo entre Jóse María Hinojo, Fernando Muñoz y servidor. Agradezco toda la ayuda aportada por ambos profesores y los nuevos conocimientos obtenidos en el desarrollo de este. También agradezco a mi ordenador que no se haya estropeado durante el desarrollo del proceso. Pablo Ramírez Pons Estudiante de la Escuela Técnica Superior de Ingeniería Sevilla, 2022 xi Resumen Desde la creación de los circuitos eléctricos, ha sido imprescindible seguir una serie de reglas para evitar problemas por la naturaleza de la electricidad. Con el posterior desarrollo de estos circuitos, ha surgido la necesidad de crear comunicaciones entre ellos que deben de seguir una serie de pautas para lograr la mayor complejidad en la comunicación utilizando la menor cantidad de material posible. Es así como surge la necesidad de crear los protocolos de comunicación. En este proyecto se va a implementar un protocolo de comunicación cuyo desarrollo empezó hace bastante poco en la historia de la electrónica (2015) llamado I3C y se va a probar su funcionamiento implementándolo en una FPGA. xiii Abstract Since the creation of electrical circuit boards, it has been essential to follow a set of rules to avoid the consequences of the nature of electricity. As circuits grew in complexity, it rised the necessity to create intercommunication between diverse components trying to use the less quantity of materials in order to achieve higher complexity. This is the reason behind the creation of the communication protocols. In this project we are going to implement a pretty new communication protocol in the history of electronics (2015) known as I3C and we will implement it using a FPGA. Índice Agradecimientos ix Resumen xi Abstract xiii Índice xiv Índice de Códigos xvi Índice de Figuras xviii 1 Introducción 1 1.1 Objetivos 1 1.2 Herramientas Utilizadas 2 2 Protocolo I2C VS I3C 5 2.1. Protocolo I2C 5 2.1.1 ¿Qué es el I2C? 5 2.1.2 Implementación física del I2C 5 2.1.3 Funcionamiento del protocolo I2C 6 2.1.4 Ventajas del bus I2C 7 2.2. Necesidad de actualizar el protocolo 8 2.3. Protocolo I3C 8 2.3.1 Objetivos y propósito del I3C 8 2.3.2 Resumen técnico 10 2.3.3 Principios fundamentales del bus 10 2.3.4 I3C Maestro 13 2.3.5 I3C esclavo 13 2.3.6 Modo SDR 14 3 Aplicación y hardware 17 3.1 Aplicación 17 3.2 Hardware 18 3.2.1 Sensor de temperature TMP139 18 3.3 Placa de adaptación 21 3.3.1 PCB de ajuste 21 3.3.2 PCB de voltajes 21 3.4 Cableado 23 4 Implementación en VHDL 25 4.1 Máquinas de estado y esquemas de funcionamiento 25 4.1.1 Maestro I3C 25 4.1.2 Sensor initializer 27 4.1.3 Top level registers 30 xv 4.1.4 Serial transmiter 31 4.2 Código VHDL 32 4.2.1 I3C_master.vhd 32 4.2.2 SENSOR_INITIALIZER.vhd 42 4.2.3 SERIAL_TRANSMITER.vhd 43 4.2.4 Top_level.vhd 47 5 Resultados y Conclusión 55 5.1. Resultados finales 55 5.1.1 Simulaciones 55 5.1.2 Resultados de la implementación física 60 6 Líneas futuras y conclusión 63 6.1 Líneas Futuras 63 6.2 Conclusión 64 Referencias 65 Glosario 67 ÍNDICE DE CÓDIGOS Código 4-1 Generación de señales de reloj SDA y SCL. 33 Código 4-2 Divider. 34 Código 4-3 Máquina de estados general maestro I3C. 41 Código 4-4 Puertos y generics maestro I3C. 42 Código 4-5 Gestor de maestro I3C. 43 Código 4-6 Señales y parte concurrente Serial Transmiter. 44 Código 4-7 Puertos y generics Serial Transmiter. 44 Código 4-8 Proceso síncrono Serial Transmiter 45 Código 4-9 Máquina de estados general Serial Transmiter. 46 Código 4-10 Proceso síncrono registros nivel superior. 47 Código 4-11 Proceso combinacional del registro 1 de nivel superior. 48 Código 4-12 Proceso combinacional del registro 2 de nivel superior. 49 Código 4-13 Port map Top level. 50 Código 4-14 Descripción concurrente nivel superior. 51 Código 4-15 Conexionado de instancia SERIAL_TRANSMITER nivel superior. 52 Código 4-16 Conexionado de instancia I3C_master nivel superior. 52 Código 4-17 Conexionado de instancia sensor_initializer nivel superior. 53 Código 4-18 Declaración de componente IOBUF. 53 Código 4-19 Instancia de componente IOBUF. 54 xvii ÍNDICE DE FIGURAS Figura 2-1 Condiciones de START y STOP del protocolo I2C. 6 Figura 2-2 Traza I2C. 7 Figura 2-3 Características del bus I3C. 9 Figura 2-4 Consumo eléctrico I3C vs I2C. 10 Figura 2-5 Traza I3C con múltiples tipos de mensaje. 11 Figura 2-6 Máquina de estados general I3C. 12 Figura 2-7 Roles dispositivos I3C. 13 Figura 2-8 Configuración general del bus. 14 Figura 2-9 Mensajes SDR I3C. 15 Figura 2-10 Ejemplo traza I3C SDR. 16 Figura 3-1 Esquema de aplicación del proyecto. 17 Figura 3-2 Esquema pines externos TMP139. 18 Figura 3-3 Esquema módulos internos TMP139. 19 Figura 3-4 Registros internos de temperatura del TMP139. 19 Figura 3-5 Dirección variable TMP139. 20 Figura 3-6 Traza de lectura de registro sensor TMP139 usando I3C. 20 Figura 3-7 Traza de envio de SETAASA. 21 Figura 3-8 PCB del adaptador del sensor. 21 Figura 3-9 Esquemático placa de voltajes. 22 Figura 3-10 PCB placa de voltajes, vista superior. 22 Figura 3-11 PCB placa de voltajes, vista inferior. 23 Figura 4-1 Máquinade estados I3C maestro. 26 Figura 4-2 Máquina de estados Sensor Initalizer. 28 Figura 4-3 Esquema de montaje Sensor Initializer. 29 Figura 4-4 Esquema general registros del nivel superior. 30 Figura 4-5 Máquinas de estado de registros de nivel superior. 31 xix Figura 4-6 Máquina de estados de Serial Transmiter. 32 Figura 4-7 Diagrama de timings de SDA y SCL. 34 Figura 5-1 Waveform SERIAL_TRANSMITER.vhd. 55 Figura 5-2 Waveform INITIALIZER.vhd. 56 Figura 5-3 Waveform i3c_master.vhd Modo escritura. 56 Figura 5-4 Waveform i3c_master.vhd Modo Lectura. 57 Figura 5-5 Waveform Registro intermedio Serial Transmitter y comparación. 58 Figura 5-6 Waveform Registro intermedio Master_I3C. 58 Figura 5-7 Waveform Sensor Initializer nivel superior. 58 Figura 5-8 Waveform Master I3C nivel superior - Parte 1. 59 Figura 5-9 Waveform Master I3C nivel superior - Parte 2. 59 Figura 5-10 Waveform Top Level. 60 Figura 5-11 Placa de voltajes física. 60 Figura 5-12 Placa de adaptación física. 61 Figura 5-13 Captura de Osciloscopio Broadcast I3C. 61 Figura 5-14 Captura de Osciloscopio cambio de Initializer a Master I3C. 62 Figura 5-15 Captura de Osciloscopio Envío de dirección de chip y ACK. 62 1 1 INTRODUCCIÓN A RAE describe un sensor como “Dispositivo que detecta una determinada acción externa, temperatura, presión, etc., y la transmite adecuadamente”. En la actualidad vivimos en un mundo gobernado por sensores dado que esta es la principal forma que tiene un dispositivo digital de percibir el mundo exterior, y cada vez más y más sensores se van implementando para aumentar las funcionalidades de los instrumentos que utilizamos en nuestro día a día. Los sensores también son los encargados de transformar la información que perciben en señales eléctricas con las que podamos trabajar y esto conlleva una serie de problemas por la naturaleza de la electricidad. Dado que la información que recibimos de estos está codificada en ceros y unos correspondientes a niveles altos y bajos de tensión, si tenemos varios sensores conectados a un mismo dispositivo mediante un mismo bus, no podemos dejar que estos escriban y lean información a su antojo ya que esto puede provocar cortocircuitos en los integrados dañándolos severemante. Por tanto, es importante que los sensores se comuniquen de una manera ordenada para evitar este tipo de problemas. Es así como surgen los protocolos de comunicación, siendo estos no más que una conveción para tratar la información que se quiere transmitir o recibir de estos sensores. Un protocolo maestro-esclavo (master-slave en inglés) se define como un modelo asimétrico de comunicación o control donde un dispositivo llamado maestro controla a otros dispositivos o procesos llamados esclavos y hace el papel principal en el proceso. Tanto los protocolos I2C como I3C siguen este tipo de protocolo y el principal objetivo del proyecto es el de la implementación de un dispositivo maestro que se comunique con un esclavo en I3C. 1.1 Objetivos El principal objetivo del presente trabajo es crear un controlador I3C funcional que permite establecer una comunicación básica (lecturas y escrituras) con un sensor (dispositivo esclavo). Este controlador será implementado en una FPGA. Dado que el protocolo I3C es una versión mejorada de su predecesor I2C, el estándar incorpora multitud de modos nuevos. Por tanto, para limitar el alcance del proyecto, debido a que la implementación de un controlador que soporte el estándar completo excedería el alcance de un Trabajo Fin de Grado, se ha optado por desarrollar una versión limitada pero funcional del protocolo. Esta versión da soporte a los accesos en modo lectura y escritura, así como los principales comandos definidos por el estándar. L “Ser autodidacta es, estoy convencido, el único tipo de educación que existe.” - Isaac Asimov - Introducción 2 Los principales objetivos del trabajo han sido los siguientes: • Determinar el funcionamiento del protocolo de comunicación I3C y los diferentes modos de operación. • Describir las operaciones esenciales para un correcto funcionamiento del controlador. • Implementar en una FPGA un maestro que sea capaz de comunicarse por I3C. • Comprobar el funcionamiento del protocolo leyendo datos de un sensor de temperatura que soporte una comunicación I3C. 1.2 Herramientas Utilizadas Para ello, vamos a precisar de varios programas y elementos hardware que se listan a continuación: • FPGA. En este caso utilizaremos la Basys 3 Xilinx Artix-7 (XC7A35-1CPG236C). • Sensor I3C. Sensor de temperatura TMP139 de Texas Instruments. • Vivado. Programa provisto por Xilinx para sintetizar e implementar un leguaje HDL en FPGAs (Version 2020.2). • Altium Designer. Programa empleado para la creación de esquemáticos y PCBs (Versión 19.1.5). • Docklight. Herramienta software usada para la lectura de datos por el puerto serie del ordenador. FPGA fue elegida por la gran cantidad de recursos hardware disponibles, así como por el número de interfaces de entrada y salida puestas a disposición del usuario. Además, este kit de desarrollo es compatible con el programa de diseño VHDL Vivado. El sensor de temperatura fue elegido ya que soporta el protocolo I3C en su mayoría. Además, el sensor permite hacer uso del protocolo I2C en un primer momento, ideal para familiarizarse con su funcionamiento. Se eligió un sensor en vez de un micrcontrolador ya que en el inicio del presente Trabajo Fin de Grado no había ninguna opción disponible en el mercado. Por tanto, se optó por buscar un dispositivo esclavo. La falta de dispositivos compatibles en el mercado se debe a que el protocolo I3C es de reciente diseño y aún no está muy extendido de manera comercial (Junio - 2021). 3 3 Diseño VHDL de un driver I3C 5 2 PROTOCOLO I2C VS I3C L protocolo I3C es parte de una evolución de otro protocolo de comunicación creado en los años 80 llamado I2C [1]. Dado que se trata de una versión mejorada y actualizada del mismo, ambos comparten bastantes similitudes y, por lo tanto, lo más natural para desarrollar un proyecto I3C es partir de una implementación I2C para ver cómo se maneja el mismo. En este capítulo se va a describir las principales características del protocolo I2C. A continuación, se indicará la necesidad de actualizar dicho protocolo para resolver los problemas del presente. Finalmente, se detallará el protocolo I3C. 2.1. Protocolo I2C 2.1.1 ¿Qué es el I2C? El protocolo para bus I2C fue diseñado por Philips para permitir una comunicación fácil y sencilla entre componentes electrónicos que se encuentren en una misma PCB. Su sigla proviene del inglés Inter-Integrated Circuit y es conocido también como I2C o IIC [1]. En su origen, I2C estaba pensado para transmitir datos a una velocidad estandar de 100kbit/s (Slow Mode, SM) y un modo de transmisión rápida de 400kbit/s (Fast Mode, FM). Más adelante, se implementaron modos de comunicación que incrementaban las tasas de transmisión hasta 1Mbit/s (FM+), 3.4Mbit/s (HS-Mode) y 5Mbit/s (UFM) [2]. Este último roza los límites del bus y es, por tanto, el único modo que es unidireccional. El protocolo I2C sigue un modelo maestro-esclavo el cual es definido de una forma asimétrica de comunicación en la que un dispositivo maestro controla a uno o más dispositivos denominados esclavos[3]. 2.1.2 Implementación física del I2C El bus solamente necesita de dos líneas para funcionar, la línea SCL, que es la que define el reloj de las transacciones, y la línea SDA, que es por donde se transmiten los datos que queramos leer o escribir. Estas doslíneas son de tipo colector o drenador abierto. Por tanto, requieren de una resistencia de pull-up, dejando así un valor de 1 lógico débil, para su correcto funcionamiento. De esta forma, cuando se libera el bus, quedando este en un estado de alta impedancia, el estado lógico del mismo queda correctamente definido. Estas dos líneas E Proyecto planteado y elaborado por Pablo Ramírez Pons, estudiante de la Escuela Técnica Superior de Ingeniería de la Universidad de Sevilla Protocolo I2C VS I3C 6 son bidireccionales. 2.1.3 Funcionamiento del protocolo I2C Cada dispositivo que quiera comunicarse bajo este protocolo tiene una dirección asignada de 7 bits y tiene uno de los roles maestro o esclavo. En la notación mas reciente, debido a controversia por la naturaleza del nombre los dos roles, son también conocidos como controlador y objetivo (controller y target en inglés). Sin embargo, para este proyecto vamos a utilizar la notación original [2]. Cabe destacar que aparte de los bits de información, el bus I2C introduce dos condiciones adicionales a la hora de intercambiar información que son las condiciones de START y STOP. Estas trabajan como delimitadores del mensaje o trama I2C. De esta manera se puede saber cuándo empieza y cuándo. La comunicación se inicia cuando el dispositivo maestro manda la condición de START para que los dispositivos esclavos estén a la escucha. La condición de START se define como una transición de nivel alto a bajo en la línea SDA cuando SCL se encuentra aún a nivel alto. La condición de STOP se define de la manera opuesta, siendo la transición de bajo nivel a lato nivel mientras SCL se encuentra a nivel bajo. La ¡Error! No se encuentra el origen de la referencia. muestra un ejemplo de estos valores. Figura 2-1 Condiciones de START y STOP del protocolo I2C[4]. Cualquier traspase de información distinto a estas dos condiciones se lee cuando SCL se encuentra a nivel alto, por lo tanto, el dato que queramos leer tiene que transmitirse por el bus con un poco de antelación para que el dato se estabilice. Acto seguido el maestro manda una traza de 8 bits que consiste en la dirección de 7 bits del dispositivo esclavo con el que nos queremos comunicar y el último bit que refleja el modo de funcionamiento en el que va a transcurrir la información pudiendo ser modo escritura o modo lectura. En I2C los bits se transmiten desde el MSB al LSB. Una vez se ha enviado la traza de 8 bits, el esclavo debe responder con un ACK, dando así a entender que está preparado para leer o enviar datos. Para esto, el maestro deja el bus libre, y comprueba su valor. Si el dispositivo esclavo pone a nivel bajo el bus, condición de ACK, se considera que está listo para recibir o transmitir información y la comunicación puede continuar. Por el contrario, si el esclavo pone la línea a nivel alto durante esta fase, se considera que no está preparado para continuar la comunicación y el maestro debe abortarla mediante la generación de la condición de STOP. Esto se conoce como condición NACK. Un ejemplo se puede ver en la ¡Error! No se encuentra el origen de la referencia.. El maestro o el esclavo empieza a mandar datos por el bus hasta completar los 8 bits de la traza. Una vez acabada la transacción en función de quien hubiera mandado los datos, debe dejar libre el bus para que su análogo mande el ACK (o NACK en su defecto en caso de haber habido un problema con la transacción). 7 7 Diseño VHDL de un driver I3C Finalmente, el maestro genera la condición de STOP dando fin a la comunicación. Esto funciona así, salvo algunas excepciones, ya que es posible que el maestro o esclavo quiera seguir recibiendo o mandando datos y, por tanto, la condición de STOP no tiene por qué generarse al enviarse una única trama de 8 bits. De esta manera, se podría llegar a un estado de START nuevo que se conoce como REPEATED START, volviendo a reiniciar todo el proceso anterior. Esta condición tiene una funcionalidad idéntica al START. Figura 2-2 Traza I2C. Adicionalmente, el protocolo I2C posee características adicionales que aportan mayor flexibilidad. Por lo general, la única forma que tiene un esclavo de transmitir su estado es mediante los ACKs. Sin embargo, esto no es del todo cierto ya que existe un concepto conocido como clock stretching. Cuando el esclavo determina que el reloj del maestro es superior al que puede manejar, el esclavo puede mantener la línea SCL a bajo nivel cuando el maestro está intentando forzarlo a alto nivel siguiendo su reloj interno. De esta manera, cuando el maestro lee que el reloj se encuentra en un estado que no debería (nivel bajo en vez de nivel alto), el maestro detiene la transacción y la maquina de estado se queda en estado de suspensión hasta que el esclavo deje libre la línea. De este modo, el esclavo puede modificar ligeramente el ritmo de la transacción. Cabe decir que el clock stretching es una característica opcional que muchos dispositivos no incluyen en los controladores que implementan [2]. 2.1.4 Ventajas del bus I2C La forma de implementación del bus y su funcionamiento hace que sea tanto atractivo a niveles de diseño como de fabricación y creación de periféricos para circuitos integrados. A nivel de diseño tiene las siguientes ventajas: • Debido a la sencillez de la integración física del bus, es sencillo su integración en PCBs. • No hay necesidad de diseñar interfaces del bus ya que se encuentran integrados en el propio IC. • Tiene un modo de direccionamiento y protocolo de transferencia de datos integrado lo que permite simplificar la gestión y manejo de los dispositivos. • Permite flexibilidad en sus aplicaciones. • Permite que los IC se acoplen o desacoplen sin afectar al resto de los IC. • Los fallos son fácilmente localizables. • Debido a sus características, las implementaciones resultantes pueden ser de muy bajo consumo, haciéndolo ideal para dispositivos alimentados a baterías, donde la potencia estática disipada es un factor crítico. Además, su gran tolerancia al ruido, su gran rango de tensiones de funcionamiento Protocolo I2C VS I3C 8 (dependiente de la tecnología CMOS seleccionada) y su amplio rango de velocidades de funcionamiento, hace muy versátil el protocolo I2C. Desde el punto de vista de la fabricación, podemos observar las siguientes ventajas: • Al poseer únicamente dos líneas se reducen las interconexiones y el tamaño de las pistas, así como la cantidad de los pines. Esto hace que se puedan usar PCBs más pequeñas y, en consecuencia, mas baratas. • No requiere del uso de decodificadores de dirección ni otro tipo de lógica de adaptación. Finalmente, desde el punto de vista del desarrollo de ICs, su principal atractivo es que el protocolo está bastante extendido en el mercado en la actualidad y por tanto es mas sencillo buscar otros ICs compatibles para comunicarse [5] 2.2. Necesidad de actualizar el protocolo En los últimos años, la proliferación de los dispositivos móviles, así como su complejidad. Esto lleva consigo un aumento del número de sensores del que dispone cada móvil para ejecutar diversas tareas. Se necesitan cada vez más pines y líneas para gestionar la comunicación y el control. Uno de los principales problemas que se encuentra con el I2C es que en el protocolo no está definido en ningún momento cómo se gestionan las interrupciones ni señales de sleep de los distintos dispositivos conectados al bus, por lo que se necesitan unas líneas auxiliares. Además, los smartphones más recientes ya incluyen del orden de diez o más sensores incorporados en un mismo bus, lo cual da lugar a que los límites físicos del mismo rocen su límite (el número máximo de dispositivos conectados a un mismo bus I2C se estima en 20 sensores). Otro problema deriva de la propia sencillez del protocolo I2C. Como ya se ha mencionado anteriormente,el bus I2C sólo precisa de dos líneas de comunicación, esto viene con algunos costes como la inahibilitación de los esclavos del bus para iniciar la comunicación. El uso de una resistencia de pull-up también provoca problemas tanto en la tasa de transmisión como en el consumo que, aunque siendo considerado bajo en los años de su creación (década de los 80), en la actualidad no resulta competitivo. Finalmente, los dispositivos I2C disponen de un filtro de ruido llamado spike filter que trabaja a 50 ns, lo que también limita la velocidad máxima a la que se puede transmitir en el bus sin considerar la información como un glitch. Una alternativa para cambiar de protocolo de comunicación es utilizar la interfaz SPI. Este protocolo requiere de cuatro líneas de comunicación y es, principalmente, utilizado cuando queremos transmitir grandes cantidades de datos en un intervalo pequeño como, por ejemplo, borrar memorias de almacenamiento estático o leer grandes volúmenes de datos de sensores. Aunque puede presentar mayores tasas de transmisión que el bus 2C, requiere de un mayor número de líneas de control, incrementando el área ocupada, así como los costes de fabricación. Como se puede ver, ambos protocolos tienen ventajas y desventajas que ni uno de los dos puede realmente solucionar. De esta manera surge un nuevo tipo de protocolo que sea escalable, sencillo y se uso como nuevo estándar para la comunicación de sensores añadiendo las funcionalidades de ambos métodos. Surge así un nuevo protocolo de comunicación centrado en la comunicación entre sensores y que fuera compatible con los antiguos sensores I2C y con los nuevos. Este es el conocido como I3C [6] 2.3. Protocolo I3C 2.3.1 Objetivos y propósito del I3C La interfaz I3C es una evolución del estándar que mejora las características de del I2C manteniendo compatibilidad hacia atrás. Esta gestionada por la organización MIPI[7]. La finalidad del bus I3C cumple con los siguientes requisitos: • Estandarizar la comunicación entre sensores 9 9 Diseño VHDL de un driver I3C • Reducir el número de pines utilizado en la integración de sistemas de sensores • Soportar modos de bajo consumo, altas velocidades y otras características críticas que están actualmente cubiertos por I2C y SPI Originalmente, el protocolo I3C estaba pensado para crear una única interfaz entre aplicaciones móviles que requiriesen de sensores, permitiendo ubicar varios en un mismo bus para minimizar la lógica adicional que gestionaba las interrupciones o los modos de sleep. Sin embargo, dicha utilidad no quedó reducida exclusivamente al uso de móviles ya que ofrecía altas velocidades de transmisión con un consumo energético reducido. Esta característica es fundamental para cualquier tipo de comunicación en un circuito integrado [6]. Figura 2-3 Características del bus I3C. Además, podemos comprobar en la Figura 2-4 que los modos de funcionamiento del I3C consumen menos energía a la vez que logran una mayor tasa de transmisión de datos [6]. Protocolo I2C VS I3C 10 Figura 2-4 Consumo eléctrico I3C vs I2C. 2.3.2 Resumen técnico I3C es un bus de comunicación serie bidireccional optimizado para trabajar con múltiples dispositivos objetivo (generalmente sensores) y controlados mediante un único controlador I3C. Este protocolo es retrocompatible con una gran variedad de dispositivos I2C, pero también soporta velocidades significativamente mayores, nuevos modos de comunicación y nuevos roles para los dispositivos. Además, los roles pueden cambiar a lo largo del tiempo; por ejemplo, si el dispositivo maestro quiere ceder su rol de manera cooperativa para que el nuevo dispositivo trabaje como un maestro secundario, se puede efectuar. En cuanto a los modos de comunicación disponibles se encuentran lo siguientes. • Modo Compatibilidad (Legacy Mode): Soporte para dispositivos de legado I2C y mensajes. • I3C Single Data Rate (SDR) Mode: Versión mejorada del protocolo I2C que soporta el envío de mensajes privados. En este modo se añaden dos tipos de mensaje distintos. • Broadcast Messages: Mensajes que se envían a todos los dispositivos que se encuentran conectados al bus. • Direct Messages: Mensajes dirigidos a un solo dispositivo. • I3C High Data Rate (HDR) Modes: Modos de funcionamiento opcionales que añaden funcionalidades significativas. • Dual Data Rate (HDR - DDR) Mode: Funciona igual que el SDR pero al doble de velocidad. • Bulk Transport (HDR - BT) Mode: Consigue la máxima tasa de transmisión de datos aprovechándose del DDR y de los relojes de SDA y SCL. Para este proyecto, se va a desarrollar un maestro que pueda trabajar exclusivamente en modo SDR. De cualquier manera, es importante conocer los distintos modos de los que dispone el protocolo [7]. 2.3.3 Principios fundamentales del bus Al igual que en I2C el protocolo I3C utiliza dos líneas de comunicación. Estas líneas comparten el mismo 11 11 Diseño VHDL de un driver I3C nombre que sus predecesoras siendo SCL y SDA. • SDA: Linea bidireccional de información. • SCL: Puede ser tanto línea de reloj como línea de datos bidireccional en algunos modos de HDR. Un bus I3C soporta además el uso de distintos tipos de mensajes en una solo línea de comunicación cambiando entre diversos modos mientras se transmiten datos de un tipo o de otro. Un ejemplo del tráfico del bus es muestra en la Figura 2-5. Figura 2-5 Traza I3C con múltiples tipos de mensaje. De igual forma que ocurría en I2C, las comunicaciones en I3C ocurren dentro de un intervalo delimitado entre las condiones de START (o REPEATED START) y STOP. Los paquetes de datos se transmiten entre las dos condiciones y se pueden transferir diversas tramas de datos antes de terminar la comunicación [7]. Protocolo I2C VS I3C 12 Figura 2-6 Máquina de estados general I3C. Las trazas en I3C difieren con respecto a las de su antecesor I2C, y dependen además del modo de comunicación en el que se trabaja. En cualquier momento, el bus de comunicación siempre tendremos un sólo dispositivo que funciona como maestro y uno o más dispositivos que funcionan como esclavos. Lo cual significa que, aunque dispongamos de dispositivos que puedan funcionar en ambos roles en ningún momento se puede tener una configuración que disponga de más de un maestro o menos de un esclavo. Aún así, a lo largo del ciclo de comunicación los roles pueden ir cambiando. Se define así el rol de maestro activo, siendo el dispositivo que está trabajando como maestro en un momento dado. La variabilidad de los roles da como resultado un espectro de posibles funciones que puede tener cada dispositivo, siendo todas unas variaciones de las denominaciones clásicas de maestro y esclavo. En la siguiente figura se pueden ver los siguientes roles compatibles con I3C [7]. 13 13 Diseño VHDL de un driver I3C Figura 2-7 Roles dispositivos I3C. 2.3.4 I3C Maestro El dispositivo maestro activo es el principal encargado de mandar la mayoría de los comandos I3C (CCC) que pueden ser dirigidos a todos los dispositivos conectados del bus (Broadcast CCC) o a un dispositivo en particular (Directed CCC). El maestro es también el único dispositivo que permite mandar mensajes I2C en Legacy Mode. Adicionalmente, el maestro I3C debe encargarse de las siguientes tareas: • Generar la señal de reloj cuando se encuentra se encuentra en los modos SDR y los HDR que lo precisen (Para algunos modos de HDR no se utiliza un reloj convencional). • Gestionar las estructuras de pull-up del bus. • Gestionar los modos de asignación dinámica de direcciones. • Gestionar las solicitudes de START del bus y las solicitudes de arbitraje de direcciones como pueden ser: • Generar IBIs. • Eventos Hot-Join. • Solicitudes de transferencia del rol de maestro activo. • Obviamente debe también soportary gestionar los modos de funcionamiento tanto de Legacy I2C como los modos SDR y cualquiera de los HDR. 2.3.5 I3C esclavo Dado la naturaleza de los protocolos maestro-esclavo, un esclavo debe simplemente encargarse de la otra parte de la comunicación en lo mencionado anteriormente. Por lo tanto, un esclavo I3C generalmente se encarga de lo siguiente. • Escuchar y actuar correctamente a cada CCC que se recibe. • Debe soportar siempre el modo de operación SDR del protocolo. • Debe seguir la señal de reloj generada por el maestro. Protocolo I2C VS I3C 14 • Leer o escribir en los modos HDR (HDR-BT es opcional). • Soportar alguno de los tipos de asignación dinámica de direcciones. • Opcionalmente el dispositivo puede: • Solicitar IBIs. • Generar eventos Hot-Join. • Solicitar la transferencia de rol a maestro activo. 2.3.6 Modo SDR Como ya se ha mencionado previamente, para este proyecto vamos a crear un maestro simple que trate de comunicarse con el nuevo protocolo I3C. Para ello se ha implementado un maestro con las funcionalidades más simples del protocolo, trabajando exclusivamente en modo SDR. SDR es el modo principal de comunicación del I3C, siendo también el principal nexo para trabajar en otros modos, submodos o estados del bus; y para para características propias del mismo como los CCCs, IBIs o transiciones de modo Legacy I2C a I3C mediante asignación dinámica de dirección. El modo SDR es muy parecido funcionalmente al I2C, en términos de procedimiento y condiciones de funcionamiento. Como resultado, tanto dispositivos I3C como esclavos I2C (los dispositivios configurados como maestros no son compatibles) pueden cohexistir en el mismo bus I3C. Sin embargo, SDR también incluye ciertas nuevas características que no se encuentran en el protocolo I2C. Esto da como resultado que no se pueda trabajar con ambos dispositivos a la vez ya que, si tenemos un I3C que funciona en modo Legacy I2C, los dispositivos I3C esclavos ignorarán las trazas de datos y si mandamos mensajes I3C, los dispositivos I2C no serán capaces de leerlos ya que el spike filter de los dispositivos I2C hace la información se filtre debido a la alta velocidad del protocolo. Una configuración general del bus sería la mostrada en la Figura 2-8. Figura 2-8 Configuración general del bus. SDR en su raíz es bastante similar al protocolo I2C, pero tiene algunas diferencias como las indicadas a continuación. 15 15 Diseño VHDL de un driver I3C • Las condiciones de START (o REPEATED START) y STOP, son idénticas salvo por presentar una temporización ligeramente más estricta. • Las trazas de dirección son iguales que que las del I2C en forma de señales y bits utilizados, pero con una temporización más estricta. • Las trazas de datos de 9 bits (8 bits de datos más 1 bit de ACK/NACK en I2C), son idénticas salvo en el noveno bit. En vez de las condiciones de ACK o NACK se crea una nueva condición llamada TRANSICTION BIT. Esta nueva condición determina si se van a seguir leyendo o enviando mensajes en ráfaga. • En I3C la línea SCL solo la maneja el maestro. Esto significa que el clock stretching del I2C no funciona en I3C. Normalmente es una línea push-pull pero puede también trabajar a drenador abierto. Entonces un mensaje se considera I3C SDR si el valor en la dirección es el 7’h7E (valor perteneciente al CCC BROADCAST) y por tanto los dispositivos I3C leerán este valor y empezarán la comunicación (los dispositivos I2C no podrán leer este valor de dirección ya que en su protocolo este es un valor reservado) o si la dirección de la traza de dirección coincide con su dirección asignada de manera dinámica. De forma resumida, los mensajes en SDR pueden ser de los siguientes tipos. Figura 2-9 Mensajes SDR I3C. En la Figura 2-10 se ilustra un ejemplo de una transacción utilizando el modo I3C SDR. En ella se muestra un maestro leyendo un byte de datos de un esclavo con la dirección 7h2B. Protocolo I2C VS I3C 16 Figura 2-10 Ejemplo traza I3C SDR [7]. En este ejemplo, partimos de la condición de bus libre (ninguno dispositivo está accediendo al mismo), el maestro manda la condición de START mediante un flanco de bajada en SDA cuando tenemos SCL a nivel alto (de forma similar al bus I2C). Entonces, se envía la dirección de broadcast seguido de un ‘0’ lógico que indica una operación de escritura. Esto no puede ser de otra forma ya que los CCC siempre son en modo escritura. Después, el maestro deja el bus en modo drenador abierto o alta impedancia para que el esclavo tome el control y pueda responder con un ACK (cualquiera puede responder dado que todos reciben el CCC). Posteriormente, el maestro vuelve a tomar control del bus y manda la condición de REPEATED START seguido de la dirección del esclavo con el que se quiere comunicar y el modo de operación (en este caso 1 dado que vamos a leer). El maestro vuelve a dejar la línea en drenador abierto y pasa el control del bus al esclavo que debe responder con el ACK (aquí únicamente el que coincida con la dirección privada). Como se encuentra en modo de escritura, el control del bus sigue en manos del esclavo, que manda los datos que le toque enviar (en este caso se manda una traza de valor 0x4A). Una vez mandada la traza datos se manda el bit de transición T. En este caso T = ‘1’ significa que hay más trazas de datos para mandar en cascada y por tanto en el ejemplo se puede ver que se envía otra traza adicional. Una vez no se quieren recibir más datos el esclavo pone T = ‘0’ y acaba la comunicación. El bit T es una forma bidireccional de comunicación ya que una vez se le ha dado control al maestro este puede también cambiar el valor de T para comunicar al esclavo que ha acabado de leer y que por tanto no va a leer mas datos y que retoma el control del bus. Esto significa que para que la comunicación continúe, tanto el maestro como el esclavo deben establecer T = ‘1’. Finalmente, el maestro envía la condición de STOP mediante un flanco de subida cuando SCL está a nivel alto (al igual que en I2C). 17 3 APLICACIÓN Y HARDWARE Na vez descrito el protocolo a implementar, procederemos a describir la aplicación desarrollada para probar su funcionamiento, así como el hardware que se va a utilizar para implementarlo. 3.1 Aplicación Con el fin de probar el protocolo de comunicación, se ha desarrollado una aplicación para comunicarse con un sensor de temperatura que es capaz de hablar en I3C. Para ello vamos a intentar establecer una serie de bloques para hacer posible la comunicación del sensor con una FPGA, después para comprobar que los datos se han recibido correctamente utilizaremos un puerto serie para comunicarnos desde la FPGA a un ordenador, del cual leeremos datos abriendo un puerto COM mediante el programa Docklight. De esta manera podremos leer los datos de temperatura desde nuestro ordenador. Además, podremos controlar algunos aspectos del funcionamiento del sistema mediante algunos botones e interruptores de los que dispone la propia FPGA y mediante el uso de jumpers en la placa de adaptación. Debido a la naturaleza del sensor, también se ha tenido que hacer una placa de adaptación para poder hacer la comunicación sensor-FPGA. Por lo tanto, tenemos una aplicación con 4 bloques fundamentales. Un primer bloque, que es el propio sensor de temperatura. Un segundo bloque, que se corresponde con una tarjeta de adaptación, que es responsable de hacer posible la comunicación sensor-FPGA. El tercer bloque está asociado con la propia FPGA. Esta gestiona y transmite la información recibida. El último bloque es el encargado de la lectura de datos desde un puerto serie, que se puede hacer directamente desde el ordenador. Figura 3-1 Esquema de aplicación del proyecto. U Si el conocimiento puede crear problemas, no es conla ignorancia que podemos resolverlos. -Isaac Asimov - Aplicación y hardware 18 3.2 Hardware Como cualquier proyecto que se quiera llevar a una aplicación del mundo real, se precisa de elementos hardware que soporten la implementación del diseño que se ha realizado. En cuanto a las partes hardware, solamente disponemos de tres bloques (sin contar el ordenador): FPGA, la placa de adaptación y el sensor. 3.2.1 Sensor de temperature TMP139 El TMP139 es un sensor de temperatura de gran precisión que tiene una interfaz digital capaz de comunicarse en los protocolos I2C e I3C. Tiene una precisión de ±0.25 ºC y un rango de temperatura de medida que va desde los -40 ºC a los 125 ºC. El tiempo de conversión del sensor es de 125ms. Sus dimensiones son 1.328 mm x 0.828 mm. Además, presenta dos tensiones de alimentación diferentes: • 1.8V para alimentar la electrónica digital/analógica que integra el sensor. • 1.0V para alimentar las interfaces de entrada-salida a 1.0 V con una corriente media de 4.7 µA. Este sensor está pensado para los siguientes usos: • Gestionar la temperatura de memorias DDR5. • Integración en placas base de servidores, ordenadores portátiles, estaciones de trabajo o discos SSD. En la carcasa del sensor posee tres pares de pines de cuyo diámetro es de 0.20 mm separados verticalmente 0.5 mm. Dos de los pines, se corresponden con las líneas SCL y SDA, dos pines de alimentación para el núcleo y los I/O, una tierra y un último pin, llamado SA, para gestionar la dirección del IC. Este último, puede estar conectado a VDDIO o a tierra, en función de si queremos utilizar una dirección u otra. Como se puede ver, el tamaño de los pines es un problema para intentar conectarlos directamente a una FPGA, además el uso de dos voltajes de alimentación (distintos a los 3.3 ó 5 V que suminitstra la FPGA elegida) crea la necesidad de diseñar y fabricar una placa de adaptación, descrita posteriormente en el presente capítulo. Figura 3-2 Esquema pines externos TMP139. Internamente, el sensor posee el transductor de temperatura, un ADC, los registros de temperatura y configuración, una interfaz de comunicación I3C/I2C y la lógica de control tanto de la interfaz de bus como de los registros y el ADC. En la Figura 3-3 se puede ver el esquema completo del sensor elegido. 19 19 Diseño VHDL de un driver I3C Figura 3-3 Esquema módulos internos TMP139. De todos los registros del sensor, centraremos nuestra atención en dos de ellos, asociados a la medida actual de la temperatura. En uno de ellos, se guarda la parte alta de la medida de temperatura y, en el segundo, la parte baja. De esta manera, tendremos que leer los dos para poder obtener una medida de la temperatura registrada por el sensor. Además, aunque los dos registros son de ocho bits, lo que conforman una palabra de 16 bits, únicamente 11 de estos presentan información útil. Los datos se distribuyen como se presentan en la siguiente figura. Figura 3-4 Registros internos de temperatura del TMP139. Por lo tanto, cuando concatenemos los datos de los dos registros, tenemos que ignorar los 3 primeros bits y los 2 últimos. Un ejemplo de una lectura sería el “000001010 0101000”, al eliminar los bits no utilizados, nos quedaría un valor de +85 ºC. Como se puede observar, el rango máximo es de -128 ºC a 128 ºC, pero los valores límites son de -40 ºC a 125 ºC por lo que, aunque se puedan medir temperaturas fuera de ese rango esto no es recomendable. La dirección de los registros está recogida en el mapa de memoria descrito la hoja de especificaciones del sensor [8]. Esto se corresponde con las direcciones 31h y 32h, expresadas en formato hexadecimal. Otro valor que nos interesa es la dirección del chip ya que, dado que no vamos a utilizar la gestión dinámica de direcciónes, vamos a tener que utilizar la dirección por defecto establecida por el fabricante. Esta puede tener dos valores en función de la tensión conectada al pin SA. La siguiente figura muestra el valor de dicho identificador. Aplicación y hardware 20 Figura 3-5 Dirección variable TMP139. a) Operación de lectura y escritura La gestión tanto de escritura como de lectura se hace de la siguiente manera. Vamos a necesitar dos direcciones, la dirección del chip que se define en función de SA y la dirección de los registros a los que se van a acceder en modo lectura. Una traza de lectura de registro funcionaría del siguiente modo: 1. Se manda la dirección del chip y se pone el modo escritura. 2. A continuación, se envía la dirección más baja del registro que se desea leer. En nuestro caso, se manda la dirección 31h. 3. Una vez se recibe el bit de transacción cambiamos el modo de funcionamiento a modo de lectura. Para ello, se genera la condición REPEATED START para realizar una operación de lectura. 4. Volvemos a mandar la dirección del chip con el bit R/W a ’1’. 5. A partir de este punto, ya podemos leer los datos del registro devueltos por el sensor. Si decidimos que la condición del bit de transacción es de seguir leyendo, entonces leeremos los datos del registro de dirección+1, si seguimos así; leeremos el registro de dirección+2 y así, sucesivamente. Cuando queramos abortar la lectura en serie de registros mandamos la condición de transición T = 0 y dejamos de leer datos. El procedimiento anteriormente descrito se muestra en la Figura 3-6. Cabe indicar que el color gris indica una escritura por parte del maestro mientras que el color blanco representa una escritura en el bus por parte del esclavo. El color negro indica el final de la negociación ya sea por parte del esclavo o del maestro, cualquiera de los dos pondrá su bit de transición a ‘0’. Figura 3-6 Traza de lectura de registro sensor TMP139 usando I3C. La implementación del procedimiento anterior sería suficiente para poder recuperar las medidas de temperatura efectuadas por el sensor. Sin embargo, es necesario solventar una problemática previa. Tras conectar la alimentación, el sensor elegido establece su comunicación en modo I2C. Por tanto, antes de empezar a leer información, necesitamos inicializar la configuración del sensor mediante el uso de un CCC llamado SETAASA. Este comando hace que el dispositivo pase de modo I2C a I3C. Para que sea reconocido por el sensor, se debe enviar la trama mostrada en la ¡Error! No se encuentra el origen de la referencia.. 21 21 Diseño VHDL de un driver I3C Figura 3-7 Traza de envio de SETAASA. Una vez configurado el sensor para usar el procolo I3C, ya se puede leer y escribir datos mediante lecturas y escrituras I3C [8] 3.3 Placa de adaptación El encapsulado del sensor (WLCSP) hace que sea muy poco manejable por lo que para trabajar con él necesitamos una placa de adaptación. La placa de adaptación consta de dos partes, una primera parte que sirve para que los 6 pines del sensor estén a la misma distancia que un socket PMOD y una segunda placa que se encarga de gestionar los reguladores de tensión necesarios para alimentar la placa y de rutar los cables de SDA y SCL a otro socket PMOD para conectarlo a la FPGA. 3.3.1 PCB de ajuste Este PCB tiene un diseño muy simple, únicamente se rutan los pines para que pasen de estar separados 0.5 mm y usar una conexión de tipo BGA a una separación de 2.54 mm, compatible con los conectores tipo PMOD que presenta la tarjeta Basys 3. Además, se incrementa el tamaño de los pads y de los agujeros para que sea mucho más sencillo su frabicación. La PCB queda de la siguiente manera. Figura 3-8 PCB del adaptador del sensor. El sensor va en medio de los 6 pines interiores. Para su conexión, se procederá a soldar cables de espesor 30AWG que unan eléctricamente cada pin con su pad correspondiente. 3.3.2 PCB de voltajes En esta placa incorpora dos reguladores de tensión para generarlos voltajes de 1.0 y 1.8V necesarios. Además, permite rutar las señales SCL y SDA a un PMOD de 12 pines para su conexión directa a la FPGA. Se van a utilizar dos reguladores de tensión. El LM317 para bajar de 3.3V a 1.8V y el TPS74401 para reducir de 3.3V a 1.0V. Además, tenemos que introducir una serie de condensadores y resistencias que vienen dadas por el datasheet de ambos dispositivos. Dado que ambos permiten ajustar las tensiones de salida, se ha optado por utilizar potenciómetros para ajustar manualmente dichas tensiones. El esquema final queda de la siguiente manera. Aplicación y hardware 22 Figura 3-9 Esquemático placa de voltajes. Cabe destacar que de los jumpers J4 y J5, sólo uno de ellos puede estar conectado a la vez ya que es la manera de elegir la dirección por defecto que tiene el sensor. La placa del adaptador del sensor va encajada entre los dos headers J1 y J2. Esto permite que el sensor pueda ser reemplazado fácilmente en caso de avería sin tener que modifcar la tarjeta de adaptación. Una vez rutado y aplicado un plano de tierra, tanto en la capa sueprior como la inferior, el diseño queda de la siguiente manera. Figura 3-10 PCB placa de voltajes, vista superior. 23 23 Diseño VHDL de un driver I3C Figura 3-11 PCB placa de voltajes, vista inferior. Ambas placas fueron hechas y soldadas manualmente en el Laboratorio de Ingeniería Electrónica de la Universidad de Sevilla. 3.4 Cableado Para el cableado entre los distintos bloques, se utilizan cables con pines doble macho o hembra-macho. Excepto para la comunicación de la FPGA con el PC, que esta se realiza mediante un cable conversor USB- UART. 25 4 IMPLEMENTACIÓN EN VHDL Aquellas personas que piensan que lo saben todo, son una gran molestia para aquellos de nosotros que lo estamos intentando -Isaac Asimov- n este capítulo vamos a describir las partes de las que consta la implementación VHDL del proyecto. Se pueden distinguir cuatro bloques diferentes que están integrados de la siguiente manera. Tenemos un inicializador del sensor que también trabaja manejando al maestro I3C, un módulo que se comunica con el ordenador mediante puerto serie, el propio maestro I3C y un top level que incluye todo lo anterior rutado correctamente con dos registros para almacenar de forma temporal la información leída ya que el I3C trabaja más rápido que el puerto serie. 4.1 Máquinas de estado y esquemas de funcionamiento Debido a la necesidad que presenta el sistema de alterar su comportamiento en función de los estímulos de entradas recibidos, así como generar las salidas correspondientes en instantes de tiempo determinados; se han implementado diferentes máquinas de estado que supervisan y controlan la ejecución del controlador I3C y de la propia aplicación. Cada bloque tiene su propia máquina que va a ser detallada en su respectivo subapartado. El código utilizado se podrá ver en la segunda parte de este capítulo. 4.1.1 Maestro I3C Este es el módulo principal de todo el proyecto, el resto sóo se utilizan para comprobar su correcto funcionamiento. Su principal funcionalidad es la de leer o escribir una trama I3C y pasar dicha información a un nivel superior, por esto necesitamos una máquina de estados externa que controle su operación (el sensor initializer). La máquina de estados que rige el funcionamiento principal del módulo es la siguiente. E Implementación en VHDL 26 26 Figura 4-1 Máquina de estados I3C maestro. 27 27 Diseño VHDL de un driver I3C En la máquina podemos encontrar los siguientes estados: • Ready: Empezamos la ejecución en este estado y nos mantenemos en él mientras el enable se encuentre a 0. Durante este estado la máquina se encuentra en reposo y por tanto las salidas se encuentran en alta impedancia. • Start: Una vez el enable se encuentre activo, se genera la condición de START del protocolo de comunicación y una vez finalizada se pasa al siguiente estado. • Broadcast: Se escriben por SDA los 8 bits del Broadcast concatenado con el modo (siempre es “11111100”). Mientras no se hayan mandado todos los bits permanecemos en este estado y bajamos un contador para leer el siguiente bit. Una vez el contador llega a 0 reiniciamos el contador y pasamos al siguiente estado. • Broadcast ACK: Esperamos a que el sensor nos responda con un ACK clásico (igual que en I2C). Si recibimos el ACK pasamos al siguiente estado y si no pasamos al estado de error. • Repeated Start: A este estado venimos la primera vez que queremos empezar una trama de comunicación y cada vez que queramos mandar una traza con distinto modo o dirección sin interrumpir la comunicación. Se genera una segunda condición de START igual a la primera. Una vez finalizada se avanza al siguiente estado. • Addressing + Mode (o Command): Se escriben por SDA los 8 bits correspondientes a a dirección del dispositivo concatenado con su modo de funcionamiento. Utilizamos un contador para ver cuando se han transmitido los 8 bits. • Cmd ACK: La máquina espera a recibir un ACK. En caso de recibirlo pasamos a la rama de lectura o escritura según el modo definido en el estado anterior o en caso contrario pasamos al estado de error. • Write: La máquina escribe en el bus SDA los 8 bits que se han leído del puerto de entrada. Una vez finalizados se pasa al estado siguiente. • Transit Bit Write: En este caso en la última mitad de ciclo de escritura se escribe el valor del bit de transit por parte del maestro, una vez finalizado se libera el bus y se recibe el valor del bit transit por parte del esclavo. Una vez finalizado se evalúa si ha habido un cambio en las entradas que y se pasa al estado correspondiente en función de dichos valores. Si hemos cambiado el modo o dirección tenemos que volver a empezar la trama con el Repeat Start, si alguno de los bits de transición o el enable valen 0 pasamos al estado de Stop y si no ha cambiado nada podemos seguir escribiendo en ráfaga (El dato de entrada si que puede cambiar entre ráfaga y ráfaga). • Read: La máquina libera el bus SDA para leer datos. Una vez se han leído los 8 bits pasamos al siguiente estado. Los datos se guardan en un registro de salida. • Transit Bit Read: En este caso tenemos que empezar a leer la última mitad de ciclo del ultimo bit de lectura para leer el trasit bit por parte del esclavo. Una vez leído se pone el valor del transit bit maestro en el bus. Una vez finalizado se evalúa si ha habido un cambio en las entradas que y se pasa al estado correspondiente en función de dichos valores. Si hemos cambiado el modo o dirección tenemos que volver a empezar la trama con el Repeat Start, si alguno de los bits de transición o el enable valen 0 pasamos al estado de Stop y si no ha cambiado nada podemos seguir leyendo en ráfaga. • Stop: Se genera la condición de STOP y se libera el bus. • Error: A este estado sólo se va a llegar en caso de recibir un NACK o si se llega a un estado imposible. Se reinicia la máquina y se vuelve a empezar la traza. 4.1.2 Sensor initializer El sensor arranca por defecto en modo I2C por lo que hay que mandar un comando CCC para cambiar el modo de funcionamiento a I3C antes de intentar interactuar con el sensor. Este comando es el SETAASA. Además, necesitamos una máquina de estados externa que maneje el funcionamiento del I3C Maestro una vez se ha puesto en marcha ya que necesitamos hacer una escritura seguida de dos lecturas para leer los datos de Implementación en VHDL 28 28 temperatura del sensor. La máquina de estados que rige este módulo es la siguiente. Figura 4-2 Máquina de estados Sensor Initalizer. Está máquina no es más que una versión simplificada de la del maestro I3C ya que tenemos que mandarúnicamente una sola traza con el CCC SETAASA. Sin embargo, dado que queremos que esta misma máquina 29 29 Diseño VHDL de un driver I3C maneje al maestro una vez ha finalizado la trama, tenemos tres estados cíclicos que se encargan de ello. Por lo tanto, está máquina tiene dos partes bien diferenciadas: el envío del CCC y el manejo del maestro. Para que esté modulo sea capaz de enviar una traza y después activar al maestro, tiene que ser capaz de multiplexar los pines SDA y SCL para ceder el control. A continuación, se muestra un diagrama de bloques del sistema. Figura 4-3 Esquema de montaje Sensor Initializer. Una vez aclarado esto, la maquina consta de los siguientes estados: • Ready: La máquina comienza en este estado, mientras el enable no se encuentre activo se mantendrá en este. • Broadcast: Se escriben por SDA los 8 bits del Broadcast concatenado con el modo (siempre es “11111100”). Mientras no se hayan mandado todos los bits permanecemos en este estado y bajamos un contador para leer el siguiente bit. Una vez el contador llega a 0 reiniciamos el contador y pasamos al siguiente estado. • ACK Broadcast: Esperamos a que el sensor nos responda con un ACK clásico (igual que en I2C). Si recibimos el ACK pasamos al siguiente estado y si no pasamos al estado de error. • SETAASA CCC: Se escriben por SDA los 8 bits del CCC SETAASA. Mientras no se hayan mandado todos los bits permanecemos en este estado y bajamos un contador para leer el siguiente bit. Una vez el contador llega a 0 reiniciamos el contador y pasamos al siguiente estado. • Transit bit: En este caso en la última mitad de ciclo de escritura se escribe el valor del bit de transit Implementación en VHDL 30 30 por parte del maestro, una vez finalizado se libera el bus y se recibe el valor del bit transit por parte del esclavo. Una vez finalizado se evalúa el valor del bit transit del esclavo. Si se recibe un 1 se pasa al siguiente estado, en caso contrario se pasa al estado de error. • Stop: Se genera la condición de STOP. Una vez ha finalizado se procede al siguiente estado. • Write Master: Primer estado de la segunda parte de la máquina de estados. Se activa el enable, se cambia el multiplexor de salida y se pone la entrada del modo del maestro I3C a modo escritura. El valor necesario que hay que escribir es siempre el mismo luego en esta aplicación se le asigna desde el top level. Se espera a recibir un pulso de write_ready por parte del maestro para saber cuando ha finalizado la transacción y se pasa al siguiente estado. • Read Master 1: Segunda estado de la segunda parte de la máquina. Se cambia el modo del maestro a modo escritura. Se espera a recibir un pulso de data_ready por parte del maestro para saber cuando ha finalizado la transacción y se pasa al siguiente estado. • Read Master 2: Segunda estado de la segunda parte de la máquina. Se cambia el modo del maestro a modo escritura. Se espera a recibir un pulso de data_ready por parte del maestro para saber cuando ha finalizado la transacción y se pasa al siguiente estado. 4.1.3 Top level registers Para comprobar el correcto funcionamiento del sensor y del protocolo se necesitan leer los datos en algún sitio. Para ello hay que establecer una comunicación entre el maestro I3C y el Serial Transmiter. Sin embargo, estos dos trabajan a distintas velocidades de transmisión, además dado que los datos se tienen que leer por parejas para que tengan sentido, necesitamos implementar una pequeña adaptación entre ambos bloques. Para ello se implementan los registros del nivel superior. Esquemáticamente, los registros funcionan de la siguiente manera. Figura 4-4 Esquema general registros del nivel superior. El registro 1 se encarga de comunicarse con el Serial Transmiter y el Registro 2 con el I3C Master. Ambos tienen que serializar datos de 2 bytes. Por lo tanto, primero leen o escriben en el primer byte del registro y después en el segundo de manera cíclica. Estos cambian en función de las señales Data_ready y Busy_serial que generan un pulso cada vez que se ha finalizado una transacción de cualquiera de los dos. Además, el registro 1 copia los datos del registro 2 cuando el segundo avisa al primero mediante el flag Ready_reg2. Las máquinas de estado de los dos registros funcionan de la siguiente manera. 31 31 Diseño VHDL de un driver I3C Figura 4-5 Máquinas de estado de registros de nivel superior. La máquina del registro 1 posee los siguientes estados: • Ready: La máquina se mantiene en este estado hasta que Ready_reg2 tenga valor 1. • Serial Byte 1: Se escribe en el registro de entrada del Serial Transmiter el primer byte de datos. Se espera a que el Serial Transmiter acabe la transacción para actualizar el dato al segundo dato. • Serial Byte 2: Se escribe en el registro de entrada del Serial Transmiter el segundo byte de datos. Se espera a que el Serial Transmiter acabe la transacción para volver al estado inicial. La máquina del registro 2 posee los siguientes estados: • Master Byte 1: Se lee el primer byte del registro de salida de datos del Master I3. El ready_reg2 se mantiene a 1 ya que tenemos el dato completo (salvo la primera iteración que va a mandar el valor del reset). Una vez se recibe el fin de la transacción con el data ready pasamos a leer el segundo byte. • Master Byte 2: Se lee el segundo byte del registro de salida de datos del Master I3C. Ready_reg2 se pone a 0 para no mandar datos incompletos (byte 1 actualizado, pero byte 2 de una medida antigua). De esta manera podemos transmitir los datos de dos en dos sin importar la velocidad de transmisión de ambos protocolos. 4.1.4 Serial transmiter Este bloque se encarga de transmitir la información que recibe por puerto serie. Este se leerá desde el ordenador. La máquina de estados funciona de la siguiente manera. Implementación en VHDL 32 32 Figura 4-6 Máquina de estados de Serial Transmiter. La máquina posee lo siguientes estados: • Ready: La máquina se mantiene en este estado mientras el enable se encuentre a 0. • Start: Se manda la condición de comienzo del protocolo de transmisión por puerto serie. • Bit transfer: Se mandan los datos 8 bits del puerto de entrada por el puerto serie. Una vez se han transmitido todos se pasa al estado siguiente. • Parity bit: Se manda un bit de paridad para ver el correcto funcionamiento de la traza (ya que este es un protocolo asíncrono). En este caso se trata de una paridad par medianta un XOR de todos los bits anteriores. • Stop: Se manda la condición de fin del protocolo de transmisión por puerto serie. 4.2 Código VHDL Cada una de las máquinas de estado anteriores han sido implementadas en VHDL y testeadas. Todas las máquinas de estado poseen un reset asíncrono que reinicia la máquina de estados y una variable enable que habilita su funcionamiento. 4.2.1 I3C_master.vhd Este módulo consta de dos partes fundamentales que corresponden a dos procesos distintos. El primer proceso genera las señales de reloj internas de SDA y SCL. 33 33 Diseño VHDL de un driver I3C Como ya se ha visto, los datos se leen durante los ciclos de subida de SCL. Por lo tanto, si queremos tener los datos estabilizados cuando sea el momento de leerlo necesitamos que se vuelquen al bus con un poco de --generate the timing for the bus clock (scl_clk) and the data clock (data_clk) PROCESS(clk, reset_a) VARIABLE count : INTEGER RANGE 0 TO divider*4; --timing for clock generation BEGIN IF(reset_a = '0') THEN --reset asserted stretch <= '0'; data_clk <= '0'; data_clk_prev <= '0'; scl_clk <= '0'; scl_clk_prev <= '0'; count := 0; ELSIF(rising_edge(clk)) THEN data_clk_prev <=data_clk; --store previous value of data clock scl_clk_prev <= scl_clk; IF(count = divider*4-1) THEN --end of timing cycle count := 0; --reset timer ELSIF(stretch = '0') THEN --clock stretching from slave not detected count := count + 1; --continue clock generation timing END IF; CASE count IS WHEN 0 TO divider-1 => --first 1/4 cycle of clocking scl_clk <= '0'; data_clk <= '0'; WHEN divider TO divider*2-1 => --second 1/4 cycle of clocking scl_clk <= '0'; data_clk <= '1'; WHEN divider*2 TO divider*3-1 =>--third 1/4 cycle of clocking scl_clk <= '1'; --release scl data_clk <= '1'; WHEN OTHERS => --last 1/4 cycle of clocking scl_clk <= '1'; data_clk <= '0'; END CASE; END IF; END PROCESS; Código 4-1 Generación de señales de reloj SDA y SCL. Implementación en VHDL 34 34 antelación. Por lo tanto, para los relojes internos necesitamos que las señales de reloj tengan las siguientes formas. Figura 4-7 Diagrama de timings de SDA y SCL. Donde 1, 2, 3 y 4 son los cuartos del ciclo total de las señales. De esta manera dejamos ¼ de ciclo para que el valor de SDA se estabilice. En este proceso primeramente guardamos los valores anteriores de la señal de reloj para detectar los flancos de subida y de bajada que nos servirá para cambiar de estado más adelante. Tenemos también un contador que cuenta hasta llegar al ciclo entero. En cada cuarto de ciclo se actualiza el valor de las doce señales de reloj para generar la forma de onda de la figura anterior. Definimos por tanto el valor de divider como el numero de ciclos de reloj que hay que contar hasta llegar a ¼ de ciclo. Esta forma de generar las señales de reloj se mantiene también en el módulo SENSOR_INITIALIZER.vhd ya que es una versión simplificada de esta. En cuanto al resto del código, se trata de una implementación de la máquina de estados de la Figura 4-1 con alguna excepción. En esta implementación hay más estados, pero tiene la misma funcionalidad. Esto es debido a que necesitamos más de un solo estado para hacer condiciones de espera o sincronización de los estados de START y STOP. CONSTANT divider : INTEGER := (input_clk/bus_clk)/4; --number of clocks in 1/4 cycle of scl, we want the scl_clk to delay 1/4 of a cycle to let the data in sda stabilize Código 4-2 Divider. --state machine and writing to sda during scl low (data_clk rising edge) PROCESS(clk, reset_a) BEGIN IF(reset_a = '0') THEN --reset asserted state <= ready; --return to initial state busy <= '0'; --indicate not available ena_scl <= '1'; --sets scl high impedance ena_sda <= '1'; 35 35 Diseño VHDL de un driver I3C sda_o_m2s <= '0'; ack_error_flg <= '0'; --clear acknowledge error flag bit_cnt <= 7; --restarts data bit counter addr_m2s <= (others => '0'); --clear address read port data_ready <= '0'; --clear data ready flag write_ready <= '0'; cmd_m2s <= (others => '0'); data_m2s <= (others => '0'); data_s2m <= (others => '0'); ELSIF(rising_edge(clk)) THEN busy <= '0'; ena_sda <= '1'; sda_o_m2s <= '0'; ena_scl <= '1'; ts <= '0'; data_ready <= '0'; --clear data ready flag write_ready <= '0'; CASE state IS when READY => --idle state cmd_m2s <= ccc_i & ccc_op_i; IF(ena = '1') THEN --transaction requested state <= SYNC_RISE_EDGE_DATA_CLK; --go to start bit END IF; when SYNC_RISE_EDGE_DATA_CLK => busy <= '1'; -- flag busy if data_clk = '1' and data_clk_prev = '0' then state <= SYNC_RISE_EDGE_SCL_CLK; end if; when SYNC_RISE_EDGE_SCL_CLK => busy <= '1'; -- flag busy if scl_clk = '1' and scl_clk_prev = '0' then state <= BIT_START; end if; when BIT_START => ack_error_flg <= '0'; busy <= '1'; ena_sda <= '0'; --sda_o_m2s <= '0'; ena_scl <= '0'; if scl_clk = '0' and scl_clk_prev = '1' then state <= INIT_CCC; end if; Implementación en VHDL 36 36 when INIT_CCC => busy <= '1'; ena_sda <= '0'; -- enable iobuf sda sda_o_m2s <= '0'; -- set first CCC bit. ena_scl <= '0'; -- enable iobuf scl if data_clk = '1' and data_clk_prev = '0' then state <= CCC_SEND; end if; when CCC_SEND => -- BROADCAST busy <= '1'; ena_sda <= '0'; sda_o_m2s <= cmd_m2s(bit_cnt); ena_scl <= '0'; if data_clk = '1' and data_clk_prev = '0' then if bit_cnt = 0 then ena_sda <= '1'; bit_cnt <= 7; state <= CCC_ACK; else bit_cnt <= bit_cnt - 1; end if; end if; when CCC_ACK => -- BROADCAST ACK busy <= '1'; ena_scl <= '0'; if data_clk = '0' and data_clk_prev = '1' then if sda_i_s2m = '0' then state <= SYNC_RISE_EDGE_SCL_CLK_2; else ack_error_flg <= '1'; ena_scl <= '1'; ena_sda <= '1'; busy <= '1'; state <= ERROR; end if; end if; when SYNC_RISE_EDGE_SCL_CLK_2 => busy <= '1'; -- flag busy data_ready <= '0'; write_ready <= '0'; ena_scl <= '0'; sda_o_m2s <= '0'; if scl_clk = '1' and scl_clk_prev = '0' then 37 37 Diseño VHDL de un driver I3C state <= REPEATED_START; end if; when REPEATED_START => busy <= '1'; ena_sda <= '0'; ack_error_flg<= '0'; --sda_o_m2s <= '0'; ena_scl <= '0'; if scl_clk = '0' and scl_clk_prev = '1' then state <= INIT_CMD; end if; when INIT_CMD => busy <= '1'; ena_sda <= '0'; -- enable iobuf sda sda_o_m2s <= '0'; -- set first CCC bit. ena_scl <= '0'; -- enable iobuf scl addr_m2s <= i3c_addr_i & i3c_op_i; if data_clk = '1' and data_clk_prev = '0' then state <= CMD_SEND; end if; when CMD_SEND => busy <= '1'; ena_sda <= '0'; sda_o_m2s <= addr_m2s(bit_cnt); ena_scl <= '0'; if data_clk = '1' and data_clk_prev = '0' then if bit_cnt = 0 then ena_sda <= '1'; bit_cnt <= 7; state <= CMD_ACK; else bit_cnt <= bit_cnt - 1; end if; end if; when CMD_ACK => -- BROADCAST ACK busy <= '1'; ena_scl <= '0'; if data_clk = '0' and data_clk_prev = '1' then if sda_i_s2m = '0' then if i3c_op_i = '0' then state <= INIT_WRITE; else state <= INIT_READ; Implementación en VHDL 38 38 end if; else ack_error_flg <= '1'; ena_scl <= '1'; ena_sda <= '1'; busy <= '1'; state <= ERROR; end if; end if; when INIT_WRITE => busy <= '1'; ena_sda <= '0'; -- enable iobuf sda sda_o_m2s <= '0'; -- set first CCC bit. ena_scl <= '0'; -- enable iobuf scl data_m2s <= i3c_data_i; if data_clk = '1' and data_clk_prev = '0' then state <= WRITE; end if; when WRITE => -- BROADCAST busy <= '1'; ena_sda <= '0'; sda_o_m2s <= data_m2s(bit_cnt); ena_scl <= '0'; if data_clk = '1' and data_clk_prev = '0' then if bit_cnt = 0 then --No deberia llegar aqui nunca else bit_cnt <= bit_cnt - 1; end if; elsif data_clk = '0' and data_clk_prev = '1' then if bit_cnt = 0 then write_ready <= '1'; bit_cnt <= 7; --sda_o_m2s <= '0'; state <= SET_TM_BIT_WR; end if; end if; when SET_TM_BIT_WR => busy <= '1'; ena_sda <= '0'; sda_o_m2s <= tm; ena_scl <= '0'; if data_clk = '1' and data_clk_prev = '0' then state <= READ_TS_BIT_WR; 39 39 Diseño VHDL de un driver I3C end if; when READ_TS_BIT_WR => busy <= '1'; ena_scl <= '0'; ena_sda <= '1'; --Free the bus sda_o_m2s <= '0'; if data_clk = '0' and data_clk_prev = '1' then if ena = '1' and sda_i_s2m = '1' and tm = '1' then if addr_m2s = (i3c_addr_i & i3c_op_i) then state <= INIT_WRITE; else state <= SYNC_RISE_EDGE_SCL_CLK_2; -- Repeated start end if; else ack_error_flg <= '1'; ena_scl <= '1'; ena_sda <= '1'; busy <= '1'; state <= SYNC_RISE_EDGE_DATA_CLK_STOP; end if; end if; when INIT_READ => busy <= '1'; sda_o_m2s <= '0'; ena_scl <= '0'; data_ready <= '0'; if scl_clk = '0' and scl_clk_prev = '1' then state <= READ; end if; when READ => busy <= '1'; sda_o_m2s <= '0'; ena_scl <= '0'; if data_clk = '1' and data_clk_prev = '0' then data_s2m(bit_cnt) <= sda_i_s2m; elsif data_clk='0' and data_clk_prev='1' then if bit_cnt = 0 then --ts <= sda_i_s2m; data_ready <= '1'; bit_cnt <= 7; state <= READ_TS_BIT_RD; else bit_cnt <= bit_cnt - 1; Implementación en VHDL 40 40 end if; end if; when READ_TS_BIT_RD => busy <= '1'; sda_o_m2s <= '0'; ena_scl <= '0'; if data_clk = '1' and data_clk_prev = '0' then ts <= sda_i_s2m; state <= WRITE_TM_BIT_RD; end if; when WRITE_TM_BIT_RD => busy <= '1'; sda_o_m2s <= tm; ena_scl <= '0'; ena_sda <= '0'; if data_clk = '0' and data_clk_prev = '1' then ts <= '0'; --Reset the slave flag if ena = '1' and ts = '1' and tm = '1' then if addr_m2s = (i3c_addr_i & i3c_op_i) then state <= INIT_READ; else state <= SYNC_RISE_EDGE_SCL_CLK_2; --Repeated start end if; else ack_error_flg <= '1'; ena_scl <= '1'; ena_sda <= '1'; busy <= '1'; state <= SYNC_RISE_EDGE_DATA_CLK_STOP; end if; end if; WHEN SYNC_RISE_EDGE_DATA_CLK_STOP
Compartir