Buenas a todos/as,
No dispongo de mucho tiempo y me váis a perdonar si no lo encapsulo y explico mejor, pero como veo que ya hay interés en ir usando el módulo I2C para hacer funcionar algún que otro dispositivo externo (como esta mañana ha preguntado @MrChuxMan con un display OLED), voy a explicar un poco el encapsulamiento que hice en el bloque I2C para el proyecto
screen-pong y así os resulte más fácil modificarlo si queréis investigar el tema.
En dicho proyecto la idea era utilizar dos potenciómetros para el control de los jugadores, para eso se usaba el integrado convertidor Analógico-Digital que dispone la
iceZum Alhambra en un chip externo a la FPGA (y que se comunica con ella usando el I2C). Todo está encapsulado en el fichero de icestudio
"control-pong.ice". Si lo abrís tiene un aspecto como este:
He marcado los bloques más importantes. El primero es la constante de la dirección I2C del integrado (para saber la de vuestro integrado I2C mirar el datasheet del mismo). El segundo es el módulo I2C encapsulado de Obijuan (i2c.ice + i2c.v) que se encarga de controlar el bus I2C. El tercero es la máquina de estados del integrado (fsm-adc.v) y que se encarga de la secuencia de órdenes para que se grabe o lea del integrado por el bus I2C. El cuarto bloque marcado es simplemente un "bombeo de bits" (un reloj) que marca la frecuencia con la que se ejecutan las órdenes en la máquina de estados (en nuestro caso, tras una inicialización del integrado, a cada "pálpito" del bombeo se encarga de leer los dos canales del ADC a una determinada frecuencia y actualizar la posición de cada uno de los jugadores).
El bloque más importante quizás sea la máquina de estados. Está implementada solo en código (el bloque de icestudio hace de interfaz) y la podéis usar como referencia (no está para nada optimizada, adaptarla a vuestro integrado y sed muy críticos con el código...), fundamentalmente es una secuencia de órdenes en forma de bytes que se escriben en el bus I2C y bytes que se leen del bus, para controlar el integrado que deseamos conectar a la FPGA (en este caso conocer el
datasheet del integrado es fundamental).
El módulo del bus I2C (a parte de los bits y bytes de configuración) usa un byte de entrada de escritura (
data_wr) donde se sitúa el byte que se quiere escribir en el bus I2C (hacia el esclavo), otro de lectura (
data_rd) donde encontraremos el byte que se leea por I2C (proveniente del esclavo), un bit de entrada (SDA) que se conectará a nuestro chip esclavo externo y otro de salida (SCL) que marcará el reloj del esclavo (el módulo I2C que sinteticemos en la FPGA hará siempre de maestro) y que conectaremos igualmente al integrado externo con el que queramos comunicarnos (estas dos serán las conexiones físicas al bus). El bit
busy indica que el bus está ocupado (escribiendo el byte en
data_wr o leyendo de
data_rd) y el
ready que hay un byte listo para ser leído en
data_rd proveniente del bus (del único esclavo conectado a él). Como véis es prácticamente como funcionan los distintos módulos UART que ya hay iencapsulados en bloques en
icestudio.
Las conexiones externas se harán en el fichero que utilice el bloque. En el ejemplo del
screen-pong:
Como véis los pines rodeados en rojo deben ser los pines externos que uséis para conectar la
iceZum Alhambra y vuestro integrado I2C. La señal
star_clk era para un simple debug (nunca viene mal ver que la cosa está funcionando mediante el parpadeo de un LED) y el bloque de control entrega las posiciones de los jugadores en dos palabras de 10 bits (En el caso del OLED imagino que será unas posiciones
x e
y de la pantalla, junto un byte con el código ASCII que queráis escribir en la misma,... eso depende ya de como lo queráis implementar).
Creo que con esto ya podéis haceros una idea general de como funciona el bloque del bus I2C y como utilizarlo tal y como está (siempre se puede mejorar).
Animaros a usarlo y si necesitáis aclaración y/o ayuda no dudéis en preguntar.
Saludos.
Juan Manuel Rico