MD, USA
Offline
God Member
Karma: 1
Posts: 663
A jack of all trades and a master of none!
|
 |
« on: January 22, 2010, 02:07:15 pm » |
I figure the one thing that the arduino is missing is a display. I'm short on cash so buying a display was out of the question. But i do have a PSone with a 5" LCD. I did a little search online and found a previous attempt at composite video on the arduino in the forums. http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1166667354/0But it seam there where still problems with it. I then found this site. http://dailyduino.com/archives/368So i figured i'd give it a try and see how it went. I can't say i understand even half of the code but it does work... to an extent. Problem i'm having, and the problem presented in the thread, is getting the V sync worked out. It displays what its designed to say on the screen but its rolling from bottom to top. Maybe someone wiser then I can figure out what could be changed to get this to sync up. //Adapted by phizone from: // //Arduino Tv framebuffer //Alastair Parker //2007
// Video out voltage levels #define _SYNC 0x00 #define _BLACK 0x01 #define _GRAY 0x02 #define _WHITE 0x03
// dimensions of the screen #define WIDTH 38 #define HEIGHT 14
//number of lines to display #define DISPLAY_LINES 240
// update speed for the main loop of the game #define UPDATE_INTERVAL 1
//video pins #define DATA_PIN 8 #define SYNC_PIN 9
// the video frameBuffer byte frameBuffer[WIDTH][HEIGHT];
// loop indices byte index, index2;
// pal video line loop byte line; // current drawing line in framebuffer byte newLine;
// if displaying the title boolean showingTitle = true;
// draw a pixel to the buffer void setPixel(byte x,byte y) { frameBuffer[x][y]= _WHITE; }
void grayPixel(byte x, byte y) { frameBuffer[x][y]= _GRAY; }
// draw a black pixel to the buffer void clearPixel(byte x,byte y) { frameBuffer[x][y]= _BLACK; }
//draw the title message void drawArduinoPong() {
//DAILY setPixel(6,3); setPixel(7,3); setPixel(11,3); setPixel(12,3); setPixel(14,3); setPixel(15,3); setPixel(16,3); setPixel(18,3); setPixel(21,3); setPixel(23,3); setPixel(6,4); setPixel(8,4); setPixel(10,4); setPixel(12,4); setPixel(15,4); setPixel(18,4); setPixel(21,4); setPixel(22,4); setPixel(23,4); setPixel(6,5); setPixel(8,5); setPixel(10,5); setPixel(11,5); setPixel(12,5); setPixel(15,5); setPixel(18,5); setPixel(22,5); setPixel(6,6); setPixel(7,6); setPixel(10,6); setPixel(12,6); setPixel(14,6); setPixel(15,6); setPixel(16,6); setPixel(18,6); setPixel(19,6); setPixel(20,6); setPixel(22,6);
//DUINO setPixel(9,8); setPixel(10,8); setPixel(13,8); setPixel(15,8); setPixel(17,8); setPixel(18,8); setPixel(19,8); setPixel(21,8); setPixel(24,8); setPixel(27,8); setPixel(28,8); setPixel(9,9); setPixel(11,9); setPixel(13,9); setPixel(15,9); setPixel(18,9); setPixel(21,9); setPixel(22,9); setPixel(24,9); setPixel(26,9); setPixel(29,9); setPixel(9,10); setPixel(11,10); setPixel(13,10); setPixel(15,10); setPixel(18,10); setPixel(21,10); setPixel(23,10); setPixel(24,10); setPixel(26,10); setPixel(29,10); setPixel(9,11); setPixel(10,11); setPixel(13,11); setPixel(14,11); setPixel(15,11); setPixel(17,11); setPixel(18,11); setPixel(19,11); setPixel(21,11); setPixel(24,11); setPixel(27,11); setPixel(28,11); } // clear the screen void clearScreen() { for (index = 0; index < WIDTH; index++) for (index2=0;index2<=HEIGHT;++index2) { frameBuffer[index][index2] = _BLACK; } }
// the setup routine void setup() { cli(); pinMode (SYNC_PIN, OUTPUT); pinMode (DATA_PIN, OUTPUT); digitalWrite (SYNC_PIN, HIGH); digitalWrite (DATA_PIN, HIGH); clearScreen(); drawArduinoPong(); }
void loop() { // iterate over the lines on the tv for ( line =0;line< DISPLAY_LINES;++line) {
// HSync // front porch (1.5 us) PORTB = _BLACK; delayMicroseconds(1.5); //sync (4.7 us) PORTB = _SYNC; delayMicroseconds(4.7); // breezeway (.6us) + burst (2.5us) + colour back borch (1.6 us) PORTB = _BLACK; delayMicroseconds(0.6+2.5+1.6);
//calculate which line to draw to newLine = line >>4; delayMicroseconds(1);
//display the array for this line // a loop would have been smaller, but it messes the timing up PORTB = frameBuffer[0][newLine]; delayMicroseconds(1); PORTB = frameBuffer[1][newLine]; delayMicroseconds(1); PORTB = frameBuffer[2][newLine]; delayMicroseconds(1); PORTB = frameBuffer[3][newLine]; delayMicroseconds(1); PORTB = frameBuffer[4][newLine]; delayMicroseconds(1); PORTB = frameBuffer[5][newLine]; delayMicroseconds(1); PORTB = frameBuffer[6][newLine]; delayMicroseconds(1); PORTB = frameBuffer[7][newLine]; delayMicroseconds(1); PORTB = frameBuffer[8][newLine]; delayMicroseconds(1); PORTB = frameBuffer[9][newLine]; delayMicroseconds(1); PORTB = frameBuffer[10][newLine]; delayMicroseconds(1); PORTB = frameBuffer[11][newLine]; delayMicroseconds(1); PORTB = frameBuffer[12][newLine]; delayMicroseconds(1); PORTB = frameBuffer[13][newLine]; delayMicroseconds(1); PORTB = frameBuffer[14][newLine]; delayMicroseconds(1); PORTB = frameBuffer[15][newLine]; delayMicroseconds(1); PORTB = frameBuffer[16][newLine]; delayMicroseconds(1); PORTB = frameBuffer[17][newLine]; delayMicroseconds(1); PORTB = frameBuffer[18][newLine]; delayMicroseconds(1); PORTB = frameBuffer[19][newLine]; delayMicroseconds(1); PORTB = frameBuffer[20][newLine]; delayMicroseconds(1); PORTB = frameBuffer[21][newLine]; delayMicroseconds(1); PORTB = frameBuffer[22][newLine]; delayMicroseconds(1); PORTB = frameBuffer[23][newLine]; delayMicroseconds(1); PORTB = frameBuffer[24][newLine]; delayMicroseconds(1); PORTB = frameBuffer[25][newLine]; delayMicroseconds(1); PORTB = frameBuffer[26][newLine]; delayMicroseconds(1); PORTB = frameBuffer[27][newLine]; delayMicroseconds(1); PORTB = frameBuffer[28][newLine]; delayMicroseconds(1); PORTB = frameBuffer[29][newLine]; delayMicroseconds(1); PORTB = frameBuffer[30][newLine]; delayMicroseconds(1); PORTB = frameBuffer[31][newLine]; delayMicroseconds(1); PORTB = frameBuffer[32][newLine]; delayMicroseconds(1); PORTB = frameBuffer[33][newLine]; delayMicroseconds(1); PORTB = frameBuffer[34][newLine]; delayMicroseconds(1); PORTB = frameBuffer[35][newLine]; delayMicroseconds(1);
// klugdge to correct timings PORTB = frameBuffer[36][newLine]; PORTB=PORTB; PORTB=PORTB; PORTB=PORTB; delayMicroseconds(2); }
//vsync PORTB = _SYNC;
// wait for the remainder of the sync period
delayMicroseconds(565);
}
I've tried to change the #define _SYNC 0x00 value but it doesn't seam to change anything. I'm pretty sure this is an issue with the hardware that we may not be able to overcome. But i sure do want to give it a try. This is a simple setup and could have allot of uses. I think i'll start looking into the pin out of the playstation AV connection and see if i can go strait digital to the screen.
|
|
|
|
« Last Edit: January 22, 2010, 02:10:18 pm by digimike »
|
Logged
|
|
|
|
|
UK
Offline
Faraday Member
Karma: 15
Posts: 2852
Gorm deficient
|
 |
« Reply #1 on: January 22, 2010, 02:20:17 pm » |
You may be having problems that this display is only 240 lines high.
US standard images are 262.5 lines per field (525 lines total), and whilst older analogue monitors will be OK with short fields, more modern digital sets may not be so forgiving.
(BTW, it isn't really composite, which combines luminance and chrominance into a single signal, it's just luminance)
|
|
|
|
|
Logged
|
Per Arduino ad Astra
|
|
|
|
MD, USA
Offline
God Member
Karma: 1
Posts: 663
A jack of all trades and a master of none!
|
 |
« Reply #2 on: January 22, 2010, 03:11:58 pm » |
Yes there are 525 scan lines on a TV of which only 486 are visible. So i have changed the number of scan lines to 243. I then went to the bottom of the code and played around with the ms delay in the last line and got a stable image with it set at 50 on this LCD. Though you can still see the scan line running threw the image. So there is still a bit of tweaking to be done. On a standard def CRT TV the image is still screwy. But i think once i get everything dialed in perfectly on the LCD that will be fixed as well.
I won't re post the code since the changes are simple. I may bring the scan lines up to 262 and see how it goes. The code errors out if i try and do a decimal place. But when i set the lines that high the image is blank.
EDIT: The best image i've been able to get so far on my LCD is using 100 in the last line of the code. But the timing is still off to propperly support a stable image on the CRT. Guess its time to move the arduino to the laptop so i can test it while on the TV.
BTW, if i get this all worked out, how hard will it be to have it coverted into a library?
|
|
|
|
« Last Edit: January 22, 2010, 04:55:18 pm by digimike »
|
Logged
|
|
|
|
|
SE USA
Offline
Faraday Member
Karma: 33
Posts: 3618
@ssh0le
|
 |
« Reply #3 on: January 22, 2010, 05:34:04 pm » |
library are not that hard, its the first thing I tried when I got an arduino http://www.arduino.cc/en/Hacking/LibraryTutorial
|
|
|
|
|
Logged
|
http://arduino.cc/forum/index.php?action=unread;boards=2,3,4,5,67,6,7,8,9,10,11,66,12,13,15,14,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,86,87,89,1;ALL
|
|
|
|
MD, USA
Offline
God Member
Karma: 1
Posts: 663
A jack of all trades and a master of none!
|
 |
« Reply #4 on: January 22, 2010, 06:21:19 pm » |
Right now i'm at work so i'm unable to play with the settings right now. I wish i could get the IDE running on the PCs here. Then i'd bring my arduino with me and work on it more. Though i have been reviewing the code and trying to get my head around all these timings. I have found a couple of lines in the code that are references to the original game this code was adapted from so i'll be removing those. Correct me if i'm wrong. As far as i can tell defining gray isn't needed at all. Either the areas specified will be black or white. Trying to do gray scale here would be too much for the arduino to handle. I am considering redefining the size of the pixels. Since i'll have to redefine the number of scan lines to fit an NTSC display. Been trying to figure out how the width and height of the pixels first came to be. I figure with a NTSC display being 720x480 the width would need to be 40 and the height would have to be 15. Thats the only way to break it down into large pixels evenly. So each pixel the arduino will display will take up 48x32 block of pixels. The Display lines will remain at 240. Current untested sketch. These changes have likely effected the timing. //Adapted by phizone from: // //Arduino Tv framebuffer //Alastair Parker //2007
// Video out voltage levels #define _SYNC 0x00 #define _BLACK 0x01
#define _WHITE 0x03
// dimensions of the screen #define WIDTH 40 #define HEIGHT 15
//number of lines to display #define DISPLAY_LINES 240
//video pins #define DATA_PIN 8 #define SYNC_PIN 9
// the video frameBuffer byte frameBuffer[WIDTH][HEIGHT];
// loop indices byte index, index2;
// video line loop byte line; // current drawing line in framebuffer byte newLine;
// draw a pixel to the buffer void setPixel(byte x,byte y) { frameBuffer[x][y]= _WHITE; }
// draw a black pixel to the buffer void clearPixel(byte x,byte y) { frameBuffer[x][y]= _BLACK; }
//draw the title message void drawscreen() {
//DAILY setPixel(6,3); setPixel(7,3); setPixel(11,3); setPixel(12,3); setPixel(14,3); setPixel(15,3); setPixel(16,3); setPixel(18,3); setPixel(21,3); setPixel(23,3); setPixel(6,4); setPixel(8,4); setPixel(10,4); setPixel(12,4); setPixel(15,4); setPixel(18,4); setPixel(21,4); setPixel(22,4); setPixel(23,4); setPixel(6,5); setPixel(8,5); setPixel(10,5); setPixel(11,5); setPixel(12,5); setPixel(15,5); setPixel(18,5); setPixel(22,5); setPixel(6,6); setPixel(7,6); setPixel(10,6); setPixel(12,6); setPixel(14,6); setPixel(15,6); setPixel(16,6); setPixel(18,6); setPixel(19,6); setPixel(20,6); setPixel(22,6);
//DUINO setPixel(9,8); setPixel(10,8); setPixel(13,8); setPixel(15,8); setPixel(17,8); setPixel(18,8); setPixel(19,8); setPixel(21,8); setPixel(24,8); setPixel(27,8); setPixel(28,8); setPixel(9,9); setPixel(11,9); setPixel(13,9); setPixel(15,9); setPixel(18,9); setPixel(21,9); setPixel(22,9); setPixel(24,9); setPixel(26,9); setPixel(29,9); setPixel(9,10); setPixel(11,10); setPixel(13,10); setPixel(15,10); setPixel(18,10); setPixel(21,10); setPixel(23,10); setPixel(24,10); setPixel(26,10); setPixel(29,10); setPixel(9,11); setPixel(10,11); setPixel(13,11); setPixel(14,11); setPixel(15,11); setPixel(17,11); setPixel(18,11); setPixel(19,11); setPixel(21,11); setPixel(24,11); setPixel(27,11); setPixel(28,11); } // clear the screen void clearScreen() { for (index = 0; index < WIDTH; index++) for (index2=0;index2<HEIGHT;++index2) { frameBuffer[index][index2] = _BLACK; } }
// the setup routine void setup() { cli(); pinMode (SYNC_PIN, OUTPUT); pinMode (DATA_PIN, OUTPUT); digitalWrite (SYNC_PIN, HIGH); digitalWrite (DATA_PIN, HIGH); clearScreen(); drawscreen(); }
void loop() { // iterate over the lines on the tv for ( line =0;line< DISPLAY_LINES;++line) {
// HSync // front porch (1.5 us) PORTB = _BLACK; delayMicroseconds(1.5); //sync (4.7 us) PORTB = _SYNC; delayMicroseconds(4.7); // breezeway (.6us) + burst (2.5us) + colour back borch (1.6 us) PORTB = _BLACK; delayMicroseconds(0.6+2.5+1.6);
//calculate which line to draw to newLine = line >>4; delayMicroseconds(1);
//display the array for this line // a loop would have been smaller, but it messes the timing up PORTB = frameBuffer[0][newLine]; delayMicroseconds(1); PORTB = frameBuffer[1][newLine]; delayMicroseconds(1); PORTB = frameBuffer[2][newLine]; delayMicroseconds(1); PORTB = frameBuffer[3][newLine]; delayMicroseconds(1); PORTB = frameBuffer[4][newLine]; delayMicroseconds(1); PORTB = frameBuffer[5][newLine]; delayMicroseconds(1); PORTB = frameBuffer[6][newLine]; delayMicroseconds(1); PORTB = frameBuffer[7][newLine]; delayMicroseconds(1); PORTB = frameBuffer[8][newLine]; delayMicroseconds(1); PORTB = frameBuffer[9][newLine]; delayMicroseconds(1); PORTB = frameBuffer[10][newLine]; delayMicroseconds(1); PORTB = frameBuffer[11][newLine]; delayMicroseconds(1); PORTB = frameBuffer[12][newLine]; delayMicroseconds(1); PORTB = frameBuffer[13][newLine]; delayMicroseconds(1); PORTB = frameBuffer[14][newLine]; delayMicroseconds(1); PORTB = frameBuffer[15][newLine]; delayMicroseconds(1); PORTB = frameBuffer[16][newLine]; delayMicroseconds(1); PORTB = frameBuffer[17][newLine]; delayMicroseconds(1); PORTB = frameBuffer[18][newLine]; delayMicroseconds(1); PORTB = frameBuffer[19][newLine]; delayMicroseconds(1); PORTB = frameBuffer[20][newLine]; delayMicroseconds(1); PORTB = frameBuffer[21][newLine]; delayMicroseconds(1); PORTB = frameBuffer[22][newLine]; delayMicroseconds(1); PORTB = frameBuffer[23][newLine]; delayMicroseconds(1); PORTB = frameBuffer[24][newLine]; delayMicroseconds(1); PORTB = frameBuffer[25][newLine]; delayMicroseconds(1); PORTB = frameBuffer[26][newLine]; delayMicroseconds(1); PORTB = frameBuffer[27][newLine]; delayMicroseconds(1); PORTB = frameBuffer[28][newLine]; delayMicroseconds(1); PORTB = frameBuffer[29][newLine]; delayMicroseconds(1); PORTB = frameBuffer[30][newLine]; delayMicroseconds(1); PORTB = frameBuffer[31][newLine]; delayMicroseconds(1); PORTB = frameBuffer[32][newLine]; delayMicroseconds(1); PORTB = frameBuffer[33][newLine]; delayMicroseconds(1); PORTB = frameBuffer[34][newLine]; delayMicroseconds(1); PORTB = frameBuffer[35][newLine]; delayMicroseconds(1);
// klugdge to correct timings PORTB = frameBuffer[36][newLine]; PORTB=PORTB; PORTB=PORTB; PORTB=PORTB; delayMicroseconds(2); }
//vsync PORTB = _SYNC;
// wait for the remainder of the sync period
delayMicroseconds(100);
}
can't help but wonder if this would be better suited on the analog pins.
|
|
|
|
« Last Edit: January 22, 2010, 06:29:20 pm by digimike »
|
Logged
|
|
|
|
|
UK
Offline
Faraday Member
Karma: 15
Posts: 2852
Gorm deficient
|
 |
« Reply #5 on: January 22, 2010, 06:34:50 pm » |
can't help but wonder if this would be better suited on the analog pins. The analogue pins are inputs - why do you think that?
|
|
|
|
|
Logged
|
Per Arduino ad Astra
|
|
|
|
MD, USA
Offline
God Member
Karma: 1
Posts: 663
A jack of all trades and a master of none!
|
 |
« Reply #6 on: January 22, 2010, 06:50:53 pm » |
I figure it would be better with an analogue output or at least take advantage of a PWM since this is an analog signal we are trying to create for an analog TV. Even though all i'm after is for a good looking display on that PS1 LCD. But i figure if i'm going to get this working i better make it so it will work on any display that uses composite input.
|
|
|
|
|
Logged
|
|
|
|
|
UK
Offline
Faraday Member
Karma: 15
Posts: 2852
Gorm deficient
|
 |
« Reply #7 on: January 22, 2010, 07:02:11 pm » |
An RS-170 (NTSC minus the colour carrier) video signal is an analogue signal with a very specific waveform and a bandwidth of around 4 - 5MHz. Your PWM signals ("analogue outputs") from the Arduino run at around 4-500Hz, and are digital signals.
|
|
|
|
« Last Edit: January 22, 2010, 07:10:49 pm by GrooveFlotilla »
|
Logged
|
Per Arduino ad Astra
|
|
|
|
MD, USA
Offline
God Member
Karma: 1
Posts: 663
A jack of all trades and a master of none!
|
 |
« Reply #8 on: January 23, 2010, 01:35:27 pm » |
I've come across some interesting findings trying to break down this code. I've got everything set to give a nice solid display on my LCD. Problem is the very top row, row 0 is displayed at the very bottom of the screen. Column 34 is off a bit in its width on the LCD but gets cut off at just the right size on the TV. Also on the TV we loose row 1. it gets cut off.   This project definitely needs a solid power source to the arduino. When using a battery pack of 4 AAA batteries that are a bit weak, the image isn't very solid on the LCD. The TV however is more forgiving here. So as a reminder this is how you hook this up. Code will be broken into 2 sections to fit in the limited post space. /* Adapted by phizone from:
Arduino Tv framebuffer Alastair Parker 2007
Modified for use on NTSC monitors and displays 2009 Michael Pilcher
*/
// Video out voltage levels #define _SYNC 0x00 #define _BLACK 0x01 #define _WHITE 0x03
// dimensions of the screen #define WIDTH 35 // sets # of columns 0-34. Column 34 is oversized on some displays #define HEIGHT 15 // sets # of rows 0-14. row 0 wrapped around to the bottom
//number of lines to display #define DISPLAY_LINES 255
//video pins #define DATA_PIN 9 #define SYNC_PIN 8
// the video frameBuffer byte frameBuffer[WIDTH][HEIGHT];
// loop indices byte index, index2;
// video line loop byte line; // current drawing line in framebuffer byte newLine;
// draw a pixel to the buffer void setPixel(byte x,byte y) { frameBuffer[x][y]= _WHITE; }
// draw a black pixel to the buffer void clearPixel(byte x,byte y) { frameBuffer[x][y]= _BLACK; }
//draw the title message void drawScreen() { // possible unusable column. may appear too wide on some displays setPixel(34,0); setPixel(34,1); setPixel(34,2); setPixel(34,3); setPixel(34,4); setPixel(34,5); setPixel(34,6); setPixel(34,7); setPixel(34,8); setPixel(34,9); setPixel(34,10); setPixel(34,11); setPixel(34,12); setPixel(34,13); setPixel(34,14); // row 0, this row displays at the bottom of the screen not the top setPixel(1,0); setPixel(2,0); setPixel(3,0); setPixel(4,0); setPixel(5,0); setPixel(6,0); setPixel(7,0); setPixel(8,0); setPixel(9,0); setPixel(10,0); setPixel(11,0); setPixel(12,0); setPixel(13,0); setPixel(14,0); setPixel(15,0); setPixel(16,0); setPixel(17,0); setPixel(18,0); setPixel(19,0); setPixel(20,0); setPixel(21,0); setPixel(22,0); setPixel(23,0); setPixel(24,0); setPixel(25,0); setPixel(26,0); setPixel(27,0); setPixel(28,0); setPixel(29,0); setPixel(30,0); setPixel(31,0); setPixel(32,0); setPixel(33,0); // checked test pattern, CHANGE THESE TO BUILD YOUR IMAGE setPixel(0,2); setPixel(0,4); setPixel(0,6); setPixel(0,8); setPixel(0,10); setPixel(0,12); setPixel(0,14); setPixel(1,1); setPixel(1,3); setPixel(1,5); setPixel(1,7); setPixel(1,9); setPixel(1,11); setPixel(1,13); setPixel(2,2); setPixel(2,4); setPixel(2,6); setPixel(2,8); setPixel(2,10); setPixel(2,12); setPixel(2,14); setPixel(3,1); setPixel(3,3); setPixel(3,5); setPixel(3,7); setPixel(3,9); setPixel(3,11); setPixel(3,13); setPixel(4,2); setPixel(4,4); setPixel(4,6); setPixel(4,8); setPixel(4,10); setPixel(4,12); setPixel(4,14); setPixel(5,1); setPixel(5,3); setPixel(5,5); setPixel(5,7); setPixel(5,9); setPixel(5,11); setPixel(5,13); setPixel(6,2); setPixel(6,4); setPixel(6,6); setPixel(6,8); setPixel(6,10); setPixel(6,12); setPixel(6,14); setPixel(7,1); setPixel(7,3); setPixel(7,5); setPixel(7,7); setPixel(7,9); setPixel(7,11); setPixel(7,13); setPixel(8,2); setPixel(8,4); setPixel(8,6); setPixel(8,8); setPixel(8,10); setPixel(8,12); setPixel(8,14); setPixel(9,1); setPixel(9,3); setPixel(9,5); setPixel(9,7); setPixel(9,9); setPixel(9,11); setPixel(9,13); setPixel(10,2); setPixel(10,4); setPixel(10,6); setPixel(10,8); setPixel(10,10); setPixel(10,12); setPixel(10,14); setPixel(11,1); setPixel(11,3); setPixel(11,5); setPixel(11,7); setPixel(11,9); setPixel(11,11); setPixel(11,13); setPixel(12,2); setPixel(12,4); setPixel(12,6); setPixel(12,8); setPixel(12,10); setPixel(12,12); setPixel(12,14); setPixel(13,1); setPixel(13,3); setPixel(13,5); setPixel(13,7); setPixel(13,9); setPixel(13,11); setPixel(13,13); setPixel(14,2); setPixel(14,4); setPixel(14,6); setPixel(14,8); setPixel(14,10); setPixel(14,12); setPixel(14,14); setPixel(15,1); setPixel(15,3); setPixel(15,7); setPixel(15,5); setPixel(15,9); setPixel(15,11); setPixel(15,13); setPixel(16,2); setPixel(16,4); setPixel(16,6); setPixel(16,8); setPixel(16,10); setPixel(16,12); setPixel(16,14); setPixel(17,1); setPixel(17,3); setPixel(17,5); setPixel(17,7); setPixel(17,9); setPixel(17,11); setPixel(17,13); setPixel(18,2); setPixel(18,4); setPixel(18,6); setPixel(18,8); setPixel(18,10); setPixel(18,12); setPixel(18,14); setPixel(19,1); setPixel(19,3); setPixel(19,5); setPixel(19,7); setPixel(19,9); setPixel(19,11); setPixel(19,13); setPixel(20,2); setPixel(20,4); setPixel(20,6); setPixel(20,8); setPixel(20,10); setPixel(20,12); setPixel(20,14); setPixel(21,1); setPixel(21,3); setPixel(21,5); setPixel(21,7); setPixel(21,9); setPixel(21,11); setPixel(21,13); setPixel(22,2); setPixel(22,4); setPixel(22,6); setPixel(22,8); setPixel(22,10); setPixel(22,12); setPixel(22,14); setPixel(23,1); setPixel(23,3); setPixel(23,5); setPixel(23,7); setPixel(23,9); setPixel(23,11); setPixel(23,13); setPixel(24,2); setPixel(24,4); setPixel(24,6); setPixel(24,8); setPixel(24,10); setPixel(24,12); setPixel(24,14); setPixel(25,1); setPixel(25,3); setPixel(25,5); setPixel(25,7); setPixel(25,9); setPixel(25,11); setPixel(25,13); setPixel(26,2); setPixel(26,4); setPixel(26,6); setPixel(26,8); setPixel(26,10); setPixel(26,12); setPixel(26,14); setPixel(27,1); setPixel(27,3); setPixel(27,5); setPixel(27,7); setPixel(27,9); setPixel(27,11); setPixel(27,13); setPixel(28,2); setPixel(28,4); setPixel(28,6); setPixel(28,8); setPixel(28,10); setPixel(28,12); setPixel(28,14); setPixel(29,1); setPixel(29,3); setPixel(29,5); setPixel(29,7); setPixel(29,9); setPixel(29,11); setPixel(29,13); setPixel(30,2); setPixel(30,4); setPixel(30,6); setPixel(30,8); setPixel(30,10); setPixel(30,12); setPixel(30,14); setPixel(31,1); setPixel(31,3); setPixel(31,5); setPixel(31,7); setPixel(31,9); setPixel(31,11); setPixel(31,13); setPixel(32,2); setPixel(32,4); setPixel(32,6); setPixel(32,8); setPixel(32,10); setPixel(32,12); setPixel(32,14); setPixel(33,1); setPixel(33,3); setPixel(33,5); setPixel(33,7); setPixel(33,9); setPixel(33,11); setPixel(33,13); }
|
|
|
|
« Last Edit: January 23, 2010, 01:54:07 pm by digimike »
|
Logged
|
|
|
|
|
MD, USA
Offline
God Member
Karma: 1
Posts: 663
A jack of all trades and a master of none!
|
 |
« Reply #9 on: January 23, 2010, 01:35:56 pm » |
Code continued: // clear the screen void clearScreen() { for (index = 0; index < WIDTH; index++) for (index2 = 0; index2< HEIGHT; index2++) { frameBuffer[index][index2] = _BLACK; } /*clears stray pixel at (34,0) that doesn't get cleared by the above for() loops. If the loop that reads for (index = 0; index < WIDTH; index++) reads for (index = 0; index <= WIDTH; index++) the timing is thrown off and the image gets scrambled */ frameBuffer[35][0] = _BLACK; }
// the setup routine void setup() { cli(); pinMode (SYNC_PIN, OUTPUT); pinMode (DATA_PIN, OUTPUT); digitalWrite (SYNC_PIN, HIGH); digitalWrite (DATA_PIN, HIGH); clearScreen(); drawScreen(); }
void loop() { // iterate over the lines on the tv for ( line =0;line< DISPLAY_LINES;++line) {
// HSync // front porch (1.5 us) PORTB = _BLACK; delayMicroseconds(1.5); //sync (4.7 us) PORTB = _SYNC; delayMicroseconds(4.7); // breezeway (.6us) + burst (2.5us) + colour back borch (1.6 us) PORTB = _BLACK; delayMicroseconds(4.7);
//calculate which line to draw to newLine = line >>4; delayMicroseconds(1);
//display the array for this line // a loop would have been smaller, but it messes the timing up PORTB = frameBuffer[0][newLine]; delayMicroseconds(1); PORTB = frameBuffer[1][newLine]; delayMicroseconds(1); PORTB = frameBuffer[2][newLine]; delayMicroseconds(1); PORTB = frameBuffer[3][newLine]; delayMicroseconds(1); PORTB = frameBuffer[4][newLine]; delayMicroseconds(1); PORTB = frameBuffer[5][newLine]; delayMicroseconds(1); PORTB = frameBuffer[6][newLine]; delayMicroseconds(1); PORTB = frameBuffer[7][newLine]; delayMicroseconds(1); PORTB = frameBuffer[8][newLine]; delayMicroseconds(1); PORTB = frameBuffer[9][newLine]; delayMicroseconds(1); PORTB = frameBuffer[10][newLine]; delayMicroseconds(1); PORTB = frameBuffer[11][newLine]; delayMicroseconds(1); PORTB = frameBuffer[12][newLine]; delayMicroseconds(1); PORTB = frameBuffer[13][newLine]; delayMicroseconds(1); PORTB = frameBuffer[14][newLine]; delayMicroseconds(1); PORTB = frameBuffer[15][newLine]; delayMicroseconds(1); PORTB = frameBuffer[16][newLine]; delayMicroseconds(1); PORTB = frameBuffer[17][newLine]; delayMicroseconds(1); PORTB = frameBuffer[18][newLine]; delayMicroseconds(1); PORTB = frameBuffer[19][newLine]; delayMicroseconds(1); PORTB = frameBuffer[20][newLine]; delayMicroseconds(1); PORTB = frameBuffer[21][newLine]; delayMicroseconds(1); PORTB = frameBuffer[22][newLine]; delayMicroseconds(1); PORTB = frameBuffer[23][newLine]; delayMicroseconds(1); PORTB = frameBuffer[24][newLine]; delayMicroseconds(1); PORTB = frameBuffer[25][newLine]; delayMicroseconds(1); PORTB = frameBuffer[26][newLine]; delayMicroseconds(1); PORTB = frameBuffer[27][newLine]; delayMicroseconds(1); PORTB = frameBuffer[28][newLine]; delayMicroseconds(1); PORTB = frameBuffer[29][newLine]; delayMicroseconds(1); PORTB = frameBuffer[30][newLine]; delayMicroseconds(1); PORTB = frameBuffer[31][newLine]; delayMicroseconds(1); PORTB = frameBuffer[32][newLine]; delayMicroseconds(1); PORTB = frameBuffer[33][newLine]; delayMicroseconds(1); PORTB = frameBuffer[34][newLine]; delayMicroseconds(1); // klugdge to correct timings PORTB = PORTB; delayMicroseconds(1); PORTB = PORTB; delayMicroseconds(1); PORTB = PORTB; PORTB = PORTB; PORTB = PORTB; delayMicroseconds(1); }
//vsync PORTB = _SYNC;
// wait for the remainder of the sync period
delayMicroseconds(125);
}
|
|
|
|
« Last Edit: January 23, 2010, 02:45:58 pm by digimike »
|
Logged
|
|
|
|
|
MD, USA
Offline
God Member
Karma: 1
Posts: 663
A jack of all trades and a master of none!
|
 |
« Reply #10 on: January 23, 2010, 02:57:46 pm » |
Here are the coordinates for the classic "HELLO WORLD" // hello world // H setPixel(2,2); setPixel(2,3); setPixel(2,4); setPixel(2,5); setPixel(2,6); setPixel(3,4); setPixel(4,4); setPixel(5,2); setPixel(5,3); setPixel(5,4); setPixel(5,5); setPixel(5,6); // E setPixel(7,2); setPixel(7,3); setPixel(7,4); setPixel(7,5); setPixel(7,6); setPixel(8,2); setPixel(8,4); setPixel(8,6); setPixel(9,2); setPixel(9,6);
// L setPixel(11,2); setPixel(11,3); setPixel(11,4); setPixel(11,5); setPixel(11,6); setPixel(12,6); setPixel(13,6); // L setPixel(15,2); setPixel(15,3); setPixel(15,4); setPixel(15,5); setPixel(15,6); setPixel(16,6); setPixel(17,6); // O setPixel(19,3); setPixel(19,4); setPixel(19,5); setPixel(20,2); setPixel(20,6); setPixel(21,2); setPixel(21,6); setPixel(22,3); setPixel(22,4); setPixel(22,5); // W setPixel(2,10); setPixel(2,11); setPixel(2,12); setPixel(3,13); setPixel(3,14); setPixel(4,12); setPixel(5,13); setPixel(5,14); setPixel(6,10); setPixel(6,11); setPixel(6,12); // 0 setPixel(8,11); setPixel(8,12); setPixel(8,13); setPixel(9,10); setPixel(9,14); setPixel(10,10); setPixel(10,14); setPixel(11,11); setPixel(11,12); setPixel(11,13); // R setPixel(13,10); setPixel(13,11); setPixel(13,12); setPixel(13,13); setPixel(13,14); setPixel(14,10); setPixel(14,12); setPixel(15,10); setPixel(15,12); setPixel(15,13); setPixel(16,11); setPixel(16,14); // L setPixel(18,10); setPixel(18,11); setPixel(18,12); setPixel(18,13); setPixel(18,14); setPixel(19,14); setPixel(20,14); // D setPixel(22,10); setPixel(22,11); setPixel(22,12); setPixel(22,13); setPixel(22,14); setPixel(23,10); setPixel(23,14); setPixel(24,10); setPixel(24,14); setPixel(25,11); setPixel(25,12); setPixel(25,13); I also updated the code in the above post. After creating Hello world i found that the pixel at (34,0) was not being cleared. I tried to fix the for() statement in the clearScreen section to wipe that pixel but it caused timing issues. So i added a line to clear that single area without effecting timings. For now that pixel isn't usable. Since its in the bottom right corner i'm not even going to bother trying to fix it. It can just stay off.
|
|
|
|
|
Logged
|
|
|
|
|
MD, USA
Offline
God Member
Karma: 1
Posts: 663
A jack of all trades and a master of none!
|
 |
« Reply #11 on: January 24, 2010, 09:46:28 am » |
OK this has hit a dead end for me. Its just too much to try and get this to do anything. if you try to make it do more then show a single preset image your fighting timings. I've tried to take the original pong code, that this came from, and get it working on an NTSC display but timings are a nightmare. If you make a couple of small changes to the code you end up throwing everything off.
|
|
|
|
|
Logged
|
|
|
|
|
Left Coast, CA (USA)
Offline
Brattain Member
Karma: 279
Posts: 15312
Measurement changes behavior
|
 |
« Reply #12 on: January 24, 2010, 11:58:11 am » |
There is a lot of information avalible at the below link on composite video from a AVR chip. Their TellyMate video shield is a great little product and the avalible source code can show you how they implemented the timing needed. It is a major effort to get the timing just right, so a shield based product makes a lot of sense rather then trying to implement it inside an Arduino along with other application code. http://www.batsocks.co.uk/products/Shields/TellyMate%20Shield.htmLefty
|
|
|
|
|
Logged
|
|
|
|
|
MD, USA
Offline
God Member
Karma: 1
Posts: 663
A jack of all trades and a master of none!
|
 |
« Reply #13 on: January 24, 2010, 12:36:56 pm » |
Great link. Thanks.
Guess i need to add it to my wish list. or build it myself.
|
|
|
|
« Last Edit: January 24, 2010, 12:37:24 pm by digimike »
|
Logged
|
|
|
|
|
Offline
Sr. Member
Karma: 23
Posts: 444
|
 |
« Reply #14 on: January 29, 2010, 09:33:56 pm » |
I've been trying to do composite video myself, by using PWM to generate the sync signal. I've tried this on an LCD and CRT and it syncs ok for me (though it was better on the old CRT than the LCD.) The sync signal is now on pin 9 (as its a PWM pin) and the picture is on pin 8 so if you use the same circuit as before the wires need to be swapped over. It's still very hard to do anything more than display a static picture without losing the timing, but I've got a few ideas there... byte fb[56][12];
static inline void fbput(char x,char y,char a) { if(x<0 || x>95 || y<0 || y>55)return; a ? fb[y][x>>3] |= 1<<(x&7) : fb[y][x>>3] &= ~(1<<(x&7)) ; }
#define OPWM 0b11000010 #define OPORT 0b00000010 #define NOP __asm __volatile ("nop")
void setup() { cli(); DDRB |= 0b00000011; TCCR1A=OPWM; TCCR1B=0b00011010; //1 count = 0.5uS ICR1H=0; ICR1L=126; //period 63.5uS (126/2+1) (?) 127 for pal OCR1AH=0; OCR1AL=9; //4.5uS sync pulse (?) int i,j; for(i=0;i<12;i++)for(j=0;j<56;j++)fb[j][i]=0; // for(i=0;i<96;i++)for(j=0;j<56;j++)fbput(i,j,(i^j)&1); for(i=0;i<96;i++){fbput(i,0,1);fbput(i,55,1);} for(j=0;j<56;j++){fbput(0,j,1);fbput(95,j,1);} float a; for(a=0;a<M_PI*2;a+=M_PI/128) { fbput(48.5+27*cos(a),28.5+26*sin(a),1); fbput(48.5+3*cos(a),29.5+6*sin(a),1); fbput(34.5+6*cos(a),23.5+6*sin(a),1); fbput(62.5+6*cos(a),23.5+6*sin(a),1); if(a<=M_PI)fbput(48.5+16*cos(a),37.5+6*sin(a),1); } }
void loop() { char i,j,k; register char t; int line=0; for(;;) { while(TCNT1L != 0); //wait for start of line line++; if(line>=4 && line <= 6) { //vsync pulses PORTB=0; TCCR1A=OPORT; while(TCNT1L < 59); PORTB=2; while(TCNT1L < 63); PORTB=0; while(TCNT1L < 123); PORTB=2; while(TCNT1L < 126); TCCR1A=OPWM; continue; } if(line<=9) // lines 1-3 and 7-9 { //pre-equalising / post equalising pulses PORTB=0; TCCR1A=OPORT; while(TCNT1L < 4); PORTB=2; while(TCNT1L < 64); PORTB=0; while(TCNT1L < 68); PORTB=2; while(TCNT1L < 126); TCCR1A=OPWM; continue; } if(line>=30 && line<254) { j=20; while(TCNT1L < j); NOP;NOP; // helps stop jittering for(i=0;i<12;i++) { t=fb[(line-30)>>2][i]; PORTB = t;t>>=1;NOP; PORTB = t;t>>=1;NOP; PORTB = t;t>>=1;NOP; PORTB = t;t>>=1;NOP; PORTB = t;t>>=1;NOP; PORTB = t;t>>=1;NOP; PORTB = t;t>>=1;NOP; PORTB = t; } PORTB=0; continue; } if(line==262) line=0; // 312 for pal } }
|
|
|
|
|
Logged
|
|
|
|
|
|