Go Down

Topic: Interfacing with an NTSC TV (Read 12604 times) previous topic - next topic


Aug 28, 2007, 02:32 am Last Edit: Aug 28, 2007, 07:17 pm by xSmurf Reason: 1
Hey guys, this is a follow up on this topic. It started in French, but I figured since NTSC is used mainly in America and in Japan, English might be better suited for the topic. The basic setup is the same as the Arduino pong and the other topic. So this is just my "port" of what these guys did. I did build mine with a "structure" to allow adding pal support to be able to switch modes easily in the code.

Disabling the interrupt timer

I haven't gotten my code to work with cli() and serial so you'll have to modify lib/target/arduino/wiring.c (MAKE A BACKUP) like such:
Code: [Select]

// enable timer 0 overflow interrupt
#if defined(__AVR_ATmega168__)
   sbi(TIMSK0, TOIE0);
   sbi(TIMSK, TOIE0);

Code: [Select]

   // enable timer 0 overflow interrupt
#if defined(__AVR_ATmega168__)
   sbi(TIMSK0, TOIE0);
   sbi(TIMSK, TOIE0);

The circuit

That is... Sync to port 8 on the arduino and video to port 9. I use 900 and 300ohm resistors but it should change much anyway; these can be a little off.

Grab the latest version of the code.

Once you've uploaded the code, connect via serial (I use screen in the terminal) and wait for the uC to finish loading (you'll see "Mode:"). If everything went well there should be a dot in the middle of the TV. Now hit enter for usage. If you read through the code you will see there is a way of enabling "signal voltage mode" which allows you to debug your circuit.

There are a few things that are acting weird... I could really use some feedback.
  • If you put the resolution higher the uC seems to crash (not enough ram?).
  • Sometimes the uC acts as if the mode (output) had not been set properly. Re-uploading seemed to have fixed the problem when I've seen it.
  • There may be a timing issue while writing the first few lines. (EDIT: The issue has been fixed, see posts bellow)
  • Going into signal mode sometimes seems to crash the uC (same behavior as the first issue)

I've tested these this with both a mega8 and mega168 (thanks to the USBTiny that appeared in my mailbox this morning and a little magic from its fairy) on the NG and under 0007 and 0009. Optimally this code would need to be ported to a version with interrupt support.

P.S. If that pastie ever goes down, here is a plain text mirror.

And the obligatory picture ^-^

[size=10](The flickering at the top seems to have been fixed - at least as best as I could) FIXED[/size]


Aug 28, 2007, 05:33 am Last Edit: Aug 28, 2007, 04:04 pm by binarymillenium Reason: 1
The cli() command seems to work for me, though I have a brand new diecimilla i think with the 0009 (?) firmware.  I haven't seen any of the odd failures you mention.

From my experience the top lines are curved because of the length of your vsync too short and it curves one way and too long it curves the other way- I made a little video of the effect- http://vimeo.com/288344


Thanks for the video! that was great. Fixed the issue for real this time.

line 61 is now:
#define      _ntscDelayBackPorch            5.9
and line 64:
#define _ntscDelayVSync                  50

Now why can't I rev up the resolution?... basically anything over 21x16 seems to crash (I don't use the sprite with it, obviously!)


From a couple of experiments I don't think I can display much beyond 900 pixels- I'm pretty sure this is because I'm using a byte of memory per pixel and there's only a kilobyte of ram- maybe you have less?

But for the two shades of gray each byte of memory could be 4 different pixels, so if memory is the problem resolution should be able to go 4 times as high like this:
     PORTB = (fb
  • [y]) & 0x3;
         PORTB = (fb
  • [y] >> 2) & 0x03;
         PORTB = (fb
  • [y] >> 4) & 0x03;
         PORTB = (fb
  • [y] >> 6) & 0x03;    

    A for loop to draw the screen didn't work for me but I didn't play with timing with it much.

    delayMicroseconds of less than one microsecond also didn't work but I also didn't experiment much.
    Assuming you can get more horizontal pixels (or you could repeat the pattern horizontally) I think the best thing to do is just get rid of the delays, and the delay of setting PORTB is the limiting time for horizontal resolution- though I'm seeing some strange things doing that while trying to repeat horizontally- the second set of pixels comes out thinner.


I have a Mega168, so yeah 1k worth of RAM. that should be plenty. All I use except the frame buffer are a few int counters for looping (all in functions so they are all released fast). To my calculations, 21x16 would be 336 bytes, which is way under. Now boosting the resolution to just 24x18 (432 bytes... still plenty of room left) and the uC crashes. AS for your idea of packing more pixels per byte, yeah that's a great idea... definitely something I'll look into today.


I might have found the bug that makes the uC crash. The loadSprite function. The weird part is it's not even being called. But if I comment it out, the uC runs fine and if I don't it never boots. I've replicated this over many upload cycles. The weird part though is that it still crashes when I compile/upload from the Makefile (0007 and the recently posted 0009)


Hi, first let me compliment you on the code.  It's very clear and well written.  I had been tracking down similar video examples and this is way better written than anything else I've seen.

Now, I can't get it to work and I'm wondering if you can help.  I am trying it with a tv that shows a blank blue screen if there's no other video and when I fire this up I just get a very faint pattern of darker horizontal bars on the same blue.  The TV superimposes a "video 1" banner in the top right for a few seconds and this seems to be getting pulled up off the screen (maybe 5-10 scanlines) and it wobbles.

I've tried the debugSignal(nice feature by the way) and the levels look fine.  Any suggestions?

This is work you did a couple of years ago - Is it possible that arduino timing has changed?


I got a variation on the pong code to work out of the box last year so I dont think the timing has changed.
FYI - my code is posted here - it doubles the number of pixels in the original pong code.  Also it uses a hardware timer for vertical refresh which lets you run other code during retrace (and doesnt require disabling interrupts)

I am not positive what the code you are starting with, but Phizone posted a couple of stripped down versions of the pong code here:
This was the easiest example I found, and one of those examples should run out of the box.  

All the code I have looked at had some delay code (NOPS or duplicated OUT commands) at the end of the frame write.  You may need to add or remove the delay to get the sync to work.  

Secondly, your TV may be picky about the video level, try an old portable TV, my Sony will go blue if the signal is too low, but the junky Phillips I use for Arduino doesnt care.  Some people say that TV cards for your PC are more tolerant of wierd timing also.

Finally, double check your resistor circuit, the TV may be seeing enough signal to try to sync, but not enough to go white.  


[font=Times New Roman][size=14]
I am impressed. So what about having the Arduino take input from external hardware, such as digital logic, and then translate that input to the TV screen?
Gregg (doctorwho8)
Time moves in spirals because it can't move straight across.



Take a look at the new TellyMate shield also, his site has a ton of good info on talking to NTSC and PAL TVs



DrWho, both the medium res version I posted to the forum and the Pong mod I posted to the dailyduino can VERY easily be modified to take inputs etc.   Just put whatever you want in the loop routine (the loop routine is just an example).  Because the vertical refresh is interrupt driven you dont have to worry about timing in any code you add.  The only limitation is that loop doesnt get very many CPU cycles and the bitmap uses a bunch of RAM.  

FYI I havent gotten around to coding the "High Res" version, but I have it worked out how to double the pixels again.  It shouldnt take any more RAM than the existing code.  If anyone wants to try it I will outline the changes that need to be made.


I'm the chap behind the Batsocks TellyMate Shield.

@bill2009 - you might find that the circuit shown at the top of this thread isn't quite giving you the voltage range you expect because the TV has an (equivalent of) a 75ohm resistor within it. This forms a voltage divider with the other 75ohm resistor (shown in the circuit at the top of the thread) giving a 0.5v p2p signal, rather than the required 1v p2p.

I've found much better results without the 75ohm resistor in the circuit. Whites are white, rather than grey.

Having said that, on the more recent design of the TellyMate Shield, I've added a jumper (J7) to optionally connect this 75ohm resistor back in, because I found a small portable telly that wouldn't work otherwise.

(See this thread over at AVRFreaks)

@doctorwho8 - There shouldn't be any real problems in reading input to display, but you'll have to bear in mind that you won't be able to use interrupt driven methods because the interrupt routines will interfere with the timing of the sync and display signals - e.g. you don't want a 'USART_RXC' (serial received) interrupt called part-way through outputting your pattern!

@drspectro - I'm interested in the 'High Res' version!


Rough outline of hi-res

The original Pong video used the low 2 bits of a 38 wide by 14 high array.

medium res demo used the low 4 bits (2 at a time) of a 37 by 16 arrray.  Uses two copies of the 2 resistor D2A converter but only ONE D2A converter is really active at any time.  By bit masking the for loop index, we step through the array twice.  The first time we enable the low two bits    (0-1) of PORTC using the DDRC command.  The second time we enable the bits (2-3 ) using DDRC.   The DDRC command is a single and runs after each scan line so you dont get jitter halfway down the screen.

High Res (proposal)
Eliminate the grey tone.  Black and white only.  Instead of two copies of a 2 bit D2A, we use 4 (or8) one bit D2A converters (330 ohm resistor).  If you use all 8 this ties up all 8 bits of PORTB.  We use one bit from another port to drive a 1K resistor to get "black level" when all 9 bits go low that is blacker than black.

Finally we make the frame buffer roughly 60 bytes wide by 8 bytes high and loop through it 8 times (4 for square pixels) enable a different bit each time with DDRC. The loop logic is REALLY funky, but you can see it work in the medium res demo.

The big problems are
1) If you use all 8 bits of PORTB you loose hardware serial (could reduce vertical res and use a 6 bit port - needs thought here)
2) the DDRC mask logic has to take a constant amount of time.  Currently its an if/else but 4 or 8 options is hard to make constant time.
3) The logic for looping through the array multiple times is a bit confusing (well REALLY confusing).
5) it might be better to use only the low 4 bits and keep the high 4 for a working copy of the bitmap (thats how medium res works).  4 line pixels vs 8 line pixels depending on how you count it.
6) Sync line ties up another digital out line.
7) All the Pong type video programs depend let horizontal sync drift during the vertical sync period, it works but causes that top of the screen jitter.  Looks like you keep sync tighter in Batsocks????


[font=Times New Roman][size=14]
One of the things I forgot to mention below is that I am running on a
Arduino Duemilanove http://arduino.cc/en/Main/ArduinoBoardDuemilanove

So I suspect that something will need to be changed to accomodate this board as opposed to the ones you are using for this great idea. As for what that is, I am not sure. I am getting great smears of black and white color patterns on this set.

Time only stands still for an appointment.


Drwho8 - I am running on a Duemilanove also.

I agree with Condemmed, try removing (or increasing) the 75Ohm resistor.  There are a couple of versions of the 3 resistor D2A converter around, you might try a different one.

I guess the fact that you are getting some grey and colors indicates you are in the ballpark for voltage levels.  Unlike XSmurf who isnt really getting anything.  Yours sounds more like timing problems.

If you load the stripped down Pong example from the DailyDuino link I gave earlier I can tell you where you can tweak the timing.  I couldnt tell which code you had downloaded earlier.  Basicly there are a couple of dummy instructions at the end of line , the  "PORTB=PORTB" statement.  Add or remove these ONE AT A TIME.

The vertical refresh is set by the "FrequencyTimer2Init", but I think it is as close to the correct value as the hardware will support.  You can change the vertical refresh by changing the timer2 value.  NOTE - the timer2 code rounds your selected time to a value the timer can actually do.  You can ask for a more accureate 58.x hz time, but the timer probably will round it for you...

Condemmed -
I think it would be possible to make the vertical more accurate by halting the timer for a couple of NOP instructions then restarting it each frame. (possible, not easy..)  

Go Up