Estoy tratando de generar la salida de señal adecuada para conectar un microcontrolador AVR ATmega328P con un monitor LCD, a través de la especificación VGA. La especificación VGA que estoy tratando de cumplir es el estándar de la industria 640*480 con una frecuencia de actualización de cuadros de 60 Hz (1).
El AVR está funcionando a una frecuencia de 20 MHz , que es inferior a la frecuencia de reloj de píxeles VGA de 25,175 MHz . Sin embargo, creí, después de haber considerado proyectos similares en línea (2), que a través de alguna manipulación de la cantidad de relojes por región, podría cumplir con los tiempos estipulados en la especificación VGA. Mis tiempos ajustados para la especificación vertical y horizontal se pueden encontrar a continuación:
Temporización vertical (fotograma)
Área visible: 15,24 ms, 480 líneas (304800 ciclos de reloj @ 20 MHz)
Porche delantero: 0,3175 ms, 10 líneas (6350 ciclos de reloj @ 20 MHz)
Pulso de sincronización: 0,0635 ms, 2 líneas (1270 ciclos de reloj @ 20 MHz)
Porche trasero : 1,04775 ms, 33 líneas (20955 ciclos clk a 20 MHz)
Cuadro completo: 16,66875 ms, 525 líneas (333375 ciclos a 20 MHz)
Temporización horizontal (línea)
Área visible: 25,45 us, 508 píxeles (508 ciclos clk a 20 MHz)
Porche delantero: 0,65 us, 13 píxeles (13 ciclos clk a 20 MHz)
Pulso de sincronización: 3,8 us, 76 píxeles (76 ciclos clk a 20 MHz)
Porche trasero : 1,9 us, 38 píxeles (38 ciclos clk a 20 MHz)
Toda la línea: 31,75 us, 635 píxeles (635 ciclos clk a 20 MHz)
Según estos tiempos, la frecuencia de actualización de fotogramas es de 59,9925 Hz . La región visible en pantalla tiene una resolución de 508*480 en contraste con los 640*480 de la especificación.
Soy consciente de que a una frecuencia de reloj de 20 MHz, los tiempos no se pueden cumplir con precisión, pero si compara mis tiempos con la especificación real (3), los tiempos son muy parecidos.
El software que escribí para generar estas salidas ha sido escrito en ensamblador AVR, esto me permite contar el número de ciclos de reloj para cada región, y se puede encontrar justo debajo de este párrafo. El software mostrará indefinidamente un cuadro rojo en la pantalla.
Una imagen del esquema para la implementación del hardware se puede encontrar debajo del código.
;
; VGA_INTERFACE.asm
;
; Outputs the required signals with the correct timings for VGA output to a monitor.
;
;
;
; Created: 13/02/2018
; Author : Tom
;
; COMPILER SETTINGS
.INCLUDE "M328pDEF.INC"
; INTERRUPT VECTORS
.org 0 ; defines absolute address for interrupt vector
; ****************************************************************************************
; **** IO PORT D SETUP
; ****************************************************************************************
; ddrd pin I/O direction configured
sbi ddrd,0 ; RED BIT 0
sbi ddrd,1 ; RED BIT 1
sbi ddrd,2 ; GRN BIT 0
sbi ddrd,3 ; GRN BIT 1
sbi ddrd,4 ; BLU BIT 0
sbi ddrd,5 ; BLU BIT 1
sbi ddrd,6 ; HORIZONTAL SYNC
sbi ddrd,7 ; VERTICAL SYNC
ldi r20, 0xC0
out portd, r20 ; clears the RGB bits and sets the sync pulses high
; ****************************************************************************************
; **** STARTUP SEQUENCE
; ****************************************************************************************
; INITIALIZE STACK POINTER
ldi r16,low(ramend) ; loads the lower byte of top stack address into register 16
out spl,r16 ; stack pointer lower byte is set to lower byte of the top
; stack address stored in register 16
ldi r16,high(ramend) ; loads the upper byte of top stack address into register 16
out sph,r16 ; stack pointer upper byte is set to upper byte of the top
; stack address stored in register 16
; main program loop
main:
V_LOOP:
; ****************************************************************************************
; **** VERTICAL LOOP - BEGIN
; ****************************************************************************************
; **** V-SYNC DRIVE LOW (2 lines, 1,270 cycles)
cbi portd,7 ;2 drives v-sync active low
; ========================================================================================
; Delay 1268 cycles
ldi r18, 2
ldi r19, 165
L1: dec r19
brne L1
dec r18
brne L1
; ========================================================================================
sbi portd,7 ;2 drives v-sync high
; **** VERTICAL BACK PORCH (33 lines, 20955 cycles)
; **NOTE: Only 20951 cycles required to be wasted as 4 cycles are used by Horizontal
; loop. 2 are used when setting max loop value in r16 and r17. A further 2 are used
; setting horizontal sync active low.
; ========================================================================================
; Delay 20951 cycles
ldi r18, 28
ldi r19, 52
L2: dec r19
brne L2
dec r18
brne L2
rjmp PC+1
; ========================================================================================
; ****************************************************************************************
; **** HORIZONTAL LOOP - BEGIN (LOOPS 480 times)
; ****************************************************************************************
ldi r16,low(480) ;1 holds LSB of loop value
ldi r17,high(480) ;1 hold MSB of loop value
H_LOOP:
; **** H-SYNC DRIVE LOW (76 cycles)
cbi portd,6 ;2 drives h-sync active low
; ========================================================================================
; Delay 74 cycles
ldi r18, 24
L3: dec r18
brne L3
rjmp PC+1
; ========================================================================================
sbi portd,6 ;2 drives h-sync high
; **** HORIZONTAL BACK PORCH (38 cycles)
; **NOTE: Only 36 cycles required to be wasted as 2 cycles are used by RGB for setting
; the red bit 0 high.
; ========================================================================================
; Delay 36 cycles
ldi r18, 12
L4: dec r18
brne L4
; ========================================================================================
; **** RGB (508 cycles)
ldi r20, 0xC1 ;1
out portd, r20 ;1 sets red bit 0 high, all other RGB low, sync pulses high
; ========================================================================================
; Delay 506 cycles
ldi r18, 168
L5: dec r18
brne L5
rjmp PC+1
; ========================================================================================
ldi r20, 0xC0 ;1
out portd, r20 ;1 sets the RGB outputs low, sync pulses high
; **** HORIZONTAL FRONT PORCH (13 cycles)
; **NOTE: Only 5 cycles required to be wasted as 8 cycles are used up already. 4 are
; are used for subtracting one from the loop counter. A further 4 are used for
; jumping to start of horizontal loop and setting the Horizontal sync active low.
; ========================================================================================
; Delay 5 cycles
lpm
rjmp PC+1
; ========================================================================================
ldi r18, low(1) ;1
ldi r19, high(1) ;1
sub r16,r18 ;1
sbc r17,r19 ;1
brne H_LOOP ; 2 cycles if true, 1 if false
; ****************************************************************************************
; **** HORIZONTAL LOOP - END
; ****************************************************************************************
; **** VERTICAL FRONT PORCH (10 lines, 6350 cycles)
; **NOTE: Only 10 cycles have been used up for the Horizontal front porch, as a result a
; further 3 must be added to the vertical front porch.
; However 4 cycles are already being used, 2 to jump to start of vertical loop and a
; further 2 to drive horizontal sync active low.
; As a result taking these two factors into account, the delay needs to be 6350+3-4 =
; 6349 cycles long.
; ========================================================================================
; Delay 6349 cycles
ldi r18, 9
ldi r19, 62
L6: dec r19
brne L6
dec r18
brne L6
; ========================================================================================
rjmp V_LOOP ;2 relative jump to start of vertical loop
; ****************************************************************************************
; **** VERTICAL LOOP - END
; ****************************************************************************************
Después de probar la implementación del hardware y el software, descubrí que funciona bien en la interfaz VGA del televisor de mi sala de estar, pero no funciona en ningún otro monitor o televisor que haya probado. Descubrí que funciona en el monitor de un amigo, mostrará una pantalla roja pero con parches negros aleatorios y perderá señal periódicamente. Los otros monitores en los que he probado detectan la entrada, pero simplemente no pueden mostrar nada en la pantalla.
Creo que la razón por la que funciona en algunas pantallas y no en otras se debe simplemente a las tolerancias que los fabricantes han estipulado en sus dispositivos.
Probé numerosos ajustes en el código, esto implicó principalmente cambiar la cantidad de ciclos de reloj en cada región, pero esto no arrojó ningún resultado positivo. Esto me lleva a creer una de dos situaciones posibles:
1) (MÁS PROBABLE) He implementado el software o el hardware incorrectamente, lo que ha provocado que los tiempos estén ligeramente fuera de lugar.
2) Es muy complicado/imposible implementar la especificación VGA con un rendimiento constante en todos los dispositivos compatibles con VGA que utilicen un ATmega328P que funcione a 20 MHz.
Como resultado de esto, planeo overclockear el dispositivo Atmega con un cristal de 25,175 MHz para garantizar que se cumplan los tiempos o voy a usar un microcontrolador más capaz con mayor potencia de procesamiento, algo así como un PIC24EP128MC202.
Si alguien tiene alguna idea de por qué mi implementación actual no funciona y cómo podría rectificar esto, ¡se lo agradecería mucho!
Si has logrado leer hasta aquí, ¡gracias de todos modos! :)
(1)(3) Señal VGA 640 x 480 a 60 Hz Temporización estándar de la industria - http://tinyvga.com/vga-timing/640x480@60Hz
(2) Lucid Science VGA Video Generator (lamentablemente, el sitio se cerró ahora) https://web.archive.org/web/20141102012544/http://www.lucidscience.com:80/pro-vga%20video%20generator -6.aspx
En primer lugar, no debería haber ningún problema con la salida de VGA usando un ATMega328. Puede generar VGA que funcione con todo, desde CRT antiguos, pequeños módulos LCD misteriosos de aliexpress o un LCD moderno. Realmente nunca he oído hablar de problemas de compatibilidad con VGA, especialmente nada relacionado con el tiempo.
Hay docenas de proyectos que generan con éxito al menos un VGA monocromático de 640x480 (en paralelo con las líneas RGB) usando mucho menos que un ATMega, y ni siquiera necesita un reloj de 20 MHz; varios proyectos se manejan con un reloj de 16 MHz. Y si está de acuerdo con menos de 640x480, este proyecto genera una salida VGA válida utilizando un ATTiny15 que se ejecuta a 1,6 MHz.
Ahora, no he verificado dos veces su ensamblaje, por lo que podría estar equivocado, pero parece poco probable que la sincronización funcione bien en una pantalla pero no en otras. No, creo que esto es simplemente un problema de atenuación de la señal debido a la falta de coincidencia de impedancia.
Las 3 líneas de color esperan de 0 a 0.7V. Y veo que ha dimensionado sus resistencias de tal manera que, con una impedancia de 75 Ω, dará como resultado 0,696 V o 0,348 V.
Sé que probablemente parezca una solución muy agradable y elegante para obtener negro + dos tonos, pero me temo que no funcionará muy bien. Sus resistencias son demasiado grandes y esto está causando un mal caso de desajuste de impedancia. Y es probable que experimente los problemas exactos que describe: algunas pantallas (una pequeña minoría que esperaría con resistencias tan grandes) podrían usar la señal, pero la mayoría no lo haría, o solo leería correctamente los píxeles de forma intermitente por cada cuadro.
Si desea conducir correctamente una impedancia de 75 Ω mientras reduce un voltaje más alto al rango de voltaje correcto, debe usar una red de adaptación de impedancia, como un divisor L-pad.
Discutir la teoría detrás de los divisores L-pad está más allá del alcance de esta pregunta, pero haría bien en usar transistores para establecer correctamente los niveles de voltaje sin tener la alta impedancia de un divisor.
Aquí, solo para hacer una verificación de cordura y ver si mi suposición es correcta, deshazte de la segunda línea IO en las entradas de 3 colores. De todos modos, no puede manejar correctamente una entrada VGA usando los 75 ohmios como participante en un divisor de voltaje, por lo que me temo que tendrá que deshacerse de esa idea por completo. Puede salirse con la suya usando una escalera de estilo DAC adecuada, pero incluso entonces, todas las resistencias serán un orden de magnitud más pequeñas que 1K y 2K.
Solo use un pin IO, y me acabo de dar cuenta de que esto probablemente excede la corriente de un solo pin ... ¿50 mA, creo? Pero el l-pad ideal para 75 Ω que atenúa de 5 V a 0,7 V sería una resistencia de 64 Ω y 12 Ω en serie a tierra, con la señal que sale a la pantalla como la derivación entre los dos.
La magia aquí es que, si elimina mis errores de redondeo, esto da como resultado una resistencia de 75 Ω. Eso es lo que significa la impedancia adaptada. Que cada extremo tiene el equivalente a 75Ω desde el pin de señal a tierra.
Básicamente, los pines de su atmega no son lo suficientemente fuertes como para generar una impedancia de 75 Ω a plena potencia cuando se ejecuta desde 5 V, ya que consumiría más de 50 mA. En su lugar, use una escalera con una proporción similar, pero no tan grande. Pruebe con 220 Ω y 56 Ω, y eso debería resolver sus problemas de señal y reducir el voltaje de la señal a 0,7 V SIN tener una impedancia tan inigualable que la mayoría de las pantallas ni siquiera funcionen correctamente.
Eche un vistazo a las especificaciones de tiempo LTDC VGA. En los monitores LCD TFT, la temporización es muy similar a la de los monitores VGA estándar, pero el orden de las señales es diferente.
filo
tom finch
nazar
tom finch
winny
Tony Estuardo EE75
chris stratton
chris stratton
tom finch
chris stratton