Entries in ntsc (1)


Television + FPGA + Verilog

I love when people share their code on the internet, but have a complaint: short, obscure variable names. Also, a lack of whitespace. Most engineers aren’t the best at documentation, myself included. But I try my best to make my code very readable. It can be a pain type out 20 character variable names, but that’s where code completion, along with regular expressions and find & replace come in.

Surprisingly, unreadable code recently led me to do something I don’t often do: start from scratch. I was looking for a Verilog module to generate an NTSC signal, which is the analog television standard in North America and a few other places. There were plenty of VHDL snippets out there, and one or two Verilog, but I couldn’t make heads or tails of what the author was doing with it. So I got on Google and and found just about every document I could on the NTSC standard until it finally sunk in. I was just starting to get the hang of Verilog before I started this project, but having to go from timing specifications to an FPGA (Field Programmable Gate Array) really made it all sink in. The irony is that I really didn’t even want to generate a TV signal. I wanted to output video from my prototyping board to a VGA display, but I don’t have one. Normally they’re a dime a dozen on trash days here in NYC, until I needed one. But, I do have a small TV a neighbor threw out a few months ago.

So here I’m sharing my project. At the heart is a file named interlaced_ntsc.v, which generates 3 bit monochrome video signal. There’s one bit of code I borrowed, another file named 8x16_font_rom.v. It’s just a pixel lookup table for all the ASCII characters. Making a font rom is tedious, so I don’t feel bad about using that. The top project file is top_ntsc.v. It’s included only as reference to complete working project. You don’t need to use it unless you’re new to FPGA’s or Verilog.

Here’s the instantiation template for my NTSC code. There’s a few signals not listed, which are only needed for debugging with an oscilloscope. They’re documented in the code.

interlaced_ntsc.v instantiation template

interlaced_ntsc instance_name (                
    .clk( clk ),                              // input: 50 MHz clock input     
    .pixel_data( pixel_data ),                // input: brightness of pixel 0..5
    .pixel_y( pixel_y ),                      // output: current pixel's y coordinate (row number)
    .pixel_x( pixel_x ),                      // output: current pixel's x coordinate
    .pixel_is_visible( pixel_is_visible ),    // output: high when not a sync signal, but not necessarily visible on the screen
    .ntsc_out( ntsc_out )                     // output: the TV signal, fed to a 3 bit r2r DAC

The 50 MHz clock requirement is baked into the code right now. I’m trying to figure a way to improve that. If you need to use a different clock, adjust the timing constants in interlaced_ntsc.v. They’re pretty obvious.

That’s it. I’m the first one to admit that I’m frequently a hypocrite, so if there’s something you don’t understand, or needs more comments, please let me know. And if you see a way to improve it, definitely leave a comment.

Source Code