Está en la página 1de 151

Diseño de un sistema de captura

y análisis de imagen FullHD para


televisores LCD Sony

Memoria del proyecto final de carrera


de Ingeniería de Telecomunicación
Realizado por: Jaume Tamargo García
Dirigido por: Joan Pons Nin
Barcelona, Mayo 2010
1 Introducción.............................................................................................. 4
2 Conceptos básicos .................................................................................. 5
2.1 Imagen Full-HD........................................................................................ 5
2.1.1 FHD. Definición y características ............................................................ 5
2.1.2 Otros formatos/estándares. Definición y características........................... 6
2.2 Señal LVDS.............................................................................................. 7
2.3 Paneles LCD............................................................................................ 8
2.3.1 Funcionamiento ........................................................................................ 8
2.3.2 BackLight. Definición y tipos .................................................................. 9
2.3.3 Interfaz de entrada .................................................................................. 10
2.4 El entorno .............................................................................................. 13
2.5 Máquinas de test................................................................................... 15
2.6 LVDS Capturer ...................................................................................... 17
3 Descripción detallada del sistema........................................................ 18
3.1 Interfaz de entrada ................................................................................ 18
3.1.1 Entrada de señal LVDS .......................................................................... 18
3.1.2 THC63LVD104. Conversor a niveles TTL ............................................ 19
3.2 Etapa de procesado y análisis de señal ............................................. 20
3.3 Interfaz de salida................................................................................... 21
3.3.1 THC63LVD103. Conversor a niveles LVDS......................................... 21
3.3.2 Salida de señal LVDS............................................................................. 22
3.4 Interfaz de control y comunicación..................................................... 22
4 Diseño y verificación del circuito ......................................................... 24
4.1 Diseño del esquemático....................................................................... 24
4.1.1 Alimentación .......................................................................................... 24
4.1.2 Reset ....................................................................................................... 24
4.1.3 Oscilador y señales de reloj.................................................................... 25
4.1.4 Conversores de nivel .............................................................................. 26
4.1.5 Buses I2C................................................................................................ 26
4.1.6 Configuración de las FPGA.................................................................... 26
4.1.7 Indicadores de actividad y estado........................................................... 26
4.2 Restricciones de diseño....................................................................... 27
4.2.1 Restricciones eléctricas........................................................................... 27
4.2.2 Restricciones espaciales ......................................................................... 28
4.3 Verificación del sistema ....................................................................... 29
4.3.1 Power Up ................................................................................................ 29
4.3.2 Análisis de incidencias ........................................................................... 32

2
5 Diseño de módulos VHDL ..................................................................... 34
5.1 Conversión de entrada ......................................................................... 34
5.2 Conversión de salida............................................................................ 37
5.3 Análisis de regiones ............................................................................. 38
5.4 Contadores de posición ....................................................................... 41
5.5 Captura de imagen................................................................................ 45
5.6 Generador OSD..................................................................................... 49
5.7 Comunicación. Esclavo de I2C............................................................ 51
6 Uso y verificación del sistema completo ............................................. 55
6.1 Montaje provisional del sistema.......................................................... 55
6.2 Montaje y configuración del sistema completo ................................. 57
6.3 Control del sistema LVDS Capturer vía Telnet................................... 59
7 Arquitectura del software ...................................................................... 67
7.1 Desarrollo de librerías .......................................................................... 67
7.1.1 DLL para la comunicación con la ESIIC ............................................... 68
7.1.2 DLL para la obtención de un fichero bitmap.......................................... 71
7.2 Secuencia de test.................................................................................. 73
7.2.1 Análisis de regiones................................................................................ 74
7.2.2 Captura de regiones ................................................................................ 76
8 Implementación en la línea de producción .......................................... 80
8.1 Montaje final y proceso de la máquina de test................................... 80
8.2 Subsecuencia de video adaptada........................................................ 82
8.3 Incidencias ............................................................................................ 84
9 Conclusiones.......................................................................................... 85
10 Bibliografía.............................................................................................. 86
11 Anexos .................................................................................................... 87

3
1 Introducción

Este proyecto tiene como objetivo el desarrollo de un prototipo, hardware y software,


que permita el análisis, la captura y la modificación de la imagen Full-HD de los
televisores LCD Sony. El diseño obtenido se incorporará a un sistema más amplio de
verificación de placas de televisores LCD, dentro de la cadena de producción. Estas
máquinas de test, conocidas como Vitams o CBAs, se encargan de comprobar que la
placa de los televisores LCD funciona correctamente, tanto a nivel eléctrico como
mecánico.

El problema que plantea el sistema actual, y que se pretende solucionar con este
proyecto, consiste en que estas máquinas de test no son capaces de comprobar
exhaustivamente la señal de video enviada al panel. En la actualidad el método que se
lleva a cabo para comprobar la señal de video varía según el tipo de señal entrante al
televisor, permitiendo comprobar que se transmite algún tipo de señal hacía el panel, no
que dicha señal llegue al conector de salida de la placa de TV y mucho menos que la
señal enviada sea la correcta.

Esta comprobación del video de salida, incompleta y poco rigurosa, produce que placas
defectuosas pasen satisfactoriamente por el proceso de verificación y continúen su
camino por la línea de producción detectándose el problema al final, cuando el LCD ya
se encuentra totalmente montado, produciendo un gasto innecesario, tanto material
como humano.

Para solucionar el problema, se propone un sistema que sea capaz de analizar la imagen
de salida antes de que el televisor LCD se empiece a montar. Este sistema debe permitir,
por tanto, analizar la imagen de salida de la placa del televisor en ausencia de cualquier
interfaz visual, ya que en esta etapa de verificación no se dispone de un panel con el que
poder analizar fácilmente la imagen mediante cámaras.

Aprovechando el sistema hardware a desarrollar, se incluye la opción de utilizarlo tanto


para el análisis de la imagen como para la captura de regiones, imitando el
comportamiento de un panel LCD. De esta forma, actuando directamente sobre el
conector de salida de la placa de TV que conecta con el panel, se unifican todos los
métodos de comprobación de imagen en uno, realizando a la vez un análisis mucho más
detallado.

Por último, se desarrolla un software que aprovecha todas las capacidades del hardware
diseñado, permitiendo controlar el sistema a través de un ordenador con conexión
ethernet, y recibiendo por esta misma conexión, tanto los resultados de las regiones
analizadas como la propia región.

4
2 Conceptos básicos
Este capítulo tiene como finalidad presentar los conceptos básicos que pueden aparecer
al hablar de televisores LCD, introduciendo brevemente al lector en la terminología
técnica que rodea a este proyecto. Se aprovecha también para realizar una primera
aproximación al sistema de verificación de las placas de televisores LCD que se utiliza
hoy en día en Sony(Viladecavalls). Finalmente se explica de forma más exhaustiva la
finalidad del proyecto que se presenta en este documento.

2.1 Imagen Full-HD


2.1.1 FHD. Definición y características

El FHD(Full High Definition) es un término que podemos encontrar en cualquier


catálogo actual de televisores o reproductores multimedia. También conocido como
True HD o HD ready 1080p, es un término que hace referencia a una resolución de
pantalla que supera la definición estándar y mejora el concepto de la alta definición que
se tenía hasta el momento.

Entre los principales objetivos que persigue la alta definición se encuentran los
siguientes:

• Aumentar la resolución en los dispositivos de visualización ofreciendo


resoluciones de 1280x 720 píxels o superiores.
• Permitir la transición al formato panorámico (16:9).
• Mejorar la frecuencia de cuadro, es decir, el número de veces por segundo que
una imagen es reproducida.

En el caso de FHD, se garantiza el cumplimiento de las dos primeras características. No


obstante, la última característica no se encuentra totalmente regulada y el fabricante
tiene cierta libertad para decidir la frecuencia de refresco de su dispositivo Full-HD.
Actualmente se están vendiendo equipos con velocidades de refresco de 24, 50 ,60 Hz
aunque empiezan a aparecer en el mercado productos que alcanzan frecuencias
superiores(100, 200, 600 Hz...)

Entrando en el concepto de FHD, esta configuración ofrece una resolución máxima de


1920 columnas y 1080 filas. De esta forma se obtiene una imagen formada por
2.073.600 puntos o píxels.

Que una resolución sea de 1920 x 1080 píxeles no implica que la imagen sea Full HD,
ya que este concepto no depende solo de la resolución que es capaz de alcanzar el
televisor, sino también del modo en que lo hace. Actualmente existen dos modos con
los que se puede alcanzar esta resolución, el modo entrelazado y el modo progresivo,
que respectivamente forman las resoluciones 1080i y 1080p, con i de "interlaced" y con
p de "progressive".

5
Para el caso entrelazado(1080i) se divide la imagen en 2 partes del mismo tamaño y en
cada refresco solo se actualiza una de estas partes, más concretamente en un refresco se
actualizan las columnas impares y en el siguiente las pares. Este comportamiento
fraccionado no es totalmente percibido por el usuario ya que al realizarse a altas
velocidades ambas imágenes se acaban fusionando. En el peor de los casos se puede
llegar a detectar una ligera sensación de parpadeo.

Por otra parte, el escaneado progresivo genera en cada refresco todas las columnas de la
imagen en orden, por tanto si en ambos casos 1080i y 1080p tenemos la misma
velocidad de refresco, esto se traduce en que la FHD(1080p) tiene el doble de
definición.

2.1.2 Otros formatos/estándares. Definición y características

Un concepto muy extendido hoy en día es el conocido como "HD Ready". Este
término, que literalmente se traduce como "preparado para la alta definición", no es un
formato sino un distintivo europeo que garantiza que un dispositivo está preparado para
funcionar con alta definición. Un televisor con este distintivo se caracteriza porque
como mínimo es capaz de ofrecer una resolución de 720p, y por tanto, acepta entradas
de alta definición.

Aunque hoy en día los formatos para televisores más frecuentes del mercado suelen ser
del tipo FHD o HD Ready, no hay que olvidar que existe una gran variedad de
estándares clasificados básicamente según su resolución y relación de aspecto.

Figura 1. Formatos de resolución existentes

6
2.2 Señal LVDS

Las siglas LVDS se utilizan para definir un tipo de señalización diferencial de bajo
voltaje ( Low Voltage Differential Signaling). Este tipo de señalización permite la
transmisión a altas velocidades sobre medios de transmisión económicos.

En este sistema la señal se transmite por duplicado, por una de las líneas se envía la
señal con signo positivo y por la otra línea la misma señal pero con signo negativo. El
protocolo LVDS utiliza esta diferencia de tensión entre las dos líneas para codificar la
información.

El funcionamiento en que se basa este protocolo se muestra en la figura 2. El transmisor


inyecta una corriente de unos 3.5mA en una de las líneas dependiendo del nivel lógico
que se vaya a enviar. Si miramos en la figura, podemos apreciar que cuando los
transistores del emisor marcados con + están activados la corriente tiene un sentido, en
el caso de que se activen los marcados con -, la corriente tendrá el sentido contrario.
Esta corriente fluye por la línea de transmisión para finalmente pasar por una resistencia
situada en la terminación de línea del receptor de 100 o 120 Ohms. Después esta
corriente vuelve por la otra línea provocando que la tensión en la resistencia ronde los
350mV. Esta caída de tensión es medida por el receptor LVDS y según su signo se
determina el nivel lógico correspondiente.

Figura 2. Esquema de propagación de una señal LVDS

Una de las ventajas del LVDS consiste en que al usar amplitudes de tensión bajas y
mantener un bajo acoplamiento tanto eléctrico como magnético entre ambas líneas se
reduce drásticamente la cantidad de ruido electromagnético generado. Además al tener
una tensión en modo común muy baja (alrededor de 1,25V) el LVDS puede ser usado
con un amplio rango de circuitos integrados con tensiones de alimentación de 2,5V o
menores. Por otra parte, la baja tensión diferencial (alrededor de 350 mV) provoca que
la comunicación LVDS consuma muy poca potencia comparándola con otros sistemas.

7
Hay que remarcar que el protocolo LVDS no especifica un esquema de codificación
concreto, LVDS es simplemente un mecanismo físico para transportar bits a través de
dos líneas y por tanto no incluye bits de start, stop, etc. Por tanto cualquier codificación
especificada por un usuario puede ser enviada y recibida a través de un enlace LVDS.

El LVDS es a menudo utilizado para la transmisión de datos en serie aunque cuando la


velocidad de transmisión no es suficientemente elevada los datos se pueden transmitir
en formato paralelo(es el caso de los LCDs). A este sistema de transmisión en paralelo
se le conoce como LVDS paralelo, Bus LVDS o BLVDS y consiste en la repartición de
los bits a enviar entre pares de líneas LVDS. La alta velocidad del protocolo LVDS y su
uso de la sincronización de canal permite transportar más datos de los que podrían
enviarse con un bus paralelo normal.

Por último, añadir que la mayoría de los transmisores LVDS están diseñados para
enlaces de transmisión punto a punto, aunque sistemas de bus multipunto se pueden
llevar a cabo usando transmisores LVDS modificados con salidas capaces de
proporcionar una corriente lo bastante elevada como para atacar múltiples resistencias
de terminación.

2.3 Paneles LCD


Una pantalla de cristal líquido o LCD es una pantalla delgada y plana formada por
píxels de color o monocromos colocados delante de un fuente de luz o reflectora.

2.3.1 Funcionamiento

Cada píxel del panel LCD a su vez se divide en tres partes, conocidas como subpíxels,
de color rojo, verde y azul.

Cada subpíxel está formado por una capa de moléculas de cristal liquido alineadas y
situadas entre dos electrodos transparentes y dos filtros de polarización, normalmente
perpendiculares entre si.

Capa 1. Filtro vertical


Capa 2 y 4. Electrodos
Capa 3. Cristal líquido
Capa 5. Filtro horizontal
Capa 6. BackLight

Figura 3. Capas de un Panel LCD

En ausencia de campo eléctrico, la orientación de las moléculas de cristal líquido está


determinada por la adaptación entre superficies. En el caso más típico, las direcciones

8
de alineación de los electrodos son perpendiculares entre sí y las moléculas de cristal
líquido se organizan de forma helicoidal. Debido a esta organización, la luz que
atraviesa el primer filtro, aproximadamente la mitad de la incidente, gira por culpa del
cristal líquido atravesando con la polarización correcta el siguiente filtro y generando
imagen.

Por contra, cuando se aplica un voltaje a los electrodos, las moléculas de cristal líquido
se orientan paralelas al campo eléctrico y dejan de seguir una estructura totalmente
helicoidal. A mayor voltaje aplicado más perpendicular se va volviendo la luz incidente
al segundo filtro de polarización y por tanto en mayor medida será bloqueada.

2.3.2 BackLight. Definición y tipos

Las pantallas LCD actuales no emiten luz propia, por tanto, necesitan luces de alta
potencia en la parte trasera del panel con las que proporcionar el brillo necesario a la
imagen. A esta luz trasera se le conoce como backlight o retroiluminación y existen
diversos tipos:

CCFL(Tubo de cátodo frío): Consiste en usar tubos fluorescentes. Es la opción más


antigua que existe en el mercado, no obstante sigue dominando todavía debido a su
precio, considerablemente menor que los basados en LEDs.

LEDs: Consiste en usar diodos LED. Éstos emiten luz blanca muy brillante,
consumiendo menos energía y desprendiendo menos calor que los CCFL. Además, el
tiempo de vida de un LED es muy superior al de los tubos fluorescentes. También
proporcionan una mayor gama cromática y una iluminación más uniforme en todo el
panel. Su mayor precio respecto a los CCFL ha provocado que su cuota de mercado
por el momento sea reducida, extendiéndose su uso en los LCDs de alta gama.

OLEDs: Utiliza diodos orgánicos emisores de luz, que se basan en una capa
electroluminiscente formada por una película de componentes orgánicos que
reaccionan a una determinada estimulación eléctrica, generando y emitiendo luz por sí
mismos. Esta nueva generación, que actualmente se encuentra en fase de desarrollo,
supera las limitaciones de los LCD-TFT actuales permitiendo que sean más delgados
y flexibles, ofreciendo mayor brillo y contraste. Además ofrecen mayor ángulo de
visión y menor consumo. Al encontrarse en fase de desarrollo y debido a que el
formato LED aún no es el predominante en el mercado, los fabricantes de televisores
LCDs han decidido retrasar su lanzamiento, haciendo imposible encontrar cualquier
dispositivo en el mercado que trabaje con esta tecnología.

9
2.3.3 Interfaz de entrada

Normalmente, un panel LCD tiene dos conectores de entrada, aunque hay casos en que
ambos conectores se integran en uno solo. Por uno de ellos se reciben las señales de
control y los bits de RGB, transmitidos en forma de señales diferenciales, que formarán
la imagen. El otro conector suele recibir la salida de un circuito conocido con el nombre
de inverter, encargado de coger una tensión de entrada DC e invertirla a una tensión AC
de alto voltaje, esta tensión posteriormente se aplica a los fluorescentes que generan el
backlight del panel.

En este apartado nos centraremos en las señales transmitidas por el conector de datos, el
encargado de transferir al panel la sincronización y los bits que conformarán la imagen.

En el caso de un panel FHD, el conector se divide en dos subpartes, una referente a los
píxels impares, y otra a los píxels pares. Cada subparte está formada por 4 pares de
líneas diferenciales, encargadas de transmitir los valores R,G y B de cada píxel, y una
línea de reloj de 74.25 MHz, también diferencial, para sincronizar dichos píxels.

Input Terminal
Píxeles impares Píxeles pares
RO0- RE0-
RO0+ RE0+
RO1- RE1-
RO1+ RE1+
RO2- RE2-
RO2+ RE2+
RO3- RE3-
RO3+ RE3+
ROCLKIN- RECLKIN-
ROCLKIN+ RECLKIN+
Figura 4. Líneas diferenciales entrantes a un LCD

En el conector también puede encontrarse una línea de entrada, denominada LVDS


option. Esta señal permite elegir entre dos posibles interpretaciones de los datos
enviados por cada par diferencial. Las figuras 5 y 6 muestran la ordenación de los 24
bits que forman un píxel (8 Red, 8 Green, 8 Blue) en un panel FHD para cada una de las
configuraciones existentes, NS y JETDA. Si se observan detenidamente se puede
apreciar que el único cambio entre los dos formatos consiste en la colocación de los 8
bits de cada uno de los tres colores en cuatro tramas de 7 bits.

10
Figura 5. Ordenación de trama en formato NS

Figura 6. Ordenación de trama en formato JETDA

11
En las dos figuras anteriores cada hexágono representa un bit concreto. Por ejemplo, RX
representa el bit X del byte de color rojo, de igual manera ocurre con GX y BX.
También podemos apreciar que aparte de los bits correspondientes a los 24 bits de color,
aparecen dos señales más, DE y NA. DE es la señal de control que indica el inicio de un
nueva imagen o de una nueva línea. Su funcionalidad es claramente de sincronización y
permite junto con la señal de reloj, la representación correcta en el panel de cada píxel
enviado. En la figura 7 se puede observar como la señal DE indica el inicio de un nuevo
frame generando un pulso acompañado de un tiempo de silencio Tblk(v). Después de
este periodo de silencio aparecen pulsos de forma continuada, donde cada uno de ellos
indica el inicio de una nueva línea de la imagen, así hasta el siguiente tiempo de silencio
Tblk(v) que indicará el inicio del siguiente frame.

Figura 7. Sincronización vertical usando únicamente la señal DE

La figura 8 detalla los datos enviados durante el intervalo en el cual la señal DE se


encuentra a nivel alto, es decir, cuando estamos dentro de la zona visible de una nueva
línea. Se puede apreciar como la imagen se divide en dos canales, uno que transporta los
pixels pares y otro los impares. Durante el tiempo en que la señal DE se encuentra a
nivel bajo, nos encontramos fuera del margen visible de la pantalla, y por tanto, los
datos no son válidos.

Figura 8. Sincronización horizontal usando únicamente la señal DE

12
Por otra parte, los campos marcados con NA en las figuras 5 y 6, corresponden en teoría
a posiciones vacías, no obstante 2 de los 3 campos marcados con NA, los
correspondientes a la línea diferencial RIN2, transportan dos señales de gran utilidad
VSYNC y HSYNC. Estas señales realizan prácticamente la misma funcionalidad que la
señal DE, indican del inicio de un nuevo frame y de una nueva línea respectivamente.

Por tanto, en la práctica existen dos formas de sincronización: una utilizando la señal
DE, y otra forma más popular, utilizando las líneas de sincronización vertical y
horizontal. No obstante, existe una gran diferencia entre ambos métodos. En la señal
VSYNC aparece un pulso cada vez que se inicia un frame, y en la señal HSYNC
aparece un pulso cada vez que se inicia una línea, pero que se inicie una línea no
implica que nos encontremos en la zona visible de la pantalla. Tras un pulso de
HSYNC pasan múltiples ciclos de reloj antes de que nos encontremos en la parte útil de
la pantalla y hasta que no llega este momento, no se están enviando píxels. Esto no
ocurre en el caso de sincronización mediante DE, ya que justo en el momento en que la
señal DE se activa, ya se encuentra en el bus el valor del primer píxel. Esto hace que la
sincronización mediante DE sea más cómoda de usar que la basada en H/VSYNC.

2.4 El entorno

En este proyecto se diseña un sistema que permite analizar la imagen de salida de la


placa principal de los televisores LCD Sony. Esta placa contiene todos los conectores de
entrada de imagen como puede ser HDMI, DVI, Scarts, S-Video y se encarga de
procesar la imagen que le llega, o incluso crearla por sí misma. Esta señal, una vez
procesada, se envía a través de un cable formado por pares de líneas LVDS hacia el
panel, que es el encargado de interpretar estos datos y representarlos, tal y como se ha
descrito en el capítulo anterior.

Conseguir este objetivo no implicaría un gran desarrollo si ya dispusiéramos del


televisor totalmente montado. Bastaría con colocar una cámara al final de la cadena de
producción que capturase la imagen que sale del televisor, la enviase al ordenador y allí
se analizase. No obstante, esta opción conlleva un gran problema: no saber si la imagen
de salida es correcta hasta el final de la cadena de producción. En caso de que no lo
fuese, se podría deber, entre otros motivos, a un problema con la placa principal, con el
panel o incluso con el cableado interno. De todos modos, se habrían dedicado recursos a
montar un televisor que no funciona correctamente, teniendo que desmontarlo, repararlo
y volver a montarlo.

Para detectar errores similares a estos antes de que el monitor esté totalmente montado,
Sony dispone de máquinas de test, conocidas como Vitams o CBAs. Estas máquinas se
situan después de la etapa de montaje de las placas de televisión, punto en que no se
dispone ni de panel, ni de cableado. La figura 9 se muestra una placa de un televisor
LCD, justo después de su montaje y lista para introducirse en la máquina de test.

13
Figura 9. Placa de TV del modelo EX2N.
En amarillo, el conector de salida LVDS hacía el panel

Los Vitams o CBAs por un lado incorporan unas secuencias de test que controlan las
electroválvulas que permiten introducir conectores, señales y alimentación a las placas.
Una vez las placas tienen todo lo que necesitan para funcionar, la máquina comprueba
que la placa, TV PCB (Print Circuit Board) en adelante, funciona correctamente, tanto a
nivel eléctrico como mecánico.

Figura 10. Máquina de test o CBA

14
Aunque en este proceso se comprueba gran parte del funcionamiento de la TV PCB,
esta comprobación no es exhaustiva. Una de las comprobaciones no realizadas es el
caso que nos incumbe, la salida de imagen hacia el panel. En la actualidad, los
VITAMS, en cuanto a lo que imagen se refiere solo comprueban que la TV PCB
produce algún tipo de señal, pero no que dicha señal llegue al conector de salida, y
mucho menos que la señal de salida sea correcta.

Así, el proyecto que se presenta, nace con la finalidad de ampliar las verificaciones que
realiza dicha maquina de test. Como objetivo se plantea el desarrollo de un sistema
completo, hardware y software, que permita la captura y el análisis de la imagen de
salida de los televisores LCD Sony.

2.5 Máquinas de test


Los Vitams o CBAs, como se ha comentado antes, son las máquinas de test donde se
verifican las PCB TV que se han fabricado, antes de continuar con la cadena de montaje
que dará como resultado un televisor LCD.

En la figura 10 se puede observar que estas máquinas de test están formadas por una
gran cantidad de dispositivos: ordenador, electroválvulas, fuente de alimentación,
generadores de señal, etc. Debido a que detallar el funcionamiento de esta máquina no
es el objetivo de este documento, solo comentaremos la parte que tiene relación directa
con el proyecto, es decir, la parte hardware/software que controla gran parte de este
sistema, la ESIIC.

Figura 11. Placa de desarrollo ESIIC

15
La ESIIC(Ethernet Specific Interface I2C) es un sistema compuesto por un kit fabricado
por Altera y una plataforma diseñada por Sony. El sistema que se desarrollará en este
proyecto deberá mantener una comunicación con la ESIIC, ya que a través de ésta se
llevará a cabo tanto el control como el envio de información hacia el ordenador.

El kit de Altera proporciona todo lo necesario para el desarrollo SOPC (System-On-


Programable-Chip). Utiliza una FPGA (Field Programable Gate Array) económica del
tipo Cyclone II. La plataforma trabaja sobre un entorno Nios II, con sistema operativo
en tiempo real y comunicación con el ordenador vía TCP/IP.

Figura 12. Kit de desarrollo Nios II, edición Cyclone II

La plataforma diseñada por Sony es una placa conectada al kit anterior. Esta plataforma
actúa como dispositivo periférico y su finalidad es controlar gran parte del proceso de
verificación que realiza el VITAM. Entre sus principales características se puede decir
que tiene gran número de pines de entrada y salida, ya que consta de 2 FPGAs Cyclone,
es capaz de generar y recibir audio en múltiples formatos, dispone de switchs de HDMI
y genera VGA. No obstante, nosotros la usaremos, más que por estos periféricos,
porque nos facilitará el proceso de comunicación al disponer de las siguientes
características:

• Permite establecer una comunicación TCP/IP con el ordenador. Además al tener


implementado un sistema en Nios II, permite programar la FPGA en un lenguaje
de programación llamado MicroC, similar a C. De esta forma, estableciendo una
comunicación TCP/IP desde el ordenador se puede controlar la ESIIC
totalmente, así como recibir los resultados de ella.

• Las FPGAs de la plataforma diseñada por Sony tienen programados en lenguaje


VHDL masters para buses I2C. El bus I2C, es un bus muy común, que usando
dos líneas, una para el reloj y otra para datos, permite implementar una
comunicación entre dispositivos a baja velocidad. Actualmente se usa en diseños
profesionales para traspasar información entre integrados, y como se detallará en
futuros apartados, esto facilitará la etapa de comunicación con nuestro sistema.

16
Figura 13. Plataforma de la ESIIC. A la izquierda cara top, a la derecha cara bottom

2.6 LVDS Capturer


Con la finalidad de realizar un análisis de la imagen en las máquinas de test, unificado y
preciso, se plantea en este apartado un sistema hardware, de forma general, que permita
capturar y procesar la imagen que se envía desde la TV Board hacia el panel, aunque
este último no se encuentre conectado. A este sistema le llamaremos LVDS Capturer.

Debido a que la entrada de la placa LVDS Capturer será la imagen que sale por el
conector LVDS de la TV, se decide usar como conexionado el mismo tipo de cable que
se usa para conectar la placa de TV al panel.

La señal correspondiente a la imagen debe pasar de forma transparente a través de la


placa LVDS Capturer, de esta forma conectando un panel en salida de la placa se puede
comprobar si la señal pasa correctamente a través de nuestro diseño, así como observar
posibles cambios que se hayan efectuado sobre la imagen de entrada.

Al pasar la imagen por nuestro hardware, éste debe ser capaz de seleccionar y analizar,
en tiempo real, zonas de la imagen o incluso la imagen FHD completa. En caso que se
desee, aunque no es la finalidad de este hardware, también debe permitir la captura y
almacenamiento de la imagen.

El resultado del análisis o incluso la propia región de imagen seleccionada, se enviará a


través del bus I2C aprovechando la infraestructura para este protocolo parcialmente
implementada en la ESIIC. Por último estos datos serán enviados hacía el ordenador a
través de una comunicación TCP/IP.

Figura 14. Estructura del sistema propuesto

17
3 Descripción detallada del sistema
En el capítulo anterior se ha introducido al lector en el entorno que rodea nuestro
sistema. También, de forma algo genérica, se ha mostrado la finalidad y las
funcionalidades que deseamos que tenga el sistema desarrollado, así como la relación
que existirá entre la plataforma ESIIC y la placa LVDS Capturer.

Una vez dadas las nociones básicas, procederemos a describir con detalle las partes que
forman el sistema, y propondremos soluciones a los problemas que se irán presentando.

3.1 Interfaz de entrada


De forma generalizada, por interfaz de entrada incluimos tanto la recepción del señal
procedente de la placa de TV como la conversión de las señales diferenciales a niveles
TTL, fácilmente analizables.

3.1.1 Entrada de señal LVDS

Para evitar la fabricación y el montaje de cables LVDS, formados por gran cantidad de
líneas que a la vez requieren gran precisión en su montaje, se decide utilizar el mismo
cable que utiliza la placa de TV EX2N para conectar con su correspondiente panel. De
esta forma se reducen por un lado posibles problemas relacionados con un montaje
incorrecto, por otra parte en caso de avería es fácilmente sustituible y por último, el
sistema diseñado para testear la imagen de salida será aún más parecido al caso real de
un televisor LCD.

En la figura 9 se muestra el conector de LVDS de salida de la placa de TV para el


modelo EX2N. Este modelo es uno de los más fabricados por Sony y por tanto, de cara
al desarrollo del prototipo que se presenta en este documento nos basaremos en su
interfaz de salida.

El cable de líneas diferenciales LVDS que conecta por un extremo con este conector y
por el otro con el panel será el mismo que usaremos para interconectar la placa de TV
con la placa LVDS Capturer. Por este cable viajan multitud de señales, la mayoría
diferenciales, que contienen entre otras informaciones, los bits de la imagen que se está
enviando hacía el panel, o en nuestro caso, hacia el capturador de señales LVDS.

18
Línea cable LVDS Señal Tipo de Línea
1-5 VCC Alimentación para el inverter del panel
6-9, 16, 19, 24,31,34,39 GND Masa
10,11 RO[0] Línea diferencial impar 1( O=odd)
12,13 RO[1] Línea diferencial impar 2( O=odd)
14,15 RO[2] Línea diferencial impar 3( O=odd)
20,21 RO[3] Línea diferencial impar 4( O=odd)
17,18 ROCLK Línea diferencial de reloj. Píxels impares
25,26 RE[0] Línea diferencial par 1( E=even)
27,28 RE[1] Línea diferencial par 2( E=even)
29,30 RE[2] Línea diferencial par 3( E=event)
35,36 RE[3] Línea diferencial par 4( E=even)
32,33 RECLK Línea diferencial de reloj. Píxels pares
45 LVDS OPTION Orden de codificación de la trama enviada( NS o JETDA)
Figura 15. Contenido de las líneas que forman el cable de LVDS (visto desde el panel)

3.1.2 THC63LVD104. Conversor a niveles TTL

Como se ha comentado en el apartado dedicado a los paneles LCD, toda la información


referente a la imagen es enviada a través de líneas diferenciales del tipo LVDS
aprovechando las altas velocidades y la inmunidad al ruido que este tipo de transmisión
ofrece. No obstante, estas características que de cara a la transmisión son idóneas, de
cara al procesado de señal presentan grandes inconvenientes. Por un lado tratar con
señales diferenciales directamente complica el procesado de la información. Además,
las familias de integrados que permiten como entradas este tipo de señales es más
limitada que las de niveles TTL. Deseando facilitar lo máximo posible el procesado de
la información recibida, se decide deserializar la trama LVDS y realizar una conversión
de esta información a niveles TTL estándares de 3,3V.

Para llevar a cabo esta conversión utilizamos el integrado THC63LVD104 de THine.


Este dispositivo soporta la recepción de datos a muy altas velocidades, permitiendo
resoluciones de todo tipo, desde las más básicas como la NTSC hasta WXGA. Este
integrado convierte tramas de datos de imagen en formato LVDS en 35 bits de niveles
CMOS/TTL, 30 de datos y 5 de sincronización y control. Además permite fijar el
instante de conversión por flanco de subida o de bajada del reloj, según el tipo de
controlador del LCD.

19
Figura 16. Diagrama de bloques de la conversión realizada por el THC63LVD104

Como se aprecia en la figura 16, este integrado tiene un máximo de 5 líneas


diferenciales de entrada más una adicional para la señal de reloj. En cambio si miramos
la tabla de la figura 15, nosotros utilizamos 4 líneas más una de reloj para los píxels
impares y la misma cantidad para los píxels pares, por tanto, necesitamos utilizar dos de
estos conversores, uno para los píxels pares y otro para los impares. Además como
dejaremos sin usar la línea diferencial RE+/- el número total de líneas de salida será de
29 (28 de datos y una de reloj).

3.2 Etapa de procesado y análisis de señal


Una vez disponemos de los datos en niveles TTL, basta con enviarlos a un dispositivo
programable para realizar el posterior análisis de la señal.

A la hora de decidir el dispositivo a usar para este análisis se han barajado distintas
posibilidades, eligiendo finalmente una FPGA por los siguientes motivos:

• El uso de FPGAs está muy extendido a la hora de desarrollar prototipos. Éstas


vienen acompañadas de un software de diseño que permite hacer uso del
lenguaje VHDL para traducir comportamientos complejos a un nivel hardware.

• Son reprogramables y el tiempo de desarrollo se reduce considerablemente.

• Gran stock de FPGAs Cyclone II de Altera en Sony, debido a que un modelo de


televisor antiguo las incorporaba.

En base a los anteriores motivos decidimos usar como núcleo de procesado la FPGA
Cyclone II EP2C8T144C7N de Altera, que dispone de 85 pines de entrada/salida
para usuario.

20
Teniendo en cuenta que uno de los requisitos que marcamos en el proyecto es que la
señal tenía que poder pasar a través de la placa LVDS Capturer de forma
transparente, necesitamos que las 29 líneas que salen del conversor LVDS a TTL
entren a la FPGA por 29 pins de entrada y salgan por otros 29 pins de salida. En
resumen, 58 pins de los 85 disponibles ya son ocupados solo con el paso de la señal
hacía el panel. Si además reservamos algunos pines para la etapa de comunicación
posterior y la colocación de algunos indicadores visuales del estado de la FPGA, se
puede ver que solo los bits correspondientes a los píxels pares ocupan una FPGA
entera, por tanto necesitamos otra para los píxels impares, siguiendo de esta forma
con la simetría par/impar que también hemos fijado en los conversores de entrada.

3.3 Interfaz de salida


Igual que para la interfaz de entrada, incluimos dentro de la interfaz de salida tanto la
conversión de la señal de niveles TTL a LVDS como la posterior transmisión de esta
señal hacía el panel.

3.3.1 THC63LVD103. Conversor a niveles LVDS

Como se ha dicho en apartados anteriores, la señal que llega del televisor y pasa por las
FPGAs, debe poder enviarse en el caso que sea deseado hacía un panel LCD, de esta
forma se podrían visualizar las modificaciones que realicemos en la imagen, o
simplemente verificar que la señal pasa por el sistema sin degradarse. Para poder
insertar esta imagen en el panel antes debemos devolverla a su estado inicial, es decir, al
formato LVDS que teníamos antes de pasar por los conversores de entrada.

Para realizar esta conversión utilizamos otro integrado de la marca THine, el


THC63LVD103. En este caso, el dispositivo es un transmisor que soporta la
transmisión entre una fuente de datos y un panel a resoluciones elevadas, hasta SXGA.
De forma análoga al otro conversor, éste convierte 35 líneas de entrada de niveles TTL
en 5 pares diferenciales más otro par diferencial para el reloj.

Figura 17. Diagrama de bloques de la conversión realizada por el THC63LVD103

21
Los siete bits correspondientes a TE0-6 no los usamos, la línea diferencial TE+/-
tampoco, y por tanto volvemos a tener las cuatro líneas diferenciales más una de reloj,
que era exactamente la mitad de la información que nos llegó a la placa LVDS Capturer
desde la televisión. Para seguir con la dualidad necesitamos dos conversores de TTL a
LVDS, uno para píxels pares y otro para impares.

3.3.2 Salida de señal LVDS

Por los mismos motivos que se detallaron en el apartado 3.1.1 se decide utilizar para la
conexión entre la placa LVDS Capturer y el panel, el mismo cable que utiliza el
televisor en su estado final para unir la placa de TV con el panel.

Así el conector que debemos introducir en nuestro diseño es el que corresponde al otro
extremo del cable LVDS, es decir, el que inicialmente conectaba con la placa de
televisión, y por tanto la numeración de las líneas es distinta.

Línea cable LVDS Señal Tipo de Línea


2,4,6,8,10 VCC Alimentación para el inverter del panel
12,24,26,28,30,32,34,36 GND Masa
37,39 RO[0] Línea diferencial impar 1( O=odd)
33,35 RO[1] Línea diferencial impar 2( O=odd)
29,31 RO[2] Línea diferencial impar 3( O=odd)
21,23 RO[3] Línea diferencial impar 4( O=odd)
25,27 ROCLK Línea diferencial de reloj. Píxels impares
17,19 RE[0] Línea diferencial par 1( E=even)
13,15 RE[1] Línea diferencial par 2( E=even)
9,11 RE[2] Línea diferencial par 3( E=event)
1,3 RE[3] Línea diferencial par 4( E=even)
5,7 RECLK Línea diferencial de reloj. Píxels pares
18 LVDS OPTION Orden de codificación de la trama enviada( NS o JETDA)
Figura 18. Contenido de las líneas que forman el cable de LVDS (visto desde el televisor)

3.4 Interfaz de control y comunicación


En los anteriores apartados se han descrito las interfaces de entrada y salida del sistema,
así como el bloque donde se llevará a cabo el análisis de la imagen. No obstante, falta
por determinar un punto importante: cómo se controla el sistema y a través de qué
interfaz se establece esta comunicación.

Para poder seleccionar un tipo de comunicación, debemos tener en cuenta un par de


aspectos respecto al modo de funcionamiento que se desea tener. Inicialmente deseamos
que el sistema sea transparente, es decir, conectando en un lado una placa de TV y en el
otro extremo un panel, el comportamiento debería ser el de una televisión normal. Por
otro lado, deseamos que bajo demanda el sistema sea capaz de analizar regiones,

22
modificar la imagen de salida, capturar imagen y guardar los resultados para que
posteriormente sean leídos desde otro dispositivo.

Este comportamiento bajo demanda a implementar es muy similar al comportamiento


de cualquier dispositivo esclavo en un bus: no tiene la habilidad de iniciar una
comunicación con otro dispositivo por sí mismo y si no se le realiza ninguna petición no
transmite información por el bus.

Además, si recordamos que la comunicación con el ordenador que controla la máquina


de test se debe realizar a través de la plataforma ESIIC vía comunicación TCP/IP, es
necesario que estas peticiones a la placa LVDS Capturer las realice esta plataforma. La
ESIIC tiene implementados masters de bus I2C que se usan interactuar con algunos
integrados de las placas de TV. Aprovechando estos masters de I2C ya desarrollados, se
decide utilizar el protocolo I2C para llevar a cabo el control y la lectura de información
de la placa LVDS Capturer.

El inconveniente que plantea este protocolo de comunicación es que necesitamos


desarrollar un esclavo de I2C personalizado según nuestras necesidades en lenguaje
VHDL para incorporarlo a las FPGAs.

Conversor FPGA Conversor


5 LVDS Pairs Odd Pixel TTL Cyclone II Odd Pixel TTL 5 LVDS Pairs
LVDS-TTL TTL-LVDS

LVDS Input I2C LVDS Output


Conector To ESIIC Conector Conector

Conversor FPGA Conversor


5 LVDS Pairs Even Pixel TTL Even Pixel TTL 5 LVDS Pairs
LVDS-TTL Cyclone II TTL-LVDS

Figura 19. Diagrama de bloques completo del sistema LVDS Capturer propuesto

23
4 Diseño y verificación del circuito

Una vez detallada la arquitectura del sistema, se procede al desarrollo de un prototipo.


La finalidad de este prototipo es comprobar si el sistema es funcional, y por tanto,
permite el análisis y la manipulación de la imagen con una calidad y velocidad
aceptable.

4.1 Diseño del esquemático


4.1.1 Alimentación

En nuestro sistema podemos encontrar cuatro alimentaciones distintas:


• 5V que proceden de la fuente de alimentación y que se utilizan para alimentar a
unos pocos integrados, entre ellos, un oscilador de 40 MHz.
• 3.3V para alimentar a la mayoría de los integrados del sistema. Utilizados
también por las FPGAs para las tensiones de salida de sus pins de I/O.
• 1.2V para la alimentación interna de las FPGAs.
• 2.5V que se incorporan de forma opcional. Se habilita la opción de poder utilizar
estos 2.5V en vez de los 3.3V para los pins I/O de la FPGA, así como para la
alimentación de los conversores THine.

En base a la variedad de tensiones utilizadas se hace necesario el uso de tres reguladores


de tensión, dos para la conversión de 5V a 3.3 o 2.5V, y otro más para el paso de 3.3V a
1.2V.

4.1.2 Reset

Con la finalidad de disponer de una señal de reset para las FPGAs se propone el uso del
integrado TLC77331D. Este integrado genera una señal de reset a partir de la actuación
sobre un pulsador externo o mediante una señal de control, además la duración de la
señal de reset es fácilmente configurable a través de un condensador externo. En nuestro
caso incorporamos las dos opciones, la manual y una señal controlable desde la ESIIC
por si deseamos realizar un reset vía software de las FPGAs.

24
Figura 20. Esquemático del módulo de reset

4.1.3 Oscilador y señales de reloj


Para asegurar unas velocidades elevadas en el sistema incorporamos un oscilador de 40
MHz. El hecho de incorporar este oscilador no implica que todos los bloques
desarrollados en VHDL funcionen con esta señal de reloj. En realidad la mayoría de los
bloques relacionados con la imagen deben funcionar sincronizados a través de la señal
de reloj procedente de los conversores LVDS a TTL, que traducen la señal diferencial
de reloj proporcionada por la placa de televisión a una señal TTL de 74.25 MHz.
Recordamos que cada conversor produce una señal distinta de 74.25 MHz, pero una
sincroniza los píxels pares y otra los impares.

En otro tipo de diseño, donde se asegurase la existencia de estas señales de reloj de


74.25 MHz, se podría utilizar esta señal como única señal de clock para las FPGAs,
reduciendo así el gasto y el número de dispositivos a incluir en el diseño. No obstante,
considerando que nuestro sistema debe verificar la salida de imagen LVDS que se dirige
al panel, en caso de que no hubiese imagen debido a cualquier error en la placa de TV,
las placas LVDS Capturer tampoco funcionarían.

Por último remarcar, que las dos señales de clock, de 40MHz y de 74.25 MHz, no se
pueden introducir en cualquier pin de entrada de la FPGA. Si no tenemos en cuenta este
detalle podría darse el caso de que varios módulos implementados dentro de la misma
FPGA, que funcionan con la misma señal de reloj, no trabajen de forma coordinada, y
por tanto el resultado podría no ser el esperado. Este suceso ocurre porque la señal que
llega a un pin de entrada corriente no se reparte de forma equitativa por todas las partes
del dispositivo, esto provoca retardos entre distintos bloques hardware, es lo que se
conoce como skew. Para solucionar este problema las FPGAs suelen tener pines de
entrada dedicados para señales de reloj. Estos pins especiales se reparten de forma
equitativa por todas las partes del hardware interno, de esta forma se garantiza la calidad
y la sincronización de la señal en todo el dispositivo.

25
4.1.4 Conversores de nivel

Como se ha explicado en el capítulo anterior, para realizar el paso de LVDS a TTL y


viceversa se necesita un total de 4 conversores. Ambos tipos de conversores constan de
tres señales de control que permiten habilitar el dispositivo y fijar el flanco del reloj en
el cual se realiza la conversión. Con la finalidad de tener un control sobre estas señales
se decide enviarlas a sus respectivas FPGAs, por tanto cada una de estas FPGAs tienen
seis líneas de control, tres por cada conversor.

4.1.5 Buses I2C


Tal y como se ha detallado en el capítulo anterior, el bus utilizado para controlar y
comunicar con la placa LVDS Capturer es un I2C. Debido a este protocolo de
comunicación cada FPGA debe contener un esclavo de I2C programado en VHDL y
esto implica que las dos líneas que forman este tipo de bus, SDA(Datos) y SCL(Clock),
deben estar conectadas a las FPGAS.
En el diseño del bus de comunicación se implementan dos opciones de control:

• Un único master de I2C controla los esclavos de I2C de las dos FPGAs.
• Se utilizan dos masters de I2C. Cada uno controla el esclavo de una FPGA.

4.1.6 Configuración de las FPGA


Existen diversas opciones para realizar la grabación del sistema que se desea
implementar dentro de las FPGAs, aunque las más utilizadas son: active serial y JTAG(
Join Test Action Group).

El active serial permite la grabación de un fichero .pof en una memoria externa, que
debe incluirse en el diseño. Este sistema tiene la ventaja de que el contenido que se
desea implementar en la FPGA se almacena en una memoria, y cada vez que se reinicia
el sistema, la FPGA lee la información que contiene esta memoria para configurarse de
forma automática.

La otra posibilidad de grabación, hace uso del sistema de test JTAG, para grabar un
fichero .sof de configuración en la memoria volátil de la FPGA. Este sistema permite
depurar fácilmente el sistema implementado dentro del dispositivo, no obstante su
duración es temporal. Al resetear, la información de configuración ha desaparecido y es
necesario repetir el proceso.

4.1.7 Indicadores de actividad y estado


Para comprobar el correcto funcionamiento del sistema y facilitar el proceso de
depuración se incorporan una serie de LEDs:
• Un LED de grandes dimensiones. Indica si el sistema esta siendo alimentado.
• Un LED para ra informar sobre el proceso de configuración de las FPGAs
• Un grupo de 5 LEDs para cada FPGA para facilitar el proceso de desarrollo y
depuración a nivel VHDL.

26
4.2 Restricciones de diseño
Una vez comentadas las principales del hardware del proyecto queda remarcar un
aspecto importante que forma parte de todo diseño electrónico, las restricciones.

4.2.1 Restricciones eléctricas

Una restricción o condición importante que se debe tener en cuenta a la hora de realizar
un circuito impreso que trabaja a altas velocidades, como es el caso de las señales
LVDS, consiste en fijar unas normas para el enrutado de este circuito. La comunicación
vía señales LVDS, como se ha comentado en capítulos anteriores, se basa en pares de
líneas diferenciales D- y D+, y la relación diferencial entre estas dos líneas en el
receptor permite identificar el valor lógico de los bits recibidos. En base a lo anterior, si
ambas señales de alta velocidad sufren la misma distorsión o son afectadas por el
mismo ruido, el receptor no tendrá problema para detectar correctamente el valor
recibido, ya que al receptor lo que le interesa es únicamente la diferencia entre ambas
señales, y no el valor absoluto de estas.Por tanto, se puede decir que una señalización
diferencial presenta una gran robustez frente a ruidos o interferencias externas, lo que le
permite trabajar a velocidades muy elevadas y con niveles de tensión reducidos.

No obstante, para que estas ventajas puedan conseguirse hay que cuidar el diseño del
circuito impreso. El motivo es simple, si estas pistas diferenciales, que forman el
protocolo de comunicación LVDS, se enrutasen de forma independiente, cada una
siguiendo un recorrido distinto, cada pista se vería afectada por interferencias distintas y
esto se traduciría en problemas a la hora de descodificar. Además, si la longitud de las
pistas o incluso los ángulos no son prácticamente iguales, una de las líneas se retardaría
más y por tanto, la decodificación en el receptor se dificultaría.

Para asegurar que la señal LVDS llega a su destino en condiciones óptimas, se deben
asegurar las siguientes normas de diseño:

1. Las líneas diferenciales deben seguir un recorrido paralelo y próximo.

2. Se debe evitar en el mayor grado las interferencias provocadas por otras zonas del
propio diseño, como podrían ser zonas de alimentación o vías que unen las dos
partes del circuito impreso, que solo afecten a una de las líneas.

Figura 21. Líneas diferenciales enrutadas de forma paralela y simétrica. Ambas líneas son de igual
longitud y se encuentran afectadas de igual forma por la vía.

27
3. Los pares de líneas diferenciales deben ser lo más cortos posible para reducir así
su resistencia parásita.

4. Los pares de líneas diferenciales entre sí deben estar lo más separados posible. Al
ser señales rápidas y de baja tensión tienen gran facilidad para afectar y ser
afectadas por otros pares diferenciales. No es recomendable cruzar pares de líneas
diferenciales aunque estos se encuentren en caras distintas del circuito impreso.

Existen softwares de diseño profesionales, como Altium Designer, que permiten


garantizar el cumplimiento de estas normas de forma automática. Entre otros aspectos,
permite fijar la separación entre pares de líneas diferenciales, la longitud máxima de
las pistas, mantener un enrutado paralelo, e incluso realizar enrutados en S para
obtener una resistencia específica con la finalidad de adaptar la carga y reducir así las
reflexiones. No obstante, debido a que el software de diseño disponible en el lugar
donde se ha llevado a cabo este proyecto es PCAD 2006, un antecesor de Altium
Designer, estas opciones aún no están incluidas, y por tanto se ha intentado cumplir
estas normas de forma manual.

4.2.2 Restricciones espaciales


Otra restricción importante a tener en cuenta consiste en el tamaño máximo disponible
para la placa LVDS Capturer. Anteriormente se ha dicho que este diseño formará parte
de la máquina de verificación global Vitam o CBA, por tanto el espacio máximo
disponible para nuestro diseño dependerá de la posición donde coloquemos la placa
dentro de esta máquina. Al encontrarnos limitados por la longitud de los cables de
LVDS que se utilizan para la televisión, y que deseamos usar para nuestro diseño, la
placa LVDS Capturer deberá situarse lo más próxima posible a la placa de TV una vez
esta se haya introducido en la máquina de test.

En base a esto, el tamaño máximo disponible para la placa LVDS Capturer es de


103x133 cm.

28
4.3 Verificación del sistema

4.3.1 Power Up

Como power up se conoce al proceso de poner en marcha un diseño una vez se ha


montado y se va a probar por primera vez. En esta fase se procede a comprobar el
sistema tanto a nivel eléctrico como funcional, y es donde se pueden encontrar
problemas relacionados con un diseño erróneo o simplemente con un mal montaje de
los componentes. Esto último tiene mucha importancia en el caso de los prototipos ya
que normalmente estos circuitos suelen ser montados de forma manual, y los procesos
manuales suelen ser muy vulnerables a errores humanos.

El problema que plantea el proceso de power up en un sistema con FPGAs es que es


complicado verificar completamente la funcionalidad del sistema. Esto se debe, a que
no podremos saber si el sistema funciona en su totalidad ya que gran parte del
funcionamiento del sistema requiere el diseño de unos cores en lenguaje VHDL que
posteriormente se introducirán dentro de las FPGAs, y en esta etapa de verificación
estos cores aún no se han desarrollado.

En base a la anterior problemática, dentro de este power up solo podemos verificar los
siguientes puntos:
• Obtención de la tensión esperada a la salida de los reguladores
• Funcionamiento correcto de los conversores LVDS-TTL y viceversa.
• Grabación de las FPGAs mediante los dos métodos disponibles.
• Aceptación de la imagen de salida por el panel LCD.

Verificación de la alimentación del circuito

En este primer paso se conecta directamente el circuito a una tensión de 5V procedente


de una fuente de alimentación externa y se verifica mediante el LED grande situado en
la placa, que esta alimentación esta siendo recibida correctamente. Además, la fuente de
alimentación dispone de un sistema de protección que en caso de cruce deshabilita la
alimentación al circuito. Al no haberse activado esta protección podemos garantizar que
el sistema no tiene ningún cruce que manifieste un problema grave de diseño.

A continuación procedemos a medir las tensiones de salida de los reguladores y


comprobamos que son las esperadas, 3.3V, 2.5V y 1.2V.

Grabación de las FPGAs

Para verificar el funcionamiento y los métodos de grabación de las FPGAs, lo más


sencillo es la grabación de cualquier sistema simple en ellas. En nuestro caso,
aprovechando los cinco LEDs de depuración que habíamos incluido en cada FPGA,
creamos un circuito en Quartus II que modifique el estado de éstos.

29
Procedemos inicialmente con la grabación active serial, que hace uso de la memoria
externa, y por tanto, la grabación es permanente. Tras realizar la grabación de la
memoria sin incidentes, realizamos un reset en la placa LVDS Capturer, ya que es en el
momento de arranque cuando la FPGA procede a la lectura de esta memoria. Al
reiniciarse la FPGA, los LEDs se encuentran el estado deseado, garantizando el correcto
funcionamiento del modo de grabación active serial y de la FPGA.

Posteriormente intentamos repetir el proceso con el modo de grabación JTAG. En este


caso detectamos algún tipo de error en el sistema, ya que desde Quartus II somos
incapaces de detectar el dispositivo FPGA al cual deseamos acceder vía JTAG. Debido
a que mediante el método anterior la grabación ha sido correcta, descartamos la
posibilidad de que el problema esté relacionado directamente con la FPGA y nos
centramos en la interfaz de grabación JTAG.

Con la segunda FPGA el resultado es idéntico, el modo JTAG sigue sin funcionar,
incrementando la probabilidad de que la hipótesis sobre el origen del error sea cierta.

Verificación del sistema como bypass

Con esta comprobación deseamos garantizar que por un lado los conversores funcionan
correctamente, y por otro lado que la señal de salida de la placa de LVDS Capturer
mantiene una calidad lo suficientemente buena como para que el panel la acepte sin
problemas, es decir, que la placa LVDS Capturer sea de cara a la señal, transparente.

Hay que decir que lo más correcto sería comprobar uno a uno los conversores, antes de
realizar una comprobación global del sistema como bypass. No obstante, la alta
velocidad y la codificación diferencial del protocolo LVDS hace muy complicado el
proceso de verificación con un simple osciloscopio, por tanto verificando previamente
que los conversores de entrada generan algún tipo de salida en niveles TTL, se pasa al
proceso de verificación global.

Para realizar esta verificación, se debe realizar con Quartus II una conexión de las
señales de entrada de la FPGA que proceden de los conversores LVDS-TTL con las
salidas de la FPGA que conectan con las entradas de los conversores TTL-LVDS.

En total debemos interconectar 28 líneas de datos (7 bits por par LVDS x 4 pares LVDS
de datos), más una línea adicional procedente del par LVDS del clock en cada una de
las FPGAs. Recordamos que la primera FPGA transporta solo los píxels impares y la
segunda los pares, por tanto, si solo realizamos esta conexión en una de las FPGAs el
panel debería mostrar únicamente la mitad de los pixels que forman la imagen.

A continuación debemos fijar en las FPGAs el estado deseado para las 6 líneas de
control que cada FPGA controla, 3 por cada uno de los conversores. Las fijamos de tal
modo que los conversores estén habilitados y que la conversión se realice por flanco de
subida de la señal de reloj.

Por último procedemos a grabar el sistema en las memorias, provocamos un reset en el


hardware para que las FPGAs lean el contenido de éstas y colocamos una de nuestras
placas LVDS Capturer entre la placa de TV y un panel LCD. Introduciendo una carta de

30
grises, comprobamos en las figuras 22 y 23 la imagen que se visualiza en el panel sin y
con placa LVDS Capturer entre ambos dispositivos.

Figura 22.Televisor LCD Sony en estado normal. A la izquierda vista frontal, a la derecha
vista trasera.

Figura 23. Televisore LCD Sony con placa LVDS Capturer entre panel y TV Board. A la
izquierda vista frontal, a la derecha vista trasera.En la imagen frontal se puede llegar a apreciar
unos caracteres de color blanco en la esquina superior derecha, estos son provocados de forma
voluntaria por la placa LVDS Capturer y se detalla su funcionalidad en futuros apartados.

Como se ha podido comprobar, tras pasar por un cable de LVDS, convertirse a niveles
TTL, atravesar las FPGAs y volver a convertirse a nivel LVDS para volver a pasar
finalmente por otro cable LVDS hasta llegar al panel, la señal sigue llegando en un
estado óptimo, sin observarse ningún tipo de degradación en este proceso.

Habiendo superado con éxito esta prueba, podemos garantizar que el sistema podrá ser
totalmente funcional una vez se haya implementado en las FPGAs los módulos de
procesado y comunicación.

31
4.3.2 Análisis de incidencias

Una vez comprobado que el sistema realiza las funciones básicas, es el momento de
solucionar los incidentes que han aparecido.

Básicamente el sistema no ha presentando ningún incidente de importancia a nivel


funcional. No obstante, se ha detectado algún pequeño error cometido con el software
de diseño PCAD, que ha requerido la realización de varios reworks(modificaciones)
sobre el hardware del prototipo.

El modo de grabación y depuración JTAG nunca funcionó. Este problema es debido a


un error cometido en el diseño del esquemático, realizado en PCAD. El protocolo JTAG
esta formado por 2 líneas de datos, una de entrada y una salida, TDI y TDO, un reloj
TCK y la línea TMS, que indica el modo en que se desea utilizar el protocolo JTAG.
Las líneas TMS y TDI, para el correcto funcionamiento del protocolo JTAG requieren
una resistencia de pull-up de 1000 ohms en los pines de entrada/salida de las FPGAs.
Un error en el esquemático provocó que ambas resistencias de pull-up se aplicasen
sobre la línea de entrada de datos TDI. Al no encontrarse la línea TMS a nivel alto en
estado de reposo, el protocolo se encontraba en bloqueo, impidiendo la detección y la
grabación de las FPGAs. Tras colocar sobre estas líneas la resistencia de pull-up, el
sistema de grabación vía JTAG pasó a funcionar correctamente.

Las memorias que almacenan los ficheros .pof de configuración para las FPGAs deben
alimentarse a 3.3V, no obstante están siendo alimentadas a 5V. Aunque el datasheet
indica que su sistema de protección interno permite su funcionamiento con tensiones
más elevadas, se decide por seguridad modificar su tensión de alimentación a los 3.3V
recomendados. Como disponemos de una memoria para cada FPGA, se deben realizar
dos modificaciones sobre el hardware.

Los dos puntos anteriores, describen los dos reworks fundamentales. De todos modos,
se ha realizado alguna modificación adicional relacionada con el bus de comunicación
I2C, que se detallará en los próximos capítulos, con la finalidad de aumentar la
velocidad de este bus.

En la figura 24 se puede apreciar la placa LVDS Capturer, en su estado final:

• En marrón los conectores para los cables LVDS. Abajo el conector de entrada
para la señal procedente de la placa de TV, arriba el conector de salida para la
señal que va hacía el panel.
• En lila los conversores de entrada de LVDS a TTL.
• En azul los conversores de salida de TTL a LVDS.
• En rojo las FPGAs Cyclone II.
• En amarillo el conector para la grabación de las FPGAs en modo active serial y
las memorias necesarias para esta grabación.
• En naranja los conectores para la grabación mediante protocolo JTAG.
• En azul celeste el conector para la comunicación I2C. Incluyendo dos
resistencias pull-up para las dos líneas que forman el bus I2C.

32
• En negro el conector de entrada para la alimentación. Incluyendo un filtro
externo para los 5V de entrada.

Figura 24. LVDS Capturer Board en su estado


final. Todas las modificaciones están aplicadas

33
5 Diseño de módulos VHDL
Hasta el momento se ha diseñado un hardware, se ha verificado su funcionamiento y se
han solventado incidencias. No obstante, aunque el sistema a nivel de hardware
funciona, solo es capaz de convertir las señales diferenciales de entrada a niveles TTLs,
más manejables. Estas señales atraviesan las FPGAs, pero por el momento no se realiza
ningún procesado sobre ellas.

Con la finalidad de dotar al sistema de múltiples funcionalidades, en este capítulo se


procede a detallar un conjunto de módulos VHDL desarrollados.

5.1 Conversión de entrada


En este apartado se describe un módulo combinacional que facilita el análisis de la señal
de video en etapas posteriores.

Si observamos la figura 16, podemos apreciar que los conversores de LVDS a TTL
generan siete bits por cada una de las líneas diferenciales de entrada. Estos bits son
directamente los que transportan internamente cada una de las tramas de señal LVDS,
indistintamente del contenido de la imagen. Para conocer qué información transporta
cada trama, tenemos que analizar el tipo de codificación que genera el emisor, en este
caso la placa de televisión. Los bits que envía cada trama LVDS y la correspondencia de
éstos con la imagen, se puede apreciar en las figuras 4 y 5.

Debido a las dos posibles ordenaciones que pueden tener los bits de estas tramas, este
módulo tiene una señal de control que permite seleccionar una de ellas, esta señal se
llama JETDA_NS. Según el valor de esta señal de control, el módulo reordena los bits
de entrada, creando salidas que corresponden a R, G, B y las señales de sincronismo
DE, HSYNC y VSYNC.

A partir de este momento todo el tratamiento de la señal de video se realizará sobre


estas señales de salida.

Figura 25. Módulo de reordenación de la información de entrada

34
Descripción de señales
TTL_I!PUT_RA,RB,RC,RD[6..0]: Entradas. Señales procedentes del conversor
LVDS a TTL Su formato depende del tipo de codificación JETDA o NS.

J_!S: Entrada. Señal de control que específica la codificación con que se está
trabajando. A nivel alto JETDA, a nivel bajo NS.

R,G,B[7..0]: Salidas que forman el píxel que se esta recibiendo, en formato RGB.

V_SY!C/H_SY!C: Salidas de sincronismo vertical/horizontal. Indican el inicio


de un nuevo frame y una nueva línea.

DE (Display Enable): Salida de sincronismo general. Permite realizar la


sincronización ignorando las dos señales anteriores. Se activa cuando nos
encontramos en un píxel de la zona visible del panel.

Para más información sobre las señales de sincronismo anteriores revisar el apartado
2.3.3 de este documento.

SignalTap
SignalTap es una herramienta incluida en Quartus II que permite capturar en tiempo real
la actividad de las entradas y salidas de la FPGA. Se podría decir que es similar a un
osciloscopio digital con la ventaja de que no necesita la conexión de ningún dispositivo
externo sobre los pins de la FPGA, además de permitir la captura de un gran número de
señales de forma simultánea.

Al igual que los ficheros de simulación, SignalTap permite comprobar el


funcionamiento del sistema diseñado en la FPGA, siendo mucho más rápido y cómodo
que el método de simulación, en casos donde el número de líneas a observar es elevado.

Uno de los problemas que conlleva el uso de SignalTap consiste en que para realizar
esta comprobación hay que crear un fichero con las señales a observar, indicar la señal
que actuará como trigger(señal de disparo), fijar el número de muestras a tomar de la
señal de entrada, volver a compilar todo el proyecto y por último cargarlo en la FPGA.
Esta compilación, que es el proceso que mayor tiempo conlleva, es obligatoria ya que
hay que crear una nueva configuración del hardware interno de la FPGA para que sea
capaz de capturar y almacenar en registros internos la actividad de las señales deseadas.

En nuestro caso, debido al elevado número de señales que participan en el módulo de


conversión de las señales de entrada, optamos por mostrar su funcionamiento con la
captura de la figura 26, realizada con SignalTap.

Para comprobar el correcto funcionamiento del conversor LVDS a TTL, así como la
ordenación de los bits propuesta en este módulo, creamos un fichero con esta aplicación
donde se capturan las señales de video y sincronización que entran a la FPGA. En este
caso conectamos a la TV una señal de video que corresponde a una carta de grises,
ordenamos las señales correctamente y realizamos la captura.

35
Figura 26. Captura con SignalTap ordenando las líneas de entrada a la FPGA. En este caso se esta
introduciendo como señal a la TV una carta de grises

En la figura 26 se puede observar, como la señal DE(DEN en la figura), que indica


cuando nos encontramos en la zona activa de la pantalla, sólo se activa en los tramos
donde estamos recibiendo píxels pertenecientes a la carta de grises. En este caso
permanece activada durante una línea horizontal del panel, es decir, 960 píxels para
cada FPGA. El tiempo que se encuentra desactivada es el espacio de blanking horizontal
entre filas consecutivas.

Por otro lado, en esta figura se muestra también que tras agrupar las líneas en tres buses
de 8 bits (Red, Green y Blue) el resultado corresponde a tres rampas, comportamiento
que coincide con una carta de grises. En una carta de grises el primer píxel horizontal es
totalmente oscuro( R=0,G=0,B=0), y el último píxel es muy cercano al blanco (R=255,
G=255,B=255).

36
5.2 Conversión de salida

Debido a que en el apartado 5.1 hemos reordenado la señal para facilitar su


interpretación, ahora debemos deshacer estos cambios. Este modulo se encarga por
tanto de reestablecer el orden que tenía la señal de entrada, antes de enviarla hacia los
conversores de salida que la devolverán a su estado original, dejándola lista para ser
enviada hacia el panel.

Figura 27. Módulo de reordenación de la información de salida

Este módulo no sería necesario si solo quisiésemos dejar pasar la señal procedente de la
placa de televisión, ya que bastaría con interconectar las líneas de la señal de entrada
con sus respectivas salidas. Sin embargo, como deseamos analizar regiones concretas de
la imagen nos interesará poder modificarla remarcando por ejemplo la zona que estamos
analizando.

Las señales que participan en este módulo son idénticas al módulo de entrada, por este
motivo no se detallarán de nuevo.

37
5.3 Análisis de regiones
El módulo secuencial síncrono Mesure_ROI de la figura 28 analiza una región
específica de la imagen en tiempo real, devolviendo la siguiente información sobre
dicha región de interés (ROI):

• La media de los valores Red, Green y Blue.


• Valor de la luminancia.
• Valores máximos y mínimos de R,G,B.

Se debe tener en cuenta que las señales de video de entrada a la televisión en la máquina
de test CBA son siempre cartas de barras de colores. Las cartas de barras de colores,
como su nombre indica, son imágenes de video fijas formadas por un conjunto de barras
de distintos colores.

Para comprobar si la imagen es correcta, se selecciona una región de una de estas barras
y se comparan los valores obtenidos con los esperados. Para realizar este proceso se
fijan unas especificaciones de valores R, G, B y luminancia para las regiones que se van
a analizar y si los valores obtenidos no coinciden con los especificados, la placa de TV
se descarta de la cadena de montaje y se envía a reparación.

Figura 28. Módulo de análisis de las regiones de interés

38
Descripción de señales
clk: Entrada. Señal de reloj procedente de los conversores LVDS-TTL, por tanto,
es la frecuencia de los píxeles pares/impares.

nrst: Entrada. Reset asíncrono. Activo a nivel bajo.

enable: Entrada. Señal de habilitación del módulo. Una vez indicada la región de
interés a analizar, se debe provocar un pulso de un ciclo de reloj en esta señal para
iniciar el análisis.

off_v, off_h[10..0]: Entradas. Respectivamente, offset vertical y horizontal, en


píxels, respecto los márgenes de la pantalla. Indican la posición del primer píxel
de la ROI. off_v debe estar comprendido entre 0 y 1079 para una resolución
FHD(1920 x 1080p). Off_h debe estar comprendido entre 0 y 960, debido a que la
imagen FHD se divide en dos partes, píxels pares e impares. Recordamos que cada
una de estas partes es tratada por una FPGA distinta.

Width,length[10..0]: Entradas. Delimitan el tamaño de la ROI.

R,G,B[7..0]: Entradas. Valores RGB del píxel actual. Estos valores corresponden
a un nuevo píxel cuando nos encontramos dentro de la zona visible del panel y
además se produce un flanco de bajada de la señal de reloj clk.

cont_hori,cont_vert[10..0]: Entradas. Contadores que indican la posición,


horizontal y vertical, del píxel que se está enviando.

R_mean,G_mean,B_mean[7..0]: Salida. Valores RGB medios de la zona


analizada.

Y[7..0]: Salida.Valor de luminancia medio de la ROI

Gmin,Rmin,Bmin, Gmax,Rmax,Bmax [7..0]: Salida. Valores RGB mínimos y


máximos hallados en la ROI.

read_strobe: Salida. Indica que el proceso de análisis de la ROI ha finalizado y se


puede proceder a la lectura de la información obtenida o iniciar un nuevo análisis.

39
Funcionamiento
Tras un reset el módulo pasa al estado de espera Waiting, donde se mantiene a la espera
de un pulso de la señal Enable. Al generar este pulso las señales que limitan la región de
interés, off_v, off_h, width y length deben haber sido previamente fijadas. En este
momento, el sistema pasa al estado Wait2, en el que permanece a la espera de que el
píxel actual sea el primer píxel de la ROI, es decir que contador_vert=off_v y
contador_hori=off_h. Cuando esta condición se cumple pasamos al estado Run que se
encarga de incrementar los valores totales de RGB por cada píxel valido de la ROI, así
como de contar el número de píxels que forman esta región. A la vez actualiza, si es el
caso, el valor RGB máximo o mínimo encontrado hasta el momento. En este estado con
cada ciclo de reloj se garantiza que estemos dentro de los márgenes de la ROI, por tanto,
cada vez que salgamos de la zona hasta que volvamos a entrar en ella, el estado
permanece inactivo sin incrementar las variables que se desean medir. Cuando nos
encontramos en el último píxel de la ROI, es decir, contador_vert = off_v + length -1 y
cont_hori = off_h + width, el sistema pasa al estado Math donde realiza los cálculos de
los valores RGB medios, los pone en las líneas de salida e indica mediante la señal
read_strobe que los datos están listos para ser leídos.

Figura 29. Diagrama de estados del módulo Mesure_ROI. Las líneas azules indican las condiciones para
la transición entre estados, las rojas las acciones que se realizan en ese estado

40
5.4 Contadores de posición
Con la finalidad de simplificar el proceso de análisis y modificación de la imagen se
decide crear un módulo que indica la posición (en píxels) dentro de la parte visible de la
pantalla donde nos encontramos. En este apartado se describen las principales
características de este módulo.

Para obtener estos indicadores de posición se hace uso de las señales de sincronización
Hsync, Vsync y DE procedentes de los conversores LVDS a TTL. Tal y como se
describió en el apartado 2.3 dedicado a paneles LCD existen dos opciones de
sincronización: Hsync conjuntamente con Vsync o DE.

Inicialmente se planteó usar la opción de Hsync más Vsync por ser la más conocida, no
obstante esta opción plantea serias limitaciones. Una de estas limitaciones como se
muestra en la figura 30 consiste en que en estas señales, para indicar el inicio de un
nuevo frame en el caso de Vsync o una nueva línea en el caso de Hsync, pasan a nivel
bajo, manteniéndose en este estado durante cierto tiempo para después volver al estado
de reposo, a nivel alto. El problema es que tras este flanco de bajada existe un tiempo
variable(Thb/Tvb-Time Horizontal/Vertical Blanking) hasta la llegada del primer píxel
que pertenece a la parte visible o activa del panel y de igual forma existe otro tiempo
variable(Thf/Tvf. Time Horizontal/Vertical offset) desde que finaliza la zona activa del
panel hasta que se genera un nuevo flanco de bajada en las señales de sincronismo.

Figura 30. Sincronización con Hsync y Vsync

El uso de este tipo de sincronización implica tener que contar los píxels de la zona
pasiva para conocer cuando nos encontramos dentro de la zona útil del panel.

No obstante, la limitación más importante, es que el fabricante del panel garantiza una
cantidad de píxels fija para las zonas activas del panel, en el caso de un panel FHD,
estos valores suelen ser de 1080 píxels verticales y 960 horizontales. Volvemos a
recordar que estos 960 horizontales es debido a que la imagen se encuentra dividida en
píxels pares e impares que se tratan de forma independiente. En cambio, las zonas del
panel de píxels pasivos no son de tamaño fijo y el fabricante simplemente proporciona

41
un valor mínimo y máximo para estas zonas. Además estas cotas son variables según
diversos parámetros de configuración del panel, como por ejemplo la frecuencia de
refresco.

Figura 31. Información sobre periodos verticales y horizontales, número de píxels


de las zonas activas y zonas de blanking del panel AUO de 37'' para 50 y 60 Hz.

En resumen, implementar esta opción requería el uso de un gran número de contadores,


a la vez que debíamos fijar unas especificaciones, difíciles de definir, para las zonas de
blanking. El hecho de fijar unas zonas de blanking de n píxels para la zona activa y
pasiva del panel hacía que el sistema no fuese escalable directamente a otro tipo de
panel, y mucho menos si este panel era de resolución diferente. Por ello se descartó esta
opción.

Como alternativa se planteaba el uso de la señal DE( Display Enable), que como se
puede ver en la figura 30 solo se encuentra a nivel alto cuando nos encontramos dentro
de la zona activa del panel, permitiendo que el sistema sea escalable a otros paneles y
resoluciones fácilmente, reduciendo a la vez el número de necesarios. No obstante, el
comportamiento de la señal DE (ver figura 7 y 8) muestra la necesidad de utilizar un
contador adicional para calcular el tiempo que la señal DE permanece a nivel bajo, ya
que un tiempo prolongado a nivel bajo antes de un flanco de subida indica que estamos
en el píxel número uno de un nuevo frame, un tiempo corto a nivel bajo indica que
estábamos en la zona de blanking existente entre líneas horizontales.

Para solucionar estos inconvenientes y reducir al máximo el número de contadores en el


sistema se plantea una nueva opción: utilizar las señales Vsync y DE.

42
Descripción de señales

clk: Entrada. Señal de reloj procedente de los conversores LVDS-TTL, por tanto,
es la frecuencia de los píxeles pares/impares.

nrst: Entrada. Reset asíncrono. Activo a nivel bajo.

DE: Entrada. Señal de sincronismo Display Enable

hori_pos, vert_pos: Salidas. Entero comprendido entre 0 y 960 para hori_pos y


entre 0 y 1080 para vert_pos que indican la columna/fila donde se encuentra el
píxel que actualmente se está recibiendo.

Funcionamiento

Tras un reset el módulo permanece a la espera de un flanco de subida de Vsync, esta


señal indica que empieza un nuevo frame. Durante el tiempo que el sistema permanece
en el estado Sincro_V, fija la variable Waiting_First_DE='1' indicando que aún no se
ha recibido el primer ciclo activo de la señal DE, es decir, aún no nos encontramos en la
primera fila activa de la imagen.

Cuando se produce el flanco de subida en Vsync se pasa al estado Sincro_H en el cual


se espera a que DE se active mientras se mantienen ambos contadores a cero, cuando
esto ocurra se incrementará el contador de posición horizontal y se fijará la señal
Waiting_First_DE='0' ya que estamos antes el primer píxel de la imagen. En este
estado se permanecerá, incrementando a cada ciclo de reloj el contador horizontal, hasta
que se produzca un flanco de bajada de la señal DE, indicando que la primera línea de la
imagen ha concluido y por tanto incrementando el contador vertical. Mientras DE='0' y
como ya no estamos en la primera fila, ya que Waiting_First_DE='0', solo se reinicia el
contador horizontal.

El sistema repite el bucle anterior, hasta que se produce un flanco de subida de la señal
Vsync, indicando que se inicia un nuevo frame, fijando de nuevo Waiting_First_DE='1'
y reiniciando ambos contadores.

43
Sincro_H
B
Reset(Cont_vert)
Vsync_rise_edge=’1' Reset(Cont_hori)

Waiting_First_DE=’1'
Sincro_H
DE=’0' &Waiting_First_DE=’1'
B

Sincro_H
DE=’0' &Waiting_First_DE=’0'
B

nrst=’0'
Sincro_H
Sincro_V Vsync_rise_edge=’1'

Reset(Cont_hori)

Sincro_H
DE=’1'
B
Waiting_First_DE=’1'

Waiting_First_DE=’0'
INCREMENT(Cont_hori)

DE_fall_edge=’1'

Sincro_H
B

INCREMENT(Cont_vert)

Figura 32. Diagrama de estados del indicador de posición

En la figura 33 se muestra el correcto funcionamiento del módulo desarrollado mediante


una simulación en Quartus II.

Figura 33. Simulación del contador de posición sincronizado mediante Vsync y DE

44
5.5 Captura de imagen
Hasta el momento se han descrito módulos cuya finalidad es reorganizar la información,
generar indicadores de posición y permitir el análisis de forma rápida y directa en las
FPGAs de una región específica. No obstante, es posible que se desee obtener algo más
que los valores RGB medios, mínimos y máximos de una región de la imagen, por
ejemplo, que se desee adquirir una imagen completa para procesarla en un ordenador.

Aunque esta opción no es la finalidad de este hardware, debido a las limitaciones de


velocidad del protocolo de comunicación I2C así como a la escasa memoria interna
disponible en las FPGAs utilizadas, se habilita la posibilidad mediante el módulo
LVDS_Capturer de llevar a cabo capturas de la imagen.

Para realizar una captura de imagen rápida haría falta un enlace de comunicaciones más
rápido que la frecuencia de píxel, que es de 75 MHz. Como éste no es el caso, nos
vemos con la necesidad de almacenar temporalmente los píxels hasta que sean leídos
por el ordenador. Por ello incluimos un bloque FIFO de palabras de 24 bits, que es el
número de bits que forman un píxel.

Figura 34. Módulo de captura de imagen

Este bloque de memoria FIFO presenta un serio problema ya que en las FPGAs se
puede almacenar un máximo de 4096 palabras de 24 bits o lo que es lo mismo 4096
píxels. Esto implica que como máximo podemos guardar en estas FIFOs regiones de un
tamaño similar a 64x64 píxels que comparando con los 960x1080 píxels que maneja
cada FPGA es una zona muy reducida.

45
Figura 35. FIFO para el almacenamiento de píxels

Para solventar este problema y poder capturar regiones de hasta 960x1080 píxels se
implementa la siguiente estrategia:

1. Al llegar al primer píxel de la zona de interés, el módulo lvds_capturer empieza


a enviar píxels del mismo frame a la FIFO de forma continua hasta que la FIFO
se llena.
2. Si la FIFO está llena el módulo deja de enviar píxels y almacena la posición del
píxel siguiente.
3. Si la FIFO vuelve a indicar que tiene espacio para almacenar más píxels, el
módulo lvds_capturer espera a que el frame actual se encuentre en el píxel
donde se había quedado en el punto anterior.
4. Cuando se llega a la posición del último píxel guardado se continua el recorrido
por la imagen guardando los nuevos píxels en la FIFO hasta que se vuelve a
llenar
5. Se repiten los pasos 3 y 4 hasta que se ha recorrido toda la región a capturar.

Con este algoritmo se consiguen capturar imágenes de cualquier tamaño, aunque el


tiempo que se tarda en enviar esta información al ordenador es elevado y depende de las
dimensiones de la captura.

Descripción de señales

clk: Entrada. Señal de reloj procedente de los conversores LVDS-TTL, por tanto,
es la frecuencia de los píxeles pares/impares.

nrst: Entrada. Reset asíncrono. Activo a nivel bajo.

enable: Entrada. Señal de habilitación del módulo. Una vez indicada la región de
interés a capturar, se debe provocar un pulso de un ciclo de reloj en esta señal para
iniciar la captura.

off_v, off_h[10..0]: Entradas. Respectivamente, offset vertical y horizontal, en


píxels, respecto los márgenes de la pantalla. Indican la posición del primer píxel
de la ROI. off_v debe estar comprendido entre 0 y 1079 para una resolución

46
FHD(1920 x 1080p). Off_h debe estar comprendido entre 0 y 960, debido a que la
imagen FHD se divide en dos partes, píxels pares e impares.

Width,length[10..0]: Entradas. Delimitan el tamaño de la ROI.

R,G,B[7..0]: Entradas. Valores RGB del píxel actual. Estos valores corresponden
a un nuevo píxel cuando nos encontramos dentro de la zona visible del panel y
además se produce un flanco de bajada de la señal de reloj clk.

V_sync, H_sync: Entrada. Señal de sincronismo vertical/horizontal. Indica con un


pulso el inicio de un nuevo frame o una nueva línea.

DE (Display Enable): Entrada. Señal de sincronismo general. Permite la


sincronización, ignorando las dos señales anteriores. Se activa cuando nos
encontramos en un píxel de la zona visible del panel.

Fifo_full: Entrada. Línea de salida de la FIFO que indica cuando está completa.

o_R, o_G, o_B[7..0]: Salidas. Valores RGB del píxel actual modificado. Estas
señales corresponden en general a las señales de entrada R,G,B[7..0], con un
recuadro de un color verde alrededor de la zona de interés prefijada, que indica
visualmente la zona que se esta analizando/ capturando.

o_hsync, o_vsync, o_DE: Salidas. Bypass de las señales de sincronismo.

Fifo_wr_enable: Salida. Orden de escritura de una nueva muestra en la FIFO.

Data_to_fifo[23..0]: Salida. Los 24 bits que forman un píxel enviados a la FIFO


para su almacenaje.

o_contador_hori, o_contador_vert[10..0]: Salida. Resultado del contador de


posición incluido en este módulo. Indica la posición en píxels dentro de la zona
activa del panel donde nos encontramos.

reset_enable: Salida. Señal de reset para la FIFO.

Funcionamiento
Tras un reset el módulo va al estado waiting, en el que permanece a la espera de un
pulso de enable. En el momento que se genera el pulso todos los parámetros que
configuran la ROI ya han sido prefijados, la FIFO se ha resetado y el contador de
posición se ha activado.

Cuando se recibe la señal de enable el sistema pasa al estado full. Tras la generación de
un pulso de enable la FIFO se vacía por tanto en este caso la señal fifo_full ='0'.
Además el sistema almacena el punto desde donde la captura de imagen debe continuar.
Como partimos de una condición de reset, se almacena el primer punto de la ROI, es
decir, point_hori= off_H y point_vert=off_V

47
Al haber sitio en la FIFO, el sistema espera a leer el primer píxel de la ROI( point_hori
y point_vert). Al llegar a la situación de este píxel cont_hori=point_hori y
cont_vert=point_vert y al haber sitio en la FIFO el sistema pasa al estado run.

Al llegar a este nuevo estado con un ciclo de reloj de retardo el sistema almacena en la
FIFO el píxel anterior que se va almacenando de forma continua con cada ciclo de reloj.
Mientras la captura de la ROI no haya finalizado, sigamos dentro de la ROI y siga
habiendo sitio en la FIFO el sistema continua almacenando píxels. Si se sale de la zona
de la ROI, habiendo sitio en la FIFO el sistema permanece inactivo en este estado
esperando a que se vuelva a entrar en la zona de interés. Por contra, si la FIFO se llena,
el sistema actualiza la situación del último píxel grabado en la FIFO actualizando la
posición donde se encuentra y que se debería guardar en un futuro en la FIFO, es decir,
hace que point_hori= cont_hori y point_vert= cont_vert y pasa al estado full.

El sistema permanece en este estado hasta que vuelve a haber sitio en la FIFO. Cuando
esto sucede vuelve al estado run y espera a encontrarse en el píxel donde se había
quedado para proseguir con la captura. El salto entre el estado run y full se repite hasta
que se completa la captura de la ROI, se genera una señal de reset o se genera otro pulso
de enable para capturar una región distinta.

Por último indicar que tras haber seleccionado una zona de interés y haber generado un
pulso de enable, cada vez que el píxel actual corresponde a la periferia de esta zona, el
color de estos píxels se modifica a un color verde intenso. Esta acción en el modo de
prototipado permite conocer con exactitud la zona del panel que se esta capturando, ya
que en este modo de pruebas si que se conecta en el otro extremo de la placa LVDS
Capturer un panel LCD.

Figura 36. Diagrama de estados simplificado para la captura de imagen

48
5.6 Generador OSD

Un OSD(On Screen Display) es un interfaz de configuración que incorpora distintos


tipos de receptores de televisión. Este interfaz controla la información propia y se lleva
a cabo normalmente mediante un circuito integrado que realiza una conmutación
controlada entre la señal de video de entrada al televisor y la señal correspondiente al
color de los caracteres y parámetros a monitorizar. De ésta forma, sólo se ven afectadas
algunas líneas y columnas de la imagen y el resto siguen mostrando la señal del video
de entrada. En un televisor una muestra del OSD son por ejemplo los números que
indican el canal y que aparecen sólo de forma temporal al cambiar de canal.

En nuestro caso el OSD solo tiene utilidad si en el otro extremo de la placa LVDS
Capturer se conecta un panel. Esta situación solo se dará en el caso de prototipado, en el
caso de reparación de un VITAM o en el departamento de reparación de placas. En
estos dos últimos casos, disponer de un panel facilita la detección del problema. En
estas tres situaciones se podría usar este OSD para dar una información adicional a
través del panel del estado actual del proceso que se está llevando a cabo.

Para generar un OSD se ha modificado un módulo VHDL existente cuya finalidad


inicial era escribir caracteres sobre VGA(Video Graphics Array), es decir, para una
pantalla analógica estándar de ordenador. Más concretamente lo que se ha hecho es:
primero adaptar este módulo para que funcione con resoluciones FHD y después hacer
que el texto generado se superponga a la imagen, sustituyéndola en los píxels
correspondientes al texto.

Al tratarse de un módulo parcialmente desarrollado no se tratará su comportamiento de


forma detallada, sino que nos limitaremos a describir su funcionamiento.

Funcionamiento
El generador de OSD se basa en un módulo llamado TopSchemROM3. Este módulo a
su vez está formado por dos módulos: comparPos4Rom3 y Char_ROM.

Figura 37. Módulo TopSchemROM3

Char_ROM: Es una memoria ROM que contiene caracteres de tamaño 8x8 píxels,
character_address[5..0] indica la dirección de memoria del carácter que se desea dibujar

49
y font_row y font_col indican un píxel específico de los 64 que forman el carácter. El
valor del píxel seleccionado con cada ciclo de reloj ( 1 o 0) se envia por romout.

Figura 38. Ejemplo de un carácter de la memoria ROM

ComparPos4Rom3: Controla el comportamiento de TopSchemRom3. Internamente


contiene la información del número de caracteres que se desean dibujar, la posición
donde se desean colocar respecto al panel y la dirección de memoria de la ROM donde
se encuentra este carácter. Según la posición del píxel actual y de la posición donde se
desean representar cada uno de los caracteres que tiene especificados en su interior,
coloca en sus salidas una dirección y un píxel en concreto del carácter que se debe
representar. A la vez genera una salida print[4..0] que indica a cada ciclo de reloj si nos
encontramos dentro de la región asociada a uno de estos caracteres.

Las dos salidas del módulo TopSchemROM3 por tanto son print, para indicar si
estamos en la región 8x8 de un caracter, y romout que indica si el valor a imprimir por
pantalla corresponde a 0(negro) o 1 (blanco). Los valores de la salida romout se
muestran en binario en la figura 38.

Para superponer sobre la imagen de entrada únicamente los valores lógicos '1', que
corresponden a la escritura de un carácter, se realiza el montaje de la figura 39.

Figura 39. Estructura de módulos para el generador OSD

Cuando print[4..0]= "00000", es decir, fuera de la región 8x8 de un carácter, el


multiplexor muxsel hace que la salida RGB[23..0] que va directamente hacia el panel
corresponda a data[23..0], que es la señal de salida del módulo lvds_capturer( imagen
de entrada más la ROI remarcada). Por otro lado, cuando print[4..0] tiene alguno de sus
bits activos significa que estamos en la región 8x8 de uno de los caracteres, en este caso
el valor de romout decide el canal seleccionado por el multiplexor. Si romout='1',
corresponde a la zona activa de un carácter ( '1' lógico). En este caso la señal que va
hacia el panel, será un píxel blanco que servirá para dibujar el carácter deseado.

50
5.7 Comunicación. Esclavo de I2C
Uno de los módulos importantes del sistema es el que gestiona la comunicación con la
placa ESIIC. A través de esta comunicación se puede controlar el funcionamiento de la
placa LVDS Capturer, así como transferir información hacia la ESIIC para
posteriormente enviarla al ordenador. Como se ha dicho, esta comunicación se establece
a través de un bus I2C, donde la ESIIC hará las funciones de master y nuestro hardware
el de esclavo.

En este apartado se describe el funcionamiento del módulo de comunicación


desarrollado. En el Anexo I se puede encontrar una descripción detallada sobre el
funcionamiento del bus I2C.

Figura 40. Módulo del esclavo de I2C

El módulo de la figura 40, además de implementar el comportamiento de un esclavo de


I2C, consta de una serie de registros de escritura y lectura, como se puede ver en la
figura 41. Los de escritura tienen la finalidad de configurar y activar los diversos
módulos del diseño. Los de lectura se corresponden a las salidas de los demás módulos
descritos anteriormente y sirven para almacenar los resultados obtenidos a la espera de
que sean leídos por el master de I2C desde la ESIIC.

51
Register Name Utility Register Name Utility
Mem(0) Offset vertical - MSB Mem(13) Red mean value
Mem(1) Offset vertical - LSB Mem(14) Green mean value
Mem(2) Offset Horizontal - MSB Mem(15) Blue mean value
Mem(3) Offset Horizontal - LSB Mem(16) Luminance
Mem(4) Length(ROI)- MSB Mem(17) Locked
Mem(5) Length(ROI)- LSB Mem(18) Rmin
Mem(6) Width(ROI)- MSB Mem(19) Rmax
Mem(7) Width(ROI)- LSB Mem(20) Gmin
Mem(8) Control/Configuration: Mem(21) Gmax
Bit0= Reset
Bit1= Enable
Bit2 = Jetda/NS
Mem(9) Empty Mem(22) Bmin
Mem(10) Red pixel Mem(23) Bmax
Mem(11) Green pixel Mem(24) Bit0= '1' Available read data
Mem(12) Blue pixel
Figura 41. Registros internos del módulo de comunicación. En amarillo los de
escritura, en gris los de lectura

Descripción de señales

clk: Entrada. Señal de reloj procedente de los conversores LVDS-TTL, por tanto,
es la frecuencia de los píxeles pares/impares.

rst_i: Entrada. Reset síncrono. Activo a nivel alto.

data_from_fifo[23..0]: Entrada. Los 24 bits que forman el último píxel leido de la


FIFO.

Fifo_empty: Entrada. Indica si la FIFO está vacía.

X_mean,Xmin,Xmax,Luminancia: Entradas. Resultados procedentes del


módulo Mesure_ROI. Valor medio, mínimo, máximo de los colores RGB y valor
medio calculado de la luminancia.

Locked: Entrada. Señal de salida de un PLL incorporado en el diseño, indica


cuando el PLL se ha sincronizado con la señal de reloj procedente del panel. Se
encuentra a nivel bajo cuando no hay señal de reloj o no se produce la
sincronización.

read_strobe: Entrada. Indica la existencia de nuevas medidas sobre la ROI.

Scl: Bidireccional. Línea de reloj del bus I2C.

Sda: Bidireccional. Línea de datos del bus I2C.

rst_o: Salida. Señal de reset para los diversos módulos del sistema.

enable: Salida. Señal de activación de los demás módulos.

52
off_v, off_h[10..0]: Salida. Offset vertical y horizontal de la región a analizar.

Width, Length [10..0]: Salida. Ancho y longitud de la región a analizar.

rd_enable: Salida. Señal de lectura para la FIFO.

J_V: Salida. Selección de la codificación de la señal de entrada: JETDA o NS.

Funcionamiento

Tras un reset el módulo permanece en el estado idle, en que permanece a la espera de


una condición de start. Al producirse un start el sistema pasa al estado
dev_addr_recognition en que captura la dirección del dispositivo al que va destinada
la información, así como el bit indicador de escritura o lectura. Si la dirección no es la
del propio dispositivo se vuelve al estado idle, en caso afirmativo el sistema genera un
ACK y pasa al estado read_write_mem_addressing tanto en caso de lectura como de
escritura. Esto se debe a que todo proceso de lectura implica inicialmente una escritura
seguida de un repeated start esta vez con indicador de lectura (ver anexo comunicación
i2c random read).

A continuación en el estado read_write_mem_addressing se captura la posición de


memoria en la que el master desea escribir o leer, y vuelve a generar un ACK.

Seguidamente se pasa al estado write_byte, en que pueden darse tres situaciones


distintas:

1. Se detecta condición de start, lo que implica un proceso de lectura. Se


vuelve de nuevo al estado dev_addr_recognition.

2. Se detecta condición de stop, lo que implica el final del proceso. Se vuelve


al estado idle.

3. Si no se detecta condición de start ni de stop, el proceso corresponde a una


escritura en la dirección del esclavo que anteriormente se específicó. Tras la
escritura de los ocho bits de datos, el esclavo genera un ACK. Este proceso
de escritura de 8 bits más reconocimiento se repite incrementando cada vez
la dirección donde se escribirá el siguiente byte. El master de I2C finaliza el
proceso de escritura mediante una condición de stop.

En caso de que en el estado write_byte se reciba de nuevo una condición de


start(situación 1), lo que implica una lectura, pasamos de nuevo al estado
dev_addr_recognition donde se captura otra vez la dirección del dispositivo esclavo al
que va dirigida la información, así como el bit de escritura/lectura que en este caso si
indica una lectura. Tras reconocer que la dirección leida es la suya, el esclavo genera de
nuevo un ACK, toma el control sobre el bus I2C y pasa al estado data_out. En este
estado el esclavo envía los 8 bits del registro que anteriormente se había especificado
para lectura. En este caso, el master es el encargado de generar los ACKs/No ACKS de

53
cada byte recibido. Tras leer estos 8 bits, el proceso se repite incrementando la
dirección de lectura y volviendo a enviar los 8 bits siguientes. El proceso de envio y
reconocimiento se repite hasta que el master genera una condición de stop que envía al
sistema al estado idle.

Figura 42. Diagrama de estados simplificado del módulo esclavo de I2C

Hasta aquí se ha descrito el funcionamiento de nuestro esclavo de I2C con registros


internos. Una de las modificaciones que incluye respecto a un esclavo de I2C corriente,
y que por simplicidad no se ha descrito en el diagrama de estados de la figura 42,
consiste en la lectura de los píxels, que se almacenan en la FIFO.

Para facilitar y agilizar el proceso de captura de una región desde el ordenador, el propio
esclavo de I2C se encarga de coger los tres bytes que forman un píxel de la FIFO( si hay
muestras disponibles) y los guarda en los registros internos de lectura Mem(10),
Mem(11), y Mem(12). En caso de que se realice un proceso de lectura de N píxels
(N*3 bytes), con dirección inicial la correspondiente al registro Mem(10), el esclavo
funciona de un modo continuo. Es decir, a medida que se leen los 3 registros que
corresponden a un píxel, el propio I2C comprueba si la FIFO tiene otro píxel disponible,
en caso afirmativo vuelve a cargar estos registros Mem(10..12) con la información del
siguiente píxel. Además cuando la dirección de lectura inicial corresponde a la del
registro Mem(10), el esclavo internamente genera un bucle con los tres registros que
contienen el píxel, Mem(10), Mem(11) y Mem(12).Es decir, cuando llega a Mem(12) y
se desean leer más píxels , el esclavo directamente vuelve a colocar la dirección de
lectura a Mem(10) para que éste sea este el siguiente registro a leer.

54
6 Uso y verificación del sistema completo
En el capítulo anterior se han descrito los módulos VHDL que dotan de funcionalidad a
la placa LVDS Capturer. En el transcurso del capítulo se ha descrito de forma detallada
el funcionamiento, así como las señales y el diagrama, para la mayoría de los bloques
que se van a incorporar. Además se ha mostrado su funcionamiento mediante
simulaciones o capturas con SignalTap.

Con la finalidad de comprobar si los comportamientos descritos son los obtenidos en la


práctica, a continuación se detalla el proceso seguido para utilizar el sistema
desarrollado.

6.1 Montaje provisional del sistema

El primer paso consiste en realizar el montaje que se describió en la figura 14.


Inicialmente partiremos de un montaje aún más simple que permite verificar solo parte
del funcionamiento del sistema. Para este montaje básico sólo se necesita: un LCD del
modelo EX2N, una placa LVDS Capturer y una fuente de alimentación.

Figura 43. Elementos necesarios para el montaje provisional. A la izquierda un LCD Sony EX2N, a la
derecha la placa desarrollada, LVDS Capturer.

Tras comprobar que el panel funciona correctamente, sin la placa LVDS Capturer,
realizamos los siguientes pasos para llevar a cabo el montaje básico:

1. Conectamos la salida de la TV Board del LCD a la placa LVDS Capturer con el


mismo cableado que usa este tipo de LCD.
2. Conectamos la salida de la placa LVDS Capturer a la entrada del panel.
3. Alimentamos la placa LVDS Capturer con una fuente externa de 5V.
4. Grabamos los proyectos desarrollados en Quartus II en las dos FPGAs a través
de sus conectores para la grabación Active Serial(permanente).

55
Figura 44. Montaje básico del sistema. Se puede apreciar la conexión entre las placas, los cables de
alimentación para la placa LVDS Capturer (a la izquierda) y un cable HDMI procedente de un DVD
conectado a la TV Board, encargado de proporcionar la imagen.

En este momento estamos listos para proceder a verificar el funcionamiento básico del
sistema. Por el momento no existe ninguna conexión con la placa externa ESIIC y por
tanto aún no existe comunicación con el ordenador que permita su control.

Encendemos el LCD y apreciamos que en ausencia de señal de entrada y con el canal


AV1 seleccionado, la pantalla se encuentra en negro, apareciendo en el lateral izquierdo
el número del canal.

Figura 45.LCD EX2N con el módulo generador de OSD funcionando en su estado por defecto. A la
izquierda imagen completa del panel LCD, a la derecha zoom de la esquina superior derecha.

Se observa en la esquina superior derecha de la imagen unos caracteres en blanco, que


en ausencia de la placa LVDS Capturer no aparecían. Estos caracteres están siendo
generados por el módulo generador de OSD. Este generador puede ser utilizado para

56
devolver alguna información visual a través del panel, útil por ejemplo para los
departamentos de reparación o simplemente para mostrar el logotipo de la empresa.

Con esta prueba realizada se verifica que la señal es capaz de pasar por el hardware de
forma óptima, y además se ha mostrado que el generador de OSD (preconfigurado con
el texto "JAUME") funciona correctamente.

6.2 Montaje y configuración del sistema completo

Una vez verificado el funcionamiento básico del sistema, procedemos a realizar el


montaje completo. Este montaje incluye la comunicación a través del bus I2C con la
ESIIC, así como la conexión entre ESIIC y ordenador.

Para llevar a cabo este montaje lo único que necesitamos es un cable que conecte alguno
de los masters de I2C que posee la ESIIC con nuestro conector I2C, que comunica con
los esclavos de I2C implementados en cada FPGA. Para poder utilizar un mismo bus
I2C para controlar ambas placas, se ha configurado en cada FPGA una dirección
distinta, la primera ( píxels impares) se ha configurado con la dirección 0xA4 y la
segunda (píxels pares) con la dirección 0xA6.

Por otro lado necesitamos alimentar la ESIIC y conectarla a través de un cable Ethernet
a la tarjeta de red del ordenador.

Figura 46. Montaje completo del sistema

57
El siguiente paso es configurar el ordenador para establecer comunicación con la ESIIC,
para ello se requiere que la tarjeta de red se configure con una dirección específica. El
procesador Nios II que implementa la comunicación vía TCP/IP tiene por defecto la IP
10.0.0.51 y como puerto de acceso, el 30. Debido a esta IP y a la máscara IP usada, se
debe configurar la tarjeta de red con una IP del rango 10.0.0.XX.

Figura 47. Configuración de la tarjeta de red. Se opta por seleccionar la dirección IP 10.0.0.56

Una vez configurada la tarjeta de red, debemos establecer una comunicación entre el
ordenador y la ESIIC. El modo más sencillo de llevar a cabo esta comunicación es
creando un enlace entre ambos dispositivos a través de un terminal telnet.
Inmediatamente después de que la ESIIC acepte la conexión, el menú devuelto indica
que la comunicación se encuentra establecida y que la ESIIC se encuentra a la espera de
recibir una nueva orden.

Figura 48. Menú inicial devuelto por la ESIIC

En este momento, debemos enviar un conjunto de comandos según un formato


preestablecido en la ESIIC. Internamente creará una rutina para este proceso, que
gestionará y utilizará los módulos VHDL que la ESIIC tiene grabados. En nuestro caso,
el interés consiste en la utilización de un módulo master de I2C.

58
6.3 Control del sistema LVDS Capturer vía Telnet

Una vez realizado el montaje completo, y habiendo introducido los principios básicos
para utilizar la ESIIC, sólo necesitamos enviar los comandos adecuados a través del
terminal Telnet para que el master de I2C genere las tramas con la información deseada.

Estos comandos realizan dos funciones básicas: Escritura de los registros de


configuración del esclavo de I2C y lectura de los registros que contienen los resultados
obtenidos.

Sintaxis del comando de escritura:

I2CMaster -write_data -rate XX -i2caddr XX -subaddrini XX -num_bytes X -data XX

I2CMaster: Master de I2C que debe establecer la comunicación. Ex: i2c1, i2c2,..
write_data: Acción de escritura.
rate: Velocidad de la comunicación, en bps.
i2caddr: Dirección del esclavo de I2C con el que se desea interactuar, en
hexadecimal.
subaddrini: Dirección del registro interno al que se desea acceder, en decimal
num_bytes: número de bytes a escribir, en decimal
data: Información en hexadecimal a enviar.

Sintaxis del comando de lectura:

I2CMaster -read_rx -rate XX -i2caddr XX -subaddrini XX -num_bytes XX

I2CMaster: Master de I2C que debe establecer la comunicación. Ex: i2c1, i2c2,..
read_Rx: Acción de lectura.
rate: Velocidad de la comunicación, en bps.
i2caddr: Dirección del esclavo de I2C con el que se desea interactuar, en
hexadecimal.
subaddrini: Dirección del registro interno al que se desea acceder, en decimal
num_bytes: número de bytes a leer, en decimal

En base a las funciones anteriores y a la tabla de registros del esclavo de I2C de la


figura 41, 9 registros deben ser configurados para poder obtener la información de una
región: Mem(0) a Mem(8). Los ocho primeros permiten delimitar la zona de interés, el
noveno permite activar la captura de la ROI, generar un reset por software o seleccionar
el tipo de codificación se la señal de entrada (JETDA/NS).

Antes de intentar obtener información de alguna región del panel introducimos al


televisor LCD una carta de video formada por barras verticales de distintos colores.
Seleccionando una parte específica de una de estas barras y obteniendo las estadísticas

59
de esta región el proceso de comprobación de los resultados será más sencillo que con
cualquier otro tipo de imagen.

Figura 49. LCD Sony con una carta de barras de colores como señal de entrada

A continuación realizamos una escritura sobre el esclavo de I2C de la FPGA que se


encarga de los píxels impares, seleccionado una ROI dentro de una de estas barras de
colores. El comando a enviar es el siguiente:

i2c2 -write_data -rate 100000 -i2caddr A4 -subaddrini 00 -num_bytes 9 -data


000100010028002800

El comando utiliza el master de I2C de la ESIIC denominado i2c2 para realizar un


proceso de escritura a una velocidad de 100Kbps sobre un esclavo que tiene como
dirección 0xA4, y que en nuestro caso corresponden al esclavo de I2C de píxels
impares. El proceso de escritura se realiza sobre la posición 0, que corresponde al
registro Mem(0) y consiste en la escritura de nueve bytes, lo que implica que se
escribirán los registros Mem(0) a Mem(8) con la información 0x000100010028002800.
Comprobando con la tabla de registros de la figura 41 el significado es el siguiente:

0x0001 0001 0028 0028 00


00 01 →Vertical Offset. 00(MSB), 01(LSB). Fila: 1( de 1080)
00 01 →Horizontal Offset. 00(MSB), 01(LSB). Columna: 1( de 960)
00 28 →Length of ROI. 00(MSB), 28(LSB). Largo de la ROI: 40
00 28 →Width of ROI. 00(MSB), 28(LSB). Ancho de la ROI: 40
00 →Configuración 00. No reset, no enable, codificación JETDA.

Esta descripción aparentemente delimita una región de la pantalla de tamaño 40x40


píxels con origen la posición X=1 e Y=1. No obstante, esto no es cierto, ya que el
número de columnas de un panel, a diferencia de lo que ocurre con las filas, se reparte
entre píxels pares y píxels impares, tratando cada FPGA con un tipo de píxel distinto.
Esto hace que aunque la región que procesará cada FPGA sea de 40x40 píxels, en el
LCD veamos remarcada en verde una región de 80x40 píxels.

60
Al introducir en el terminal de telnet el comando anterior, el resultado devuelto por la
ESIIC se puede apreciar en la figura 50.

Figura 50. Respuesta devuelta por la ESIIC ante un comando de escritura por I2C

Y observando la pantalla del LCD en la figura 51a, a primera vista vemos que se ha
remarcado en un color verde intenso los píxels que rodean la zona de interés
seleccionada, aunque en realidad solo se han remarcado de color verde los píxels
impares que rodean esta zona. Para seleccionar la zona completa, incluyendo también
los píxels pares, se hace necesario enviar el mismo comando de I2C anterior, pero esta
vez destinado al otro esclavo de I2C, el configurado con la dirección 0x06.

i2c2 -write_data -rate 100000 -i2caddr A6 -subaddrini 00 -num_bytes 9 -data


000100010028002800

El resultado devuelto por terminal es idéntico al caso anterior y en el panel LCD vemos
que ahora si se encuentran en verde los píxels pares que rodean la ROI( figura 51b). De
hecho si ampliásemos la zona remarcada, veríamos que debido a esta dualidad de píxels
pares e impares, la zona remarcada en verde no es únicamente de un píxel de anchura si
no que el marco superior e inferior si que es de un píxel, en cambio los marcos laterales
son de dos píxels de anchura.

(a) (b)

Figura 51. a) Panel LCD con los píxels impares que rodean la ROI remarcados en verde.
b) Panel LCD con todos los píxels que rodean la ROI remarcados en verde.

61
Una vez prefijada la zona de interés es el momento de analizar esta región, para ello
activamos el bit de enable del registro Mem(8) en los dos esclavos de I2C. Los
comandos son los siguientes:

i2c2 -write_data -rate 100000 -i2caddr A4 -subaddrini 08 -num_bytes 1 -data 02


i2c2 -write_data -rate 100000 -i2caddr A6 -subaddrini 08 -num_bytes 1 -data 02

Nota: Al realizar una escritura sobre el bit de enable en uno de los esclavos, éstos generan un único pulso
de un ciclo de reloj del esclavo de I2C hacia los demás módulos y automáticamente vuelven a colocar el
bit de enable de este registro a cero.

Antes de leer los resultados deberíamos asegurarnos de que el análisis de la región ha


concluido leyendo el estado del bit 0 del registro Mem(24). No obstante, como por el
momento el proceso lo realizamos de forma manual el tiempo que tardamos en
introducir los comandos de lectura es suficientemente elevado como para asegurar que
el análisis ha concluido.

A continuación leemos los registros que contienen los resultados obtenidos


introduciendo en el terminal el siguiente comando. Los resultados de la región analizada
se almacenan en los registros Mem(13) a Mem(16) y de Mem(18) a Mem(23). Como de
momento solo interesan los valores RGB medios, ya que son los más sencillos de
comprobar, enviamos los siguientes comandos que realizan una lectura de los registros
Mem(13), Mem(14) y Mem(15) que corresponden con Rmean, Gmean y Bmean
respectivamente.

i2c2 -read_rx -rate 100000 -i2caddr A4 -subaddrini 0D -num_bytes 3


i2c2 -read_rx -rate 100000 -i2caddr A6 -subaddrini 0D -num_bytes 3

Obteniendo por el terminal Telnet las siguientes respuestas:

Figura 52. Valores RGB medios devueltos por cada uno de los esclavos de I2C.

62
Colocando la información obtenida en un formato más visual obtenemos la siguiente
tabla:

FPGA píxels impares FPGA píxels pares


Hexadecimal Decimal Hexadecimal Decimal
Rmean FF 255 FF 255
Gmean FB 251 FB 251
Bmean F4 244 F4 244
Figura 53. Tabla de conversión de los valores obtenidos a decimal

Como se puede observar los valores parecen tener coherencia con la región analizada,
de todos modos una forma fácil de comprobarlo es utilizar cualquier herramienta de
dibujo, como por ejemplo paint, y generar un color con estos valores RGB. Debido a
que estos valores decimales son muy próximos a 255 es evidente que el resultado
obtenido es un color prácticamente blanco.

Con la finalidad de obtener un valor que sea más fácil de comparar, capturamos esta vez
una región de la barra de color lila.

Figura 54. Imagen del panel donde se remarca la zona a analizar.

La información obtenida se ha puesto directamente en un formato más visual en la tabla


de la figura 55.

FPGA píxels impares FPGA píxels pares


Hexadecimal Decimal Hexadecimal Decimal
Rmean C4 196 C4 196
Gmean 01 1 01 1
Bmean BC 188 BC 188
Figura 55. Tabla de conversión de los valores obtenidos a decimal

Si ahora vamos a paint y creamos un color con los valores RGB medios calculados,
obtenemos el siguiente resultado:

63
Figura 56. Color creado en paint con las características anteriores.

Si comparamos ahora el color obtenido mediante paint de la figura 56 con la zona que
se encuentra remarcada en la figura 54 se aprecia que ambos colores coinciden,
quedando validado en la práctica que el sistema de análisis de regiones desarrollado,
principal objetivo de este proyecto, funciona satisfactoriamente.

Captura de ROIs

Habiendo comprobado que las medidas realizadas sobre las ROIs son correctas, queda
por comprobar que el sistema desarrollado con FIFOs para la captura y envio de
regiones enteras hacía el PC también funciona.

Realizar esta comprobación directamente sobre un terminal telnet resulta bastante


compleja por los siguientes motivos:

1. La ESIIC no esta programada para enviar grandes cantidades de información de


forma simultánea a través de Telnet, de hecho esta limitada a envíos con tamaño
máximo de 96 bytes, lo que corresponde a 32 píxels.

2. Una región relativamente pequeña como la que hemos tratado en el caso anterior
ronda unas dimensiones de 40x40 píxels, lo que implica 1600 píxels, o lo que es
lo mismo realizar manualmente 50 lecturas de 96 bytes por cada esclavo de I2C.

3. Cada FPGA contiene una FIFO capaz de almacenar 4096 palabras de 3 bytes, o
lo que es lo mismo 4096 píxels. Esto implica que para comprobar el correcto
funcionamiento del sistema de captura de imagen de forma manual al completo
deberíamos exceder este límite. De esta forma se comprobaría que cuando la
FIFO se llena, ésta se mantiene a la espera de que empiece a ser vaciada para
proseguir con la captura de los píxels pendientes.

4. Al leer una zona de un único color todos los valores devueltos deben ser iguales
lo que implica que si los registros que contienen el siguiente píxel a leer no se
actualizan a cada ciclo de reloj no notaremos la diferencia.

Los anteriores motivos en conjunto hacen inviable en esta fase del proyecto comprobar
totalmente la captura de regiones. Lo que si que se puede hacer es delimitar como ROI
una región de tamaño pequeño, de unos 10x10 píxels y comprobar que los valores

64
devueltos coinciden con la ROI seleccionada. Comprobar una región de 100 píxels
implica realizar una lectura de 300 bytes, o lo que es lo mismo tres capturas de 96 bytes
y una más de 12 bytes. En caso de que intentásemos leer más bytes de los que incluye la
ROI, al encontrarse la FIFO vacía deberíamos leer valores nulos. Para comprobar que la
FIFO se vacía totalmente cuando leamos los 300 bytes lo que hacemos es conectar la
salida FIFO_empty, que indica cuando la FIFO no tiene más muestras, a uno de los
LEDs que la placa LVDS Capturer incluye. De esta forma cuando capturemos una zona
el LED se apagará y no se debería encender hasta que hayamos leído los 300 bytes que
contiene FIFO.

Para definir una zona de tamaño 10x10 píxels debemos realizar las siguientes escrituras:
i2c2 -write_data -rate 100000 -i2caddr A4 -subaddrini 00 -num_bytes 9 -data
00010001000A000A00
i2c2 -write_data -rate 100000 -i2caddr A6 -subaddrini 00 -num_bytes 9 -data
00010001000A000A00

Si observamos la pantalla del LCD al enviar este comando la región seleccionada se ha


reducido drásticamente.

Figura 57. Pantalla LCD con una ROI reducida de 10x10 píxels

A continuación volvemos a enviar los comandos de enable y realizamos cuatro lecturas


de 96 bytes sobre las direcciones de memoria del esclavo de I2C que contiene el
siguiente píxel a leer, es decir, sobre Mem(10), Mem(11) y Mem(12).

i2c2 -write_data -rate 100000 -i2caddr A4 -subaddrini 08 -num_bytes 1 -data 02


i2c2 -write_data -rate 100000 -i2caddr A6 -subaddrini 08 -num_bytes 1 -data 02

i2c2 -read_rx -rate 100000 -i2caddr A4 -subaddrini 0A -num_bytes 96


i2c2 -read_rx -rate 100000 -i2caddr A6 -subaddrini 0A -num_bytes 96

El resultado de las lecturas devuelto por Telnet se muestra en la figura 58, y se aprecia
que a partir del byte 300 en ambos esclavos el valor devuelto no es válido, expresado
como FF.

65
Figura 58. Información devuelta por Telnet al leer cuatro bloques de 96 píxels

Por otro lado, se aprecia que los valores RGB devueltos para cada píxel son idénticos a
los valores RGB medios que en el caso de análisis de regiones se habían obtenido.
Además como se había pronosticado el LED que se ha configurado para que indique si
la FIFO se encuentra vacía, al leer los 300 bytes almacenados se ha activado.

En base a la anterior comprobación, y al hecho de que por el momento no disponemos


de ninguna librería que permita automatizar el proceso de lectura de bytes y tampoco
disponemos de ninguna utilidad que transforme la información obtenida en una imagen,
se pospone el resto de comprobaciones relacionadas con la captura de ROIs a los
próximos capítulos.

66
7 Arquitectura del software
En capítulos anteriores se ha establecido un orden cronológico en el que se detallaban
las motivaciones que llevaron al desarrollo de este proyecto, los objetivos que se
querían conseguir, la funcionalidad y estructura del sistema propuesto, el diseño
hardware desarrollado, y por último, los módulos VHDL que dotaron de funcionalidad
al hardware. Luego, hasta el momento, el documento solo se ha centrado en una parte
del sistema, la parte hardware.

No obstante, este hardware no podría ser automatizado sin un desarrollo software


adecuado, que sea capaz de aprovechar todas las posibilidades que ofrece.

En este capítulo, por tanto, se pretende profundizar en el desarrollo software realizado,


que ha permitido controlar y automatizar el sistema.

7.1 Desarrollo de librerías

Antes de realizar cualquier aplicación, se hace necesario partir de unas funciones o


módulos de código que por su funcionalidad deben ser utilizados de forma más o menos
frecuente en el desarrollo del software.

La finalidad de estas funciones es reducir y sintetizar en el mayor grado posible el


software final y permitir un desarrollo de forma más modular y cómoda, que facilite su
interpretación.

Este conjunto de funciones se agrupan en uno o varios ficheros, formando librerías o


DLLs, ficheros de extensión .DLL que se añaden al proyecto y permiten utilizar las
funciones básicas que contienen sin tener que repetir todo su código. En el caso que
contemplamos, todas las librerías se han desarrollado en el lenguaje de programación C.

Por último añadiremos que para mantener una estructura común en todas las funciones
de librería se ha decidido que en general todas estas sean del tipo boolean, es decir, que
la función solo pueda devolver dos resultados. True o '1' será devuelto en caso de que la
función haya finalizado con éxito y False o '0' en caso de que haya ocurrido algún
problema. Esto implica que tanto las entradas como las salidas de las funciones, en caso
de que sean necesarias, serán en forma de parámetros. Además únicamente en el caso de
que la función devuelva False, es decir para el caso de error, las funciones incluyen un
parámetro denominado Err_Msg o message, que como su nombre indica devuelve
información detallada del error que ha ocurrido.

67
7.1.1 DLL para la comunicación con la ESIIC

En el capítulo anterior se ha mostrado como se podía establecer una comunicación,


enviar comandos y recibir resultados de la placa LVDS Capturer a través de un terminal
Telnet. Esta opción que en el modo de prueba, y para caso simples, resulta la forma más
sencilla de comprobar el funcionamiento del sistema desarrollado, cuando se necesita
enviar una gran cantidad de comandos o leer grandes cantidades de informaciones deja
de ser viable. Si además consideramos que estas muestras se deben obtener, almacenar y
analizar de forma automática es evidente que necesitamos desarrollar unas librerías que
permitan interactuar con la ESIIC como si de un terminal se tratase.

Esta librería a desarrollar, debido a que la comunicación es vía TCP/IP, debe ser capaz
de gestionar una comunicación vía sockets con el servidor, que en este caso es la ESIIC.
Para ello entre las funciones básicas que esta librería debe incorporar se encuentran las
siguientes: Conexión con la ESIIC, envio de comandos, lectura de resultados y
finalización de la conexión.

Figura 59. Diagrama de flujo para el uso de la ESIIC

En este apartado, por tanto, se presenta de una forma muy esquemática el


funcionamiento de las principales funciones que aparecen en esta librería. El código
integro y comentado de esta DLL se anexa en el fichero esiic.c.

int __declspec(dllexport)__stdcall ConnectWithESIIC(char message[512],


unsigned int *esiicFileDes, char *ipString, int ipPort, int
nonBlocking, int timeout);

Esta función crea un cliente socket que establece la comunicación con la ESIIC.
Haciendo uso de las funciones para sockets que incorpora la API de Windows. Entre los
parámetros más importantes que recibe esta función se encuentran los dos básicos de
una comunicación TCP/IP, una dirección IP(char *ipString) y un puerto específico al
que conectar(int ipPort). El parámetro unsigned int *esiicFileDes es el
objeto resultante de esta función y permite posteriormente realizar escrituras y lecturas
directamente sobre este objeto sin tener que volver a establecer comunicación.

El proceso interno que realiza esta función es por tanto inicializar un cliente socket,
asociarlo con cualquier puerto o interfaz de la máquina local, conectar con el servicio
Telnet en la dirección y puerto que se indico como parámetro de la función y
finalmente, se asegura de recibir y eliminar la información que devuelve la ESIIC al
conectarse por primera vez con ella, es decir el menu que se aprecia en la figura 50. En

68
caso de que el timeout (int timeout) se agote y no se haya conseguido establecer una
comunicación con la ESIIC o en caso de que se produzca cualquier otro tipo de error, la
función devuelve un 0(false) y un mensaje de error(char message[512]).

int __declspec(dllexport)__stdcall SendI2cCommandLVDSESIIC (char


message[512], unsigned int esiicFileDes, char i2c_selected[256], int
rate, unsigned char i2c_address, int subaddr_ini, int bytes_data,
char cs_selected[256], int rcv_timeout,unsigned short offsetx,unsigned
short offsety,unsigned short length,unsigned short width,int
enable,int format);

Esta función genera un comando como el utilizado en el terminal para que un master
I2C de la ESIIC genere una escritura sobre un esclavo específico, es decir la trama
generada es la siguiente:

I2CMaster -write_data -rate XX -i2caddr XX -subaddrini XX -num_bytes X -data XX

Entre los parámetros de entrada incluye el nombre del I2CMaster que deseamos que
realice la escritura(char i2c_selected[256]), la velocidad de escritura (int rate),
sobre qué esclavo(char i2c_address), sobre qué registro(int subaddr_ini) y el
número de bytes a enviar(int bytes_data), así como los bytes a enviar.

El proceso interno que realiza esta función consiste en generar a partir de los parámetros
de entrada una trama idéntica a la que enviábamos por el terminal de Telnet. Además
para evitar escribir en hexadecimal los nueve bytes a enviar que delimitan la ROI, se
incorpora en esta cabecera 4 parámetros: offsetx, offsety, length y width.
Estos parámetros se introducen en formato decimal e internamente la función los
convierte a formato hexadecimal, para formar finalmente una línea de comando como la
siguiente:

i2c2 -write_data -rate 100000 -i2caddr A4 -subaddrini 00 -num_bytes 9 -data


000100010028002800

Una vez se tiene el comando preparado se utiliza la función send() de la API de


Windows para enviar estos bytes a través de la comunicación establecida y
posteriormente permanece en un bucle continuo a la espera de recibir respuesta de la
ESIIC. Para estas lecturas se hace uso de la función recv() de la API de Windows.

El tiempo máximo para enviar o recibir información se ha fijado con el parámetro de


entrada int rcv_timeout y en caso de que este tiempo expire y no haya habido éxito
la función finaliza devolviendo 0(False) y acompañando la respuesta del mensaje de
error pertinente.

En caso de que se reciba respuesta antes de que el timeout expire la función analiza la
respuesta recibida. Si la trama comienza con un OK significa que el envio ha sido
correcto y la función finaliza, en caso de recibir KO el envio ha sido incorrecto y la
función finaliza devolviendo un error.

69
int __declspec(dllexport)__stdcall ReadI2cIndividualBytesLVDSESIIC
(char message[512], unsigned int esiicFileDes, char i2c_selected[256],
int rate, unsigned char i2c_address, int subaddr_ini, int
bytes_subaddr, int bytes_to_read, int*recv_data);

Esta función, similar a la anterior, genera un comando como el utilizado en el terminal


para que un master I2C de la ESIIC genere una lectura sobre un esclavo específico, es
decir la trama generada es la siguiente:

I2CMaster -read_rx -rate XX -i2caddr XX -subaddrini XX -num_bytes XX

Entre los parámetros de entrada se incluye el nombre del I2CMaster que deseamos que
realice la lectura(char i2c_selected[256]), la velocidad de lectura (int rate),
sobre qué esclavo(char i2c_address), sobre qué registro(int subaddr_ini) y el
número de bytes a leer(int bytes_to_read).Los bytes leidos (int*recv_data) se
guardan en un buffer que se devuelve como parámetro de salida de la función.

El funcionamiento interno de esta función es análogo al caso anterior, genera una línea
de comandos con los parámetros de entrada, la envia a través del enlace de
comunicaciones y espera una respuesta. En este caso la respuesta si que es de interés ya
que corresponde con la información de los registros leidos que almacenan los resultados
de la ROI, por tanto, estos bytes leidos se guardan en el buffer recv_data.

int __declspec(dllexport)__stdcall GetInfoImageLVDS(char message[512],


unsigned int esiicFileDes, char i2c_selected[256], int * Rmean, int *
Gmean, int * Bmean, int* luminancia);

Para facilitar la lectura de los resultados de una ROI y devolverlos de forma separada
como valores RGB y Luminancia media se crea esta función. Esta función encapsula
internamente dos llamadas a la función ReadI2cIndividualBytesLVDSESIIC para que
genere una línea de comandos que lea directamente los bytes que interesan de los dos
esclavos de I2C, es decir, los registros de los esclavos de I2C que contienen los valores
medios de la región analizada. En resumen envia las dos tramas siguientes:

i2c2 -read_rx -rate 100000 -i2caddr A4 -subaddrini 0D -num_bytes 3


i2c2 -read_rx -rate 100000 -i2caddr A6 -subaddrini 0D -num_bytes 3

Con cada envio de las líneas de comandos anterior, captura los resultados devueltos por
la placa LVDS Capturer, lo que serían los valores RGB medios calculados, los separa
en R, G y B, y los convierte de formato hexadecimal a decimal. Finalmente pondera los
resultados obtenidos por los dos esclavos de I2C y los devuelve como los parámetros de
salida Rmean, Gmean,Bmean y Luminancia.

int__declspec(dllexport)__stdcall GetLimitValueLVDS(char message[512],


unsigned int esiicFileDes, char i2c_selected[256], int * Rmin, int *
Gmin, int * Bmin, int * Rmax, int * Gmax, int * Bmax);

Función análoga a la anterior, pero esta vez realizando lecturas sobre los registros que
contienen información de los valores mínimos y máximos de las regiones analizadas.

70
int__declspec(dllexport)__stdcall Create_Data_Storage_LVDS (char
message[512] , int *bits,int width, int heigth);

En el capítulo anterior se ha descrito uno de los problemas que impedía capturar


regiones de la imagen de forma manual a través del terminal Telnet. En este punto ya
hemos desarrollado una función denominada ReadI2cIndividualBytesLVDSESIIC
que permite la lectura de un número configurable de bytes, no obstante la limitación de
esta función viene fijada por la cantidad de bytes que de forma simultánea es capaz de
realizar en un único envio la ESIIC: 96 bytes. Por este motivo, se hace necesario crear
un buffer de memoria que vaya almacenando los bytes leidos con cada una de las
llamadas a la función ReadI2cIndividualBytesLVDSESIIC. Esta función por tanto
reserva una zona de memoria, apuntada por int *bits donde se almacenarán todos los
bytes de la ROI leidos, es decir, reserva una zona de memoria de tamaño 3 x width x
height bytes, siendo width y heigth el tamaño de la ROI en píxels.

int__declspec(dllexport)__stdcall Close_Data_Storage_LVDS(char
message[512],int *bits);

Libera la zona de memoria reservada a la que hace referencia el parámetro int *bits.

int __declspec(dllexport)__stdcall CloseConnectionWithESIIC(char


message[512], unsigned int esiicFileDes);

Utiliza las funciones de la API de Windows para finalizar la conexión establecida que
tenia como enlace el objeto creado con la función Connect, es decir, unsigned int
esiicFileDes.

7.1.2 DLL para la obtención de un fichero bitmap

Uno de los objetivos deseables de este proyecto consistía en la captura y el envio de una
ROI hacia el PC. En capítulos anteriores se ha descrito el proceso que se realiza para
capturar una de estas regiones, así como los registros que hay que leer para obtener cada
uno de los píxels que forman esta ROI y las limitaciones que estas lecturas tienen.
También se ha mostrado que la información obtenida corresponde a un conjunto de
bytes en formato hexadecimal que difícilmente permite conocer si los píxels leídos
corresponden realmente a la imagen que se deseaba capturar.

Para solventar este problema y obtener una imagen bitmap a través del conjunto de
bytes leídos que permita conocer directamente si los píxels leídos desde el ordenador
coinciden con los de la ROI se crea esta librería.

En este apartado, por tanto, se pretende presentar de una forma muy esquemática el
funcionamiento de las principales funciones que aparecen en esta librería. El código
íntegro y comentado de esta DLL se anexa en el fichero Bitmaps.c.

71
int__declspec(dllexport)__stdcall Create_Data_Storage(char
message[512], int *bits, int width, int height);

Para generar una imagen, una de las funciones que se incluye en esta librería necesita
disponer de los píxels RGB almacenados en forma de vector o array de una única
dimensión. La función por tanto reserva una zona de memoria, apuntada por int *bits
donde se almacenarán todos los bytes de la ROI leidos en forma de vector, es decir,
reserva una zona de memoria de tamaño 3 x width x height bytes, siendo width y heigth
el tamaño de la ROI en píxels.

int __declspec(dllexport) __stdcall Store_RGB_BLOCK(char message[512],


int *bits, int *datablock1,int *datablock2, int width,int height);

Esta función coge los bloques de memoria creados con la función


Create_Data_Storage_LVDS, que se han llenado con los píxels obtenidos de la ROI a
través de múltiples llamadas a la función ReadI2cIndividualBytesLVDSESIIC.
Como una ROI esta formada por píxels pares y píxels impares, en realidad lo que
tenemos son dos zonas de memoria reservadas mediante Create_Data_Storage_LVDS,
una para cada tipo de píxels.

Internamente lo que hace esta función es coger tres bytes(un píxel) del bloque de píxels
impares datablock1 y lo guarda en tres posiciones consecutivas del array bits¸ a
continuación coge otro tres bytes del bloque de píxels pares datablock2 y lo guarda en
las tres posiciones siguientes. Este proceso alternado se realiza hasta que todos los
píxels capturados han sido correctamente ordenados, formando en conjunto un array bits
que alterna los dos tipos de píxels existentes.

int __declspec(dllexport) __stdcall Save_Bitmap(char message[512], int


width, int heigth, int *bits, char filepath[512],int *Rmean,int
*Gmean,int *Bmean);

Esta función genera un fichero imagen bitmap de tamaño width x heigth con las
muestras almacenadas en la dirección de memoria referenciada por el puntero bits
guardando la imagen en la ruta especificada por el parámetro char filepath[512].

Además aprovecha que disponemos en un único vector con todos los píxels que forman
la imagen para calcular los valores RGB medios.

72
7.2 Secuencia de test
Una vez disponemos de unas librerías que permiten controlar y obtener información de
las placas LVDS Capturer, es el momento de implementar estas funciones dentro de una
secuencia de test. Esta secuencia de test nos permite obtener dos resultados importantes.
Por un lado comprobaremos si el proceso completo para la captura de regiones
funciona, por otro lado será más fácil someter al sistema a pruebas continuas que
garanticen su fiabilidad

Hay que tener en cuenta que la finalidad de este proyecto es mejorar la comprobación
actual de la salida de video hacía el LCD de la TV Board en de una cadena de
producción, a la vez que se intenta reducir el tiempo de este proceso. No hace falta decir
que un sistema poco seguro podría provocar un comportamiento anómalo de la máquina
de test CBA con los problemas que esto conllevaría, pudiendo provocar la parada
temporal de las líneas de producción.

Para realizar esta secuencia de test se ha uso de TestStand, una utilidad de National
Instruments que hace la función de secuenciador, permitiendo la llamada a funciones de
librerías desarrolladas en entornos de programación muy distintos como LabView,
LabWindows, C, C++, C# desde un mismo entorno gráfico. También tiene funciones
básicas como pueden ser condicionales como while, if, else y funciones de
sincronización. El uso de este programa implica que todos los parámetros de
entrada/salida que se deben pasar a las funciones se crean como variables locales o
parámetros propios de TestStand, de esta forma se puede debugar la secuencia llamada a
llamada, observando el valor actual de dichos parámetros.

La secuencia desarrollada mediante TestStand tiene la estructura de la figura 60.


Start Global Sequence

Process
Setup

Main
Sequence

Proces
Cleanup

Finished Sequence

Figura 60. Estructura de la secuencia global de Test

73
La secuencia global de Test está formada por 3 partes, el Process setup, Main sequence
y Process Cleanup.

Pocess Setup: Este código se ejecuta una única vez cuando se lanza la secuencia.
Su finalidad es realizar configuraciones y verificaciones previas del sistema,
antes de comenzar a verificar cualquier placa de televisión.

Main Sequence: Secuencia principal de verificación de la señal LVDS.

Process Cleanup: Código que se ejecuta una única vez tras finalizar la secuencia
de TestStand. Su finalidad es liberar objetos creados en las anteriores etapas.

7.2.1 Análisis de regiones


En este subapartado se describe el proceso de incorporación de las funciones de las
librerías anteriores a la secuencia creada en TestStand para poder analizar regiones
específicas del panel sin tener que recurrir a una ventana terminal.

Figura 61. Secuencia de TestStand para el análisis de tres barras de colores distintas

Como se aprecia en la figura 61, el proceso se inicia con un establecimiento de la


conexión con la ESIIC mediante llamada a la función ConnectWithESIIC.
Posteriormente se debe especificar el tamaño que tendran las ROIs a analizar, como en
total deseamos analizar zonas de un tamaño completo de 96x96 píxels, a cada una de las
funciones hay que decirles que en realidad queremos regiones de 48x96, esas
asignaciones las realizan los pasos Statement_1 y Statemente_2 de la secuencia.

Una vez establecida la comunicación y decidido el tamaño de las ROI tenemos que
hacer dos llamadas a la función SendI2CCommandLVDSESIIC, una para cada esclavo de
I2C. Estas funciones tienen prefijados unos offsetx y un offsety, que juntamente con el
tamaño de la ROI definido permiten especificar exactamente una zona de captura, en
este caso en el centro de una de las barras de colores. Tras ejecutar estas dos funciones,
la región seleccionada se remarca en el panel y se realiza su análisis.

74
Finalmente una llamada a la función GetInfoImageLVDS, devuelve el valor promedio
RGB de esta ROI.

En la secuencia de la figura 62 se han definido tres zonas a analizar, que corresponden a


tres colores distintos de la carta de la figura 49, por tanto si ejecutamos la secuencia
creada y observamos los resultados devueltos por estas funciones enTestStand
obtendremos los valores RGB medios de las tres regiones seleccionadas. Agrupamos los
resultados en la tabla de la figura 63.

Figura 62. Resultados obtenidos en TestStand para las tres regiones analizadas

Regiones
Zona 1 Zona 2 Zona 3
Rmean 198 72 196
Gmean 194 192 0
Bmean 3 2 187
Figura 63. Resumen del análisis de las tres regiones

Y si generamos un color para cada una de las zonas analizadas obtenemos tres de los
colores que aparecen en la carta, que lógicamente eran los colores que se habían
seleccionado para su análisis.

Figura 64. Colores obtenidos mediante Paint a través de los resultados mostrados en TestStand

75
7.2.2 Captura de regiones

Uno de los puntos que no se pudo comprobar en el capítulo 6 era el proceso de captura
y envio hacia el ordenador de una región específica de la imagen. Con el desarrollo de
las librerías descritas en este capítulo ya podemos realizar capturas de tamaño
considerable y además generar un bitmap que permita ver los resultados obtenidos.

La primera fase para llevar a cabo estas capturas, consiste en seleccionar la zona de
interés mediante dos escrituras por I2C, uno para cada esclavo, haciendo uso de la
función SendI2cCommandLVDSESIIC.

Figura 65. Secuencia de TestStand donde se seleccciona la ROI a capturar

El siguiente paso consiste en crear dos buffers de memoria para los píxels leidos por
cada una de las FPGAs, así como otro buffer global que se utilizará posteriormente para
unir los dos buffers anteriores y generar la imagen bitmap. Para ello usamos la función
Create_Data_Storage_LVDS para los buffers independientes y Create_Data_Storage
para el buffer global del bitmap.

Figura 66. Llamadas a las funciones de la librería para la creación de buffers

A continuación necesitamos realizar un número específico de lecturas sobre cada uno de


los esclavos de I2C, según el número de píxels a capturar y el número de bytes que se
lean en cada llamada a la función ReadI2cIndividualBytesLVDSESIIC. El resultado
de cada una de estas lecturas se va almacenando en el buffer de memoria
correspondiente. Debido a que el número máximo de bytes que se pueden leer por cada
llamada a la función ReadI2cIndividualBytesLVDSESIIC es de 96, elegimos este
número como valor por defecto para cada lectura. Esto implica que el número total de
lecturas por esclavo de I2C responde a la siguiente ecuación:

WidthROI ⋅ HeightROI ⋅ 3bytes / pixel


numlecturas =
96bytes / lectura

76
Figura 67. Cálculo del número de lecturas y bucles de lectura

Ahora pasamos los bloques de memoria que contienen los píxels pares e impares a la
función Store_RGB_Block que se encargará de rellenar el buffer global intercalando en
él píxels pares e impares. Por último generamos la imagen con la información contenida
en este buffer mediante la función Save_Bitmap y liberamos el espacio de memoria que
habíamos reservado.

Figura 68. Creación de la imagen y liberación de los buffers creados

Para comprobar el correcto funcionamiento del sistema de captura seleccionamos una


pequeña región de la barra azul de un tamaño aproximado de 96x96 píxels. Tras unos
segundos, se nos ha creado un fichero en el directorio especificado denominado
prova.bmp que contiene el siguiente resultado.

Figura 69. A la izquierda una foto del LCD donde se aprecia la región
seleccionada, a la derecha imagen capturada con la secuencia de TestStand.

La zona anterior corresponde a una región de tamaño reducido y el tiempo que la


secuencia ha tardado ha sido de unos dos segundos.

Uno de los problemas que presenta la captura anterior y que nos impide verificar por
completo el sistema consiste en que al tratarse de una región pequeña hemos obtenido
una imagen formada por un color único, en este caso azul. Para asegurar que el sistema
es capaz de capturar cualquier tipo de imagen es conveniente probar a capturar una
imagen con formas y tonalidades variadas ya que en la captura de la figura 69 cualquier
movimiento o posicionamiento incorrecto de los píxels daría un resultado equivalente,
sin ser este correcto.

Para realizar una comprobación mas exhaustiva introducimos esta vez una señal de
entrada más compleja y variada con múltiples polígonos y formas donde se podría

77
apreciar claramente cualquier desvió en el proceso de captura. La señal introducida en el
panel y la captura obtenida se muestran en la figura 70.

Figura 70. A la izquierda LCD con la señal de entrada, a la derecha la captura realizada mediante la
secuencia de TestStand. Las diferencias entre ambas tonalidades se deben a que en la imagen de la
izquierda, la del panel, al hacer una fotografía los colores se han visto ligeramente alterados. El mismo
fenómeno ocurre en todas las fotografías realizadas directamente a un televisor LCD.

En este caso como se puede apreciar la captura ha sido de mayor tamaño, 1800x1000
píxels, casí la resolución máxima de un televisor FullHD( 1920x1080píxels). Como se
puede observar la captura y la imagen del panel son idénticas (ignorando el cambio de
tonalidad provocado por la cámara), las barras de colores que incluye esta señal de
entrada coinciden y los polígonos entrelazados también.

El único problema que plantea este sistema, y que lo hace inviable para realizar capturas
en la línea de producción, consiste en la reducida velocidad del bus I2C(100 Kbps). Para
dar unos tiempos aproximados, la captura de la imagen de la figura 70 ha tardado
aproximadamente 30 minutos. Si tenemos en cuenta que en las máquinas de test, donde
se desea implementar el sistema LVDS Capturer, se deben analizar alrededor de siete
señales de video recibidas en diferentes formatos, la comprobación del video por cada
una de las TV Board rondaría los 210 minutos, tiempo excesivamente elevado para una
cadena de producción. Una posible solución consistiría en incrementar la velocidad del
bus I2C, no obstante a velocidades ligeramente superiores a 100Kbps con el hardware
actual se empiezan a producir lecturas erróneas de píxels, que degradan
considerablemente la imagen.

Aunque ya se ha remarcado que la captura de imagen no es el objetivo de este prototipo,


con la intención de aumentar la velocidad del protocolo de comunicaciones I2C se
decide incorporar sobre la placa LVDS Capturer unas resistencias de pull-up de
2.2Kohms sobre las dos líneas del bus I2C. Estas resistencias, que de inicio no se
planteó incorporarlas en el diseño ya que no se necesitaba una velocidad elevada para
enviar al ordenador los resultados del análisis, permiten al protocolo de comunicaciones
reducir el tiempo de subida de las señales, aumentando así la velocidad a la que puede
operar el sistema.

Para analizar los límites de velocidad de la nueva configuración del bus I2C decidimos
introducir otra señal de entrada, esta vez una barra de colores verticales básica. Se
realizan múltiples capturas de una imagen de 1800x1000 píxels como la anterior. En las
pruebas realizadas el sistema funciona a velocidades de 800Kbps sin mostrar ningún
tipo de degradación de la imagen capturada. De hecho, en las pruebas realizadas el

78
sistema fue capaz de funcionar a velocidades superiores a 1Mbps, pero los resultados en
algunas de estas capturas mostraban la pérdida de algunos píxels.

Figura 71. A la izquierda LCD con carta de barras de colores, a la derecha la captura realizada mediante
la secuencia de TestStand. De nuevo las diferencias entre ambas tonalidades se deben a que en la imagen
de la izquierda, la del panel, al hacer una fotografía los colores se han visto ligeramente alterados. El
mismo fenómeno ocurre en todas las fotografías realizadas directamente a un televisor LCD.

Con una velocidad de captura de 800Kbps el tiempo de captura de una imagen de


1800x1000 píxels se redujo a 4.3 minutos. Aunque es cierto que se ha reducido de
forma importante, este tiempo hace inviable el uso de la opción de captura de imagen en
la línea de producción.

79
8 Implementación en la línea de producción
Una vez verificado que el sistema es totalmente funcional tanto en su función básica de
análisis de regiones como en su versión extendida como capturador de imagen se
procede a implementar el sistema en la máquina de test CBA.

8.1 Montaje final y proceso de la máquina de test


El montaje en la máquina es exactamente el mismo que se mostró en la figura 46, la
ESIIC conectada al PC vía Ethernet, comunicada con la placa LVDS Capturer a través
del bus I2C y la placa LVDS Capturer conectada a la TV Board. Las diferencias básicas
con el sistema provisional de los capítulos anteriores son tres:

1. No se dispone de un panel LCD conectado a la placa LVDS Capturer, lo que


implica que no podemos visualizar la zona que se está analizando.

2. Tanto la ESIIC como la placa LVDS Capturer se encuentran integradas dentro


de la máquina de test CBA.

3. El conector LVDS que proporciona la señal de entrada a la placa LVDS


Capturer se conecta a través de un conjunto de electroválvulas a la TV Board
que se haya introducido en la máquina de test.

Figura 72. Máquina de test CBA remarcando la posición de los instrumentos que intervienen en el
sistema.

80
Una vez posicionado cada dispositivo en la máquina de test CBA, se procede a la
sustitución de la parte de la secuencia dedicada al "análisis" de las señales de video por
los fragmentos de secuencia desarrollados en el capítulo anterior. Además en esta
secuencia se deben añadir comprobaciones adicionales basadas en la lectura de los
registros delos esclavos de I2C, de esta forma se consiguen sustituir los tiempos de
espera estáticos introducidos en la secuencia de prueba por esperas dinámicas basadas
en el estado de los registros.

La secuencia global de TestStand en funcionamiento en las máquinas de test se divide


en un conjunto de llamadas a otras subsecuencias que se encargan de comprobar ciertas
características de la placa TV Board que se esta verificando. Por ejemplo, una
subsecuencia encargada de verificar las tensiones en diversos puntos de la placa, otra de
la comprobación de diversos tipos de audio de entrada y salida, y la que a nosotros nos
interesa, comprueba los diversos formatos de video de entrada que acepta la TV Board.
Esta última subsecuencia recibe el nombre de WRK_Check_Video.

El procedimiento que realiza la máquina de test consiste en introducir a través de los


diversos conectores de entrada de la TV Board señales de video, ir multiplexando entre
estas entradas y realizar una llamada a la subsecuencia WRK_Check_Video para la
comprobación de cada señal de entrada. Las señales de entrada son siempre cartas
formadas por barras de colores verticales, como la que se mostró en la figura 49.

81
8.2 Subsecuencia de video adaptada

Teniendo en cuenta el comportamiento anterior para analizar la señal de video con


nuestro sistema LVDS Capturer se deben definir unas regiones de análisis para cada una
de las distintas señales de entrada de video que se desean comprobar. Estas regiones de
interés consisten en tres zonas de 96x96 píxels para cada una de las señales de video.
Una región en la barra vertical roja, otra en la verde y la última en la azul. Además se
deben fijar límites máximos y mínimos que permitan decidir si los valores RGB medios,
y la luminancia, son correctos. Lógicamente el proceso para delimitar la posición
correcta donde ubicar estas regiones de análisis dentro de los colores deseados, así como
los valores límite de las especificaciones se debe realizar de forma manual y con la
ayuda de un panel en el otro extremo de la placa LVDS Capturer.

La subsecuencia empieza comprobando que la placa LVDS Capturer se encuentra


conectada y preparada para empezar a trabajar. Para realizar esta comprobación se
realiza una lectura sobre el registro interno Mem(25), de cada uno de los esclavos de
I2C. Este registro se encuentra fijado a 0xFF. Si no es posible comunicar con la placa o
el valor leído es erróneo el sistema aún no se encuentra inicializado o presenta algún
problema, lo que provocaría un fallo de la secuencia. En caso de que se realice una
lectura correcta y de valor 0xFF la secuencia continua. Esta comprobación sólo se
realiza una vez, con la primera señal de video.

Figura 73. Lectura de los registros de inicialización de la placa LVDS Capturer

Lo siguiente es comprobar que existe una señal de reloj procedente de la TV Board que
llega a la placa LVDS Capturer y que es capaz de sincronizarse con el PLL de
74.25MHz que se ha implementado en las FPGAs. Este registro recibe el nombre de
Mem(17)-Locked.

Figura 74. Lectura de los registros de sincronización del PLL de la placa LVDS Capturer

82
Si la sincronización de la placa LVDS Capturer con el reloj procedente de la TV Board
no se produce, la lectura de este registro devolverá un '0', que indica que no hay señal de
reloj o que la frecuencia es errónea.

El siguiente paso de la secuencia es el análisis de las tres regiones seleccionadas, para


cada región se debe realizar dos envios por I2C para configurar la región y
posteriormente se debe realizar un bucle de espera donde continuamente se sondea el
registro Mem(24). Cuando en alguna de estas lecturas el bit menos significativo de este
registro se encuentra a nivel alto, significa que los resultados están listos para ser leídos.

Figura 75. Envió de comandos para la selección de la ROI y bucle de lectura del registro Mem(24) que
indica la existencia de nuevos resultados

La última fase consiste en la lectura de los resultados y la comparación con las


especificaciones fijadas.

Figura 76. Lectura de los resultados con la posibilidad elegir entre comprobar los valores RGB Medios o
sólo la luminancia. Al final las llamadas Check comparan los resultados con las especificaciones.

Si los resultados de las tres regiones de video son correctos la secuencia continúa su
proceso realizando la comprobación de las demás entradas de video, en caso contrario,
la secuencia finaliza indicando un fallo debido a una TV Board dañada.

83
8.3 Incidencias
Tras realizar el montaje del sistema en la máquina de test, proceder a la modificación de
la secuencia WRK_Check_Video e introducir unas especificaciones para los resultados
de cada una de las zonas analizadas se lanza la secuencia, insertando previamente una
placa de televisión en la máquina de test. Para comprobar si la secuencia y el sistema
completo funcionan correctamente se ha colocado un panel LCD conectado a la salida
de la placa LVDS Capturer pudiendo apreciar así que con cada señal de video de
entrada el panel muestra la carta de colores correctamente, además se aprecia como se
remarcan las tres regiones especificadas para cada una de las señales de video de
entrada. La secuencia finaliza con éxito, estando todos los valores medios obtenidos
dentro de las especificaciones marcadas.

Aprovechando que el sistema se encontraba totalmente operativo en la máquina de test,


se propuso realizar una captura con la secuencia "provisional" del capítulo 7 para
comprobar totalmente el sistema. Para realizar una captura de grandes dimensiones
sobre una de las cartas de video de entrada se lanzo la secuencia provisional con una
velocidad de lectura para el I2C de 800Kbps, velocidad ya probada en el capítulo
anterior con éxito. Desgraciadamente el proceso de captura no se pudo llevar a cabo a
esta velocidad, teniendo que reducir drásticamente esta velocidad máxima para que la
captura fuese exitosa. Tras analizar este nuevo problema se llego a la conclusión de que
la única diferencia entre el montaje en la fase de prototipado y el montaje definitivo
consistía en la forma de alimentar al sistema. En la fase de prototipado los 5V para la
placa LVDS Capturer se le proporcionaban directamente de una fuente de alimentación
externa a la que no se encontraba ningún dispositivo más conectado, en cambio en la
máquina de test estos 5V de alimentación también proceden de una fuente de
alimentación externa, pero esta vez esta alimentación es común para una gran cantidad
de placas y dispositivos. Esta gran cantidad de dispositivos compartiendo la misma
alimentación provocaba que esta señal de 5V que alimentaba la placa LVDS Capturer
estuviese afectada por ruido, un ruido que reducía drásticamente la velocidad máxima
de funcionamiento del bus I2C. Para solventar este problema se opto por incluir un
filtro externo en la entrada de alimentación de la placa LVDS Capturer que estabilizaba
los 5V que posteriormente alimentaban todo el hardware. Esta modificación permitió
realizar capturas de nuevo a velocidades de 800Kbps y superiores también en la
máquina de test, aunque en la práctica solo se analizan regiones, no se capturan. El filtro
de entrada incorporado en la placa LVDS Capturer se puede apreciar en la figura 24.

84
9 Conclusiones
Se han conseguido todos los objetivos que se habían fijado al plantear el proyecto, y el
diseño desarrollado tanto a nivel hardware como a nivel software funciona
correctamente.

A lo largo de este documento se ha diseñado un sistema hardware, y se ha


implementando un comportamiento complejo mediante módulos VHDL en las FPGAs
que se incorporaron en este hardware. Con estos módulos se ha obtenido un sistema
controlable a través de un bus I2C que permite analizar regiones configurables de la
imagen de los televisores LCD Sony, sin la necesidad de disponer de un panel LCD
conectado en el otro extremo. Además con el éxito de este diseño no se ha permitido
únicamente analizar de forma exhaustiva la señal de video que se envía hacia el panel, si
no que además se ha añadido la posibilidad de realizar capturas sobre regiones de la
imagen, así como modificarla.

A continuación se ha procedido al desarrollo de librerías en C que permiten controlar,


configurar y analizar los datos procedentes de la placa LVDS Capturer. Posteriormente
se han utilizado estas librerías para la creación de una secuencia de test que permita
analizar y comprobar de forma automática múltiples regiones de la imagen, para cada
una de las señales de video de entrada posibles.

Este proyecto se desarrolló inicialmente como un prototipo para analizar la viabilidad


del proceso de captura de forma directa sobre la señal de salida de una placa de TV.
Aún así, dado el éxito del proyecto, y siendo un prototipo, el sistema se acabado
implementando en la mayoría de las máquinas de test que verifican las placas de
televisión del modelo EX2N en la cadena de producción de televisores LCD de Sony.

Con este proyecto no se ha conseguido únicamente unificar todos los métodos de


comprobación de video que existían anteriormente, si no que además ha permitido
realizar un análisis mucho más detallado de la imagen, asegurando que la imagen que se
envía al panel es totalmente correcta. Con esta comprobación exhaustiva de la señal de
video que sale de la placa de TV antes de disponer del televisor completo se pueden
detectar problemas con la imagen en los inicios de la cadena de producción, evitando así
un gasto material y humano innecesario. Por último se remarca que para el modelo
específico para el cual se desarrolló el proyecto se consiguió reducir en 8 segundos el
tiempo global del proceso de verificación en la máquina de test pasando de 80 a 72
segundos, siendo esta etapa de verificación el cuello de botella de la producción y por
tanto la que limita la producción global de televisores en la cadena de producción.

Se debe añadir también que debido al éxito que ha tenido este proyecto, se encuentra
actualmente en fase de desarrollo otra versión más completa de la placa LVDS
Capturer, compatible con todos los modelos de televisión que se fabrican en la fábrica
de Sony en Viladecavalls. Esta nueva versión, entre otras opciones, permite el envío vía
ethernet hacia el ordenador de la señal de video en tiempo real que se esta enviando al
panel, permitiendo la captura rápida de imágenes FHD, así como la captura de video, y
no únicamente imágenes fijas como permitía este proyecto. Además, se trabaja
directamente sobre las señales diferenciales, eliminando los conversores de niveles
LVDS a TLL.

85
10 Bibliografía
WEBS DE I!TERÉS

• http://www.altera.com/
• http://www.altera.com/products/devices/cyclone2/cy2-index.jsp
• http://www.altium.com/products/en/products_home.cfm
• http://www.thine.co.jp/index_e.php
• http://www.thine.co.jp/products_e/LVDS/

DOCUME!TOS DE I!TERÉS

• Dave Lewis, "LVDS: Five tips for buffering signal integrity",


National Semiconductor, December 2005
http://www.eetasia.com/ARTICLES/2001AUG/2001AUG09_RFD_E
DA_TAC.PDF
• Altera, "Cyclone II device Handbook Volume 1", February 2008
http://www.altera.com/literature/hb/cyc2/cyc2_cii5v1.pdf
• Altera, "Cyclone II Device Family Data Sheet", April 2007
http://www.altera.com/literature/hb/cyc2/cyc2_cii5v1_01.pdf
• Sony Corporation, “Product description of 37'' HDTV Color TFT-
LCD Module", July 2006
• THine, " THC63LVD104 Data Sheet", Juny 2008
http://www.thine.co.jp/products_e/LVDS/pdf/THC63LVD104C_Rev
.1.00_E.pdf
• THine, " THC63LVD103 Data Sheet", Juny 2008
http://www.thine.co.jp/products_e/LVDS/pdf/THC63LVD103D_Rev
.1.10_E.pdf
• THine, "THC63LVD103 and THC63LVD104 Application notes",
Juny 2008
http://www.thine.co.jp/products_e/LVDS/pdf/than0064_rev140_e_ap
lli_3.pdf

86
11 Anexos

[Anexo 1]. Descripción del bus I2C

[Anexo 2]. Diseño esquemático del hardware

[Anexo 3]. Código VHDL

[Anexo 4]. Código de las librerías

87
ANEXO 1
Descripción del bus I2C
2-WIRE CMOS SERIAL E2PROM
S-24CS01A/02A/04A/08A Rev.2.0_10

Operation

1. Start Condition

Start is identified by a high to low transition of the SDA line while the SCL line is stable at high.
Every operation begins from a start condition.

2. Stop Condition

Stop is identified by a low to high transition of the SDA line while the SCL line is stable at high.
When a device receives a stop condition during a read sequence, the read operation is interrupted, and the
device enters standby mode.
When a device receives a stop condition during a write sequence, the reception of the write data is halted,
2
and the E PROM initiates a write cycle.

tSU.STA tHD.STA tSU.STO

SCL

SDA

Start Condition Stop Condition

Figure 8 Start / Stop Conditions

10 Seiko Instruments Inc.


2-WIRE CMOS SERIAL E2PROM
Rev.2.0_10 S-24CS01A/02A/04A/08A

3. Data Transmission

Changing the SDA line while the SCL line is low, data is transmitted.
Changing the SDA line while the SCL line is high, a start or stop condition is recognized.

tSU.DAT tHD.DAT

SCL

SDA

Figure 9 Data Transmission Timing

4. Acknowledge

The unit of data transmission is 8 bits. During the 9th clock cycle period the receiver on the bus pulls down
the SDA line to acknowledge the receipt of the 8-bit data.
When a internal write cycle is in progress, the device does not generate an acknowledge.

SCL
(E2PROM Input) 1 8 9

SDA
(Master Output)

Acknowledge
SDA Output
2
(E PROM Output) Start Condition

tAA tDH

Figure 10 Acknowledge Output Timing

Seiko Instruments Inc. 11


2-WIRE CMOS SERIAL E2PROM
S-24CS01A/02A/04A/08A Rev.2.0_10

5. Device Addressing

To start communication, the master device on the system generates a start condition to the bus line. Next,
the master device sends 7-bit device address and a 1-bit read / write instruction code on to the SDA bus.
The 4 most significant bits of the device address are called the "Device Code", and are fixed to "1010".

In S-24CS01A/02A, successive 3 bits are called the "Slave Address". These 3 bits are used to identify a
device on the system bus and are compared with the predetermined value which is defined by the address
input pins (A0, A1 and A2). When the comparison result matches, the slave device responds with an
acknowledge during the 9th clock cycle.

In S-24CS04A, successive 2 bits are called the "Slave Address." These 2 bits are used to identify a device
on the system bus and are compared with the predetermined value which is defined by the address input
pins (A1 and A2). When the comparison result matches, the slave device responds with an acknowledge
during the 9th clock cycle.
The successive 1 bit (P0) is used to define a page address and choose the two 256-byte memory blocks
(Address 000h to 0FFh and 100h to 1FFh).

In S-24CS08A, successive 1 bit is called the “Slave Addrdess”. This 1 bit is used to identify a device on the
system bus and is compared with the predetermined value which is defined by the address input pin (A2).
When the comparison result matches, the slave device responds with an acknowledge during the 9th
clocks cycle.
The successive 2 bits (P1 and P0) are used to define a page address and choose the four 256-byte
memory blocks (Address 000h to 0FFh, 100h to 1FFh, 200h to 2FFh and 300h to 3FFh).

Device Code Slave Address

S-24CS01A/02A 1 0 1 0 A2 A1 A0 R/W

MSB LSB

Slave / Page
Device Code Address

S-24CS04A 1 0 1 0 A2 A1 P0 R/W

S-24CS08A 1 0 1 0 A2 P1 P0 R/W

MSB LSB

Figure 11 Device Address

12 Seiko Instruments Inc.


2-WIRE CMOS SERIAL E2PROM
Rev.2.0_10 S-24CS01A/02A/04A/08A

6. Write

6.1 Byte Write

When the master sends a 7-bit device address and a 1-bit read / write instruction code set to "0", following
2 2
a start condition, the E PROM acknowledges it. The E PROM then receives an 8-bit word address and
2
responds with an acknowledge. After the E PROM receives 8-bit write data and responds with an
acknowledge, it receives a stop condition and that initiates the write cycle at the addressed memory.
During the write cycle all operations are forbidden and no acknowledge is generated.

S W
T R S
A I T
R DEVICE T O
T ADDRESS E WORD ADDRESS DATA P

SDA LINE 1 0 1 0 A2 A1 A0 0 W7 W6 W5 W4 W3 W2 W1 W0 D7 D6 D5 D4 D3 D2 D1 D0

M L R A A A
S S / C C C
B B WK K K

Remark1. A1 is P1 in the S-24CS08A. ADR INC


2. A0 is P0 in the S-24CS04A/08A. (ADDRESS INCREMENT)
3. W7 is optional in the S-24CS01A.

Figure 12 Byte Write

Seiko Instruments Inc. 13


2-WIRE CMOS SERIAL E2PROM
S-24CS01A/02A/04A/08A Rev.2.0_10

6.2 Page Write

The page write mode allows up to 8 bytes to be written in a single wire operation in the S-24CS01A/02A
and 16 bytes to be written in a single write operation in the S-24CS04A/08A.
Basic data transmission procedure is the same as that in the "Byte Write". But instead of generating a stop
condition, the master transmitts 8-bit write data up to 8 bytes before the page write.
2
When the E PROM receives a 7-bit device address and a 1-bit read / write instruction code set to "0",
2
following a start condition, it generates an acknowledge. Then the E PROM receives an 8-bit word
2
address, and responds with an acknowledge. After the E PROM receives 8-bit write data and responds
with an acknowledge, it receives 8-bit write data corresponding to the next word address, and generates
2
an acknowledge. The E PROM repeats reception of 8-bit write data and generation of acknowledge in
2
succession. The E PROM can receive as many write data as the maximum page size.
Receiving a stop condition initiates a write cycle of the area starting from the designated memory address
and having the page size equal to the received write data.

S W
T R S
A I T
R DEVICE T
ADDRESS E O
T WORD ADDRESS (n) DATA (n) DATA (n+1) DATA (n+x) P
SDA
1 0 1 0 A2 A1 A0 0 W7 W6 W5 W4 W3 W2 W1 W0 D7 D6 D5 D4 D3 D2 D1 D0 D7 D0 D7 D0
LINE
M L R A A A A A
S S / C C C C C
B B WK K K K K
Remark1. A1 is P1 in the S-24CS08A.
2. A0 is P0 in the S-24CS04A/08A. ADR INC ADR INC ADR INC
3. W7 is optional in the S-24CS01A.
Figure 13 Page Write

In S-24CS01A/02A, the lower 3 bits of the word address are automatically incremented every time when
2
the E PROM receives 8-bit write data. If the size of the write data exceeds 8 bytes, the upper 5 bits of the
word address remain unchanged, and the lower 3 bits are rolled over and previously received data will be
overwritten.

In S-24CS04A, the lower 4 bits of the word address are automatically incremented every time when the
2
E PROM receives 8-bit write data. If the size of the write data exceeds 16 bytes, the upper 4 bits of the
word address and page address (P0) remain unchanged, and the lower 4 bits are rolled over and
previously received data will be overwritten.

In S-24CS08A, the lower 4 bits of the word address are automatically incremented every time when the
2
E PROM receives 8-bit write data. If the size of the write data exceeds 16 bytes, the upper 4 bits of the
word address and page address (P1 and P0) remain unchanged, and the lower 4 bits are rolled over and
previously received data will be overwritten.

14 Seiko Instruments Inc.


2-WIRE CMOS SERIAL E2PROM
Rev.2.0_10 S-24CS01A/02A/04A/08A

6.3 Acknowledge Polling

2
Acknowledge polling is used to know the completion of the write cycle in the E PROM.
2
After the E PROM receives a stop condition and once starts the write cycle, all operations are forbidden
and no response is made to the signal transmitted by the master device.
2
Accordingly the master device can recognize the completion of the write cycle in the E PROM by detecting
a response from the slave device after transmitting the start condition, the device address and the
2
read/write instruction code to the E PROM, namely to the slave devices.
2
That is, if the E PROM does not generate an acknowledge, the write cycle is in progress and if the
2
E PROM generates an acknowledge, the write cycle has been completed.
It is recommended to use the read instruction "1" as the read/write instruction code transmitted by the
master device.

6.4 Write Protection

Write protection is available in the S-24CS01A/02A/04A/08A. When the WP pin is connected to the VCC,
write operation to memory area is forbidden at all.
When the WP pin is connected to the GND, the write protection is invalid, and write operation in all memory
area is available. There is no need for using write protection, the WP pin should be connected to the GND.
The write protection is valid in the operating voltage range.

Seiko Instruments Inc. 15


2-WIRE CMOS SERIAL E2PROM
S-24CS01A/02A/04A/08A Rev.2.0_10

7. Read

7.1 Current Address Read

2
Either in writing or in reading the E PROM holds the last accessed memory address, internally
incremented by one. The memory address is maintained as long as the power voltage is higher than the
current address hold voltage VAH.
The master device can read the data at the memory address of the current address pointer without
assigning the word address as a result, when it recognizes the position of the address pointer in the
2
E PROM. This is called "Current Address Read".
2
In the following the address counter in the E PROM is assumed to be “n”.
2
When the E PROM receives a 7-bit device address and a 1-bit read / write instruction code set to “1”
following a start condition, it responds with an acknowledge. However, the page address (P0) in S-
24CS04A and the page address (P1 and P0) in S-24CS08A become invalid and the memory address of
the current address pointer becoms valid.
2
Next an 8-bit data at the address "n" is sent from the E PROM synchronous to the SCL clock. The address
counter is incremented at the falling edge of the SCL clock for the 8th bit data, and the content of the
address counter becomes n+1.
The master device has to not acknowledge the 8-bit data and terminates the reading with a stop condition.

S NO ACK from
T R Master Device S
A E T
R DEVICE A O
T ADDRESS D P

SDA LINE 1 0 1 0 A2 A1 A0 1 D7 D6 D5 D4 D3 D2 D1 D0

M L R A DATA
S S / C
B B W K
ADR INC

Remark1. A1 is P1 in S-24CS08A.
2. A0 is P0 in S-24CS04A/08A.

Figure 14 Current Address Read

2
Attention should be paid to the following point on the recognition of the address pointer in the E PROM.
2
In the read operation the memory address counter in the E PROM is automatically incremented at every
falling edge of the SCL clock for the 8th bit of the output data. In the write operation, on the other hand, the
*1
upper bits of the memory address (the upper bits of the word address and page address) are left
unchanged and are not incremented at the falling edge of the SCL clock for the 8th bit of the received
data.

*1. S-24CS01A/02A is the upper 5 bits of the word address.


S-24CS04A is the upper 4 bits of the word address and the page address P0.
S-24CS08A is the upper 4 bits of the word address and the page address P1 and P0.

16 Seiko Instruments Inc.


2-WIRE CMOS SERIAL E2PROM
Rev.2.0_10 S-24CS01A/02A/04A/08A

7.2 Random Read

Random read is used to read the data at an arbitrary memory address.


A dummy write is performed to load the memory address into the address counter.
2
When the E PROM receives a 7-bit device address and a 1-bit read / write instruction code set to "0"
2
following a start condition, it responds with an acknowledge. The E PROM then receives an 8-bit word
address and responds with an acknowledge. The memory address is loaded to the address counter in the
2
E PROM by these operations. Reception of write data does not follow in a dummy write whereas reception
of write data follows in a byte write and in a page write.
Since the memory address is loaded into the memory address counter by dummy write, the master device
can read the data starting from the arbitrary memory address by transmitting a new start condition and
performing the same operation in the current address read.
2
That is, when the E PROM receives a 7-bit device address and a 1-bit read / write instruction code set to
"1", following a start condition signal, it responds with an acknowledge. Next, 8-bit data is transmitted from
2
the E PROM in synchronous to the SCL clock. The master device has to not acknowledge and terminates
the reading with a stop condition.

S W S
T R T R NO ACK from S
A I A E Master Device T
R DEVICE T WORD R DEVICE A O
T ADDRESS E ADDRESS (n) T ADDRESS D DATA P
SDA
LINE 1 0 1 0 A2 A1 A0 0 W7W6W5W4W3W2W1W0 1 0 1 0 A2 A1 A0 1 D7 D6 D5 D4 D3 D2 D1 D0
M L R A A M L R A
S S / C C S S / C
B B WK K B B W K
ADR INC

DUMMY WRITE

Remark1. A1 is P1 in the S-24CS08A.


2. A0 is P0 in the S-24CS04A/08A.
3. W7 is optional in the S-24CS01A.

Figure 15 Random Read

Seiko Instruments Inc. 17


2-WIRE CMOS SERIAL E2PROM
S-24CS01A/02A/04A/08A Rev.2.0_10

7.3 Sequential Read

2
When the E PROM receives a 7-bit device address and a 1-bit read / write instruction code set to "1"
following a start condition both in current and random read operations, it responds with an acknowledge.
2
An 8-bit data is then sent from the E PROM synchronous to the SCL clock and the address counter is
automatically incremented at the falling edge of the SCL clock for the 8th bit data.
When the master device responds with an acknowledge, the data at the next memory address is
transmitted. Response with an acknowledge by the master device has the memory address counter in the
2
E PROM incremented and makes it possible to read data in succession. This is called "Sequential Read".
The master device has not acknowledge and terminates the reading with a stop condition.
Data can be read in succession in the sequential read mode. When the memory address counter reaches
the last word address, it rolls over to the first memory address.

NO ACK from
R Master Device S
DEVICE E A A A T
ADDRESS A C C C O
D K K K P
SDA D7 D0 D7 D0 D7 D0 D7 D0
LINE 1

R A DATA (n+1) DATA (n+2) DATA (n+x)


/ C DATA(n)
W K

ADR INC ADR INC ADR INC ADR INC

Figure 16 Sequential Read

18 Seiko Instruments Inc.


2-WIRE CMOS SERIAL E2PROM
Rev.2.0_10 S-24CS01A/02A/04A/08A

8. Address Increment Timing

The timing for the automatic address increment is the falling edge of the SCL clock for the 8th bit of the
read data in read operation and the the falling edge of the SCL clock for the 8th bit of the received data in
write operation.

SCL
8 9 1 8 9

SDA R / W=1 ACK Output D7 Output D0 Output

Address Increment

Figure 17 Address Increment Timing in Reading

SCL
8 9 1 8 9

SDA R / W=0 ACK Output D7 Input D0 Input ACK Output

Address Increment
Figure 18 Address Increment Timing in Writing

Write inhibition function at low power voltage

The S-24CS01A/02A/04A/08A have a detection circuit for low power voltage. The detection circuit cancels a
write instruction when the power voltage is low or the power switch is on. The detection voltage is 1.75 V
typically and the release voltage is 2.05 V typically, the hysteresis of approximate 0.3 V thus exists. (See
Figure 19.)
When a low power voltage is detected, a write instruction is canceled at the reception of a stop condition.
When the power voltage lowers during a data transmission or a write operation, the date at the address of
the operation is not assured.
Hysteresis width
0.3 V approximately
Power supply voltage
Release voltage (+VDET)
Detection voltage (-VDET) 2.05 V typ.
1.75 V typ.

Write Instruction
cancel

Figure 19 Operation at low power voltage

Seiko Instruments Inc. 19


ANEXO 2
Diseño esquemático del
hardware
BANK 2 BANK 3

BANK 4

BANK 1
BANK 2 BANK 3

BANK 4

BANK 1
CN1
1 2 1 2 1 2 1 2 1 2

4 3 4 3 4 3 4 3 4 3
1 2 1 2 1 2 1 2 1 2

4 3 4 3 4 3 4 3 4 3
ANEXO 3
Código VHDL
Date: May 30, 2010 COUNTER_V2.vhd Project: lvds1
1 Library IEEE;
2 Use ieee.std_logic_1164.all;
3 Use ieee.std_logic_arith.all;
4
5
6
7 entity COUNTER_V2 is
8 Port(
9 clk,nrst : in std_logic;
10 v_sync: in std_logic;
11 DE: in std_logic;
12 hori_pos: out integer range 0 to 1919;
13 vert_pos : out integer range 0 to 1079
14 );
15 end entity;
16
17
18 architecture comportament of COUNTER_V2 is
19
20 signal contador_hori: integer range 0 to 1919;
21 signal contador_vert: integer range 0 to 1079;
22 signal s_DE, sv_sync,waiting_first_de: std_logic;
23
24 type states is (sincro_v,sincro_h);
25 signal state : states;
26
27 begin
28
29 contador: process(clk,nrst)
30 begin
31 if( nrst = '0') then
32 contador_hori<=0;
33 contador_vert<=0;
34 waiting_first_de <='1';
35 state <=sincro_v;
36
37 elsif ((clk'event and clk = '1')) then
38 sv_sync <=v_sync;
39 s_DE<= DE;
40 case state is
41 when sincro_v =>
42 --A nivell vertical tot comença amb el vsync
43 if (v_sync ='1' and sv_sync ='0') then
44 state <= sincro_h;
45 waiting_first_de<='1';
46 end if;
47 --Al trobar un vsync despress hi ha blanking
48
49 when sincro_h =>
50 --Pixels parells
51 --Mentre DE estigui a baix el contador_horizontal
ha de ser 0
52 --SI DE esta a 0 ,el contrador vertical ha de
passar a 0 nomes si es el primer cop despres d'un vsync
53 if (DE='0') then
54 if (waiting_first_de='1') then
55 contador_hori <=0;
56 contador_vert <=0;
57 else

Page 1 of 2 Revision: lvds1


Date: May 30, 2010 COUNTER_V2.vhd Project: lvds1
58 contador_hori <=0;
59 end if;
60 elsif( DE='1') then
61 contador_hori<= contador_hori+ 1;
62 waiting_first_de<='0';
63 end if;
64
65 if(DE='0' and s_DE ='1') then
66 contador_vert <= contador_vert +1;
67 end if;
68
69 --Despres d'un nou vsync tenim que tornar a
esperar amb el waiting_first_de a 1
70 if (v_sync='1' and sv_sync='0') then
71 waiting_first_de<='1';
72 end if;
73
74 end case;
75 end if;
76 end process contador;
77
78 hori_pos<= contador_hori when DE='1' else 0;
79 vert_pos<= contador_vert when DE='1';
80 end comportament;
81
82

Page 2 of 2 Revision: lvds1


Date: May 30, 2010 RGB_To_LVDS_Format.VHD Project: lvds1
1 Library ieee;
2 USE ieee.std_logic_1164.all;
3
4 entity RGB_To_LVDS_Format is
5 Port(
6 output_RA,output_RB,output_RC,output_RD:out
std_logic_vector(6 downto 0);
7 R,G,B: in std_logic_vector(7 downto 0);
8 J_NS: in std_logic;
9 v_sync, h_sync, DE : in std_logic
10 );
11 end entity;
12
13 architecture comportament of RGB_To_LVDS_Format is
14
15
16
17
18 begin
19 --Si J_NS='1' vol dir que farem servir VESA, aixo implica una
nova ordenació
20
21 --RED
22 output_RA(5 downto 0) <= R(5 downto 0) when J_NS='0' ELSE R(7
downto 2);
23 output_RD(1 downto 0) <= R(7 downto 6) when J_NS='0' ELSE R(1
downto 0);
24
25 --GREEN
26 output_RA(6)<=G(0) when J_NS='0' ELSE G(2);
27 output_RB(4 downto 0)<=G(5 downto 1) when J_NS='0' ELSE G(7 downto
3);
28 output_RD(3 downto 2)<=G(7 downto 6) when J_NS='0' ELSE G(1 downto
0);
29
30 --BLUE
31 output_RB(6 downto 5)<= B(1 downto 0) when J_NS='0' ELSE B(3
downto 2);
32 output_RC(3 downto 0)<= B(5 downto 2) when J_NS='0' ELSE B(7
downto 4);
33 output_RD(5 downto 4)<= B(7 downto 6) when J_NS='0' ELSE B(1
downto 0);
34
35 --CONTROL SIGNALS- SON COMUNS PEL VESA I PEL JETDA
36
37 output_RC(4)<=h_sync;
38 output_RC(5)<=v_sync;
39 output_RC(6)<=DE;
40
41
42
43 end comportament;

Page 1 of 1 Revision: lvds1


Date: May 30, 2010 To_RGB_With_Control_Signals.vhd Project: lvds1
1 Library ieee;
2 USE ieee.std_logic_1164.all;
3
4 entity To_RGB_With_Control_Signals is
5 Port(
6 input_RA,input_RB,input_RC,input_RD:in std_logic_vector(6
downto 0);
7 J_NS:in std_logic;
8 R,G,B: out std_logic_vector(7 downto 0);
9 v_sync, h_sync, DE : out std_logic
10 );
11 end entity;
12
13 architecture comportament of To_RGB_With_Control_Signals is
14
15 begin
16
17 --RED
18 R(5 downto 0) <=input_RA(5 downto 0) when J_NS ='0' ELSE (
input_RA(3 downto 0) & input_RD(1 downto 0));
19 R(7 downto 6) <= input_RD(1 downto 0) when J_NS ='0' ELSE
input_RA(5 downto 4);
20
21 --GREEN
22 G(0) <= input_RA(6) when J_NS ='0' ELSE input_RD(2);
23 G(5 downto 1) <=input_RB(4 downto 0) when J_NS ='0' ELSE (
input_RB(3 downto 0)& input_RD(3));
24 G(7 downto 6) <= input_RD(3 downto 2) when J_NS ='0' ELSE
input_RB(4 downto 3);
25
26 --BLUE
27 B(1 downto 0) <= input_RB(6 downto 5) when J_NS ='0' ELSE
input_RD(5 downto 4);
28 B(5 downto 2) <= input_RC(3 downto 0) when J_NS ='0' ELSE (
input_RC(1 downto 0) & input_RB(6 downto 5));
29 B(7 downto 6) <= input_RD(5 downto 4) when J_NS ='0' ELSE
input_RC(3 downto 2);
30
31
32 --CONTROL SIGNALS-- COMUNS TANT PER NS COM PER JETDA
33
34 h_sync<= input_RC(4);
35 v_sync<= input_RC(5);
36 DE<= input_RC(6);
37
38
39
40 end comportament;

Page 1 of 1 Revision: lvds1


Date: May 30, 2010 Mesure_ROI.vhd Project: lvds1
1 LIBRARY IEEE;
2 USE IEEE.STD_LOGIC_1164.ALL;
3 Use ieee.std_logic_arith.all;
4
5
6 Entity Mesure_ROI is
7 PORT(
8 clk,nrst,enable: in std_logic;
9 off_v,off_h,width,length: in integer range 0 to 1979;
10 R,G,B: integer range 0 to 255;
11 contador_hori: in integer range 0 to 1919;
12 contador_vert: in integer range 0 to 1079;
13 R_mean,G_mean,B_mean,Y: out integer range 0 to 255;
14 Gmin,Gmax,Rmin, Rmax, Bmin, Bmax:out integer range 0 to
255;
15 read_strobe: out std_logic
16 );
17 end entity;
18
19 architecture comportament of Mesure_ROI is
20
21 signal R_total: integer range 0 to 16777216;
22 signal G_total: integer range 0 to 16777216;
23 signal B_total: integer range 0 to 16777216;
24 signal Luminancia: integer range 0 to 16777216;
25 signal numpixels: integer range 0 to 2073600;
26 type estados is (waiting,wait2,run,math);
27 signal estado_panel: estados;
28 signal sGmin,sGmax,sRmin, sRmax, sBmin, sBmax: integer range 0 to
255;
29 signal offsetx,offsety,s_width,s_length: integer range 0 to 1979;
30
31 begin
32
33 control:process(nrst,clk,enable) is
34 begin
35 if (nrst ='0') then
36 estado_panel <=waiting;
37 R_total<=0;
38 G_total<=0;
39 B_total<=0;
40 sRmin<=255;
41 sRmax<=0;
42 sGmin<=255;
43 sGmax<=0;
44 sBmin<=255;
45 sBmax<=0;
46 Luminancia<=0;
47 numpixels<=0;
48
49 elsif(enable='1') then
50 estado_panel <=wait2;
51 R_total<=0;
52 G_total<=0;
53 B_total<=0;
54 sRmin<=255;
55 sRmax<=0;
56 sGmin<=255;
57 sGmax<=0;

Page 1 of 3 Revision: lvds1


Date: May 30, 2010 Mesure_ROI.vhd Project: lvds1
58 sBmin<=255;
59 sBmax<=0;
60 Luminancia<=0;
61 numpixels<=0;
62
63 offsetx<=off_h;
64 offsety<=off_v;
65 s_length<=length;
66 s_width<=width;
67
68 elsif(clk'event and clk='0') then
69
70 case estado_panel is
71
72 when waiting =>
73
74 when wait2 =>
75 if ((contador_vert=offsety) and (contador_hori
=offsetx)) then
76 estado_panel<=run;
77 end if;
78
79
80 when run =>
81
82 if (contador_vert>=offsety) and (contador_vert
<offsety+s_length) then
83 if (contador_hori>=offsetx+1) and (
contador_hori<offsetx+s_width+1) then
84 R_total<=R_total + R;
85 G_total<=G_total + G;
86 B_total<=B_total + B;
87 numpixels<=numpixels+1;
88
89 --Aqui ja estem recorrent la zona
desitjada podem trobar val max y min d' aquesta zona
90 if R<sRmin then
91 sRmin<=R;
92 elsif R>sRmax then
93 sRmax<=R;
94 end if;
95
96 if G<sGmin then
97 sGmin<=G;
98 elsif G>sGmax then
99 sGmax<=G;
100 end if;
101
102 if B<sBmin then
103 sBmin<=B;
104 elsif B>sBmax then
105 sBmax<=B;
106 end if;
107
108 if (contador_vert=offsety+s_length-1)
then
109 if(contador_hori=offsetx+s_width)
then
110 estado_panel<=math;

Page 2 of 3 Revision: lvds1


Date: May 30, 2010 Mesure_ROI.vhd Project: lvds1
111 end if;
112 end if;
113
114 end if;
115 end if;
116
117 when math =>
118
119
120 end case;
121 end if;
122
123
124 end process control;
125 --Siguiente Prueba
126 Y<= Luminancia/numpixels when estado_panel= math else 0;
127 R_mean<=R_total/numpixels when estado_panel= math else 0;
128 G_mean<=G_total/numpixels when estado_panel= math else 0;
129 B_mean<=B_total/numpixels when estado_panel= math else 0;
130 --Ara ja podem llegir les dades desde el pc
131 read_strobe<='1' when estado_panel=math else '0';--
132
133
134 Rmin<=sRmin;
135 Rmax<=sRmax;
136 Gmin<=sGmin;
137 Gmax<=sGmax;
138 Bmin<=sBmin;
139 Bmax<=sBmax;
140
141 end comportament;
142

Page 3 of 3 Revision: lvds1


Date: May 30, 2010 lvds_capturer.vhd Project: lvds1
1 Library IEEE;
2 Use ieee.std_logic_1164.all;
3
4
5
6 entity lvds_capturer is
7 Port(
8 clk,nrst,enable: in std_logic;
9 off_v,off_h,width,length: in integer range 0 to 1979;
10 --offsety,offsetx,s_width,s_length: in integer range 0
to 1979;
11 R,G,B: in std_logic_vector(7 downto 0);
12 v_sync,h_sync,DE : in std_logic;
13 fifo_full: in std_logic;
14 o_R,o_G,o_B: out std_logic_vector(7 downto 0);
15 o_v_sync,o_h_sync,o_DE : out std_logic;
16 Fifo_wr_enable: out std_logic;
17 data_to_fifo: out std_logic_vector(23 downto 0);
18 o_contador_hori: out integer range 0 to 1919;
19 o_contador_vert: out integer range 0 to 1079;
20 reset_enable: out std_logic
21 );
22 end entity;
23
24
25 architecture comportament of lvds_capturer is
26
27 component COUNTER_V2
28 port( clk,nrst : in std_logic;
29 v_sync: in std_logic;
30 DE: in std_logic;
31 hori_pos: out integer range 0 to 1919;
32 vert_pos : out integer range 0 to 1079);
33 end component;
34
35 type estados is (waiting,run,full);
36 signal estado_panel: estados;
37 signal offsetx,offsety,s_width,s_length: integer range 0 to 1979;
38 signal contador_hori: integer range 0 to 1919;
39 signal contador_vert: integer range 0 to 1079;
40 signal s_R: std_logic_vector( 7 downto 0):= "00000000";
41 signal s_G: std_logic_vector( 7 downto 0):= "00000000";
42 signal s_B: std_logic_vector( 7 downto 0):= "10000000";
43 signal delayed_R: std_logic_vector( 7 downto 0);
44 signal delayed_G: std_logic_vector( 7 downto 0);
45 signal delayed_B: std_logic_vector( 7 downto 0);
46 signal point_vert: integer range 0 to 1919:=0;
47 signal point_hori: integer range 0 to 1919:=0;
48 signal s_Rw: std_logic_vector( 7 downto 0):= "00000000";
49 signal s_Gw: std_logic_vector( 7 downto 0):= "11111111";
50 signal s_Bw: std_logic_vector( 7 downto 0):= "00000000";
51 signal finish: std_logic:='0';
52
53
54 signal s_Fifo_wr_enable:std_logic;
55
56 signal zona_deseada: std_logic;
57
58 begin

Page 1 of 4 Revision: lvds1


Date: May 30, 2010 lvds_capturer.vhd Project: lvds1
59
60 counter_clock: COUNTER_V2 port map ( clk=>clk, nrst=>nrst,v_sync=>
v_sync,DE=>DE,hori_pos=>contador_hori,vert_pos=>contador_vert);
61
62 control:process (nrst,clk,enable) is
63 begin
64 if (nrst='0') then
65 estado_panel <=waiting;
66 reset_enable<='0';
67 offsetx<=0;
68 offsety<=0;
69 s_length<=0;
70 s_width<=0;
71 elsif( enable='1') then
72 s_Fifo_wr_enable<='0';
73 point_hori<=off_h;
74 point_vert<= off_v;
75 finish<='0';
76 estado_panel<= full;
77 reset_enable<='1';
78 --PROBANDO
79 offsetx<=off_h;
80 offsety<=off_v;
81 s_length<=length;
82 s_width<=width;
83
84 elsif clk'event and clk='0' then
85 --Sempre que entrem ho posa a 0 per asegurar en cas
de que no entrem a la zona desitjada
86 -- que no fem cap grabacio
87 delayed_R<=R;
88 delayed_G<=G;
89 delayed_B<=B;
90 -- offsetx<=off_h;
91 -- offsety<=off_v;
92 -- s_length<=length;
93 -- s_width<=width;
94
95 case estado_panel is
96
97 when waiting =>
98
99
100 when run =>
101
102 --Si no hem acabat la captura del frame,
seguim guardant dades a la fifo
103 if (finish='0') then
104 if (contador_vert>=offsety) and (
contador_vert<offsety+s_length) then
105 if (contador_hori>=offsetx+1) and
(contador_hori<offsetx+s_width+1) then
106 if(fifo_full='0') then

107 --A més hi ha lloc a


la fifo
108 --Grabem la mostra
anterior ja que portem un clock de retard
109 data_to_fifo(7 downto

Page 2 of 4 Revision: lvds1


Date: May 30, 2010 lvds_capturer.vhd Project: lvds1
0)<=delayed_R;
110 data_to_fifo(15 downto
8)<=delayed_G;
111 data_to_fifo(23 downto
16)<=delayed_B;
112 s_Fifo_wr_enable<='1';
113 if (contador_vert=
offsety+s_length-1) then
114 if(contador_hori=
offsetx+s_width) then
115 finish<='1';
116 end if;
117 end if;
118 elsif(fifo_full='1') then
119 --Si la fifo esta
plena hem de guardar la posició del pixel on ens hem quedat
120
--s_Fifo_wr_enable<='0';
121 --El que no ha
guardado no ha sido contador_hori, si no el valor de
contador_hori -1
122 point_vert<=
contador_vert;
123 point_hori<=
contador_hori-1;
124 estado_panel<=full;
125 s_Fifo_wr_enable<='0';
126 end if;
127 else
128 s_Fifo_wr_enable<='0';
129 end if;
130 else --NEW
131 s_Fifo_wr_enable<='0';--NEW
132 end if;
133
134 else
135 --Quan hem terminat de capturar la
zona desitjada, tornem a waiting a l'espera d'un nou flanc de
enable
136 s_Fifo_wr_enable<='0';
137 estado_panel <= waiting;
138 end if;
139
140
141 when full =>
142
143 --Esperem en aquest estat fins que hi
hagi lloc a la fifo i a més estem a un pixel anterior al desitjat.
144 reset_enable<='0';
145 if (fifo_full='0') then
146 if (contador_vert=point_vert) then
147 if(contador_hori=point_hori) then
148 estado_panel<=run;
149 end if;
150 end if;
151 elsif(fifo_full='1') then
152 estado_panel<=full;
153 end if;
154

Page 3 of 4 Revision: lvds1


Date: May 30, 2010 lvds_capturer.vhd Project: lvds1
155 end case;
156 end if;
157 end process control;
158
159
160
161 --Fem marc superior e inferior del cuadre
162 o_R<= s_Rw when (((contador_vert=offsety-1) or (contador_vert=
offsety+s_length)) and (contador_hori>=offsetx-1) and (
contador_hori<=offsetx+s_width)) else
163 --Fem marc laterals del cuadre
164 s_Rw when ((contador_vert>=offsety) and (contador_vert <
offsety+s_length) and ((contador_hori=offsetx-1) or (contador_hori
=offsetx+s_width))) else
165 --Dibuixem zona vermella
166 R when ((contador_vert>=offsety) and (contador_vert<offsety+
s_length) and (contador_hori>offsetx-1) and (contador_hori<offsetx
+s_width))
167 else R;
168
169 o_G<= s_Gw when (((contador_vert=offsety-1) or (contador_vert=
offsety+s_length)) and (contador_hori>=offsetx-1) and (
contador_hori<=offsetx+s_width)) else
170 s_Gw when ((contador_vert>=offsety) and (contador_vert <
offsety+s_length) and ((contador_hori=offsetx-1) or (contador_hori
=offsetx+s_width))) else
171 G when ((contador_vert>=offsety) and (contador_vert<offsety+
s_length) and (contador_hori>offsetx-1) and (contador_hori<offsetx
+s_width))
172 else G;
173
174 o_B<= s_Bw when (((contador_vert=offsety-1) or (contador_vert=
offsety+s_length)) and (contador_hori>=offsetx-1) and (
contador_hori<=offsetx+s_width)) else
175 s_Bw when ((contador_vert>=offsety) and (contador_vert<
offsety+s_length) and ((contador_hori=offsetx-1) or (contador_hori
=offsetx+s_width))) else
176 B when ((contador_vert>=offsety) and (contador_vert< offsety
+s_length) and (contador_hori>offsetx-1) and (contador_hori<
offsetx+s_width))
177 else B;
178
179
180
181
182
183 --Sempre hem de fer bypass de Hsync. Vsync i DE
184 o_v_sync<= v_sync;
185 o_h_sync<= h_sync;
186 o_DE <= DE;
187
188 Fifo_wr_enable<=s_Fifo_wr_enable;
189 o_contador_hori<=contador_hori;
190 o_contador_vert<=contador_vert;
191
192 end comportament;
193
194

Page 4 of 4 Revision: lvds1


Date: May 30, 2010 i2c_slave_control_backup.vhd Project: lvds1
1 library ieee;
2 use ieee.std_logic_1164.all;
3 use ieee.std_logic_arith.all;
4 use ieee.std_logic_unsigned.all;
5 use ieee.all;
6
7 entity i2c_slave_control_backup is
8 generic(
9 I2C_ADDRESS : std_logic_vector(7 downto 0) := "01010010"
-- I2C Slave Device Address (7BITS) 0x52 --> (8BITS) 0xA4
10 );
11 port (
12 -- wishbone signals
13 clk_i : in std_logic; -- master
clock input
14 rst_i : in std_logic := '0'; -- synchronous
active high reset
15 arst_i : in std_logic := not '0';-- ARST_LVL; --
asynchronous reset active low
16 data_from_fifo: in std_logic_vector(23 downto 0);
17 fifo_empty: in std_logic;
18 R_mean,G_mean,B_mean, Luminancia: in std_logic_vector( 7
downto 0);
19 Locked: in std_logic;
20 Gmin,Gmax,Rmin,Rmax,Bmin,Bmax: in std_logic_vector(7
downto 0);
21 read_strobe: in std_logic;
22 -- i2c lines
23 scl : inout std_logic; -- i2c clock line input
24 sda : inout std_logic; -- i2c data line output
25 rst_o: out std_logic:='1';
26 enable: out std_logic;
27 off_v,off_h,width,length: out integer range 0 to 1980;
28 rd_enable:out std_logic;
29 J_V: out std_logic
30 );
31 end entity i2c_slave_control_backup;
32
33 architecture structural of i2c_slave_control_backup is
34
35 -- i2c lines
36 signal scl_i : std_logic; -- i2c clock line input
37 signal scl_o : std_logic; -- i2c clock line output
38 signal scl_oen : std_logic; -- i2c clock line output enable,
active low
39 signal sda_i : std_logic; -- i2c data line input
40 signal sda_o : std_logic; -- i2c data line output
41 signal sda_oen : std_logic; -- i2c data line output enable,
active low
42
43
44 type mem_type is array (25 downto 0) of std_logic_vector (7
downto 0);
45 signal mem: mem_type;
46
47 type states is (idle, dev_addr_recognition,
read_write_mem_addressing, write_byte, data_out);
48 signal c_state : states;
49 signal sSCL, sSDA : std_logic; -- synchronized SCL

Page 1 of 12 Revision: lvds1


Date: May 30, 2010 i2c_slave_control_backup.vhd Project: lvds1
and SDA inputs
50 signal dSCL, dSDA : std_logic; -- delayed sSCL and
sSDA
51 signal sta_condition : std_logic; -- start detected
52 signal sto_condition : std_logic; -- stop detected
53
54 signal scl_rise_edge : std_logic;
55 signal scl_fall_edge : std_logic;
56
57 signal isda_oen : std_logic;
58 signal iscl_oen : std_logic;
59
60 signal dev_address : std_logic_vector(7 downto 0);
61 signal write_address_counter : std_logic_vector(7 downto 0);
--El rang es de 00 a FF (0 a 255)
62 signal read_address_counter : std_logic_vector(7 downto 0);
--El rang es de 00 a FF (0 a 255)
63
64 signal data_byte_to_master : std_logic_vector(7 downto 0);
65
66 signal data : std_logic_vector(7 downto 0);
67 signal bit_cnt : STD_LOGIC_VECTOR(4 DOWNTO 0);
68 signal read_write_bit : std_logic; -- bit de
lectura/escriptura
69 signal s_rd_enable: std_logic;
70 signal configuration_1 : std_logic_vector(7 downto 0);
71
72 signal fifo_transaction_running: std_logic;
73 signal flag_ultima_lectura: std_logic;
74 begin
75 -- synchronize SCL and SDA inputs
76 synch_scl_sda: process(clk_i, arst_i)
77 begin
78 if (arst_i = '0') then
79 sSCL <= '1';
80 sSDA <= '1';
81
82 dSCL <= '1';
83 dSDA <= '1';
84
85
86 elsif (clk_i'event and clk_i = '1') then
87 if (rst_i = '1') then
88 sSCL <= '1';
89 sSDA <= '1';
90
91 dSCL <= '1';
92 dSDA <= '1';
93 else
94 sSCL <= scl_i; --La senyal sSCL no es més que el SCL
d'entrada mostrejat amb el rellotge de la placa
95 sSDA <= sda_i;
96
97 dSCL <= sSCL; --La senyal dSCL es la mostra
anterior del SCL d'entrada
98 dSDA <= sSDA;
99
100 end if;
101 end if;

Page 2 of 12 Revision: lvds1


Date: May 30, 2010 i2c_slave_control_backup.vhd Project: lvds1
102 end process synch_SCL_SDA;
103
104 state_decoder: process(clk_i, arst_i)
105 begin
106 --Reset asíncron
107 if (arst_i = '0') then
108 c_state <= idle;
109 read_write_bit <= '0';
110 bit_cnt <= "00000";
111 dev_address <= "00000000";
112 write_address_counter <= "00000000";
113 --Només inicialitzem a 0 el contador de lectura en
els resets
114 read_address_counter <= "00000000";
115 isda_oen <= '1'; --SDA Hi-Z
116 iscl_oen <= '1'; --SCL Hi-Z
117
118 --Inicialització Registres Interns
119 mem(0) <= "00000000";
120 mem(1) <= "00000000";
121 mem(2) <= "00000000";
122 mem(3) <= "00000000";
123 mem(4) <= "00000000";
124 mem(5) <= "00000000";
125 mem(6) <= "00000000";
126 mem(7) <= "00000000";
127 mem(8) <= "00000000";
128 mem(9) <= "00000000";
129 mem(10) <= "00000000"; --Pixel R
130 mem(11) <= "00000000"; --Pixel G
131 mem(12) <= "00000000"; --Pixel B
132 mem(13) <="00000000"; --Valor R promedio
133 mem(14) <="00000000"; --Valor G promedio
134 mem(15) <="00000000"; --Valor B promedio
135 mem(16) <="00000000"; --Luminancia
136 mem(17) <="00000000"; --Locked
137 mem(18) <="00000000"; --Rmin
138 mem(19) <="00000000"; --Gmin
139 mem(20) <="00000000"; --Bmin
140 mem(21) <="00000000"; --Rmax
141 mem(22) <="00000000"; --Gmax
142 mem(23) <="00000000"; --Bmax
143 mem(24) <="00000000"; --Bmax-- Señal per indicar que
ja es pot llegir la dada promitj
144 mem(25) <="11111111"; --A llegir per coneixer si la
placa s' ha inicialitzat
145
146 elsif (clk_i'event and clk_i = '1') then
147
148 --Reset síncron
149 iscl_oen <= '1'; --SCL Hi-Z
150 --No toquem mai el SCL, no generem wait-states
151 mem(13) <= R_mean;
152 mem(14) <= G_mean;
153 mem(15) <= B_mean;
154 mem(16) <= Luminancia;
155 mem(17) <= "0000000" & Locked;
156 mem(18) <= Rmin;
157 mem(19) <= Gmin;

Page 3 of 12 Revision: lvds1


Date: May 30, 2010 i2c_slave_control_backup.vhd Project: lvds1
158 mem(20) <= Bmin;
159 mem(21) <= Rmax;
160 mem(22) <= Gmax;
161 mem(23) <= Bmax;
162 mem(24) <= "0000000" & read_strobe;
163
164 if (rst_i = '1') then
165 c_state <= idle;
166 read_write_bit <= '0';
167 bit_cnt <= "00000";
168 dev_address <= "00000000";
169 write_address_counter <= "00000000";
170 --Només inicialitzem a 0 el contador de lectura
en els resets
171 read_address_counter <= "00000000";
172 isda_oen <= '1'; --SDA Hi-Z
173
174 --Inicialització Registres Interns
175 mem(0) <= "00000000"; --Voffset-part alta
176 mem(1) <= "00000000"; --Voffset-part baixa
177 mem(2) <= "00000000"; --Hoffset-part alta
178 mem(3) <= "00000000"; --Hoffset-part baixa
179 mem(4) <= "00000000"; --Length-part alta
180 mem(5) <= "00000000"; --Length-part baixa
181 mem(6) <= "00000000"; --Width-part alta
182 mem(7) <= "00000000"; --Width-part baixa
183 mem(8) <= "00000000"; --Registre control/config
--> bit0-> 1 reset bit1->1 enable bit2 -> 0 JETDA/1 VESA
184 mem(9) <= "00000000"; --Pixel R
185 mem(10) <= "00000000"; --Pixel G
186 mem(11) <= "00000000"; --Pixel B
187 mem(12) <= "00000000"; -- Byte de guarda entre
escriptura/lectura
188 mem(13) <="00000000"; --Valor R promedio
189 mem(14) <="00000000"; --Valor G promedio
190 mem(15) <="00000000"; --Valor B promedio
191 mem(16) <="00000000"; --Luminancia
192 mem(17) <="00000000"; --Locked
193 mem(18) <="00000000"; --Rmin
194 mem(19) <="00000000"; --Rmax
195 mem(20) <="00000000"; --Gmin
196 mem(21) <="00000000"; --Gmax
197 mem(22) <="00000000"; --Bmin
198 mem(23) <="00000000"; --Bmax
199 mem(24) <="00000000"; --Bmax-- Señal per indicar
que ja es pot llegir la dada promitj
200 mem(25) <="11111111"; --A llegir per coneixer si
la placa s' ha inicialitzat
201
202 fifo_transaction_running <= '0';
203 flag_ultima_lectura <='0';
204 else
205 --Start and Stop Condition Detection
206 -- detect start condition => detect falling edge
on SDA while SCL is high
207 -- detect stop condition => detect rising edge on
SDA while SCL is high
208 sta_condition <= (not sSDA and dSDA) and sSCL;
209 sto_condition <= (sSDA and not dSDA) and sSCL;

Page 4 of 12 Revision: lvds1


Date: May 30, 2010 i2c_slave_control_backup.vhd Project: lvds1
210 scl_rise_edge <= sSCL and not dSCL; --detecció
flanc pujada del SCL
211 scl_fall_edge <= not sSCL and dSCL; --detecció
flanc baixada del SCL
212
213 if (fifo_empty='1') then
214 fifo_transaction_running <= '0';
215 end if;
216
217 case c_state is
218 when idle =>
219 --Sortir de l'estat idle quan es detecti
alguna activitat al bus, una Start Condition
220 if (sta_condition = '1') then
221 c_state <= dev_addr_recognition;
222 read_write_bit <= '0';
223 bit_cnt <= "00000";
224 dev_address <= "00000000";
225 flag_ultima_lectura <='0';
226 --Contadors de lectura/escriptura
227 write_address_counter <= "00000000";
228 --read_address_counter <= "00000000";
229 --No podem inicialitzar a 0 el
contador de lectura perque sino no podriem fer lectures seguides
230 --en les quals el contador ha d'anar
incrementant-se
231 data <= "00000000";
232 isda_oen <= '1'; --SDA Hi-Z
233 end if;
234 --Quan sortim de l'estat d'idle per una
condició de start, hem de començar a contar els bits
235 when dev_addr_recognition =>
236
237 s_rd_enable<='0';
238
239 if (scl_rise_edge = '1') then
240 --S'han de contar els flancs de
pujada del SCL per saber quin es el 8é bit.
241 bit_cnt <= bit_cnt + 1;
242 if (bit_cnt < 8) then
243 -- El operador & serveix per concatenar
244 dev_address <= dev_address(6
downto 0) & sSDA;
245 if(bit_cnt = 7) then
246
247 if ( read_address_counter = x
"0A" ) then
248 if(fifo_empty='1') then
--cambio por
empty
249 mem(CONV_INTEGER(
read_address_counter))<="11111111";
250 mem(CONV_INTEGER(
read_address_counter+1))<="11111111";
251 mem(CONV_INTEGER(
read_address_counter+2))<="11111111";
252 else
253 mem(CONV_INTEGER(
read_address_counter))<=data_from_fifo(7 downto 0);

Page 5 of 12 Revision: lvds1


Date: May 30, 2010 i2c_slave_control_backup.vhd Project: lvds1
254 mem(CONV_INTEGER(
read_address_counter+1))<=data_from_fifo(15 downto 8);
255 mem(CONV_INTEGER(
read_address_counter+2))<=data_from_fifo(23 downto 16);
256 end if;
257 end if;
258 end if;
259 elsif (bit_cnt = 8) then
260 --Entra en el 9é bit
261 if(read_write_bit = '1') then
262 --En cas de lectura, en el
flanc de baixada del 9é bit
263 --ja hem de col·locar la
dada, no només aliberar SDA
264 --Per tant hem de sortir
d'aquest estat en el flanc de pujada del 9é bit
265 bit_cnt <= "00000";
266 data_byte_to_master <= mem(
CONV_INTEGER(read_address_counter));
267 c_state <= data_out;
268 end if;
269 end if;
270 elsif (scl_fall_edge = '1') then
271 --En el flanc de baixada del SCL es
quan ja podem actuar sobre el SDA
272 if ( bit_cnt = 8 ) then
273 --ACK -->Baixem el SDA
274 if(read_write_bit = '0') then
275 --Escriptura
276 isda_oen <= '0'; -- ACK -->
SDA low
277 write_address_counter <=
"00000000";
278 else
279 --Lectura
280 isda_oen <= '0'; -- ACK -->
SDA low
281 --read_address_counter <=
"00000000";
282 --c_state <= idle; Lectura
soportada, ja no cal tornar a l'estat inicial
283 end if;
284 elsif( bit_cnt = 9 ) then
285 --En el 9e bit no només tinc
d'alliberar el SDA
286 --sino també haig de ficar la
primera dada en el cas de lectura
287 --Per tant en cas de lectura no
haig d'arribar mai aquí
288 isda_oen <= '1';
289 bit_cnt <= "00000";
290 if(read_write_bit = '0') then
291 c_state <=
read_write_mem_addressing;
292 --else
293 --En el cas que el bit de r/w
sigui 1 ja no arribo mai aquí
294 end if;
295 else

Page 6 of 12 Revision: lvds1


Date: May 30, 2010 i2c_slave_control_backup.vhd Project: lvds1
296 isda_oen <= '1';
297 end if;
298 --(8bits)0xA0=10100000 -->
(7bits)0x50=1010000
299 elsif ( bit_cnt = 7 ) then
300 --Després d'haver rebut els 7 primers
bits ja podem decidir
301 --si l'adreça i2c rebuda es la nostre.
302 --if (dev_address /= "01010000") then
303 if (dev_address /= I2C_ADDRESS) then
304 --Si es diferent --> NoAck -->
Retornar al idle i no baixar el SDA
305 bit_cnt <= "00000";
306 c_state <= idle;
307 end if;
308 -- El 8é bit de l'adreça I2C serveix per
decidir si es una operació de Read/Write
309 elsif( bit_cnt = 8 ) then
310 --El 8é bit et marca si la transacció
es de Read/Write
311 read_write_bit <= dev_address(0);
312 end if;
313
314 when read_write_mem_addressing =>
315
316 if (scl_rise_edge = '1') then
317 bit_cnt <= bit_cnt + 1;
318 if (bit_cnt < 8) then
319 -- No hi ha manera de saber si el
contador es el de lectura o escriptura.
320 -- Pressuposem escriptura si no
rebem el Repeated Start
321 write_address_counter <=
write_address_counter(6 downto 0) & sSDA;
322 -- No hem de fer cap altra
operació amb la dada rebuda
323 -- Entra aquí en els flancs de
pujada de 1er a 8é bit
324 end if;
325
326 elsif (scl_fall_edge = '1') then
327 --En el flanc de baixada del SCL es
quan ja podem actuar sobre el SDA
328 if ( bit_cnt = 8 ) then
329 --ACK -->Baixem el SDA
330 isda_oen <= '0'; -- ACK --> SDA low
331 data <= "00000000";
332 --bit_cnt <= "00000"; --
Reiniciem el contador de bit;
333 elsif( bit_cnt = 9 ) then
334 --En el 9e bit ja podem alliberar
el SDA i passar al següent estat
335 isda_oen <= '1';
336 c_state <= write_byte;

337 bit_cnt <= "00000"; -- Reiniciem


el contador de bit;
338
339 else

Page 7 of 12 Revision: lvds1


Date: May 30, 2010 i2c_slave_control_backup.vhd Project: lvds1
340 isda_oen <= '1';
341 end if;
342 end if;
343
344 when write_byte =>
345
346 if (sta_condition = '1') then
347 --DESPUES REINICIALIZO
348 --Pot ser que aquí detectem un
Repeated Start.
349 --El Master torna a enviar la Dev.
Address i amb el bit de RW a 1.
350 bit_cnt <= "00000"; -- Reiniciem el
contador de bit;
351 c_state <= dev_addr_recognition;
352 --Si la direcció es 0A, es la 1º posició
on es guarda el valor R(RGB) dels pixels
353 if (write_address_counter =x"0A"
and fifo_transaction_running = '0') then
354 --Carreguem una mostra de la
fifo(només ha de durar un clock)
355 --En el seguent estat,
write_byte, read_enable ha de tonar a 0.
356 s_rd_enable<='1';
357 fifo_transaction_running <= '1
';
358 end if;
359 read_address_counter <=
write_address_counter;
360
361 --El que s'havia rebut anteriorment
era el contador d'adreça de lectura
362 elsif (sto_condition = '1') then
363 --Quan al 10e bit detectem la stop
condition tornem a l'estat idle
364 c_state <= idle;
365 elsif (scl_rise_edge = '1') then
366 bit_cnt <= bit_cnt + 1;
367 if (bit_cnt < 8) then
368 data <= data(6 downto 0) & sSDA
;
369 else
370 --Copiem la dada en memòria en el
flanc de pujada del 9é bit (bit_cnt=8)
371 if ( write_address_counter < x"09"
) then
372 --Omplim fins a X08
373 ----Podem escriure els 10
primers bytes, la resta són entrades
374 mem(CONV_INTEGER(
write_address_counter)) <= data;
375 end if;
376 end if;
377 elsif (scl_fall_edge = '1') then
378 --En el flanc de baixada del SCL es
quan ja podem actuar sobre el SDA
379 if ( bit_cnt = 8 ) then
380 --En el flanc de baixada del 8e
bit.

Page 8 of 12 Revision: lvds1


Date: May 30, 2010 i2c_slave_control_backup.vhd Project: lvds1
381 --ACK -->Baixem el SDA
382 isda_oen <= '0'; -- ACK --> SDA low
383

384 elsif( bit_cnt = 9 ) then


385 if ( write_address_counter = x"08"
) then
386 mem(CONV_INTEGER(
write_address_counter)) <= (mem(CONV_INTEGER(write_address_counter
)) and "11111100"); --MEU
387 --El mem(8) correspon al
registre de configuració, així fem que el enable i el reset només
388 --tingui una durada limitada
d'uns quants clocks i torni a desactivar-se
389 end if;
390 --En el flanc de baixada del 9e
bit podem alliberar SDA i passar al següent byte
391 isda_oen <= '1';
392 --Ens quedem en el mateix estat.
Només sortirem per un START o STOP
393 c_state <= write_byte;
394
395 --Actualitzem el punter a memòria
396 write_address_counter <=
write_address_counter + 1;
397 bit_cnt <= "00000"; -- Reiniciem
el contador de bit;
398 else
399 isda_oen <= '1';
400 end if;
401 end if;
402
403
404
405 when data_out =>
406 s_rd_enable <='0';
407
408 if (sto_condition = '1') then
409 --Quan al 10e bit detectem la stop
condition tornem a l'estat idle
410 c_state <= idle;
411 elsif (scl_rise_edge = '1') then
412 bit_cnt <= bit_cnt + 1;

413
414
415 --Aqui carreguem el valor del nou
pixel al registre mem:
416 --La adreça quan tornem a entrar
a data_out i veniem de data_out ha de ser x"09"
417 if ( bit_cnt = 7 ) then
418 if ( read_address_counter = x"09"
) then
419 if(fifo_empty='1' and
flag_ultima_lectura ='0') then
420 mem(CONV_INTEGER(
read_address_counter+1))<="11111111";
421 mem(CONV_INTEGER(
read_address_counter+2))<="11111111";

Page 9 of 12 Revision: lvds1


Date: May 30, 2010 i2c_slave_control_backup.vhd Project: lvds1
422 mem(CONV_INTEGER(
read_address_counter+3))<="11111111";
423
424
425 else
426 mem(CONV_INTEGER(
read_address_counter+1))<=data_from_fifo(7 downto 0);
427 mem(CONV_INTEGER(
read_address_counter+2))<=data_from_fifo(15 downto 8);
428 mem(CONV_INTEGER(
read_address_counter+3))<=data_from_fifo(23 downto 16);
429
430 end if;
431 end if;
432 end if;
433 if ( bit_cnt = 8 ) then
434 --bit_cnt = 8 significa el flanc
de pujada del 9é bit
435 --Check ACK/noACK
436 read_address_counter <=
read_address_counter + 1;
437 data_byte_to_master <= mem(
CONV_INTEGER(read_address_counter+1));
438 --Si hem enviat ja els tres blocs(R,G
y B),tornem a adreça inicial de lectura(pixel R),
439 --Demanem nova mostra a la fifo
amb rd_enable(1 clock!!!)
440 --
441 if(read_address_counter = x"0B")
then
442 read_address_counter <= x
"09";
443 if (fifo_empty ='0') then
444 s_rd_enable<='1';
445 flag_ultima_lectura<='
1';
446 else
447 flag_ultima_lectura <=
'0';
448 end if;
449 --I tornem a entrar a
data_out
450 end if;
451
452 if ( sSDA = '0' ) then
453 --ACK received from Master
454 bit_cnt <= "00000"; --
Reiniciem el contador de bit;
455 c_state <= data_out; --Ens
quedem en el mateix estat
456 else
457 --noACK received from Master
458 --no more data to be sent to
the Master
459 c_state <= idle;

460 end if;


461 end if;
462 elsif (scl_fall_edge = '1') then

Page 10 of 12 Revision: lvds1


Date: May 30, 2010 i2c_slave_control_backup.vhd Project: lvds1
463 --En el flanc de baixada del SCL es
quan ja podem actuar sobre el SDA
464 --Un START es una baixada del SDA
quan SCL es High, per tant
465 if ( bit_cnt < 8 ) then
466 isda_oen <= data_byte_to_master(7
);
467 --Movem el shift register
468 data_byte_to_master <=
data_byte_to_master(6 downto 0) & "0";
469
470 --isda_oen <=
data_byte_to_master(0);
471 --Movem el shift register
472 --data_byte_to_master <= "0" &
data_byte_to_master(7 downto 1);
473
474 elsif ( bit_cnt = 8 ) then
475 --En el flanc de baixada del 8é
bit s'allibera el SDA pq el Master doni ACK/noACK
476 isda_oen <= '1';
477 else
478 isda_oen <= '1';
479 end if;
480
481
482
483 end if;
484
485 end case;
486 end if;
487 end if;
488 end process state_decoder;
489
490
491 --Assignació SCL / SDA
492 sda_o <= '0';
493 scl_o <= '0';
494 sda_oen <= isda_oen;
495 scl_oen <= iscl_oen;
496
497 scl <= scl_o when (scl_oen = '0') else 'Z';
498 sda <= sda_o when (sda_oen = '0') else 'Z';
499
500 scl_i <= scl;
501 sda_i <= sda;
502
503 --Generacio de senyal reset de sortida i enable
504 configuration_1 <= mem(8);
505 rst_o<= '0' when (configuration_1(0)='1') else '1';--reset a
nivell baix
506 enable<='1' when (configuration_1(1)='1') else '0';
507 J_V<='1' when (configuration_1(2)='1') else '0';--Si es troba
a 0 estem en VESA/1 estem a JEIDA.
508
509 --Les sortides son 10 bits concatenem els 10 bits i ho pasem
a integer
510 off_v<= CONV_INTEGER(mem(0) & mem(1));
511 off_h<= CONV_INTEGER(mem(2) & mem(3));

Page 11 of 12 Revision: lvds1


Date: May 30, 2010 i2c_slave_control_backup.vhd Project: lvds1
512 length<= CONV_INTEGER(mem(4) & mem(5));
513 width<= CONV_INTEGER(mem(6) & mem(7));
514
515 rd_enable <= s_rd_enable when (fifo_empty='0') else '0';
516
517
518
519 end architecture structural;
520

Page 12 of 12 Revision: lvds1


ANEXO 4
Código de las librerías
C:\Users\Jaume\Documents\Visual Studio 2005\Projects\esiic.c.cpp 1

int __declspec(dllexport) __stdcall ConnectWithESIIC(char message[512], unsigned int *


esiicFileDes, char *ipString, int ipPort, int nonBlocking, int timeout)
{
// 1 Pass/ 0 Fail
// message in inglisshh
char errMessage[512];
unsigned char rx_buffer[RX_BUFF_SIZE];
unsigned char *lf_addr;
int bytes_received;
int total_bytes_received=0;
WORD wVersionRequested;
WSADATA wsaData;
int err;
SOCKADDR_IN /*struct sockaddr_in*/ srv_addr,cli_addr;
LPSERVENT srv_info;
LPHOSTENT host_info;
unsigned long iMode = 1;
int ret;
struct timeval tmout;
int len;

if(nonBlocking != 1 && nonBlocking != 0){


strcpy(message,"Can't determine Socket blocking behaviour: Check nonBlocking
parameter");
return 0;
}

wVersionRequested = ((WORD) (((BYTE) (0x02)) | ((WORD) ((BYTE) (0x02))) << 8));


//Carreguem l'API de winsock versió 1.1

err = WSAStartup( wVersionRequested, &wsaData );


if ( err != 0 ) {
// Tell the user that we could not find a usable
// WinSock DLL.

strcpy(message,"Can't Start Winsock DLL");


return 0;
}

// Confirm that the WinSock DLL supports 2.2.


// Note that if the DLL supports versions greater
// than 2.2 in addition to 2.2, it will still return
// 2.2 in wVersion since that is the version we
// requested.

if ( ( wsaData.wVersion & 0xFF ) != 2 ||


(( wsaData.wVersion & 0xFF00) >> 8) != 2 ) {
// Tell the user that we could not find a usable
// WinSock DLL.
strcpy(message,"Can't Start Winsock DLL");
WSACleanup( );
return 0;
}

// The WinSock DLL is acceptable. Proceed.


//Arguments Checking
if(inet_addr(ipString)==-1){
strcpy(message,"IP Address specified not in correct string-dotted format i.e. 10.0
.0.51");
WSACleanup( );
return 0;
}
if( ipPort < 1 || ipPort > 65535 ){
strcpy(message,"TCP port specified exceed the usable port range (0<port<65535)");

WSACleanup( );
return 0;
}

// Set up client socket


*esiicFileDes = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

if (*esiicFileDes == INVALID_SOCKET){
C:\Users\Jaume\Documents\Visual Studio 2005\Projects\esiic.c.cpp 2
SocketErrorHandler(errMessage, WSAGetLastError());
strcpy(message, "Windows Sockets error: ");
strcat(message, errMessage);
WSACleanup( );
return 0;
}

cli_addr.sin_family=AF_INET;
cli_addr.sin_addr.s_addr=INADDR_ANY;
cli_addr.sin_port=0; // no specific port req'd

// Bind client socket to any local interface and port

if (bind(*esiicFileDes,(LPSOCKADDR)&cli_addr,sizeof(cli_addr)) == SOCKET_ERROR){
SocketErrorHandler(errMessage, WSAGetLastError());
strcpy(message, "Windows Sockets error: ");
strcat(message, errMessage);
// UnloadWinsockAPI(*esiicFileDes);
return 0;
}

//Get the remote port ID to connect to for Telnet service

srv_addr.sin_family = AF_INET;
srv_addr.sin_addr.s_addr = inet_addr(ipString);
srv_addr.sin_port = htons(ipPort);

// Connect to Telnet server at address SERVER

if ( connect(*esiicFileDes,(LPSOCKADDR)&srv_addr, sizeof(srv_addr)) == SOCKET_ERROR ){


SocketErrorHandler(errMessage, WSAGetLastError());
strcpy(message, "Windows Sockets error: ");
strcat(message, errMessage);
// UnloadWinsockAPI(*esiicFileDes);
return 0;
}
if(nonBlocking == 0){
// Set the timeout values //
//Timeouts in milliseconds
//timeout = 50000;

tmout.tv_sec = timeout;
tmout.tv_usec = 0;

ret = setsockopt(*esiicFileDes, SOL_SOCKET, SO_RCVTIMEO, (char*)&tmout, sizeof(


tmout ));
SocketErrorHandler(errMessage, WSAGetLastError());
if(ret == SOCKET_ERROR)
{
strcpy(message, "setsockopt(SO_RCVTIMEO) failed: ");
strcat(message, errMessage);
// UnloadWinsockAPI(*esiicFileDes);
return 0;

ret = setsockopt(*esiicFileDes, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(


tmout ));
SocketErrorHandler(errMessage, WSAGetLastError());
if (ret == SOCKET_ERROR)
{
strcpy(message, "setsockopt(SO_SNDTIMEO) failed: ");
strcat(message, errMessage);
// UnloadWinsockAPI(*esiicFileDes);
return 0;
}
}
else{
//Posar el socket en non-blocking mode, (no asynchronous, farem polling, no
notificació asíncrona)
err = ioctlsocket(*esiicFileDes, FIONBIO, &iMode);
if (err != 0){
SocketErrorHandler(errMessage, WSAGetLastError());
strcpy(message, "Windows Sockets error: ");
C:\Users\Jaume\Documents\Visual Studio 2005\Projects\esiic.c.cpp 3
strcat(message, errMessage);
// UnloadWinsockAPI(*esiicFileDes);
return 0;
}
if (iMode == 0){
strcpy(message, "Windows Sockets error: ");
strcat(message, "non-blocking mode can't be enabled");
// UnloadWinsockAPI(*esiicFileDes);
return 0;
}
}

//Client-server network interaction takes place here


//Ara hem de fer un flush del menu
//Receive all outstanding data on socket
Delay(1);
if(nonBlocking == 0){
total_bytes_received=0;
while(total_bytes_received<377){
bytes_received = recv(*esiicFileDes, &rx_buffer[total_bytes_received],
RX_BUFF_SIZE-1-total_bytes_received, 0);
//Si no fas la crida WSAGetLastError immediatament després de l'error sempre
et retorna 0
err = WSAGetLastError();
if(bytes_received > 0){
total_bytes_received = total_bytes_received + bytes_received;
// Zero terminate so we can use string functions
}
else{
//Error Checking de problemes amb el socket
if(err == WSAETIMEDOUT ){
strcpy(message, "Windows Sockets error: ");
strcat(message, "Timeout Error (likely disconnected device)");
// UnloadWinsockAPI(*esiicFileDes);
return 0;

}
else{
SocketErrorHandler(errMessage, WSAGetLastError());
strcpy(message, "Windows Sockets error: ");
strcat(message, errMessage);
// UnloadWinsockAPI(*esiicFileDes);
return 0;
}
}
}
rx_buffer[total_bytes_received]=0;
return 1;

else{
//flush menu
total_bytes_received=0;
timeout = 0;
while(total_bytes_received<377 && timeout < 20){
bytes_received = recv(*esiicFileDes, &rx_buffer[total_bytes_received],
RX_BUFF_SIZE-1-total_bytes_received, 0);
if(bytes_received > 0){
total_bytes_received = total_bytes_received + bytes_received;
// Zero terminate so we can use string functions
}
else{
//Error Checking de problemes amb el socket
err = WSAGetLastError();
if(err == WSAEWOULDBLOCK || err == 0){
timeout++;
Delay(0.1);
}
else{
SocketErrorHandler(errMessage, WSAGetLastError());
strcpy(message, "Windows Sockets error: ");
strcat(message, errMessage);
// UnloadWinsockAPI(*esiicFileDes);
C:\Users\Jaume\Documents\Visual Studio 2005\Projects\esiic.c.cpp 4
return 0;
}
}
}
if (timeout >= 20){
strcpy(message, "Windows Sockets error: ");
strcat(message, "Timeout Error (likely disconnected device)");
// UnloadWinsockAPI(*esiicFileDes);
return 0;
}
rx_buffer[total_bytes_received]=0;
return 1;
//Menu correctly flushed from receive queue
}
}
int __declspec(dllexport) __stdcall CloseConnectionWithESIIC(char message[512], unsigned
int esiicFileDes){

int err;
char errMessage[512];
//First we will need to close the default resource manager.
err = shutdown(esiicFileDes, 1 );
SocketErrorHandler(errMessage, WSAGetLastError());
if( err == SOCKET_ERROR ){
strcpy(message, "Windows Sockets error: ");
strcat(message, errMessage);
UnloadWinsockAPI(esiicFileDes);
return 0;
}
closesocket(esiicFileDes);
WSACleanup();
return 1;
}

int __declspec(dllexport) __stdcall SendI2cCommandLVDSESIIC (char message[512], unsigned


int esiicFileDes, char i2c_selected[256], int rate, unsigned char i2c_address, int
subaddr_ini, int bytes_data, char cs_selected[256], int rcv_timeout,unsigned short
offsetx,unsigned short offsety,unsigned short length,unsigned short width,int enable,
int format){

char command[256];
char data[256];
char errMessage [256];
char message_single [256];

char fileName2C35[256];
char *token;

int sizeFile=0;
unsigned char dada_llegida[256];

DWORD prewritetime;
DWORD postwritetime;
double write_time;

unsigned char rx_buffer[RX_BUFF_SIZE];


unsigned char *lf_addr;
int bytes_received;
int total_bytes_received=0;
int bytes_to_send;
int data_sent;
int bytes_sent;
int old_timeout;
int size_old_timeout;
//int timeout;
int err;
int ret;
int i;

int result;

BYTE i2c_subaddr_array[4];
C:\Users\Jaume\Documents\Visual Studio 2005\Projects\esiic.c.cpp 5

struct timeval old_tmout;


struct timeval new_tmout;
int len;

len = sizeof( old_tmout );

RemoveSurroundingWhiteSpace (i2c_selected);
RemoveSurroundingWhiteSpace (cs_selected);
//CS Modes Allowed
//"no_cs","se1boot"."vga"."vga_pin10"
//i2chdmi1 -write_data -rate 400000 -i2caddr D0 -subaddrini 00 -num_bytes 3 -data
2A0000 -cs se1boot
// for(i=0; i<bytes_data; i++){
// Fmt(&data[2*i], "%x[b1up0w2]", tx[i]);
// }

Fmt(&data[0],"%x[b2up0w4]",offsety);
Fmt(&data[4],"%x[b2up0w4]", offsetx);
Fmt(&data[8],"%x[b2up0w4]",length);
Fmt(&data[12],"%x[b2up0w4]",width);

if (enable==1 && format==0)


Fmt(&data[16],"%x[b1up0w2]",2);
else if(enable==1 && format==1)
Fmt(&data[16],"%x[b1up0w2]",6);
else{
Fmt(&data[16],"%x[b1up0w2]",0);}

//Format: 0 JETDA/1 VESA


//Abans d'enviar cap comanda fem una lectura per saber si detectem senyal de clock
(lock)
//En cas de no detectar-ho donará error i acabará

/* if(ReadI2cIndividualBytesESIIC(message,esiicFileDes,i2c_selected,rate, i2c_address,
17, 1, 1,dada_llegida) == 0){
return 0;
//Control d'errors en cas de que la funció ReadI2c... falli. Retornarem l'error d
'aquesta funció.
}

if(dada_llegida[0]==0){
//En cas que no detectem clock, ERROR
strcpy(message, "ESIIC generic error:LVDS clock not detected");
return 0;}

*/

//Passar data a MAJUSCULES


StringUpperCase( data );

if(subaddr_ini == -1){
Fmt(command, "%s -write_data -rate %d -i2caddr %x[b1up0w2] -data %s -num_bytes %d\
r\n ", i2c_selected, rate, i2c_address, data, bytes_data);
}
else{

//subaddr_ini pot arribar a ser un enter de 4 bytes que s'ha de descomposar en el


que li toca
//Per exemple una subadreça de 32 bits pot tenir un subaddr_ini 0x00000000
//Per tant necessitarem un paràmetre addicional a la funció que serà el número de
bits de la subadreça
//En principi aixó només suposarà un canvi en la funció de TS, no cal tocar res en
el NIOS pq són caràcters
//els que s'envien i pel tamany del hexastring podem saber el número de bits de la
subadreça

//i2c_subaddr_array[0] = subaddr_ini & 0xFF;


//i2c_subaddr_array[1] = (subaddr_ini & 0xFF00) >> 8;
//i2c_subaddr_array[2] = (subaddr_ini & 0xFF0000) >> 16;
//i2c_subaddr_array[3] = (subaddr_ini & 0xFF000000) >> 24;
C:\Users\Jaume\Documents\Visual Studio 2005\Projects\esiic.c.cpp 6

Fmt(command, "%s -write_data -rate %d -i2caddr %x[b1up0w2] -subaddrini %x[b4up0w2]


-data %s -num_bytes %d\r\n ", i2c_selected, rate, i2c_address, subaddr_ini, data,
bytes_data);
}

prewritetime = timeGetTime();
//Enviar la comanda al socket. Ara s'ha d'implementar amb timeouts
bytes_to_send = strlen(command);
data_sent = 0;
while(data_sent<bytes_to_send){
bytes_sent = send(esiicFileDes, command, bytes_to_send, 0);
//Socket non-blocking. Don't hang if can't send bytes, it returns SOCKET_ERROR
err = WSAGetLastError();
if (bytes_sent > 0) {
data_sent = data_sent + bytes_sent;
}
//if (bytes_sent == SOCKET_ERROR) {
else{
//Error Checking de problemes amb el socket
if(err == WSAETIMEDOUT ){
strcpy(message, "Windows Sockets error: ");
strcat(message, "Timeout Error (likely disconnected device)");
// UnloadWinsockAPI(esiicFileDes);
return 0;
}
else{
SocketErrorHandler(errMessage, WSAGetLastError());
strcpy(message, "Windows Sockets error: ");
strcat(message, errMessage);
// UnloadWinsockAPI(esiicFileDes);
return 0;
}
}
}
ret = getsockopt(esiicFileDes, SOL_SOCKET, SO_RCVTIMEO, (char*)&old_tmout, &len);
if(ret == SOCKET_ERROR){
SocketErrorHandler(errMessage, WSAGetLastError());
strcpy(message, "getsockopt(SO_RCVTIMEO) failed: ");
strcat(message, errMessage);
// UnloadWinsockAPI(esiicFileDes);
return 0;
}
new_tmout.tv_sec = rcv_timeout;
new_tmout.tv_usec = 0;

ret = setsockopt(esiicFileDes, SOL_SOCKET, SO_RCVTIMEO, (char*)&new_tmout, sizeof


(new_tmout));
if(ret == SOCKET_ERROR){
SocketErrorHandler(errMessage, WSAGetLastError());
strcpy(message, "setsockopt(SO_RCVTIMEO) failed: ");
strcat(message, errMessage);
// UnloadWinsockAPI(esiicFileDes);
return 0;
}

//Capturar ara el que retorna el socket. Ara s'ha d'implementar amb timeouts
lf_addr = NULL;
total_bytes_received=0;
while(lf_addr == NULL){
bytes_received = recv(esiicFileDes, &rx_buffer[total_bytes_received], RX_BUFF_SIZE
-total_bytes_received, 0);
err = WSAGetLastError();
if(bytes_received > 0){
total_bytes_received = total_bytes_received + bytes_received;
}
//if (bytes_sent == SOCKET_ERROR) {
else{
//Error Checking de problemes amb el socket
if(err == WSAETIMEDOUT ){
strcpy(message, "Windows Sockets error: ");
strcat(message, "Timeout Error (likely disconnected device)");
// UnloadWinsockAPI(esiicFileDes);
return 0;
C:\Users\Jaume\Documents\Visual Studio 2005\Projects\esiic.c.cpp 7
}
else{
SocketErrorHandler(errMessage, WSAGetLastError());
strcpy(message, "Windows Sockets error: ");
strcat(message, errMessage);
// UnloadWinsockAPI(esiicFileDes);
return 0;
}
}
lf_addr = strchr(rx_buffer, '\n');
}
*(lf_addr+1) = 0;
//Ara hem de interpretar el que ens ha retornat rx_buffer. Trencar en tokens
token = strtok(rx_buffer,"|");
if(!strcmp(token,"OK")){
postwritetime = timeGetTime();
write_time = (double)(postwritetime - prewritetime)/1000;
Fmt(message, "I2C transaction total time: %f[p4] segons", write_time);
strcpy(message, "Command execution succesful");

ret = setsockopt(esiicFileDes, SOL_SOCKET, SO_RCVTIMEO, (char*)&old_tmout, sizeof


(old_tmout));
if(ret == SOCKET_ERROR){
SocketErrorHandler(errMessage, WSAGetLastError());
strcpy(message, "setsockopt(SO_RCVTIMEO) failed: ");
strcat(message, errMessage);
// UnloadWinsockAPI(esiicFileDes);
return 0;
}
return 1;
}
else{

//Error Format: |NG|10|01|0001|Incorrect Format: nothing in cmdline to execute


token = strtok(NULL,"|");
//Ara es vital per saber el I2C que ha fallat
result = atoi(token);
switch(result){
case I2C_WRITE_READ_TASK_I2C1_PRIORITY:
strcpy(message_single, "ESIIC I2C1(VGA) error: ");
break;
case I2C_WRITE_READ_TASK_I2C2_PRIORITY:
strcpy(message_single, "ESIIC I2C2 error: ");
break;
case I2C_WRITE_READ_TASK_I2C3_PRIORITY:
strcpy(message_single, "ESIIC I2C3 error: ");
break;
case I2C_WRITE_READ_TASK_I2C4_PRIORITY:
strcpy(message_single, "ESIIC I2C4(VCTP) error: ");
break;
case I2C_WRITE_READ_TASK_I2C5_PRIORITY:
strcpy(message_single, "ESIIC I2C HDMI1 error: ");
break;
case I2C_WRITE_READ_TASK_I2C6_PRIORITY:
strcpy(message_single, "ESIIC I2C HDMI2 error: ");
break;
case I2C_WRITE_READ_TASK_I2C7_PRIORITY:
strcpy(message_single, "ESIIC I2C HDMI3 error: ");
break;
case I2C_WRITE_READ_TASK_I2C8_PRIORITY:
strcpy(message_single, "ESIIC I2C HDMI4 error: ");
break;
default:
strcpy(message_single, "ESIIC generic error: ");
break;
}
//Tasca que ha donat l'error
token = strtok(NULL,"|");
//SubFunció dintre la tasca que ha donat l'error
token = strtok(NULL,"|");
//Codi d'error definit
token = strtok(NULL,"|");
//Missatge d'error. De moment l'únic que utilitzarem
strcat(message_single, token);
C:\Users\Jaume\Documents\Visual Studio 2005\Projects\esiic.c.cpp 8
strcpy(message, message_single);
return 0;

}
}

int __declspec(dllexport) __stdcall ReadI2cIndividualBytesESIIC(char message[512],


unsigned int esiicFileDes, char i2c_selected[256], int rate, unsigned char i2c_address
, int subaddr_ini, int bytes_subaddr, int bytes_to_read, unsigned char recv_data[100])
{

char temp[50];
char errMessage[512];
char command[512];
char temp_subaddr_string[32];
char subaddr_ini_string[32];

unsigned char rx_buffer[RX_BUFF_SIZE];


unsigned char *lf_addr;
int bytes_received;
int total_bytes_received=0;
int bytes_to_send;
int data_sent;
int bytes_sent;
int sizeFile=0;
int timeout;
int err;
char *token;
int ret_bytes_read;
int real_checksum_read=0;
unsigned char i2c_subaddr_array[4];
int cntChar;
int i;
int firstloop;
unsigned int rx_data[100];

strcpy(subaddr_ini_string,"");
strcpy(temp_subaddr_string,"");
//i2chdmi1 -read_rx -rate 100000 -i2caddr A0 -subaddrini 00 -num_bytes 16
if(subaddr_ini == -1){
Fmt(command, "%s -read_rx -rate %d -i2caddr %x[b1up0w2] -num_bytes %d \r\n",
i2c_selected, rate, i2c_address, bytes_to_read);
}
else{
//Depenen dels bytes de subadreça, definir el que enviem
i2c_subaddr_array[0] = subaddr_ini & 0xFF;
i2c_subaddr_array[1] = (subaddr_ini & 0xFF00) >> 8;
i2c_subaddr_array[2] = (subaddr_ini & 0xFF0000) >> 16;
i2c_subaddr_array[3] = (subaddr_ini & 0xFF000000) >> 24;
firstloop=1;
for(i=bytes_subaddr-1; i>=0; i--){
Fmt(temp_subaddr_string, "%x[b1up0w2]", i2c_subaddr_array[i]);
if(firstloop==1){
strcpy(subaddr_ini_string, temp_subaddr_string);
firstloop=0;
}
else{
strcat(subaddr_ini_string, temp_subaddr_string);
}

}
Fmt(command, "%s -read_rx -rate %d -i2caddr %x[b1up0w2] -subaddrini %s -num_bytes
%d \r\n", i2c_selected, rate, i2c_address, subaddr_ini_string, bytes_to_read);
}

//Enviar la comanda al socket. Ara s'ha d'implementar amb timeouts


bytes_to_send = strlen(command);
data_sent = 0;
while(data_sent<bytes_to_send){
bytes_sent = send(esiicFileDes, command, bytes_to_send, 0);
//Socket non-blocking. Don't hang if can't send bytes, it returns SOCKET_ERROR
err = WSAGetLastError();
if (bytes_sent > 0) {
data_sent = data_sent + bytes_sent;
C:\Users\Jaume\Documents\Visual Studio 2005\Projects\esiic.c.cpp 9
}
//if (bytes_sent == SOCKET_ERROR) {
else{
//Error Checking de problemes amb el socket
if(err == WSAETIMEDOUT ){
strcpy(message, "Windows Sockets error: ");
strcat(message, "Timeout Error (likely disconnected device)");
// UnloadWinsockAPI(esiicFileDes);
return 0;
}
else{
SocketErrorHandler(errMessage, WSAGetLastError());
strcpy(message, "Windows Sockets error: ");
strcat(message, errMessage);
// UnloadWinsockAPI(esiicFileDes);
return 0;
}
}
}

//Capturar ara el que retorna el socket. Ara s'ha d'implementar amb timeouts
lf_addr = NULL;
total_bytes_received=0;
while(lf_addr == NULL){
bytes_received = recv(esiicFileDes, &rx_buffer[total_bytes_received], RX_BUFF_SIZE
-total_bytes_received, 0);
err = WSAGetLastError();
if(bytes_received > 0){
total_bytes_received = total_bytes_received + bytes_received;
}
//if (bytes_sent == SOCKET_ERROR) {
else{
//Error Checking de problemes amb el socket
if(err == WSAETIMEDOUT ){
strcpy(message, "Windows Sockets error: ");
strcat(message, "Timeout Error (likely disconnected device)");
// UnloadWinsockAPI(esiicFileDes);
return 0;
}
else{
SocketErrorHandler(errMessage, WSAGetLastError());
strcpy(message, "Windows Sockets error: ");
strcat(message, errMessage);
// UnloadWinsockAPI(esiicFileDes);
return 0;
}
}
lf_addr = strchr(rx_buffer, '\n');
}
*(lf_addr+1) = 0;
//Ara hem de interpretar el que ens ha retornat rx_buffer. Trencar en tokens
token = strtok(rx_buffer,"|");
if(!strcmp(token,"RT")){
//Return bytes Format |RT|12|00|0004|03B36A91
token = strtok(NULL,"|");
//Tasca que ha donat l'error
token = strtok(NULL,"|");
//SubFunció dintre la tasca que ha donat l'error
token = strtok(NULL,"|");
//Número de bytes que retorna
ret_bytes_read = atoi(token);
if(ret_bytes_read != bytes_to_read){
strcpy(message, "ESIIC I2C read error: bytes read by i2c different from
expected ones");
//Discutible si cal tancar
// UnloadWinsockAPI(esiicFileDes);
return 0;

}
token = strtok(NULL,"|");
//Bytes llegits. En el cas de checksum, passar a enter el valor
//Hem de convertir de hexa_string a unsigned char

// Fmt(&data[2*i], "%x[b1up0w2]", tx[i]);


C:\Users\Jaume\Documents\Visual Studio 2005\Projects\esiic.c.cpp 10

for(cntChar=0;cntChar<ret_bytes_read;cntChar++){
Fmt (&rx_data[cntChar],"%i[r16]<%s[w2]",&token[cntChar*2]);
recv_data[cntChar] = rx_data[cntChar] & 0xFF;
}

strcpy(message, "Command execution succesful");


return 1;
}
else{
//Error Format: |NG|10|01|0001|Incorrect Format: nothing in cmdline to execute
token = strtok(NULL,"|");
//Tasca que ha donat l'error
token = strtok(NULL,"|");
//SubFunció dintre la tasca que ha donat l'error
token = strtok(NULL,"|");
//Codi d'error definit
token = strtok(NULL,"|");
//Missatge d'error. De moment l'únic que utilitzarem
strcpy(errMessage, token);
strcpy(message, "ESIIC Checksum read error: ");
strcat(message, errMessage);
//Discutible si cal tancar
// UnloadWinsockAPI(esiicFileDes);
return 0;
}
}

int __declspec(dllexport) __stdcall GetInfoImageLVDS(char message[512], unsigned int


esiicFileDes, char i2c_selected[256], int * Rmean, int * Gmean, int * Bmean, int*
Luminancia){

int rate;
unsigned int rx_data[100];
unsigned char i2c_address1;
unsigned char i2c_address2;
int subaddr_ini;
int bytes_subaddr;
int bytes_to_read;
unsigned char dada_llegida[5];

//i2c2 -read_rx -rate 100000 -i2caddr A4 -subaddrini 0D -num_bytes 3


//i2c2 -read_rx -rate 100000 -i2caddr A6 -subaddrini 0D -num_bytes 3
rate=50000;
i2c_address1=0xA4;
i2c_address2 =0xA6;
subaddr_ini=13;
bytes_subaddr=1;
bytes_to_read=3;
*Rmean=0;
*Gmean=0;
*Bmean=0;

if(ReadI2cIndividualBytesESIIC(message,esiicFileDes,i2c_selected, rate, i2c_address1,


subaddr_ini, bytes_subaddr, bytes_to_read,dada_llegida) == 0){
return 0;
//Control d'errors en cas de que la funció ReadI2c... falli. Retornarem l'error d
'aquesta funció.
}

*Rmean= (int)(dada_llegida[0]/2);
*Gmean= (int)(dada_llegida[1]/2);
*Bmean= (int)(dada_llegida[2]/2);

Delay(0.1);
if(ReadI2cIndividualBytesESIIC(message,esiicFileDes,i2c_selected, rate, i2c_address2,
subaddr_ini, bytes_subaddr, bytes_to_read,dada_llegida) == 0){
return 0;
//Control d'errors en cas de que la funció ReadI2c... falli. Retornarem l'error d
C:\Users\Jaume\Documents\Visual Studio 2005\Projects\esiic.c.cpp 11
'aquesta funció.
}
*Rmean+= (int)(dada_llegida[0]/2);
*Gmean+= (int)(dada_llegida[1]/2);
*Bmean+= (int)(dada_llegida[2]/2);
*Luminancia= (int)(0.299**Rmean + 0.587**Gmean + 0.114**Bmean);

return 1;

int __declspec(dllexport) __stdcall GetLimitValueLVDS(char message[512], unsigned int


esiicFileDes, char i2c_selected[256], int * Rmin, int * Gmin, int * Bmin, int * Rmax
, int * Gmax, int * Bmax){
int rate;
unsigned int rx_data[100];
unsigned char i2c_address1;
unsigned char i2c_address2;
int subaddr_ini;
int bytes_subaddr;
int bytes_to_read;
unsigned char dada_llegida[6];

//i2c2 -read_rx -rate 100000 -i2caddr A4 -subaddrini 0D -num_bytes 3


//i2c2 -read_rx -rate 100000 -i2caddr A6 -subaddrini 0D -num_bytes 3
rate=400000;
i2c_address1=0xA4;
i2c_address2 =0xA6;
subaddr_ini=18;
bytes_subaddr=1;
bytes_to_read=6;

if(ReadI2cIndividualBytesESIIC(message,esiicFileDes,i2c_selected, rate, i2c_address1,


subaddr_ini, bytes_subaddr,bytes_to_read,dada_llegida) == 0){
return 0;
//Control d'errors en cas de que la funció ReadI2c... falli. Retornarem l'error d
'aquesta funció.
}

*Rmin= (int)(dada_llegida[0]/2);
*Gmin= (int)(dada_llegida[1]/2);
*Bmin= (int)(dada_llegida[2]/2);
*Rmax= (int)(dada_llegida[3]/2);
*Gmax= (int)(dada_llegida[4]/2);
*Bmax= (int)(dada_llegida[5]/2);

if(ReadI2cIndividualBytesESIIC(message,esiicFileDes,i2c_selected, rate, i2c_address2,


subaddr_ini, bytes_subaddr, bytes_to_read,dada_llegida) == 0){
return 0;
//Control d'errors en cas de que la funció ReadI2c... falli. Retornarem l'error d
'aquesta funció.
}
*Rmin+= (int)(dada_llegida[0]/2);
*Gmin+= (int)(dada_llegida[1]/2);
*Bmin+= (int)(dada_llegida[2]/2);
*Rmax+= (int)(dada_llegida[3]/2);
*Gmax+= (int)(dada_llegida[4]/2);
*Bmax+= (int)(dada_llegida[5]/2);

return 1;

int __declspec(dllexport) __stdcall Create_Data_Storage_LVDS(char message[512], int *bits,


int width, int height){

unsigned char *bits_alloc;


bits_alloc = (unsigned char *)malloc(width*height*3*sizeof(unsigned char) );
//bits_alloc[0] = 0x00;
*bits = (int) bits_alloc;
C:\Users\Jaume\Documents\Visual Studio 2005\Projects\esiic.c.cpp 12
return 1;

int __declspec(dllexport) __stdcall Close_Data_Storage_LVDS(char message[512],int *bits)


{
unsigned char *bits_alloc;
bits_alloc = (unsigned char *) *bits;
free(bits_alloc);
return 1;
}

int __declspec(dllexport) __stdcall ReadI2cIndividualBytesLVDSESIIC(char message[512],


unsigned int esiicFileDes, char i2c_selected[256], int rate, unsigned char i2c_address
, int subaddr_ini, int bytes_subaddr, int bytes_to_read, int* recv_data){

char temp[50];
char errMessage[512];
char command[512];
char temp_subaddr_string[32];
char subaddr_ini_string[32];

unsigned char rx_buffer[RX_BUFF_SIZE];


unsigned char *lf_addr;
int bytes_received;
int total_bytes_received=0;
int bytes_to_send;
int data_sent;
int bytes_sent;
int sizeFile=0;
int timeout;
int err;
char *token;
int ret_bytes_read;
int real_checksum_read=0;
unsigned char i2c_subaddr_array[4];
int cntChar;
int i;
int firstloop;
unsigned int rx_data[100];

unsigned char *bits_alloc;

bits_alloc = (unsigned char *) *recv_data;

strcpy(subaddr_ini_string,"");
strcpy(temp_subaddr_string,"");
//i2chdmi1 -read_rx -rate 100000 -i2caddr A0 -subaddrini 00 -num_bytes 16
if(subaddr_ini == -1){
Fmt(command, "%s -read_rx -rate %d -i2caddr %x[b1up0w2] -num_bytes %d \r\n",
i2c_selected, rate, i2c_address, bytes_to_read);
}
else{
//Depenen dels bytes de subadreça, definir el que enviem
i2c_subaddr_array[0] = subaddr_ini & 0xFF;
i2c_subaddr_array[1] = (subaddr_ini & 0xFF00) >> 8;
i2c_subaddr_array[2] = (subaddr_ini & 0xFF0000) >> 16;
i2c_subaddr_array[3] = (subaddr_ini & 0xFF000000) >> 24;
firstloop=1;
for(i=bytes_subaddr-1; i>=0; i--){
Fmt(temp_subaddr_string, "%x[b1up0w2]", i2c_subaddr_array[i]);
if(firstloop==1){
strcpy(subaddr_ini_string, temp_subaddr_string);
firstloop=0;
}
else{
strcat(subaddr_ini_string, temp_subaddr_string);
}
C:\Users\Jaume\Documents\Visual Studio 2005\Projects\esiic.c.cpp 13
}
Fmt(command, "%s -read_rx -rate %d -i2caddr %x[b1up0w2] -subaddrini %s -num_bytes
%d \r\n", i2c_selected, rate, i2c_address, subaddr_ini_string, bytes_to_read);
}

//Enviar la comanda al socket. Ara s'ha d'implementar amb timeouts


bytes_to_send = strlen(command);
data_sent = 0;
while(data_sent<bytes_to_send){
bytes_sent = send(esiicFileDes, command, bytes_to_send, 0);
//Socket non-blocking. Don't hang if can't send bytes, it returns SOCKET_ERROR
err = WSAGetLastError();
if (bytes_sent > 0) {
data_sent = data_sent + bytes_sent;
}
//if (bytes_sent == SOCKET_ERROR) {
else{
//Error Checking de problemes amb el socket
if(err == WSAETIMEDOUT ){
strcpy(message, "Windows Sockets error: ");
strcat(message, "Timeout Error (likely disconnected device)");
// UnloadWinsockAPI(esiicFileDes);

return 0;
}
else{
SocketErrorHandler(errMessage, WSAGetLastError());
strcpy(message, "Windows Sockets error: ");
strcat(message, errMessage);
// UnloadWinsockAPI(esiicFileDes);

return 0;
}
}
}

//Capturar ara el que retorna el socket. Ara s'ha d'implementar amb timeouts
lf_addr = NULL;
total_bytes_received=0;
while(lf_addr == NULL){
bytes_received = recv(esiicFileDes, &rx_buffer[total_bytes_received], RX_BUFF_SIZE
-total_bytes_received, 0);
err = WSAGetLastError();
if(bytes_received > 0){
total_bytes_received = total_bytes_received + bytes_received;
}
//if (bytes_sent == SOCKET_ERROR) {
else{
//Error Checking de problemes amb el socket
if(err == WSAETIMEDOUT ){
strcpy(message, "Windows Sockets error: ");
strcat(message, "Timeout Error (likely disconnected device)");
// UnloadWinsockAPI(esiicFileDes);

return 0;
}
else{
SocketErrorHandler(errMessage, WSAGetLastError());
strcpy(message, "Windows Sockets error: ");
strcat(message, errMessage);
// UnloadWinsockAPI(esiicFileDes);

return 0;
}
}
lf_addr = strchr(rx_buffer, '\n');
}
*(lf_addr+1) = 0;
//Ara hem de interpretar el que ens ha retornat rx_buffer. Trencar en tokens
token = strtok(rx_buffer,"|");
if(!strcmp(token,"RT")){
//Return bytes Format |RT|12|00|0004|03B36A91
token = strtok(NULL,"|");
//Tasca que ha donat l'error
C:\Users\Jaume\Documents\Visual Studio 2005\Projects\esiic.c.cpp 14
token = strtok(NULL,"|");
//SubFunció dintre la tasca que ha donat l'error
token = strtok(NULL,"|");
//Número de bytes que retorna
ret_bytes_read = atoi(token);
if(ret_bytes_read != bytes_to_read){
strcpy(message, "ESIIC I2C read error: bytes read by i2c different from
expected ones");
//Discutible si cal tancar
// UnloadWinsockAPI(esiicFileDes);

return 0;

}
token = strtok(NULL,"|");
//Bytes llegits. En el cas de checksum, passar a enter el valor
//Hem de convertir de hexa_string a unsigned char

// Fmt(&data[2*i], "%x[b1up0w2]", tx[i]);

for(cntChar=0;cntChar<ret_bytes_read;cntChar++){
Fmt (&rx_data[cntChar],"%i[r16]<%s[w2]",&token[cntChar*2]);
// recv_data[cntChar] = rx_data[cntChar] & 0xFF;
bits_alloc[cntChar] = rx_data[cntChar] & 0xFF;
}

strcpy(message, "Command execution succesful");


*recv_data = (int) &bits_alloc[ret_bytes_read];

return 1;
}
else{
//Error Format: |NG|10|01|0001|Incorrect Format: nothing in cmdline to execute
token = strtok(NULL,"|");
//Tasca que ha donat l'error
token = strtok(NULL,"|");
//SubFunció dintre la tasca que ha donat l'error
token = strtok(NULL,"|");
//Codi d'error definit
token = strtok(NULL,"|");
//Missatge d'error. De moment l'únic que utilitzarem
strcpy(errMessage, token);
strcpy(message, "ESIIC Checksum read error: ");
strcat(message, errMessage);
//Discutible si cal tancar
// UnloadWinsockAPI(esiicFileDes);

return 0;
}
}
C:\Users\Jaume\Desktop\PenDrive\PFC LVDS\Bitmaps\Bitmaps.c 1
#include "windows.h"
#include <winsock.h>

#include <formatio.h>
#include "mmsystem.h"

#include <utility.h>
#include <userint.h>
#include "inifile.h"

#include <stdio.h>
#include <stdlib.h>

//Registra zona de memoria per guarda els bits


int __declspec(dllexport) __stdcall Create_Data_Storage(char message[512], int *bits, int
width, int height){

unsigned char *bits_alloc;


bits_alloc = (unsigned char *)malloc(3*3*width*height*sizeof(unsigned char) );
//bits_alloc[0] = 0x00;
*bits = (int) bits_alloc;
return 1;

//Guarda a la zona de memoria creada anteriormente SE LI PASSA PIXEL A PIXEL (R, G y B)


int __declspec(dllexport) __stdcall Store_RGB(char message[512], int *bits, int R, int G,
int B, int width, int x, int y)
{
unsigned char *bits_alloc;

bits_alloc = (unsigned char *) *bits;

bits_alloc[y*width*3+x*3] = R & 0xFF;


bits_alloc[y*width*3+x*3+1] = G & 0xFF;
bits_alloc[y*width*3+x*3+2] = B & 0xFF;
*bits = (int) bits_alloc;
return 1;
}

int __declspec(dllexport) __stdcall Store_RGB_BLOCK(char message[512], int *bits, int *


datablock1,int *datablock2, int width,int height)
{
unsigned char *bits_alloc;
unsigned char *bits_alloc1;
unsigned char *bits_alloc2;
int i,j,pixel;
pixel=0;
i=0;
bits_alloc = (unsigned char *) *bits;

bits_alloc1 = (unsigned char *) *datablock1;

bits_alloc2 = (unsigned char *) *datablock2;

//datablock es un vector
for (j=0;j<height;j++){
for (i=0;i<width;i++){
//pixel par
if (i%2==0){
bits_alloc[j*width*3+i*3] = bits_alloc1[pixel*3] & 0xFF;
bits_alloc[j*width*3+i*3+1] =bits_alloc1[pixel*3+1] & 0xFF;
bits_alloc[j*width*3+i*3+2] =bits_alloc1[pixel*3+2] & 0xFF;}
//pixel parell
else{
bits_alloc[j*width*3+i*3] = bits_alloc2[pixel*3] & 0xFF;
bits_alloc[j*width*3+i*3+1] =bits_alloc2[pixel*3+1] & 0xFF;
bits_alloc[j*width*3+i*3+2] =bits_alloc2[pixel*3+2] & 0xFF;
pixel++;
}
}
C:\Users\Jaume\Desktop\PenDrive\PFC LVDS\Bitmaps\Bitmaps.c 2
}

*bits = (int) bits_alloc;


return 1;

//Guarda en un fitxer el resultat bits alloc


int __declspec(dllexport) __stdcall Save_Bitmap(char message[512], int width, int height,
int *bits, char filepath[512],int *Rmean,int *Gmean,int *Bmean)
{

int colorTable[12];
int handle;
int status;
int i;
unsigned char *bits_alloc;
i=0;
bits_alloc = (unsigned char *) *bits;

for(i=0; i<height*width;i++){
*Rmean+=bits_alloc[i*3];
*Gmean+=bits_alloc[i*3+1];
*Bmean+=bits_alloc[i*3+2];
}
*Rmean/=height*width;
*Gmean/=height*width;
*Bmean/=height*width;

status = NewBitmap (-1, 24, width, height, 0, bits_alloc, 0, &handle);


status = SaveBitmapToBMPFile(handle, filepath);
free(bits_alloc);
return 1;
}

int __declspec(dllexport) __stdcall Replicate_Line_Bitmap(char message[512], int rows,


char source_filepath[512], char filepath[512])
{
int status;
int handle;
int handle_dest;
unsigned char *bits_alloc;
unsigned char *line_bits_alloc;

int colorSize;
int bitsSize;
int maskSize;

int bytesPerRow;
int pixelDepth;
int width;
int height;
int *colorTable;
unsigned char *mask;
int dades_len;

int y;
int x;

//Reads a bitmap image from a file and creates a bitmap object- int GetBitmapFromFile
(char filename[], int *bitmapID);
status = GetBitmapFromFile (source_filepath, &handle);
//Obtains size information about the image associated with a bitmap. int GetBitmapInfo
(int bitmapID, int *colorSize, int *bitsSize, int *maskSize);
status = GetBitmapInfo (handle, &colorSize, &bitsSize, &maskSize);

line_bits_alloc = (unsigned char *)malloc(bitsSize*sizeof(unsigned char) );

//Obtains the bit values that define the image associated with a bitmap. int
GetBitmapData (int bitmapID, int *bytesPerRow, int *pixelDepth, int *width, int *
height, int colorTable[], unsigned char bits[], unsigned char mask[]);
C:\Users\Jaume\Desktop\PenDrive\PFC LVDS\Bitmaps\Bitmaps.c 3
status = GetBitmapData (handle, &bytesPerRow, &pixelDepth, &width, &height, 0,
line_bits_alloc, 0);

bits_alloc = (unsigned char *)malloc(rows*width*3*sizeof(unsigned char) );

dades_len = strlen(line_bits_alloc);

for(y=1 ; y < (rows-1) ; y++){


for(x=0 ; x < width ; x++){
bits_alloc[y*width*3+x*3] = line_bits_alloc[x*4];
bits_alloc[y*width*3+x*3+1] = line_bits_alloc[x*4+1];
bits_alloc[y*width*3+x*3+2] = line_bits_alloc[x*4+2];
//bits_alloc[y*width*4+x*4] = 0x00;
//bits_alloc[y*width*4+x*4+1] = line_bits_alloc[x*4+1];
//bits_alloc[y*width*4+x*4+2] = line_bits_alloc[x*4+2];
//bits_alloc[y*width*4+x*4+3] = line_bits_alloc[x*4+3];
}
}
status = NewBitmap (-1, 24, width, rows, 0, bits_alloc, 0, &handle_dest);
status = SaveBitmapToBMPFile(handle_dest, filepath);
free(bits_alloc);

return 1;
}
/*
//Exemples de codi de prova abans de la llibreria definitiva

int __declspec(dllexport) __stdcall Create_Data_Storage(char message[512], int *bits, int


width, int height){

int i;
int row;
int change=0;
int bitmap_handle;
int status;
unsigned char *bits_alloc;

bits_alloc = (unsigned char *)malloc(3*3*10*10*sizeof(unsigned char) );


for (i=0; i<10; i++){
for (row=0; row<10; row++){
if (change==0){
bits_alloc[i*10*3+row*3] = 0x00;
bits_alloc[i*10*3+row*3+1] = 0x00;
bits_alloc[i*10*3+row*3+2] = 0x00;
change = 1;
}
else{
bits_alloc[i*10*3+row*3] = 0xFF;
bits_alloc[i*10*3+row*3+1] = 0xFF;
bits_alloc[i*10*3+row*3+2] = 0xFF;
change = 0;
}
}
}
status = NewBitmap (-1, 24, 10, 10, 0, bits_alloc, 0, &bitmap_handle);
SaveBitmapToBMPFile(bitmap_handle, "c:\\prova1.bmp");
*bits = (int) bits_alloc;

return 1;
}
int __declspec(dllexport) __stdcall Store_RGB(char message[512], int *bits)
{
unsigned char *bits_alloc;

bits_alloc = (unsigned char *) *bits;

//bits_alloc = (unsigned char *)malloc(3*3*10*10*sizeof(unsigned char) );

bits_alloc[0] = 0xFF;
bits_alloc[1] = 0x00;
bits_alloc[2] = 0x00;
*bits = (int) bits_alloc;
return 1;
}
C:\Users\Jaume\Desktop\PenDrive\PFC LVDS\Bitmaps\Bitmaps.c 4

int __declspec(dllexport) __stdcall Create_Bitmap(char message[512], int *bitmap_handle){

int colorTable[12];
unsigned char bits[12];
int status;

bits[0]=0x00; //RR
bits[1]=0x00; //GG
bits[2]=0x00; //BB
bits[3]=0xFF;
bits[4]=0xFF;
bits[5]=0xFF;
bits[6]=0xFF;
bits[7]=0xFF;
bits[8]=0xFF;
bits[9]=0x00;
bits[10]=0x00;
bits[11]=0x00;

//tauler d'escacs de 2

status = NewBitmap (-1, 24, 2, 2, 0, bits, 0, bitmap_handle);


status = SaveBitmapToBMPFile(*bitmap_handle, "c:\\prova.bmp");
return 1;
}

int __declspec(dllexport) __stdcall Save_Bitmap(char message[512], int *bits, int *


bitmap_handle)
{

int colorTable[12];
int handle;
int status;
unsigned char *bits_alloc;
bits_alloc = (unsigned char *) *bits;

status = NewBitmap (-1, 24, 10, 10, 0, bits_alloc, 0, &handle);


status = SaveBitmapToBMPFile(handle, "c:\\prova2.bmp");
return 1;
}
*/

También podría gustarte