Pages: [1] 2 3 ... 5   Go Down
Author Topic: TVout: NTSC and PAL Composite Video Output.  (Read 12289 times)
0 Members and 1 Guest are viewing this topic.
Michigan, US
Offline Offline
Full Member
***
Karma: 3
Posts: 148
Go Huskies
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I had a thread in the old forums and as this section is for video output I though I would start a new thread here.

Anyway, TVout is an interrupt driven composite video output Library using only 2 resistors to generate a black and white signal at configurable resolutions (defaults to 128x96). It can output text with several included fonts, draw simple shapes, bitmaps, generate 1bit audio, and allows direct access to the frame buffer for custom display routines.

This Library does restrict the use of interrupts (like the ones used by the Serial library) to combat this it includes 2 hooks for calling functions at fixed intervals. One occurs every scan-line and is suitable for very fast methods such as polling the serial connection; this is demon-straighted in the add-on library pollserial.  The second occurs once per frame for longer methods like polling a game-pad or plying music in the background.

Full documentation on this library can be found here: http://code.google.com/p/arduino-tvout/wiki/Welcome?tm=6

Output Schematic:

Specific Connections per device can be found on the Google code page.

Example Video and Source Code (excluding image data):

Code:
#include <TVout.h>
#include <fontALL.h>
#include "schematic.h"
#include "TVOlogo.h"

TVout TV;

int zOff = 150;
int xOff = 0;
int yOff = 0;
int cSize = 50;
int view_plane = 64;
float angle = PI/60;

float cube3d[8][3] = {
  {xOff - cSize,yOff + cSize,zOff - cSize},
  {xOff + cSize,yOff + cSize,zOff - cSize},
  {xOff - cSize,yOff - cSize,zOff - cSize},
  {xOff + cSize,yOff - cSize,zOff - cSize},
  {xOff - cSize,yOff + cSize,zOff + cSize},
  {xOff + cSize,yOff + cSize,zOff + cSize},
  {xOff - cSize,yOff - cSize,zOff + cSize},
  {xOff + cSize,yOff - cSize,zOff + cSize}
};
unsigned char cube2d[8][2];


void setup() {
  TV.begin(NTSC,120,96);
  TV.select_font(font6x8);
  intro();
  TV.println("I am the TVout\nlibrary running on a freeduino\n");
  TV.delay(2500);
  TV.println("I generate a PAL\nor NTSC composite  video using\ninterrupts\n");
  TV.delay(2500);
  TV.println("My schematic:");
  TV.delay(1500);
  TV.bitmap(0,0,schematic);
  TV.delay(10000);
  TV.clear_screen();
  TV.println("Lets see what\nwhat I can do");
  TV.delay(2000);
  
  //fonts
  TV.clear_screen();
  TV.println(0,0,"Multiple fonts:");
  TV.select_font(font4x6);
  TV.println("4x6 font FONT");
  TV.select_font(font6x8);
  TV.println("6x8 font FONT");
  TV.select_font(font8x8);
  TV.println("8x8 font FONT");
  TV.select_font(font6x8);
  TV.delay(2000);
  
  TV.clear_screen();
  TV.print(9,44,"Draw Basic Shapes");
  TV.delay(2000);
  
  //circles
  TV.clear_screen();
  TV.draw_circle(TV.hres()/2,TV.vres()/2,TV.vres()/3,WHITE);
  TV.delay(500);
  TV.draw_circle(TV.hres()/2,TV.vres()/2,TV.vres()/2,WHITE,INVERT);
  TV.delay(2000);
  
  //rectangles and lines
  TV.clear_screen();
  TV.draw_rect(20,20,80,56,WHITE);
  TV.delay(500);
  TV.draw_rect(10,10,100,76,WHITE,INVERT);
  TV.delay(500);
  TV.draw_line(60,20,60,76,INVERT);
  TV.draw_line(20,48,100,48,INVERT);
  TV.delay(500);
  TV.draw_line(10,10,110,86,INVERT);
  TV.draw_line(10,86,110,10,INVERT);
  TV.delay(2000);
  
  //random cube forever.
  TV.clear_screen();
  TV.print(16,40,"Random Cube");
  TV.print(28,48,"Rotation");
  TV.delay(2000);
  
  randomSeed(analogRead(0));
}

void loop() {
  int rsteps = random(10,60);
  switch(random(6)) {
    case 0:
      for (int i = 0; i < rsteps; i++) {
        zrotate(angle);
        printcube();
      }
      break;
    case 1:
      for (int i = 0; i < rsteps; i++) {
        zrotate(2*PI - angle);
        printcube();
      }
      break;
    case 2:
      for (int i = 0; i < rsteps; i++) {
        xrotate(angle);
        printcube();
      }
      break;
    case 3:
      for (int i = 0; i < rsteps; i++) {
        xrotate(2*PI - angle);
        printcube();
      }
      break;
    case 4:
      for (int i = 0; i < rsteps; i++) {
        yrotate(angle);
        printcube();
      }
      break;
    case 5:
      for (int i = 0; i < rsteps; i++) {
        yrotate(2*PI - angle);
        printcube();
      }
      break;
  }
}

void intro() {
unsigned char w,l,wb;
  int index;
  w = pgm_read_byte(TVOlogo);
  l = pgm_read_byte(TVOlogo+1);
  if (w&7)
    wb = w/8 + 1;
  else
    wb = w/8;
  index = wb*(l-1) + 2;
  for ( unsigned char i = 1; i < l; i++ ) {
    TV.bitmap((TV.hres() - w)/2,0,TVOlogo,index,w,i);
    index-= wb;
    TV.delay(50);
  }
  for (unsigned char i = 0; i < (TV.vres() - l)/2; i++) {
    TV.bitmap((TV.hres() - w)/2,i,TVOlogo);
    TV.delay(50);
  }
  TV.delay(3000);
  TV.clear_screen();
}

void printcube() {
  //calculate 2d points
  for(byte i = 0; i < 8; i++) {
    cube2d[i][0] = (unsigned char)((cube3d[i][0] * view_plane / cube3d[i][2]) + (TV.hres()/2));
    cube2d[i][1] = (unsigned char)((cube3d[i][1] * view_plane / cube3d[i][2]) + (TV.vres()/2));
  }
  TV.delay_frame(1);
  TV.clear_screen();
  draw_cube();
}

void zrotate(float q) {
  float tx,ty,temp;
  for(byte i = 0; i < 8; i++) {
    tx = cube3d[i][0] - xOff;
    ty = cube3d[i][1] - yOff;
    temp = tx * cos(q) - ty * sin(q);
    ty = tx * sin(q) + ty * cos(q);
    tx = temp;
    cube3d[i][0] = tx + xOff;
    cube3d[i][1] = ty + yOff;
  }
}

void yrotate(float q) {
  float tx,tz,temp;
  for(byte i = 0; i < 8; i++) {
    tx = cube3d[i][0] - xOff;
    tz = cube3d[i][2] - zOff;
    temp = tz * cos(q) - tx * sin(q);
    tx = tz * sin(q) + tx * cos(q);
    tz = temp;
    cube3d[i][0] = tx + xOff;
    cube3d[i][2] = tz + zOff;
  }
}

void xrotate(float q) {
  float ty,tz,temp;
  for(byte i = 0; i < 8; i++) {
    ty = cube3d[i][1] - yOff;
    tz = cube3d[i][2] - zOff;
    temp = ty * cos(q) - tz * sin(q);
    tz = ty * sin(q) + tz * cos(q);
    ty = temp;
    cube3d[i][1] = ty + yOff;
    cube3d[i][2] = tz + zOff;
  }
}

void draw_cube() {
  TV.draw_line(cube2d[0][0],cube2d[0][1],cube2d[1][0],cube2d[1][1],WHITE);
  TV.draw_line(cube2d[0][0],cube2d[0][1],cube2d[2][0],cube2d[2][1],WHITE);
  TV.draw_line(cube2d[0][0],cube2d[0][1],cube2d[4][0],cube2d[4][1],WHITE);
  TV.draw_line(cube2d[1][0],cube2d[1][1],cube2d[5][0],cube2d[5][1],WHITE);
  TV.draw_line(cube2d[1][0],cube2d[1][1],cube2d[3][0],cube2d[3][1],WHITE);
  TV.draw_line(cube2d[2][0],cube2d[2][1],cube2d[6][0],cube2d[6][1],WHITE);
  TV.draw_line(cube2d[2][0],cube2d[2][1],cube2d[3][0],cube2d[3][1],WHITE);
  TV.draw_line(cube2d[4][0],cube2d[4][1],cube2d[6][0],cube2d[6][1],WHITE);
  TV.draw_line(cube2d[4][0],cube2d[4][1],cube2d[5][0],cube2d[5][1],WHITE);
  TV.draw_line(cube2d[7][0],cube2d[7][1],cube2d[6][0],cube2d[6][1],WHITE);
  TV.draw_line(cube2d[7][0],cube2d[7][1],cube2d[3][0],cube2d[3][1],WHITE);
  TV.draw_line(cube2d[7][0],cube2d[7][1],cube2d[5][0],cube2d[5][1],WHITE);
}

Tetris Using either a Hackvision or a Video Game Shield with a wii classic controller(can wire it up without the shield too) for input:

« Last Edit: January 30, 2011, 09:39:03 am by mdmetzle » Logged

Offline Offline
Sr. Member
****
Karma: 0
Posts: 297
Arduino rocks!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

i tried compiling the code got errors... help?
Logged

As always... Thanks for posting!!!

Michigan, US
Offline Offline
Full Member
***
Karma: 3
Posts: 148
Go Huskies
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Sure post the errors and Ill see what I can do.
Logged

Offline Offline
Sr. Member
****
Karma: 0
Posts: 297
Arduino rocks!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


DemoNTSC.cpp:1:19: error: TVout.h: No such file or directory
DemoNTSC.cpp:2:21: error: fontALL.h: No such file or directory
DemoNTSC:5: error: 'TVout' does not name a type
DemoNTSC.cpp: In function 'void setup()':
DemoNTSC:28: error: 'TV' was not declared in this scope
DemoNTSC:28: error: 'NTSC' was not declared in this scope
DemoNTSC:29: error: 'font6x8' was not declared in this scope
DemoNTSC:46: error: 'font4x6' was not declared in this scope
DemoNTSC:50: error: 'font8x8' was not declared in this scope
DemoNTSC:61: error: 'WHITE' was not declared in this scope
DemoNTSC:63: error: 'INVERT' was not declared in this scope
DemoNTSC.cpp: In function 'void intro()':
DemoNTSC:141: error: 'TV' was not declared in this scope
DemoNTSC:145: error: 'TV' was not declared in this scope
DemoNTSC:149: error: 'TV' was not declared in this scope
DemoNTSC.cpp: In function 'void printcube()':
DemoNTSC:156: error: 'TV' was not declared in this scope
DemoNTSC:159: error: 'TV' was not declared in this scope
DemoNTSC.cpp: In function 'void draw_cube()':
DemoNTSC:204: error: 'TV' was not declared in this scope
DemoNTSC:204: error: 'WHITE' was not declared in this scope
Logged

As always... Thanks for posting!!!

Michigan, US
Offline Offline
Full Member
***
Karma: 3
Posts: 148
Go Huskies
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You need to install the library, go to the google code page linked to in the first post.  Simply download TVoutBeta1 and unzip it to your arduino/libraries folder.  The posted sketch is an example sketch that can be found in File-Examples-TVout once the library has been installed.
Logged

Offline Offline
Sr. Member
****
Karma: 0
Posts: 297
Arduino rocks!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

i did as u said and put it in "C:\Users\_________\Documents\arduino-0022[1]\arduino-0022\libraries, but when i tried to open arduino i got a message saying "The library cannot be used. library names must contain only basic letters & numbers. (ASCII only and no spaces, and cannot start with a number)"....

what now?
Logged

As always... Thanks for posting!!!

Michigan, US
Offline Offline
Full Member
***
Karma: 3
Posts: 148
Go Huskies
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Place the three folders in the zip directly into the Documents\Arduino\libraries folder so it would contain:
pollserial
TVout
TVoutfonts
Logged

Offline Offline
Sr. Member
****
Karma: 0
Posts: 297
Arduino rocks!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

i'm having trouble, it would apear to be a problem w/ some sort of rate because  i'm getting the signal to go through but it is very choppy. ocasionaly somthing will line up but not very often and not the whole pic
Logged

As always... Thanks for posting!!!

Phoenix, Arizona USA
Offline Offline
Faraday Member
**
Karma: 40
Posts: 5578
Where's the beer?
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Link to old thread (mdmetzle, you should put this in your original post at the top of this thread, so that others know exactly where it is):

http://arduino.cc/forum/index.php/topic,8814.0.html

 smiley
Logged

I will not respond to Arduino help PM's from random forum users; if you have such a question, start a new topic thread.

Central MN, USA
Offline Offline
Tesla Member
***
Karma: 73
Posts: 7197
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Awesome! I love the retro-looking arduino TV icon! Will try this sometime. I now have a few RBBB boards and some ATMEGAs. Just don't have time. smiley-cry
Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you for sharing your great TV Out library with the rest of us.

I have it running on an Arduino Mega 1280 with standard resolution and on NTSC format.

1) Compatibility problem

I'm having some problems. It works great when connected to a WinTV USB dongle, I get the picture crystal clear. I am running 1.0beta1 and have no other code to interfer, this is a simple test setup.

But when I connect it to a small 3.5" TFT monitor I got off Ebay, it seems to find the signal and show about one frame of it, and then looses the signal again, then syncs and shows one frame and looses sync againg.

This means it switches from the blue "no input" screen to the wanted input and back, at a rate of about 4 switches per second.

Are there any timing issues or other things that could be improved to get this monitor working? I have tried the 75ohm to VID trick, but it makes no difference at all.

2) Servo control with TVout

My second question is, how can I drive a single servo with 1000-2000 microsecond pulses while using TVout? It doesn't seem to work with the Servo library, as you're probably using the interrupts. Any pointers?

Thanks in advance!
Logged

Michigan, US
Offline Offline
Full Member
***
Karma: 3
Posts: 148
Go Huskies
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@TECH GEEK
If you are still having troubles getting it to work properly I would try a different tv if possible and if the problem persists double check all the connections.  The last thing to try is putting a 75ohm resistor across video connection and GND.

@laarka
Yes there are some timing issues. The problem is in the vertical sync the approach I took is no where near what the signal is supposed to be.  This signal will work just fine on regular tube tvs but on newer tvs can have issue with it.  If your small lcd will accept a PAL signal try that as my capture card works far better with PAL than NTSC and maybe your little TV will too.

Yes the interrupts will screw with any existing time sensitive code.  To combat this I wrote a replacement for millis and delay that will remain accurate (just call TV.delay() and TV.millis()).
There are some restrictions to the accuracy with these replacement functions as they work by counting scan-lines.  Their are also function pointers now that will for automatic management of devices in the background.  To see how they work take a look at the included serial terminal example and the pollserial library which is just a modified version of hardware serial.

@crosh
yeah that would be a good link to add drrr.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes there are some timing issues. The problem is in the vertical sync the approach I took is no where near what the signal is supposed to be.

Is this signal or timing related? I mean if it's timing related, it must be fixable in the software. If it's signal related, a hardware fix must be done, or what? I saw a mention under issues on your googlecode page that you would look at this after beta1 ... is that now? :-P

I have already tried the PAL experiment before writing you ;-) No difference at all - same blinkety-blink no matter if it's NTSC or PAL. I have verified the monitor works by connecting a NTSC camera.

If you need a guinea pig, just let me know - it's a total showstopper for my project not being able to use this small monitor.

Quote
Yes the interrupts will screw with any existing time sensitive code.  To combat this I wrote a replacement for millis and delay that will remain accurate (just call TV.delay() and TV.millis()).

Driving servos is quite timing sensitive too - we're talking pulses between 1000 and 2000 microseconds. Do you think it's doable to just drive one or two reliably? I have zero experience with coding this stuff myself, but I guess anything is possible.

I have no need for delay() in my code, but I do need millis() a lot for the main routine smiley
Logged

Michigan, US
Offline Offline
Full Member
***
Karma: 3
Posts: 148
Go Huskies
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Well the issue that has stopped me from changing the vsync is the fact that I still don't have an oscilloscope or a logic analyzer to actually confirm the signal.  In addition to that I started working in my field and don't have as much time right now to work on this.

If you are just trying to display text then maybe the tellymate firmware or tvtext would do what is needed right away.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Well the issue that has stopped me from changing the vsync is the fact that I still don't have an oscilloscope or a logic analyzer to actually confirm the signal.

Okay, fighting in the dark can be quite frustrating.

If you are just trying to display text then maybe the tellymate firmware or tvtext would do what is needed right away.

Thank you for the pointer. As far as I can see, the schematic is very similar, except for a different resistor value for pixel data.

So what you're saying is the firmware for the tellymate is very compatible with different monitors, and the problems your library are facing are just plain timing issues?

In that case I'll stick with your library and pester you until we can work out what is wrong - I'll gladly help if I can.

How fast a scope is needed to solve this - I guess the cheapest route is the new DSO Quad from SeedStudio?
Logged

Pages: [1] 2 3 ... 5   Go Up
Jump to: