Go Down

Topic: Simulating VGA Signal (Read 5056 times) previous topic - next topic

hsadan

#15
Dec 09, 2008, 06:33 am Last Edit: Dec 09, 2008, 06:59 am by hsadan Reason: 1
dwan, I tried running your code to see if it works. I connected pin 5 to the red pin on the VGA, and it started occasionally flashing a red screen. It seems like the timing is off.

I didn't modify your code, though, and according to you it shouldn't be outputting video at all? Is getting the occasional red frame the expected behavior?

edit: how do I disable all timers to ensure better timing?

dwan

Is your wiring ok ?
As a reminder :
// HSync : pin 7 Arduino to pin 13 VGA
// VSync : pin 6 Arduino to pin 14 VGA
// Arduino's pin 5 is HIGH when video can be sent, LOW otherwise. I use it to power a transistor.

My screen syncs fine with this sketch, actually.

You're right, this sketch does not output video, only the sync signals. The occasional red screen you get is not the expected behaviour. The expected behaviour is a black screen, and your screen's ability to display its OSD.

Nonetheless, Arduino's pin 5 tells you when you can send video by switching to its HIGH state ; it's 5 volt, that's much higher than the required video voltage : you should not wire it to a video pin of your screen ! If you want to send a plain color with this pin, you have to make its high state to 1v max, and its impedance to 75 Ohm. Take a look at this : http://images.electronicsinfoline.com/View/Photo/10001/Vga.gif
As the ECG2322 component is not made anymore, I use BC177 or BC557.

If you understand this sketch well, you've seen that the sync routine is done with the help of Timer2, so disabling the timers is not recommended. However, i suggest you to avoid using a serial link with this sketch, as it breaks the sync signals -only when receiving data.

hsadan

Good news, I managed to get a steady signal going. currently have a solid red screen. It's currently 540am here, so I'm going to go get some sleep... will clean up my code and probably post it soon.

a quick overview: I didn't go with an interrupt driven approach for more control over the timing. The result is probably not the most elegant solution, more of trial and error with an oscilloscope, although after fixing the sync pulse and frame lengths, it was mainly a matter of putting them in the right place.

dwan, while I didn't use an interrupt approach, you code still was helpful in understanding how the vsync and hysncs were supposed to go together, so thanks!

dwan

You're welcome !
I'm curious about your code, as my own code was at first non-interrupt driven. I gave up because of the endless trial and error process and the inaccuracy of the timing I had.

YenTheFirst

#19
May 14, 2009, 01:41 am Last Edit: May 14, 2009, 02:38 am by YenTheFirst Reason: 1
Sorry to resurrect an old thread, but I've been trying to do this same thing, and have been having problems.
After a lot of searching, trial, error, and reinventing of wheels, my code ends up looking kind of similar to dwan's:

Code: [Select]
int LineCount=1;

#define HSYNC_PIN B00010000
#define VSYNC_PIN B00100000
#define RED_PIN   B00000010
//#define HSYNC_PIN 12
//#define VSYNC_PIN 13

void setup_pins()
{
     //set HSYNC,VSYNC pins to out. we use low level here so our HSYNC routine can go fast.
     DDRB = HSYNC_PIN | VSYNC_PIN | RED_PIN;
}
void setup_timer()
{
     cli();

     //I'll set registers in documentation order.
           //we want WaveformGenerationMode 0b0100 - CountThenClear on OCR1A
     TCCR1A = 0;
           //ClockSelect 0b001 - no prescale.
     TCCR1B = 1<<WGM22|1<<CS10;
           //508 cycles, about what we want. at 16MHz, 508 cycles is 31.75 us. the ideal is closer to 31.77 us.
     OCR1A = 507;
           //generate interrupt on OCR1A
     TIMSK1 = 1<<OCIE1A;

     PORTB=HSYNC_PIN | VSYNC_PIN;
     sei();
}

#define ten_nops __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t")
#define eight_nops __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t")

/*basically, we do this:
lines 0-9 front porch
lines 10-11 Vsync
lines 12-44 BackPorch
lines 45-524 ActiveVideo

so, the logic is, if we're on line 10, start vsync, line 12, stop vsync.
If we're in 45-524, do an hsync.
*/


ISR(TIMER1_COMPA_vect)
{
   //accordin' to [the address of dwan's code. I can't post it in my first forum post. :P], apparently, we want to HSYNC every line, not just active ones.
     if(LineCount == 10)
     {
           PORTB &= ~VSYNC_PIN;
     }
     if(LineCount == 12)
     {
           PORTB |= VSYNC_PIN;
     }

           //DO_HSYNC
     ten_nops;
     PORTB &= ~HSYNC_PIN;
     ten_nops;ten_nops;ten_nops;ten_nops;ten_nops;eight_nops;
     PORTB |= HSYNC_PIN;
     ten_nops;eight_nops;

           //generate a smiley face
     if (LineCount >= 80){
     if (LineCount < 220)
     {
           if  (LineCount < 200)
           {
                 ten_nops;ten_nops;ten_nops;ten_nops;
                 PORTB|=RED_PIN;
                 ten_nops;ten_nops;
                 PORTB&=~RED_PIN;
                 ten_nops;ten_nops;
                 PORTB|=RED_PIN;
                 ten_nops;ten_nops;
                 PORTB&=~RED_PIN;
           }
           else
           {
                 ten_nops;
                 PORTB|=RED_PIN;
                 ten_nops;
                 PORTB&=~RED_PIN;
                 ten_nops;ten_nops;ten_nops;ten_nops;ten_nops;ten_nops;ten_nops;ten_nops;ten_nops;eight_nops;
                 PORTB|=RED_PIN;
                 ten_nops;
                 PORTB&=~RED_PIN;
           }
     }
     else
     {
           if (LineCount < 240)
           {
                 ten_nops;
                 PORTB|=RED_PIN;
                 ten_nops;ten_nops;ten_nops;ten_nops;ten_nops;ten_nops;ten_nops;ten_nops;ten_nops;ten_nops;eight_nops;eight_nops;eight_nops;
                 PORTB&=~RED_PIN;
           }
     }
     }
     LineCount++;
     if(LineCount>524)
     {
           LineCount=0;
     }
}


//ok, signal magic done. happy fun arduino stuff now?

void setup()
{
     setup_timer();
     setup_pins();
}
void loop()
{
}


That code is close to working. I have a fairly new CRT monitor, and an LCD monitor. The CRT will display the image, but with some odd lines and artifacts. The LCD either wont, or with some fiddling, will flash the image every few seconds.

Do you think it's perhaps because the timing is not exactly right?  or something else? At the moment, I have VGA pin 3 connected directly to Arduino 8, VGA 13 to Arduino 12, and VGA 14 to arduino 13. Could that be the problem? I'm aware that the sync lines are 5v, but the video should only be 0.7v. But, the video actually displays on the CRT, just with sync issues.

On the CRT monitor, The image is fairly stable, but every couple lines, the HSYNC seems to be off or something, because the whole line jumps a bit to the left, or a couple inches to the right. As I've gotten the timing closer (moved from timer2 to timer1, for 16-bit goodness), the # of off lines decreased, but they still exist.

edit: I put 1.6 KOhms of resistance in line with  the video pin. It visibly dims the display quite a bit, but the syncing issues remain.
It's not stupid, it's advanced

dwan

#20
May 14, 2009, 05:15 pm Last Edit: May 14, 2009, 05:21 pm by dwan Reason: 1
Hello !

/*basically, we do this:
lines 0-9 front porch
lines 10-11 Vsync
lines 12-44 BackPorch
lines 45-524 ActiveVideo


so, the logic is, if we're on line 10, start vsync, line 12, stop vsync.
If we're in 45-524, do an hsync.
*/

I've just been reading these lines, and there are some mistakes :

  • every (i mean every) line must start with a front porch, not only the 9 first lines. These are black lines.
    A typical line is :
    0.63µs high (front porch, video must be stopped at this point)
    3.81µs low (hsync signal)
    1.906µs high (back porch)
    25.42µs still high (visible area, video can be sent)
    The first 9 lines are build like above, except there's no video during the 25.42µs of visible area.


  • On lines 10 & 11, we do the vsync pulse thing by putting the vsync line low during 2 lines (that's 0.06355ms). During those lines, we continue the hsync routine.
    Vsync pulse (remember that the front porch of the vsync pulse has been done during the first 10 lines of the screen) :
    2 lines low (pulse)
    33 lines high (vsync back porch)
    10 + 2 + 33, we get 45 non-visible lines for a 640x480 resolution (800x525 actually)


  • We continue the hsync routine with black lines until the 45th. You can send some color from the 46th line to the 525th.


  • It's important to remember that you shouldn't send video signal during the sync pulses (that is, front porch + sync pulse + back porch time), H or V. That could be interpreted by the screen as a sync pulse.


  • my advice is : do no try to make fancy stuff at first. Start with trying to display a nice & solid red, blue or green. If you want to put 1v on the color lines with the 5v of your arduino, put a 300ohms resistor in series. It will do a voltage divider with the 75 ohms resistor that's in your screen. You can also try to send 5v directly to your screen, mine has survived ! Concerning the sync lines, you need a 75 ohms in series.


  • try my code and tell me if it works  ;)

  • ok, I read the rest of your post, you don't need every word i wrote, but hey, it's typed  ;D

YenTheFirst

Ahh. My code commenting is a bit out of date, and incomplete, I see.
When I started this project, I thought you only had an HSYNC in the active video area. It didn't work at all. :P
After reading your source, though, I added HSYNCs every line, and it got closer to working.

The comment you quoted was actually just talking about VSYNC. lines 0-9 the Vertical line is held high, for lines 10 and11 , the line is held low for the pulse, and then it comes back up. lines 12-45 are the vertical 'back porch', between the vertical pulse and the start of actual active video.

Yeah, I really need to clean up my comments. :D

I tried your code, connecting vsync and hsync directly, and your 'video ready' to VGA red, with the resistor in series. It still had sync issues. I'm out of town for the weekend, but when I get home, I'll try putting the 75 ohm resistors in line for the syncs, and see if it makes a difference.

Out of curiosity, have people tried this on LCD monitors? I was thinking the problem might be that older, actual CRT, monitors actually used the HSYNCs and VSYNCs, and so a bit of timing difference wouldn't be a big deal, but the modern electronics might expect more exact timing.
It's not stupid, it's advanced

dwan

The 75ohm resistors should make the difference, I had similar issues without : red screen coming and then going away.

Some screens don't like my sync signals : I'm driving 16 identical CRT screens with 1 arduino, they all sync correctly. I had to change one screen, this is the only one not syncing   ::)

YenTheFirst

I didn't have 75 ohm resistors, so I tried 100 ohm. I still have the same sync problems. I have the same problem both with my program and yours.
It's not stupid, it's advanced

Shutter

#24
May 18, 2009, 04:24 am Last Edit: May 18, 2009, 04:24 am by Shutter Reason: 1
Here you are!
http://www.linusakesson.net/scene/craft/

I am the one who posted the eagle schematics in the reply  :3

YenTheFirst

I came across that project before. It's very impressive. :)
I notice that it just ties HSYNC and VSYNC to the pins, so I suppose that's doable. I tried to slog through the pure-assembly source, but I'm tired at the moment.
It's not stupid, it's advanced

YenTheFirst

Well, I have good and bad news!
I tried generating NTSC signals, and was having similar sync issues. I then had an epiphany - perhaps the standard timer was popping up at inconvenient times and throwing things off?

I disabled Timer0, and things were smooth and perfect!

However, now my arduino is stuck in a watchdog loop, and the only way to fix, apparently, is to re-burn the bootloader. This may or may not be related.
Once I get that fixed, I'll see if it works for VGA, too.
It's not stupid, it's advanced

dwan


YenTheFirst

I can confirm now, on VGA as well - Disabling Timer0 makes things work nicely. Of course, this means you can't use PWM on certain pins, or millis(), but who needs those anyway? :P


It's not stupid, it's advanced

jhorton

Sorry to be dense, but I have to ask, how do I disable Timer0? Is it simply adding "cbi (TIMSK0,TOIE0);" to the setup routine? Also, if I want to generate some basic rgb pulses like little-scale does, should I use the analog ports? or the digital ports? Thanks in advance!

Go Up