Go Down

Topic: Code: VGA RGB Signal (Read 16328 times) previous topic - next topic

WilliamK Govinda

Oct 19, 2011, 08:01 pm Last Edit: Oct 19, 2011, 11:35 pm by WilliamK Reason: 1
I'm trying to create a simple VGA RGB Signal with Interrupts, but so far it doesn't work. Would someone be kind to give me some pointers on what I'm doing wrong?  :smiley-red:

Edit: code removed until I fix it. ;-)

robtillaart


not read the VGA spec, but vars used in an IRQ should be volatile ...
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)


stimmer

What does the generated signal look like on an oscilloscope? How does it compare to a normal VGA signal?

Your code looks like it uses one-shot timers - I don't think one-shot timers is a good way of doing VGA as some of the intervals are too short. The horizontal timing in particular needs to be very stable. I'd suggest using PWM to generate the horizontal timing and interrupts for the vertical timing. Remember you still need to generate the horizontal sync pulse during the vertical sync, PWM would do that automatically.
Due VGA library - http://arduino.cc/forum/index.php/topic,150517.0.html

WilliamK Govinda

Thanks, I was just about to post that I managed to understand my code was bad, as the timers were too short.  :smiley-red:

I will re-do the code with a single call to timer that process an entire line, that should work.

Here's some data so far:

Code: [Select]
  VSync us
  64    - Sync   = 1024 cycles
  1020  - Blank  = 16320 cycles
  15240 - Lines  = 243840 cycles
  350   - Blank  = 5600 cycles

  HSync us (Lines)
  3.77  - Sync   = 60.32 cycles   = 60
  1.89  - Blank  = 30.24 cycles   = 30
  25.17 - RGB    = 402.72 cycles  = 402
  0.94  - Blank  = 15.04 cycles   = 16

  508 Cycles per line

  Sync Start = 2 lines
  sync blank = 32 lines
   480 lines
  Sync Blank = 11 lines

WilliamK Govinda

I still get a jiggy screen, and its terrible.

Here's a great project I found: http://avga.prometheus4.com/

It works on the ATmega168, so I wonder what would it take to make it work with the Arduino IDE or even the Arduino ATmega328?

Wk

Grumpy_Mike

I would imagine it is jiggly because there are other interrupts going off as well as those that you made. Like those for the millis() and serial data arriving.

WilliamK Govinda

Nice try, but I disabled those and still got the same result. ;-) But I will re-check, just in case, txs.

Wk

WilliamK Govinda

Ok, you were right, I must say that, I didn't really removed ALL interrupts.  :smiley-red:

So, I changed the wiring.c just to test, I know, its not good, but for testing.

Code: [Select]
void init()
{
sei();
return;
}


And its much better now, still a bit strange, but at least a few strange things are gone now.

Wk

WilliamK Govinda

Ok, now, without the Delay/Millis/Timer0 interrupt and also the Serial Interrupt, seems to be working ok, but every 8 seconds there's a halt, is that the Watchdog Timer? Can I disable it?

Also, as soon as I try to put something at the bottom of the interrupt, where I put the video, things get out of sync again, why?

So far I'm testing with this:

http://olb7.free.fr/arduino/syncInterrupt.pde

Wk

Grumpy_Mike

I would not have thought so but
The data sheet says:-
Quote
the application software should always clear the Watchdog System Reset Flag (WDRF) and the WDE control bit in the initialisation routine, even if the Watchdog is not in use.

And 8 seconds is the time for the longest setting.

Try changing the watch dog timer prescaler bits to:-
WDP3 = 0
WDP2 = 1
WDP1 = 1
WDP0 = 1
If it changes the glitching to every two seconds then it has nailed it to that.

WilliamK Govinda

One thing I wonder, how come the TVOut lib doesn't get messed out by the other timers: UART, Timer0, WD?

Still learning... ;-)

Wk

WilliamK Govinda

Anyway, good news, I managed to get it working now perfectly. I got some other libs to try and see what I will do next. ;-)

The WD didn't do anything, so it was something else, in any event, the following disabled Timer0 so I don't have to mess with the Wiring.c file anymore.

Code: [Select]
  // Disable Arduino Timer0 and UART Timer
  TCCR0A = TCCR0B = 0;
  TIMSK0 = 0;


Here's a VERY RAW code based on the following code: http://olb7.free.fr/arduino/syncInterrupt.pde

Code: [Select]
#include <avr/sleep.h>
#define NOP asm("nop")
#define vga_field_line_count 525
#define ISR_FREQ 0x3F
volatile unsigned int linecount;
volatile uint8_t renderVideo = 0;
volatile unsigned int xCount = 45;
#define videoOn PORTD |= (1 << 5);
#define videoOff PORTD &= ~(1 << 5);

void setup()
{
  set_sleep_mode(SLEEP_MODE_IDLE);
 
  pinMode(5, OUTPUT);  pinMode(6, OUTPUT);  pinMode(7, OUTPUT);
  digitalWrite(5, LOW);  digitalWrite(6, HIGH);  digitalWrite(7, HIGH);
 
  // Disable Arduino Timer0 and UART Timer
  TCCR0A = TCCR0B = 0;
  TIMSK0 = 0;
 
  TCCR2A = 0x02;                        // WGM22=0 + WGM21=1 + WGM20=0 = Mode2 (CTC)
  TCCR2B = (1 << CS01);                 // /8 prescaler (2MHz)
  TCNT2 = 0;                            // clear counter
  OCR2A = ISR_FREQ;                     // set TOP (divisor) - see #define
  TCNT2 = 0;                            // clear counter (needed here also)
  TIMSK2|=(1<<OCIE2A);                  // set interrupts=enabled (calls ISR(TIMER2_COMPA_vect)
}

volatile uint8_t flipFlop = 0;
volatile uint8_t flipFlopCounter = 0;

void loop()
{
  sleep_mode(); // Wait for the Timer Interrupt
 
  if (renderVideo == 1)
  {
    if (flipFlop) { NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; } else videoOff;
    for (char i=0; i<10; i++) { videoOn; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP;  videoOff; NOP; videoOn; videoOff; videoOn; videoOff; }
    renderVideo = 0;
    flipFlopCounter++;
    if (flipFlopCounter > 40) { flipFlopCounter = 0; flipFlop = !flipFlop; }
  }
  else
  {
    // Quick Test //
    static int xC = 0;
    xC++;
    if (xC > 100)
    {
      xC = 0;
      xCount++;
      if (xCount > 500) xCount = 45;
    }
  }
}

///////////////////////////// ISR Timer Functions ///////////////////////////
ISR(TIMER2_COMPA_vect)
{       
if ((linecount == 10 )||(linecount == 11 ))
{
PORTD &= ~(1 << 7); // hsync LOW
PORTD &= ~(1 << 6); // vsync LOW
                flipFlopCounter = flipFlop = 0;
}
else
{
PORTD &= ~(1 << 7); // hsync LOW
PORTD |= (1 << 6); // vsync HIGH
}

PORTD |= (1 << 7);  // hsync HIGH

NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP;
NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP;
NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP;

        if (linecount > xCount && linecount < 524) renderVideo = 1;       
if (++linecount == vga_field_line_count) linecount = 0;
}


It should show a very neat pattern going down and appearing again. Just to really test the whole process out. Once I have something more usable I will post some videos and screenshots.

Wk

WilliamK Govinda

Here's a fun code. Sadly there's not much to be done, as there's not enough RAM or cycles. :-(

Code: [Select]
/*

  Based on the following code by Dwan (dwanafite@yahoo.fr) and BroHogan - http://olb7.free.fr/arduino/syncInterrupt.pde
 
  For connections, use: Pin 9 = HZync = VGA Pin 13 / Pin 6 = VSync = VGA Pin 14 / Pin 5 = RGB Video = VGA Pins 1, 2 & 3 / Ground the following pins on the VGA connector: 6 and 10

  VSync us
  64    - Sync   = 1024 cycles
  1020  - Blank  = 16320 cycles
  15240 - Lines  = 243840 cycles
  350   - Blank  = 5600 cycles

266784 = cycles total (60 times per second = 60hz)

  HSync us (Lines)
  3.77  - Sync   = 60.32 cycles
  1.89  - Blank  = 30.24 cycles
  25.17 - RGB    = 402.72 cycles
  0.94  - Blank  = 15.04 cycles

  508 Cycles per line

  Sync Start = 2 lines
  sync blank = 32 lines
   480 lines
  Sync Blank = 11 lines
 
  Total of 525 lines
 
*/

#include <avr/sleep.h>
#define NOP asm("nop")
#define vga_field_line_count 525
volatile unsigned int linecount;

#define videoOn PORTD |= (1 << 5);
#define videoOff PORTD &= ~(1 << 5);
#define vSyncLow PORTB &= ~(1 << 0);
#define vSyncHigh PORTB |= (1 << 0);

uint8_t videoData[128]; // One Line Draw //

void setup()
{
  set_sleep_mode(SLEEP_MODE_IDLE);
 
  // 8 Bit Color Output - R = 3 / G = 3 / B = 2
  pinMode(0, OUTPUT); 
  pinMode(1, OUTPUT); 
  pinMode(2, OUTPUT); 
  pinMode(3, OUTPUT); 
  pinMode(4, OUTPUT); 
  pinMode(5, OUTPUT); 
  pinMode(6, OUTPUT); 
  pinMode(7, OUTPUT); 
  pinMode(8, OUTPUT); // VZync = VGA Pin 14
  pinMode(9, OUTPUT); // HZync = VGA Pin 13
 
  digitalWrite(0, LOW);
  digitalWrite(1, LOW);
  digitalWrite(2, LOW);
  digitalWrite(3, LOW);
  digitalWrite(4, LOW);
  digitalWrite(5, LOW);
  digitalWrite(6, LOW);
  digitalWrite(7, LOW);
  digitalWrite(8, LOW);
 
  memset(videoData,0,sizeof(videoData));
  for (int x=0; x<128; x += 2) videoData[x] = 0xFF;
 
  // Disable Arduino Timer0 and UART Timer
  TCCR0A = TCCR0B = 0;
  TIMSK0 = 0;
 
  TCCR1A =  _BV(COM1A1) | _BV(COM1A0) | _BV(WGM11);
  TCCR1B = _BV(WGM12) | _BV(WGM13) | _BV(CS10); // No Prescalar
  ICR1 = 508;
  TIMSK1 = _BV(TOIE1); // Enable timer overflow interrupt
  OCR1A = 60; // HSync Pulse
 
  sei(); // enable global interrupts
 
}

void loop()
{
  sleep_mode(); // Wait for the Timer Interrupt
 
  if (linecount > 42 && linecount < 506)
  {
    PORTD = videoData[0];
    PORTD = videoData[1];
    PORTD = videoData[2];
    PORTD = videoData[3];
    PORTD = videoData[4];
    PORTD = videoData[5];
    PORTD = videoData[6];
    PORTD = videoData[7];
    PORTD = videoData[8];
    PORTD = videoData[9];
    PORTD = videoData[10];
    PORTD = videoData[11];
    PORTD = videoData[12];
    PORTD = videoData[13];
    PORTD = videoData[14];
    PORTD = videoData[15];
    PORTD = videoData[16];
    PORTD = videoData[17];
    PORTD = videoData[18];
    PORTD = videoData[19];
    PORTD = videoData[20];
    PORTD = videoData[21];
    PORTD = videoData[22];
    PORTD = videoData[23];
    PORTD = videoData[24];
    PORTD = videoData[25];
    PORTD = videoData[26];
    PORTD = videoData[27];
    PORTD = videoData[28];
    PORTD = videoData[29];
    PORTD = videoData[30];
    PORTD = videoData[31];
    PORTD = videoData[32];
    PORTD = videoData[33];
    PORTD = videoData[34];
    PORTD = videoData[35];
    PORTD = videoData[36];
    PORTD = videoData[37];
    PORTD = videoData[38];
    PORTD = videoData[39];
    PORTD = videoData[40];
    PORTD = videoData[41];
    PORTD = videoData[42];
    PORTD = videoData[43];
    PORTD = videoData[44];
    PORTD = videoData[45];
    PORTD = videoData[46];
    PORTD = videoData[47];
    PORTD = videoData[48];
    PORTD = videoData[49];   
    PORTD = videoData[50];
    PORTD = videoData[51];
    PORTD = videoData[52];
    PORTD = videoData[53];
    PORTD = videoData[54];
    PORTD = videoData[55];
    PORTD = videoData[56];
    PORTD = videoData[57];
    PORTD = videoData[58];
    PORTD = videoData[59];   
    PORTD = videoData[60];
    PORTD = videoData[61];
    PORTD = videoData[62];
    PORTD = videoData[63];
    PORTD = videoData[64];
    PORTD = videoData[65];
    PORTD = videoData[66];
    PORTD = videoData[67];
    PORTD = videoData[68];
    PORTD = videoData[69];   
    PORTD = videoData[70];
    PORTD = videoData[71];
    PORTD = videoData[72];
    PORTD = videoData[73];
    PORTD = videoData[74];
    PORTD = videoData[75];
    PORTD = videoData[76];
    PORTD = videoData[77];
    PORTD = videoData[78];
    PORTD = videoData[79];   
   


    PORTD = videoData[80];
    PORTD = videoData[81];
    PORTD = videoData[82];
    PORTD = videoData[83];
    PORTD = videoData[84];
    PORTD = videoData[85];
    PORTD = videoData[86];
    PORTD = videoData[87];
    PORTD = videoData[88];
    PORTD = videoData[89];   

    PORTD = videoData[90];
    PORTD = videoData[91];
    PORTD = videoData[92];
    PORTD = videoData[93];
    PORTD = videoData[94];
    PORTD = videoData[95];
    PORTD = videoData[96];
    PORTD = videoData[97];
    PORTD = videoData[98];
    PORTD = videoData[99];   

    PORTD = videoData[100];
    PORTD = videoData[101];
    PORTD = videoData[102];
    PORTD = videoData[103];
    PORTD = videoData[104];
    PORTD = videoData[105];
    PORTD = videoData[106];
    PORTD = videoData[107];
    PORTD = videoData[108];
    PORTD = videoData[109];   

    PORTD = videoData[110];
    PORTD = videoData[111];
    PORTD = videoData[112];
    PORTD = videoData[113];
    PORTD = videoData[114];
    //PORTD = videoData[115];
    //PORTD = videoData[116];
    //PORTD = videoData[117];
    //PORTD = videoData[118];
    //PORTD = videoData[119];

    PORTD = 0;
   

    //PORTD = videoData[120];
    //PORTD = videoData[121];
    //PORTD = videoData[122];
    //PORTD = videoData[123];
   
    videoData[0]++;
    videoData[1]++;
    videoData[2]++;
   
    videoData[112]++;   
    videoData[113]++;   
    videoData[114]++;
  }
  else
  {
    if (linecount < 40)
    {
      videoData[linecount+1] = videoData[linecount+40] = videoData[linecount+80] = random();
    }
  }
}


ISR(TIMER1_OVF_vect)
{       
  if (linecount == 0) vSyncLow;
  if (linecount == 2) vSyncHigh;
  if (++linecount == vga_field_line_count) linecount = 0;
}

WilliamK Govinda

Here's another fun code. It outputs video on pins 0 to 7. So you can add some resistors and get more colors on some output combinations.

Code: [Select]
/*

  Based on the following code by Dwan (dwanafite@yahoo.fr) and BroHogan - http://olb7.free.fr/arduino/syncInterrupt.pde
 
  For connections, use: Pin 9 = HZync = VGA Pin 13 / Pin 6 = VSync = VGA Pin 14 / Pin 5 = RGB Video = VGA Pins 1, 2 & 3 / Ground the following pins on the VGA connector: 6 and 10

  VSync us
  64    - Sync   = 1024 cycles
  1020  - Blank  = 16320 cycles
  15240 - Lines  = 243840 cycles
  350   - Blank  = 5600 cycles

266784 = cycles total (60 times per second = 60hz)

  HSync us (Lines)
  3.77  - Sync   = 60.32 cycles
  1.89  - Blank  = 30.24 cycles
  25.17 - RGB    = 402.72 cycles
  0.94  - Blank  = 15.04 cycles

  508 Cycles per line

  Sync Start = 2 lines
  sync blank = 32 lines
   480 lines
  Sync Blank = 11 lines
 
  Total of 525 lines
 
*/

#include <avr/sleep.h>
#define NOP asm("nop")
#define vga_field_line_count 525
volatile unsigned int linecount;

#define videoOn PORTD |= (1 << 5);
#define videoOff PORTD &= ~(1 << 5);
#define vSyncLow PORTB &= ~(1 << 0);
#define vSyncHigh PORTB |= (1 << 0);

uint8_t videoData[128]; // One Line Draw //

void setup()
{
  set_sleep_mode(SLEEP_MODE_IDLE);
 
  pinMode(0, OUTPUT); 
  pinMode(1, OUTPUT); 
  pinMode(2, OUTPUT); 
  pinMode(3, OUTPUT); 
  pinMode(4, OUTPUT); 
  pinMode(5, OUTPUT); 
  pinMode(6, OUTPUT); 
  pinMode(7, OUTPUT); 
  pinMode(8, OUTPUT); // VZync = VGA Pin 14
  pinMode(9, OUTPUT); // HZync = VGA Pin 13
 
  digitalWrite(0, LOW);
  digitalWrite(1, LOW);
  digitalWrite(2, LOW);
  digitalWrite(3, LOW);
  digitalWrite(4, LOW);
  digitalWrite(5, LOW);
  digitalWrite(6, LOW);
  digitalWrite(7, LOW);
  digitalWrite(8, LOW);
 
  memset(videoData,0,sizeof(videoData));
  for (int x=0; x<128; x += 2) videoData[x] = 0xFF;
 
  // Disable Arduino Timer0 and UART Timer
  TCCR0A = TCCR0B = 0;
  TIMSK0 = 0;
 
  TCCR1A =  _BV(COM1A1) | _BV(COM1A0) | _BV(WGM11);
  TCCR1B = _BV(WGM12) | _BV(WGM13) | _BV(CS10); // No Prescalar
  ICR1 = 508;
  TIMSK1 = _BV(TOIE1); // Enable timer overflow interrupt
  OCR1A = 60; // HSync Pulse
 
  sei(); // enable global interrupts
 
}

uint8_t skipLine = 0;
uint8_t process = 0;

void loop()
{
  sleep_mode(); // Wait for the Timer Interrupt
 
  if (linecount > 42 && linecount < 506)
  {
    if (skipLine == 0)
    {
      PORTD = videoData[0];
      PORTD = videoData[1];
      PORTD = videoData[2];
      PORTD = videoData[3];
      PORTD = videoData[4];
      PORTD = videoData[5];
      PORTD = videoData[6];
      PORTD = videoData[7];
      PORTD = videoData[8];
      PORTD = videoData[9];
      PORTD = videoData[10];
      PORTD = videoData[11];
      PORTD = videoData[12];
      PORTD = videoData[13];
      PORTD = videoData[14];
      PORTD = videoData[15];
      PORTD = videoData[16];
      PORTD = videoData[17];
      PORTD = videoData[18];
      PORTD = videoData[19];
      PORTD = videoData[20];
      PORTD = videoData[21];
      PORTD = videoData[22];
      PORTD = videoData[23];
      PORTD = videoData[24];
      PORTD = videoData[25];
      PORTD = videoData[26];
      PORTD = videoData[27];
      PORTD = videoData[28];
      PORTD = videoData[29];
      PORTD = videoData[30];
      PORTD = videoData[31];
      PORTD = videoData[32];
      PORTD = videoData[33];
      PORTD = videoData[34];
      PORTD = videoData[35];
      PORTD = videoData[36];
      PORTD = videoData[37];
      PORTD = videoData[38];
      PORTD = videoData[39];
      PORTD = videoData[40];
      PORTD = videoData[41];
      PORTD = videoData[42];
      PORTD = videoData[43];
      PORTD = videoData[44];
      PORTD = videoData[45];
      PORTD = videoData[46];
      PORTD = videoData[47];
      PORTD = videoData[48];
      PORTD = videoData[49];   
      PORTD = videoData[50];
      PORTD = videoData[51];
      PORTD = videoData[52];
      PORTD = videoData[53];
      PORTD = videoData[54];
      PORTD = videoData[55];
      PORTD = videoData[56];
      PORTD = videoData[57];
      PORTD = videoData[58];
      PORTD = videoData[59];   
      PORTD = videoData[60];
      PORTD = videoData[61];
      PORTD = videoData[62];
      PORTD = videoData[63];
      PORTD = videoData[64];
      PORTD = videoData[65];
      PORTD = videoData[66];
      PORTD = videoData[67];
      PORTD = videoData[68];
      PORTD = videoData[69];   
      PORTD = videoData[70];
      PORTD = videoData[71];
      PORTD = videoData[72];
      PORTD = videoData[73];
      PORTD = videoData[74];
      PORTD = videoData[75];
      PORTD = videoData[76];
      PORTD = videoData[77];
      PORTD = videoData[78];
      PORTD = videoData[79];   
      PORTD = videoData[80];
      PORTD = videoData[81];
      PORTD = videoData[82];
      PORTD = videoData[83];
      PORTD = videoData[84];
      PORTD = videoData[85];
      PORTD = videoData[86];
      PORTD = videoData[87];
      PORTD = videoData[88];
      PORTD = videoData[89];   
      PORTD = videoData[90];
      PORTD = videoData[91];
      PORTD = videoData[92];
      PORTD = videoData[93];
      PORTD = videoData[94];
      PORTD = videoData[95];
      PORTD = videoData[96];
      PORTD = videoData[97];
      PORTD = videoData[98];
      PORTD = videoData[99];   
      PORTD = videoData[100];
      PORTD = videoData[101];
      PORTD = videoData[102];
      PORTD = videoData[103];
      PORTD = videoData[104];
      PORTD = videoData[105];
      PORTD = videoData[106];
      PORTD = videoData[107];
      PORTD = videoData[108];
      PORTD = videoData[109];   
      PORTD = videoData[110];
      PORTD = videoData[111];
      PORTD = videoData[112];
      PORTD = videoData[113];
      PORTD = videoData[114];
      PORTD = videoData[115];
      PORTD = videoData[116];
      PORTD = videoData[117];
      PORTD = videoData[118];
      PORTD = videoData[119];
      PORTD = videoData[120];
    }
    else
    {
      process++;
      if (process > 50)
      {
        for (char x=0; x<4; x++)
        {
          videoData[x]++;
          videoData[120-4+x]++;
        }
      }
    }
    PORTD = 0;
    skipLine++;
    if (skipLine >= 2) skipLine = 0;
  }
  else
  {
    if (linecount == 0) skipLine = 0;
    if (linecount < 40)
    {
      if (process > 25) videoData[linecount+1] = videoData[linecount+40] = videoData[linecount+80] = random();
    }
  }
}

ISR(TIMER1_OVF_vect)
{       
  if (linecount == 0) vSyncLow;
  if (linecount == 2) vSyncHigh;
  if (++linecount == vga_field_line_count) linecount = 0;
}

Go Up