Pastie now auto-senses if line-wrap is a bad or good idea. Feedback?
## mark a section (Learn more)
/* NTSC, take 3.14159265 * ------------------------------------- * Created Sun Aug 26 14:59:29 EDT 2007 * * (cleft) 2007 by Matthieu Lalonde * * Note: Ideal values for the resistors are 300ohm and 900ohm. * Using this circuit: http://www.eyetap.org/ece385/vinfo_da00.png * Bug(s): * - Jittering of the first one of two lines (should they be skipped?) */ #include "WProgram.h" /** * Constants definition **/ // Debug levels #define _debugLevelDisable 0 #define _debugLevelGeneric 1 #define _debugLevelSignal 10 #define _debugLevelSimul 20 /** * Notes about _debugLevelSignal: * * Using this mode you can go through each voltage levels (Sync, black, gray, white). * This is useful for testing the circuit as you can make sure the voltages are right by using a multimeter **/ // Select either of the above debug levels (_debugLevelDisable to disable debugging) #define _debugMode _debugLevelGeneric // Pins definition #if _debugMode > _debugLevelDisable #define _pinLED 5 // Do not use a pin from 8 to 13 or it'll be turn off automatically #endif #define _pinSync 8 #define _pinVideo 9 // Definition of signal levels for the AD 2-bit converter #define _SYNC 0x00 /* 0.00v */ #define _BLACK 0x01 /* 0.33v */ #define _GRAY 0x02 /* 0.67v */ #define _WHITE 0x03 /* 1.00v */ // Defines TV Modes #define _NTSC 1 #define _PAL 2 // Select a TV mode (PAL isn't implemented, yet) #define _tvMode _NTSC #if _tvMode == _NTSC #define _tvNbrLines 262 /* Includes the last 20 lines for the vertical sync! */ #define _tvVSyncNbrLines 20 /* These 20 lines... */ #define _ntscDelayHSyncStart 4.7 #define _ntscDelayBackPorch 6 /* Normally 5.9, but this fixes a timing issue */ #define _ntscDelayFrontPorch 1.4 #define _ntscDelayPerLine 51.5 #define _ntscDelayVSync 58.8 #endif #if _tvMode == _PAL /* Nien */ #endif #define _tvPixelWidth 21 #define _tvPixelHeight 16 #define _serialBauteRate 19200 /** * Prototypes definition **/ void generateVSync(void); void writeBufferLine(int position); void writeTVLines(void); void clearFrameBuffer(void); void fillWhiteFrameBuffer(void); void fillGrayFrameBuffer(void); void fillPatternFrameBuffer(void); void loadSprite(void); /** * Variable definition **/ byte frameBuffer[_tvPixelWidth][_tvPixelHeight]; // Video frame buffer char c; // Serial buffer // Defines a static sprite (this could come from EEPROM also) const static byte graphic[_tvPixelWidth][_tvPixelHeight] = { {_WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK }, {_GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY }, {_BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE }, {_WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK }, {_GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY }, {_WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK }, {_GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY }, {_BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE }, {_WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK }, {_GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY }, {_BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE }, {_WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK }, {_GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY }, {_BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE }, {_WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK }, {_GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY }, {_BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE }, {_WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK }, {_GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY }, {_BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE, _BLACK, _WHITE }, {_GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY, _GRAY }}; void setup(void) { clearFrameBuffer(); pinMode(_pinVideo, OUTPUT); pinMode(_pinSync, OUTPUT); #if _debugMode > _debugLevelDisable pinMode(_pinLED, OUTPUT); digitalWrite(_pinLED, HIGH); // Draws a dot in the middle frameBuffer[(_tvPixelWidth / 2)][(_tvPixelHeight / 2)] = _WHITE; #endif Serial.begin(_serialBauteRate); Serial.print("Mode: "); } void loop(void) { #if _debugMode < _debugLevelSignal // Write the tv lines writeTVLines(); #endif // Check for commands if (Serial.available()) { c = Serial.read(); Serial.println(c); switch (c) { #if _debugMode < _debugLevelSignal case 'w' : fillWhiteFrameBuffer(); // Fill the display with white break; case 'g' : fillGrayFrameBuffer(); // Fill the display with gray break; case 'p' : fillPatternFrameBuffer(); // Fill the display with a calculated patter break; case 'c' : clearFrameBuffer(); // Clear the display (all black) break; case 's' : loadSprite(); // Load a sprite to the display break; #else /** This section is used for sinal debug mode only! Use a multimeter to check the tv signal voltages **/ case '1' : PORTB = _SYNC; break; case '2' : PORTB = _BLACK; break; case '3' : PORTB = _GRAY; break; case '4' : PORTB = _WHITE; break; #endif /** * Display usage **/ default : #if _debugMode < _debugLevelSignal Serial.println("c: clear screen | p: fill with pattern 1 | s: fill with sprite | w: fill with white | g: fill with gray"); #else Serial.println("Debug Levels >> 1: _SYNC | 2: _BLACK | 3: _GRAY | 4: _WHITE"); #endif break; } Serial.print("Mode: "); } } /** * Begin the NTSC Specific block **/ #if _tvMode == _NTSC /** NTSC Signal definition: -- Horizontal sync (hsync) pulse: Start each scanline with 0.3V, then 0V for 4.7us (microseconds), and then back to 0.3V. This tells the TV to start drawing a new scanline -- The "Back Porch": A transition region of 0.3V for 5.9us between the hsync pulse and the visible region, off the left edge of the TV -- Visible scan region: This is the part you actually see. 0.3V shows up as black, 1V as white, everything in between is greyscale. The visible region lasts for 51.5us -- The "Front Porch": A transition region of 0.3V for 1.4us before the hsync pulse of the next line, off the right edge of the TV -- Vertical sync (vsync) pulse: Lines 243-262 of each frame (off the bottom of the TV) start with 0.3V for 4.7us, and the rest is 0V. This tells the TV to prepare for a new frame. Think of it as just 0V with an inverted sync pulse *** http://www.eyetap.org/ece385/lab5.htm *** **/ /** * Writes every line from what's inside the frameBuffer * * Warning: You cannot take the beginning and end sync out of this functions or the sync will fail * (This has been tested on a Mega8) **/ void writeTVLines(void) { unsigned int i; for (i=0;i<(_tvNbrLines - _tvVSyncNbrLines);i++) // Correction for the 20 lines of vertical sync { /* Begin Line Sync */ // H Sync PORTB = _SYNC; delayMicroseconds(_ntscDelayHSyncStart); // Back Porch PORTB = _BLACK; delayMicroseconds(_ntscDelayBackPorch); writeBufferLine(i>>4); // Visible scan (51.5µs) /* End Line Sync (Front Porch) */ PORTB = _BLACK; delayMicroseconds(_ntscDelayFrontPorch); } // Vertical Sync follows generateVSync(); // _tvVSyncNbrLines lines for vertical sync } /** * Writes each pixel of a line **/ void writeBufferLine(int position) { unsigned int ii; for (ii = 0; ii < _tvPixelWidth; ii++) { PORTB = frameBuffer[ii][position]; // Waste some time to make sure the line is sent during the proper timing delayMicroseconds((_ntscDelayPerLine / _tvPixelWidth)); } } /** * Generate sync pulse for the virtual sync (lasts _tvVSyncNbrLines lines) **/ void generateVSync(void) { unsigned int ii; for (ii = 0; ii < _tvVSyncNbrLines; ii++) { // Begin V Sync PORTB = _BLACK; delayMicroseconds(_ntscDelayHSyncStart); PORTB = _SYNC; delayMicroseconds(_ntscDelayVSync); } } /** * End of the NTSC Specific block **/ #endif /** * Clears the frame buffer (if mode is true it will fill it with a chess board pattern) **/ void clearFrameBuffer(void) { byte index, index2; for (index2 = 0; index2 < _tvPixelHeight; index2++) { for (index = 0; index < _tvPixelWidth; index++) { frameBuffer[index][index2] = _BLACK; } } } /** * Fills the frame buffer with white **/ void fillWhiteFrameBuffer(void) { byte index, index2; for (index2 = 0; index2 < _tvPixelHeight; index2++) { for (index = 0; index < _tvPixelWidth; index++) { frameBuffer[index][index2] = _WHITE; } } } /** * Fills the frame buffer with gray **/ void fillGrayFrameBuffer(void) { byte index, index2; for (index2 = 0; index2 < _tvPixelHeight; index2++) { for (index = 0; index < _tvPixelWidth; index++) { frameBuffer[index][index2] = _GRAY; } } } /** * Fills the frame buffer with a pattern **/ void fillPatternFrameBuffer(void) { byte index, index2; for (index2 = 0; index2 < _tvPixelHeight; index2++) { for (index = 0; index < _tvPixelWidth; index++) { frameBuffer[index][index2] = (index + index2) % 3 + 1; } } } /** * Copies a sprite to the frameBuffer **/ void loadSprite(void) { unsigned int ii,jj; for (ii=0;ii<_tvPixelWidth;ii++) { for(jj=0;jj<_tvPixelHeight;jj++) { frameBuffer[ii][jj] = graphic[ii][jj]; } } }
This paste will be private.
From the Design Piracy series on my blog: