NTSC problem with ATMega328 - Page 1
Forum section: electronics / beginners

author: nychold
author_rank: Newbie
timestamp: October 21, 2021, 05:30:13 pm
content: So let me just start by apologizing for the length of this post, but I want to include as much information as possible.So a few months ago I began tinkering with creating a small, hobby (retro) computer for my own purposes and wanted to create some kind of graphic display. I own Andre LaMothe's "Black Art of Game Console Development" book, and I know he talks about different display systems in there, so I took a stab at the "easiest" one. He has schematics and diagrams, so I copied the design as much as I could, making a few chip substitutions to cut down on the number of analog multiplexers from 2 (74HC4051) to 1 (74HCT4067). The timings of the two chips look similar, so I didn't think it would cause much of a problem. And after a week or so of timing issues, it worked.Sort of.The test pattern created was a series of colored bars on the TV, but the colors didn't seem stable. They would produce a small ripple or wave like effect that became very pronounced, then very subtle, in some instances disappearing completely. This pattern came in waves, which lead me to believe the issue was noise. Since the board I made was just the driver, and didn't include the ATMega328 on the board (I was using a generic, Chinese Arduino Nano clone), it would be very easy for some stray noise to get into the system and cause a jiggle or two.So I pushed on, and created a new board design which included the Arduino Nano (just to program the ATMega328 easily) on the board itself. I also added more colors because the color palette I had picked originally was crap. The NTSC color wheel starts at yellow, but I made my calculations assuming it started at red like a standard HSV wheel. Oh well, live and learn.When I finished the programming of the board, I was shocked to see that I had gained a saturation problem. Between colors 29 and 32, most of the color had been sucked out of the system. I attribute this to noise being added due to the 74HCT244 as the oscillator's signal passes between the VIL and VIH thresholds, which gets progressively worse the more gates it has to go through. Makes sense to me, but if any of you much more experienced guys has a clue, I'm all ears.(Otherwise, I plan to deal with the issue by using Schmitt Trigger gates in the future.)But my noise issue was also still there, and worse now. Both the top and bottom of my board are ground-filled as much as possible, to help cut down on noise, so it should have gotten better, right? Now, in addition to the ripple effect, I also have what looks like a rainbowing effect on some lines. I tried the timings LaMothe mentioned in his book, as well as the Nintendo timings I found here:https://wiki.nesdev.org/w/index.php/NTSC_videoas well as the timings I found here:https://www.avrfreaks.net/sites/default/files/ntsctime.pdf. The Nintendo timings didn't work at all (though I may have messed them up) and both LaMothe's and AVR Freak's timings seem to exhibit the same problem.Since the design I'm using is based on a copyrighted book, I'm not sure what the legality is on posting the designs directly, but for now, I'll just describe the boards (they're all pretty much the same):A 3.579545 MHz crystal oscillator feeds directly into one of the inputs of a 74HCT244 where it ripples through all of the available inputs, as well as the inputs of 3 other chips except 1. This adds delay in order to achieve the phase shift needed for NTSC color. Then, those signals are all feed into 2 74HCT4067 chips, and the color value from the ATMega328 is used as the selector (plus an extra signal for LOW or HIGH bank). The output of that is passed through into the empty input of a 74HCT244 (this was copied from the original design...I don't think it's necessary), then piped through a 75Ohm resistor. A 1nF capacitor is used to smooth out the signal, in an attempt to get close to a sine wave, and is combined with an intensity signal (also coming from the ATMega328) through an R2R ladder (400 and 200 Ohms). A couple of potentiometers allow for adjustment of the brightness and saturation (copied from the original design), but I couldn't get the values he suggested, so mine are as close as possible (1K and 10K, both linear).I also use a 12ns RAM chip (W24257AK-12) to handle some of the color decoding, so that I can use a single port (PORTD) to change colors, but I highly doubt that's the culprit. My first test board didn't even use it, but the issue has gotten worse, so who knows?I've attached an image to show the issue I'm having, easily visible on the left and right sides of the image. Here is the code for the ATMega328 (all assembly to ensure timing):Code:;; Arduino timing:;; 16 MHz = 62.5ns per clock;; 16 MHz / 3 = 187.5ns per pixel;; https://www.avrfreaks.net/sites/default/files/ntsctime.pdf;; NSTC Timing:;; Normal pulses 253 EVEN LINES, 254 ODD LINES 14/15 TOP OVERSCAN 15 BOTTOM OVERSCAN;; SYNC 4.7us 4700ns 25 pixels;; BREEZEWAY 1.6us 1687.5ns 9 pixels;; COLOR BURST 2.5us 2437.5ns 13 pixels;; BACK PORCH 2.1us 2062.5ns 11 pixels;; VIDEO DATA 51.2us 51187.5ns 273 pixels;; LEFT BORDER 1.5us 1500ns 8 pixels;; ACTIVE VIDEO 48us 48000ns 256 pixels;; RIGHT BORDER 1.6us 1687.5ns 9 pixels;; FRONT PORCH 1.5us 1500ns 8 pixels;;;; Equalizing pulses;; BOTH 3 LINES;; SYNC 2.3us 2250ns 12 pixels;; BLANK 29.5us 29625ns 158 pixels;; SYNC 2.3us 2250ns 12 pixels;; BLANK 29.5us 29625ns 158 pixels;; ODD 1 LINE;; SYNC 2.3us 2250ns 12 pixels;; BLANK 29.5us 29625ns 158 pixels;; SYNC 27.3us 27375ns 146 pixels;; BLANK 4.5us 4500ns 24 pixels;;;; Serration pulses;; EVEN 3 LINES;; SYNC 27.3us 27375ns 146 pixels;; BLANK 4.5us 4500ns 24 pixels;; SYNC 27.3us 27375ns 146 pixels;; BLANK 4.5us 4500ns 24 pixels;; ODD 1 LINE (2 LINES OF ABOVE);; SYNC 27.3us 27375ns 146 pixels;; BLANK 4.5us 4500ns 24 pixels;; SYNC 2.3us 2250ns 12 pixels;; BLANK 29.5us 29625ns 158 pixels;;;;;; Frame process;; EVEN FRAME;; 14 OVERSCAN;; 224 ACTIVE VIDEO LINES;; 15 OVERSCAN;; 3 EQUALIZING PULSE;; 1 EQUALIZING PULSE ODD;; 2 SERRATING PULSE;; 1 SERRATING PULSE ODD;; 2 EQUALIZING PULSE;; 263 LINES;; ODD FRAME;; 15 OVERSCAN;; 224 ACTIVE VIDEO;; 15 OVERSCAN;; 3 EQUALIZING PULSE;; 3 SERRATING PULSE;; 3 EQUALIZING PULSE;; 262 LINES.def wait1 = r16.def wait2 = r17.def lineCount = r18.def color = r19.def colorCount = r20.def voltage = r21.def colorIncrease = r22.def ledStatus = r23.def ledMask = r24.set HSYNC = $00.set VSYNC = $00.set BLANK = $01.set COLOR_BURST = $09.set BLACK = $02.set OVERSCAN_COUNT = 15.set OVERSCAN_COUNT_EVEN = 14;; Takes 1 parameter (x) and waits 3x clock cycles;; Timing: 3x clock cycles -- x pixels;; Proof:;; WAIT 6 => 6 pixels;; ldi r16, 6 ;; 1 clock;; loop: subi r16, 1 ;; 1 clock -- r16 = 5;; brne loop ;; 2 clocks;; loop: subi r16, 1 ;; 1 clock -- r16 = 4;; brne loop ;; 2 clocks;; loop: subi r16, 1 ;; 1 clock -- r16 = 3;; brne loop ;; 2 clocks;; loop: subi r16, 1 ;; 1 clock -- r16 = 2;; brne loop ;; 2 clocks;; loop: subi r16, 1 ;; 1 clock -- r16 = 1;; brne loop ;; 2 clocks;; loop: subi r16, 1 ;; 1 clock -- r16 = 0;; brne loop ;; 1 clocks;; ;; 18 clocks = 3 * 6 => 6 pixels.macro WAITldi wait1, @0 ;; 1 clockloop: subi wait1, 1 ;; 1 clockbrne loop ;; 2 clocks, 1 if fall through.endmacro;; Takes 2 parameters (x, y) and waits 3x(y+1) clock cycles;; Timing: 3x(y + 1) clock cycles -- x(y + 1) pixels;; Proof:;; WAIT_LONG 6, 5 => 36 pixels;; ldi r17, 6 ;; 1 clock;; loop: WAIT 5 ;; 15 clocks;; subi r17, 1 ;; 1 clock -- r17 = 5;; brne loop ;; 2 clocks;; loop: WAIT 5 ;; 15 clocks;; subi r17, 1 ;; 1 clock -- r17 = 4;; brne loop ;; 2 clocks;; loop: WAIT 5 ;; 15 clocks;; subi r17, 1 ;; 1 clock -- r17 = 3;; brne loop ;; 2 clocks;; loop: WAIT 5 ;; 15 clocks;; subi r17, 1 ;; 1 clock -- r17 = 2;; brne loop ;; 2 clocks;; loop: WAIT 5 ;; 15 clocks;; subi r17, 1 ;; 1 clock -- r17 = 1;; brne loop ;; 2 clocks;; loop: WAIT 5 ;; 15 clocks;; subi r17, 1 ;; 1 clock -- r17 = 0;; brne loop ;; 1 clock;; ;; 108 clocks = 3 * 36 => 36 pixels.macro WAIT_LONGldi wait2, @0 ;; 1 clockloop: WAIT @1 ;; 3 * @1 clockssubi wait2, 1 ;; 1 clockbrne loop ;; 2 clocks, 1 if fall through.endmacro;; Takes 1 parameter (voltage);; Timing: 2 clock cycles.macro SET_VOLTAGEldi voltage, @0out PORTD, voltage.endmacro;; Takes 1 parameter (colorburst);; Timing: 186 clock cycles -- 62 pixels.macro LINE_START;; SYNC 4.7us 4700ns 25 pixels;; BREEZEWAY 1.6us 1687.5ns 9 pixels;; COLOR BURST 2.5us 2437.5ns 13 pixels;; BACK PORCH 2.1us 2062.5ns 11 pixels;; VIDEO DATA 51.2us 51187.5ns 273 pixels;; LEFT BORDER 1.5us 1500ns 8 pixels;; ACTIVE VIDEO 48us 48000ns 256 pixels;; RIGHT BORDER 1.6us 1687.5ns 9 pixels;; FRONT PORCH 1.5us 1500ns 8 pixels;; HSYNC -- 25 pixelsnop ;; 1 clockSET_VOLTAGE HSYNC ;; 2 clocks -- pixelWAIT 25 ;; 72 clocks -- 24 pixels, HSYNC now over;; BREEZEWAY -- 9 pixelsnop ;; 1 clockSET_VOLTAGE BLANK ;; 2 clocks -- pixelWAIT 8 ;; 24 clocks -- 8 pixels, BREEZEWAY now over;; COLOR_BURST -- 13 pixelsnop ;; 1 clockSET_VOLTAGE @0 ;; 2 clocks -- pixelWAIT 12 ;; 36 clocks -- 12 pixels, COLOR_BURST now over;; BACK PORCH -- 11 pixelsnop ;; 1 clockSET_VOLTAGE BLANK ;; 2 clocks -- pixelWAIT 10 ;; 30 clocks -- 10 pixels, BACK PORCH now over;; 8 clock black pixels for left bordernop ;; 1 clockSET_VOLTAGE BLACK ;; 2 clocks -- pixelWAIT 7 ;; 21 clocks -- 7 pixels, LEFT BORDER now over.endmacro;; Takes 1 parameter (color + intensity).macro INTENSITY_LINE;; 256 pixels of 1 intensitynop ;; 1 clockSET_VOLTAGE @0 ;; 2 clocks -- pixelWAIT 255 ;; 255 more pixels, INTENSITY_LINE now over.endmacro;; Takes 1 parameter (intensity).macro DISPLAY_LINE;; 8 pixels of 32 colors = 256 pixels totalldi colorIncrease, $08 ;; 1 clockldi color, @0 ;; 1 clockout PORTD, color ;; 1 clock -- pixelldi colorCount, 31 ;; 1 clocknop ;; 1 clocknop ;; 1 clock -- pixelWAIT 6 ;; 18 clocks -- 6 pixels, next colorloop: nop ;; 1 clockadd color, colorIncrease ;; 1 clockout PORTD, color ;; 1 clock -- pixelWAIT 6 ;; 18 clocks -- 6 pixelssubi colorCount, 1 ;; 1 clockbrne loop ;; 2 clocks, 1 fall throughnop ;; 1 clock -- pixel, DISPLAY_VIDEO now over.endmacro// Takes no parameters, ends 1 pixel early, for looping.macro LINE_END;; RIGHT BORDER 1.6us 1687.5ns 9 pixels;; FRONT PORCH 1.5us 1500ns 8 pixels;; 9 black pixels for bordernop ;; 1 clockSET_VOLTAGE BLACK ;; 2 clocks -- pixelWAIT 8 ;; 24 clocks -- 8 pixels;; FRONT PORCH, 8 pixels (really 7 for external looping)nop ;; 1 clockSET_VOLTAGE BLANK ;; 2 clocks -- pixelWAIT 6 ;; 18 clocks -- 6 pixels;; Skip last pixel.endmacro;; Takes no parameters.macro BLACK_VIDEO;; 256 black pixelsnop ;; 1 clockSET_VOLTAGE BLACK ;; 2 clocks -- pixelWAIT 255 ;; 765 clocks -- 255 pixels, BLACK_VIDEO now over.endmacro;; Takes no parameters, lineCount must be set before using, leaves 1 unused clock cycle.macro OVERSCANloop: LINE_START BLACKBLACK_VIDEOLINE_ENDsubi lineCount, 1 ;; 1 clockbrne loop ;; 2 clocks, 1 if fall through;; 1 unused clock.endmacro;; Takes 2 parameters (linecount, intensity), requires 1 extra clock cycle.macro INTENSITY_BARldi lineCount, @0 ;; 1 clock (extra clocks burned)loop: LINE_START BLACKINTENSITY_LINE @1LINE_END ;; 3 unused clockssubi lineCount, 1 ;; 1 clockbrne loop ;; 2 clocks, 1 if fall through;; 1 unused clock.endmacro;; Takes 2 parameters (linecount, intensity), requires 1 extra clock cycle.macro COLOR_BARldi lineCount, @0 ;; 1 clock (extra clocks burned)loop: LINE_START COLOR_BURSTDISPLAY_LINE @1LINE_END ;; 3 unused clockssubi lineCount, 1 ;; 1 clockbrne loop ;; 2 clocks, 1 if fall through;; 1 unused clock.endmacro;; Takes 4 parameters (syncTime1, blankTime1, syncTime2, blankTime2).macro VSYNC_PULSEnop ;; 1 clockSET_VOLTAGE VSYNC ;; 2 clocks -- pixelWAIT @0 ;; syncTime1 - 1 pixelsnop ;; 1 clockSET_VOLTAGE BLANK ;; 2 clocks -- pixelWAIT @1 ;; blankTime1 - 1 pixelsnop ;; 1 clockSET_VOLTAGE VSYNC ;; 2 clocks -- pixelWAIT @2 ;; syncTime2 - 1 pixelsnop ;; 1 clockSET_VOLTAGE BLANK ;; 2 clocks -- pixelWAIT @3 ;; blankTime2 - 1 pixels.endmacro;; Equalizing pulses;; BOTH 3 LINES;; SYNC 2.3us 2250ns 12 pixels;; BLANK 29.5us 29625ns 158 pixels;; SYNC 2.3us 2250ns 12 pixels;; BLANK 29.5us 29625ns 158 pixels;; ODD 1 LINE;; SYNC 2.3us 2250ns 12 pixels;; BLANK 29.5us 29625ns 158 pixels;; SYNC 27.3us 27375ns 146 pixels;; BLANK 4.5us 4500ns 24 pixels;;;; Serration pulses;; EVEN 3 LINES;; SYNC 27.3us 27375ns 146 pixels;; BLANK 4.5us 4500ns 24 pixels;; SYNC 27.3us 27375ns 146 pixels;; BLANK 4.5us 4500ns 24 pixels;; ODD 1 LINE (2 LINES OF ABOVE);; SYNC 27.3us 27375ns 146 pixels;; BLANK 4.5us 4500ns 24 pixels;; SYNC 2.3us 2250ns 12 pixels;; BLANK 29.5us 29625ns 158 pixels;; Leaves three clock cycles unused.macro VSYNC_ODD;; 3 EQUALIZING PULSEVSYNC_PULSE 11, 157, 11, 157VSYNC_PULSE 11, 157, 11, 157VSYNC_PULSE 11, 157, 11, 157;; 3 SERRATING PULSEVSYNC_PULSE 145, 23, 145, 23VSYNC_PULSE 145, 23, 145, 23VSYNC_PULSE 145, 23, 145, 23;; 3 EQUALIZING PULSEVSYNC_PULSE 11, 157, 11, 157VSYNC_PULSE 11, 157, 11, 157VSYNC_PULSE 11, 157, 11, 156 ;; Leave 1 pixel accounted for.endmacro;; Leaves three clock cycles unused.macro VSYNC_EVEN;; 3 EQUALIZING PULSEVSYNC_PULSE 11, 157, 11, 157VSYNC_PULSE 11, 157, 11, 157VSYNC_PULSE 11, 157, 11, 157;; 1 EQUALIZING PULSE ODDVSYNC_PULSE 11, 157, 145, 23;; 2 SERRATING PULSEVSYNC_PULSE 145, 23, 145, 23VSYNC_PULSE 145, 23, 145, 23;; 1 SERRATING PULSE ODDVSYNC_PULSE 145, 23, 11, 157;; 2 EQUALIZING PULSEVSYNC_PULSE 11, 157, 11, 157VSYNC_PULSE 11, 157, 11, 156 ;; Leave 1 pixel accounted for.endmacro; Replace with your application codestart: jmp frame ;; RESETjmp halt ;; IRQ0 handlerjmp halt ;; IRQ1 handlerjmp halt ;; PCINT0 handlerjmp halt ;; PCINT1 handlerjmp halt ;; PCINT2 handlerjmp halt ;; WDT (watchdog) handlerjmp halt ;; TIM2_COMPA handlerjmp halt ;; TIM2_COMPB handlerjmp halt ;; TIM2_OVF handlerjmp halt ;; TIM1_CAPT handlerjmp halt ;; TIM2_COMPA handlerjmp halt ;; TIM2_COMPB handlerjmp halt ;; TIM2_OVF handlerjmp halt ;; SPI_STC handlerjmp halt ;; USART_RXC handlerjmp halt ;; USART_UDRE handlerjmp halt ;; USART_TXC handlerjmp halt ;; ADC handlerjmp halt ;; EE_RDY handlerjmp halt ;; ANA_COMP handlerjmp halt ;; TWI handlerjmp halt ;; SPM_RDY handler;; https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf;; page 50halt: jmp haltframe: ;; Set up port Dclr voltagests UCSR0B, voltageldi voltage, 0xff ;; All outputsout DDRD, voltage;; Set up port Bldi ledMask, $20 ;; bit 5 = Arduino D13 = onboard LEDout DDRB, ledMask;;ldi ledStatus, $20;;out PORTB, ledMaskldi lineCount, OVERSCAN_COUNT_EVENjmp display_loop;; WAIT TEST;; 2665 pixels ~ 1kHz (but leave 2 for looping);; 2663 = 2662 + 1 = 22 * 121 + 1blink_1khz: WAIT_LONG 22, 120 ;; 2662 pixelsnopnopnop ;; 2663 pixelsnopeor ledStatus, ledMaskout PORTB, ledStatus ;; 2664 pixelsjmp blink_1khz ;; 2665 pixels;; OVERSCAN TEST1;; 1 clock + 338 pixels - 1 clock + 5 clocks = 339 px + 2 clocks = 63,687.5 ns;; 15,701.6 kHz / 2 =;; 7,850.83 kHzoverscan_test1: ldi lineCount, 1OVERSCANeor ledStatus, ledMaskout PORTB, ledStatusjmp overscan_test1;; OVERSCAN TEST2;; 438.3 Hzoverscan_test2: ldi lineCount, OVERSCAN_COUNTOVERSCANeor ledStatus, ledMaskout PORTB, ledStatusjmp overscan_test2;; DISPLAY TEST;; 337 pixels + 4 clocks = 338 + 1 clocks =;; 7.874.0157 kHzdisplay_test: LINE_START COLOR_BURSTDISPLAY_LINE 15LINE_ENDeor ledStatus, ledMaskout PORTB, ledStatusjmp display_test;; COLOR_BAR TEST;; 357.9 Hzcolorbar_test: COLOR_BAR 36, 15eor ledStatus, ledMaskout PORTB, ledStatusjmp colorbar_test;; VSYNC TEST;; 1.312 kHz;;vsync_test: VSYNC_PULSE;; eor ledStatus, ledMask;; out PORTB, ledStatus;; jmp vsync_testdisplay_loop:even_frame:OVERSCAN ;; 1 unused clock cycle;; 224 lines by 6 intensities = 37 lines per color bar (+1 for top and bottom)COLOR_BAR 38, 7 ;; requires 1 extra clock cycle, leaves 1 unused clock cycleCOLOR_BAR 37, 6 ;; requires 1 extra clock cycle, leaves 1 unused clock cycleCOLOR_BAR 37, 5 ;; requires 1 extra clock cycle, leaves 1 unused clock cycleCOLOR_BAR 37, 4 ;; requires 1 extra clock cycle, leaves 1 unused clock cycleCOLOR_BAR 37, 3 ;; requires 1 extra clock cycle, leaves 1 unused clock cycleCOLOR_BAR 38, 2 ;; requires 1 extra clock cycle, leaves 1 unused clock cycleldi lineCount, OVERSCAN_COUNT ;; 1 clock cycle, timing caught upOVERSCAN ;; 1 unused clock cycleldi lineCount, OVERSCAN_COUNT ;; 1 clock cycle (required for first odd OVERSCAN)VSYNC_EVEN ;; Perform vsync pulses for even frame;; 3 unused clock cyclesnop ;; 1 clocknop ;; 1 clocknop ;; 1 clockodd_frame:OVERSCAN ;; 1 unused clock cycle;; 224 lines by 6 intensities = 37 lines per color bar (+1 for top and bottom)COLOR_BAR 38, 7 ;; requires 1 extra clock cycle, leaves 1 unused clock cycleCOLOR_BAR 37, 6 ;; requires 1 extra clock cycle, leaves 1 unused clock cycleCOLOR_BAR 37, 5 ;; requires 1 extra clock cycle, leaves 1 unused clock cycleCOLOR_BAR 37, 4 ;; requires 1 extra clock cycle, leaves 1 unused clock cycleCOLOR_BAR 37, 3 ;; requires 1 extra clock cycle, leaves 1 unused clock cycleCOLOR_BAR 38, 2 ;; requires 1 extra clock cycle, leaves 1 unused clock cycleldi lineCount, OVERSCAN_COUNT ;; 1 clock cycle, timing caught upOVERSCAN ;; 1 unused clock cycleldi lineCount, OVERSCAN_COUNT_EVEN ;; 1 clock cycle (required for first even OVERSCAN)VSYNC_ODD ;; Perform vsync pulses for odd frame;; 3 unused clock cyclesjmp display_loopIf you are confused why there are "ODD" lines in the EVEN frames, it's because I adjusted the timing from the PDF linked above to create tighter code.Frankly, at this point, I'm at a loss. I don't know if this belongs in the "beginner" section, but I think I'm missing something totally obvious. Help?

author: Renate
author_rank: Super Contributor
timestamp: October 21, 2021, 08:27:25 pm
content: I haven't looked closely enough to see what you are doing, but...You might not be having a coherent subcarrier phase.There are supposed to be 227.5 subcarrier cycles/line (in NTSC).If you sync your scope on line you should see the burst is mirrored (high peaks and low peaks).Still, that doesn't tell you if your line length is correct.

author: Benta
author_rank: Super Contributor
timestamp: October 21, 2021, 08:49:08 pm
content: I'm in no mood the read through all your code.But I rather suspect a hardware design problem, and as your schematic is "Top Secret", I can't help any further here.Do you at least have a black-and-white schematic without the terrible copyright?

author: SL4P
author_rank: Super Contributor
timestamp: October 22, 2021, 12:19:27 am
content: As it iappears to be a vertical issue, remember that’s ‘low frequency’ vs the high frequency of line rate…Guessing that you’re running a 60Hz monitor, and there are 6? bands, you’re probably looking for something around 360Hz…?That may help isolate the problem…The vertical ‘lines’ seem straight, so that suggests the horizontal / line rate is stable.The other thing is, if your output field/frame rate is off, you may be writing the raster more than once per field/frame ?Nice looking output though !

author: Renate
author_rank: Super Contributor
timestamp: October 22, 2021, 12:49:22 am
content: How are you dividing a 3.58 Xtal by 227.5?Digital televisions don't take wacky timing.I think it's taking 1/10 of a line to resync on the color burst?I'd start with a 14.318 Xtal.

author: nychold
author_rank: Newbie
timestamp: October 22, 2021, 02:09:32 am
content: I've looked up what 227.5 has to do with NTSC and I just can't figure it out. I know I output 525 lines every "frame" as per the spec (263 on "even" frames, 262 on "odd" frames). I have a typo in the code I posted where I mention 253 and 254 lines, but that's all it is...a typo. Since I'm using a 3.58 MHz crystal, and am generating the exact number of lines necessary, I'm guessing I have this 227.5 subcarrier? But I have no idea how to verify that.Quote from: Renate on October 22, 2021, 12:49:22 amIt's interesting you mention this because it actually works on a digital TV. On an old analog TV, I get no color at all, just black and white, and all the same "ripple" artifacts. I think my color burst signal is just not close enough to a sine wave to generate color, an issue I was going to work on later.Quote from: Benta on October 21, 2021, 08:49:08 pmI'm attaching my schematics for this board. Since this is for educational purposes (namely my own, but also for any one else reading) and I have no intention of selling it, I believe it falls under Fair Use.

author: BrianHG
author_rank: Super Contributor
timestamp: October 22, 2021, 02:35:30 am
content: Funny you are not clocking the atmega at 14.31818MHz, exactly 910 clocks for each horizontal sync.I know in way in the past, I over-clocked an old 20MHz PIC with 28.63636MHz and with nothing but a resistor DAC on a 4 bit or 8 bit port, with nothing more than an NPN follower amp to drive an NTSC cable, I generated a full legit color signal text on screen display. Adding an EPM7128 CPLD, I removed a ton of the dedicated timing functions inside the MCU and with an analog switch, I then had a super-impose genlock feature by having the EPM7128 running the 14.31818 crystal with a PLL tuning logic to lock onto the incoming external NTCS circuit and also feed the XTAL input of the MCU.Today with 4x PLLs inside PICs and interupts, this would be easy with the standard 14.31818MHz to generate quite a bit of patterns, or with an external rom with 2 bit binary counter feeding the LSB holding fatter Luma and Chroma patterns with preset levels for the sync positions, it would be easy to get everything dead on timing Y/C and CVBS output. Though using something like the EPM7128 CPLD in place of the rom would offer a background sync generator in place of any bad timing coming from the MCU.Note that the old weird 240p of old game consoles do run at 262 lines missing that 1/2 line giving you just above 60.05hz progressive and that many modern TV/Video grabbers which use cheap NTSC ADC grabber logic which may have problems decoding that signal. They are expecting that 525 interlaced signal.

author: oPossum
author_rank: Super Contributor
timestamp: October 22, 2021, 03:42:50 am
content: 3.579545 MHz (colorburst) / 227.5 = 15.734 kHz (horizontal frequency)The colorburst phase will alternate by 180 degrees every other line (as it should) because of the 1/2 of a colorburst cycle per line.An LCD monitor may be sensitive to this. Using the same clock for the AVR and colorbust (divided as necessary) may solve the problem you are having.Edit: Fix cb freq typo - thanks Brian

author: BrianHG
author_rank: Super Contributor
timestamp: October 22, 2021, 07:05:59 am
content: Quote from: oPossum on October 22, 2021, 03:42:50 am

author: BrianHG
author_rank: Super Contributor
timestamp: October 22, 2021, 04:20:28 pm
content: @nychold, if you have an eprom, why in the world are you generating all those delays and 3.57MHz crystal?What a waste.Use a 28.63636Mhz crystal, with a 3 bit counter feeding the A0, A1 and A2 of the eeprom.Feed your desired output color and syncs/blk porch/color burst enable into the upper address.Feed the 8 bit out into an 8 bit dac with a RLC low pass notch filter to notch out the 28.63636Mhz reference.You may use a 74HC574 to buffer the eprom, clocked on the 28.63636Mhz crystal to clean the read data, with a resistor dac on the 8 bit output.Generate all your display colors with 3.579545MHz phases into the upper address with with the color phases calculated across every 8 words. Don't forget to encode the sync and colorburst levels as well.Do the math correctly when generating the video levels from an 8 bit dac and your output will be as high quality at a mid-tier (around 2000's) digital video encoder with 27MHz dacs. You can even go to 57.27272MHz with the first 4 bits of the eprom to encode your NTSC colors making that RLC notch filter easier to implement.I will stop here.

author: nychold
author_rank: Newbie
timestamp: October 22, 2021, 04:51:40 pm
content: I question that 15.734 kHz horizontal refresh rate. Not because I know better, but because the timings never match that on any of the specifications I've seen. Take this page from Maxim:https://www.maximintegrated.com/en/design/technical-documents/tutorials/7/734.htmlThere's mention that the US standard for NTSC is supposed to be 15.734 kHz, but then they show the wave form and it doesn't match:Front Porch = 1.5usSync Tip = 4.7usBreezeway = 0.6usColor Burst = 2.5usBack Porch = 1.6usThe sum of that is exactly equal to the 10.9us they mention for horizontal blanking, so there aren't any obvious rounding issues. Then, when you combine that with the 52.6us of active video, you get 63.5us. 1000000 / 63.5 = 15748 or 15.748 kHz. It's not off by much, 14 Hz, but it suggests that either the timings are wrong, the graph is wrong, or there's quite a bit of slop in the protocol.The timings in my original test code produced a blinking LED at 7.874 kHz, which is exactly half of 15.748 kHz, so it matches (more or less) the diagram shown. It doesn't, match the 15.734 kHz, but neither does their diagram.

author: Renate
author_rank: Super Contributor
timestamp: October 22, 2021, 05:31:05 pm
content: In ye olde days a television could not correlate color subcarrier because they were two unrelated phase locked loops.Now that processing is fancier we do count color subcarriers in a line and we do expect them to be synchronized.Only that way can we implement comb filters and other processing.If you run everything off a 14.318 Xtal you can probably swing it a bit without annoying your digital television.But you can't play fast and loose with the relationship between color/H/V.

author: BrianHG
author_rank: Super Contributor
timestamp: October 22, 2021, 05:37:00 pm
content: If your monitor sample the NTSC input, there may be no room for error unless you guarantee it can lock cleanly onto a non TBC'ed all analog VHS videotape signal. And I've seen many having color decoding problems with VHS tape.The formula is a H-SYNC every 227.5 clocks at 3.57954545454545454545454545MHz = 15734.26573Hz HS-HS.Or, 910 clocks at 14.31818181818MHz.Since many generators use the 14.31818181818MHz standard, here is the clock count using that frequency:from HS-HS = 910 clocks, IE count from 0-909 and loop.Front porch = 4 clocksSync = 66 clocksBack porch before color burst = 12 clocksback porch with color burst = 36 clocksback porch after color burst = 24 clocksactive video display = 768 clocksTotal = 910 clocks.These are from notes around 20years old.Sorry, lost the pixel counts for stabilization pulses and V-sync pattern.You will need to get a scope which can lock onto fields and analyze a true NTSC broadcast signal.

author: Benta
author_rank: Super Contributor
timestamp: October 22, 2021, 05:40:21 pm
content: The hypothesis that the color carrier frequency is an integer multiple of the horizontal line frequency sounds nice, but is wrong!Quite the opposite.Both for NTSC and PAL, the color frequency was carefully chosen to NOT be a multiple of horizontal to avoid interference and beating.

author: BrianHG
author_rank: Super Contributor
timestamp: October 22, 2021, 05:49:30 pm
content: Quote from: Benta on October 22, 2021, 05:40:21 pmThen why that perfect scrolling comb pattern. Also why can it be computed out with video line memory to a ok quality extent, and even better quality with Z video frame memory unless it didn't divide in every 2 or 4 lines evenly.Do not get confused with the allowed drift/error in timing between the B&W video sync & frame with relation to the color sub-carrier which is what you got with non-time base corrected analog VHS recordings. Many TVs today did not configure their NTSC analog sampling front-end's I2C controls to support analog VTR signals and their color with analog VHS tapes can flutter the color across the display unless the engineers who made these NTSC samplers have tested their TV with an old analog VHS deck, in cheap ELP mode, you cannot guarantee good solid still color decoding on such a signal.

author: Benta
author_rank: Super Contributor
timestamp: October 22, 2021, 06:03:02 pm
content: I'm not confused about anything.I can highly recommend "Video Demystified" by Keith Jack, but it'll set you back around $75 unless you buy it used. The best book on video I know of.The color carrier for NTSC was carefully selected to NOT be a multiple of 15625 Hz and 60 Hz. Same thing for PAL (4.43361875 MHz), except here the goal was to avoid multiples of 50 Hz and 15625 Hz.Think about it: otherwise why choose such wacky frequencies? 15625 Hz x 64 is 1 MHz; much simpler.

author: BrianHG
author_rank: Super Contributor
timestamp: October 22, 2021, 06:25:30 pm
content: Quote from: Benta on October 22, 2021, 06:03:02 pmThat is not the NTSC Hsync frequency.It is 15734Hz.Even wikipedia got it right:https://en.wikipedia.org/wiki/NTSCStating exactly 15.734 kHz.As stated above, the normal color subcarrier frequency of 3.579545MHz (the 45 supposed to be infinite repeat, but it doesn't need to be that accurate.) Also correctly stated in wikipedia.Divide that 3.579545 MHz clock by 227.5 and you get the 15.734 kHz.Look at any close-up scope shot of an NTSC sync and color burst signal and you will see a 2 sine waves at perfect 180 degree phase overlapped illustrating that the color burst clock does indeed divide by evenly every 2 horizontal lines of video.Heck, go looking for a NTSC encoder FPGA HDL core which generates an NTSC signal and you will see the clock cycles extrapolated. Even the easily gen-lock able Amiga computers had a 4x NTSC color clock at 14.31818MHz. Even my VCR's had such crystals in them, both in the analog section and in the TBC section. This includes my laser-disc's TBC as well.The only new-comer clock frequency is the 27MHz used for cross compatibility with NTSC/PAL/SECAM decoders and encoders because it can divide with an even fraction into the 2 video format color sub-carrier frequencies as well as offer 720 sample active pixel per line for both standards.

author: Renate
author_rank: Super Contributor
timestamp: October 22, 2021, 06:28:34 pm
content: The number that was/is set in stone is 4.5 MHz, the sound carrier.You could screw around with any number but not that.So, since the color subcarrier spectrum was near the audio subcarrier that meant that it shouldn't clash.That meant that the baseband spectrumshouldclash.4.5 MHz / 525 / 30 = ~285.7Therefore use 286 (closest integer).4.5 MHz / 286 = ~15734.3Now pick out a color subcarrier at random that is a half multiple of line rate, fits nicely between baseband and audio, has small prime factors (so your master sync generator is not too complex).

author: oPossum
author_rank: Super Contributor
timestamp: October 22, 2021, 06:41:36 pm
content: Quote from: BrianHG on October 22, 2021, 04:20:28 pmThat would require a ~30 ns EEPROM. Does such exist in friendly form?A shift register clocked at 28.636 MHz could probably be done with fast 74xx such as 74LVC or 74AHC. That wouldn't be dependent on gate delays.

author: oPossum
author_rank: Super Contributor
timestamp: October 22, 2021, 06:43:24 pm
content: Quote from: nychold on October 22, 2021, 04:51:40 pmMore detailed references attached...

author: oPossum
author_rank: Super Contributor
timestamp: October 22, 2021, 06:47:27 pm
content: Quote from: Benta on October 22, 2021, 06:03:02 pmThe color carrier falls between the 227th and 228th harmonic of Hsync. That is 'not harmonically related'.

author: oPossum
author_rank: Super Contributor
timestamp: October 22, 2021, 06:52:16 pm
content: Quote from: BrianHG on October 22, 2021, 06:25:30 pmYep. Grab any pro or consumer video product and look at it on a waveform monitor. You will see what I posted in reply #7. That is from a DVD player.Open up something that uses digital video and you will typically find a.... 27 MHz xtal.27 MHz / 1716 == 3.579545 MHz / 227.5 == 15.734 kHz

author: BrianHG
author_rank: Super Contributor
timestamp: October 22, 2021, 07:09:45 pm
content: 27Mhz *35 /66 = 14.3181818181818181818181818181818... MHz.Divide that by 4 and get the 3.579545 MHz.Nice solid numbers if you want to perfectly PLL a 27MHz into a 14.31818MHz or the other way around.Or, /33 if you want the 28.63636MHz used in Amiga computers and some older TBC circuits.great for FPGA PLLs when cross converting 27MHz and NTSC sub-carrier frequencies.

author: Benta
author_rank: Super Contributor
timestamp: October 22, 2021, 07:19:13 pm
content: Quote from: oPossum on October 22, 2021, 06:47:27 pmExactly. That was my point. There is nointegerrelationship between color carrier and HSync. The relationship is 227.5, as others have mentioned.BTW, "227th and 228th harmonic" would be somewhat higher.