loading
Picture of watch futurama on an 8x8 pixel screen
tired of hi-def? (booo!!!)

here's how to convert otherwise reasonable quality video into pixelated garbage and play it on a 2 color 8x8 led matrix, with no sound and only moderate sync.

ingredients:
- (1) 8x8 2 color led matrix
- (1) atmel avr atmega168
- (2) 74hc595 shift register
- (1) 3.3V regulator
- (1) a linux system

this is a mid level avr project, in that it assumes ( does not explain ) how to get a program onto a chip. it's pretty easy once you've done it though, so don't worry. to see how to actually load up a program, The Real Elliot has a nice introduction.

onto the show!
 
Remove these adsRemove these ads by Signing Up

Step 1: Have linux, avr-gcc, python, mplayer...


you'll need linux to use this method, because i used common linuxy things in it. these things are, in no particular order:

1. avr-gcc: needed to make c code into avr code --> wiki stuff about it

2. python: a surprisingly nice programming language --> official site

3. python image library: used here to turn nice video into tiny specs of light without nearly as much hassle as that sounds like. --> pil

4. mplayer: used to turn video into stills --> mplayer

5. mencoder: (optional) change the frame rate of video --> same place as mplayer

i think that is all of the dependancies.

Step 2: Circuit overview

Picture of circuit overview
shift registers:

we use 2 of them, one for green and one for red.

the 74hc595 shift register is a simple latched device that converts serial 1's and 0's to parallel 1's and 0's. the 'don't clear' pin is held high while the serial data is clocked in, then the latch pin is set high triggering the output of the parallel data. dropping the 'don't clear' pin empties the output register and gets ready for fresh data.

all that means is the chip acts as a friendly robot that patiently waits until you have said 8 things while touching it on the shoulder. and then when you punch it in the stomach the robot says them all at once out of its 8 mouths. just slap it upside the head and it forgets, ready to go again.

Step 3: Circuit overview: led matrix

Picture of circuit overview: led matrix
matrix_with_pins.jpg
this particular led matrix has a green and a red led in each of the 64 positions. if you light them both at once you get a sort of yellowyorange color.

the only thing special about this matrix is that it is the one i had when i did this. a HUGE improvement in the final result would be to use an RGB led matrix and an additional shift register, but i don't have 64 RGB leds lying around.


moving on:


say the green shift register outputs some fancy pattern like 10110011, that would light up the matrix like this:

g x g g x x g g
g x g g x x g g
g x g g x x g g
g x g g x x g g
g x g g x x g g
g x g g x x g g
g x g g x x g g
g x g g x x g g

(x means off)

as long as all of the ground pins were held low. same deal with the red register.

so to achieve animation, just hold all of the ground pins high except for the one that is on the line you want to draw to.

x x x x x x x x
x x x x x x x x
g x g g x x g g
x x x x x x x x
etc.






Step 4: Atmega168 == brains

Picture of atmega168 == brains
the atmega168 has a bunch of storage space and 28 pins, which is more than we need. by default it runs at 1MHz on an internal RC oscillator, which is not very stable. but that's ok.

PORTD:
to control the ground pins on the matrix, they are wired to PORTD of the avr. in code this will use the &= ~ (see step 6) type of method to keep all pins HI except the one for the row we want to display.

PORTB:
the latch will be on pin 0. the shift register clock is pin 3, green serial is pin2, red serial is pin4, and the no_clear is on pin1.

Step 5: Put it together

Picture of put it together
wires_for_matrix.jpg
oh my, there are some wires involved.

Step 6: Code for avr

the avr's job is pretty easy. the overall procedure is as follows:

1. read a byte from memory and write it to the red shift register
2. read a byte from memory and write it to the green shift register
3. set the appropriate pin low to ground the row we want to display
4. throw the latch to trigger the shift register outputs
5. wait.
6. clear the shift registers and repeat.

easy.

this is all done in code using a lot of bit shifts and bit masks. a quick refresher:

the << operator means shift the thing before, over by the amount after.
in an 8bit world,
(1<<3) means: 0000 1000
(1<<0) means: 0000 0001
(1<<7) means: 1000 0000

a |= means to apply an OR to the thing before and after, saving it in the before's spot. this is how you make sure that a bit is set high, or that a corresponding pin is on.
so if
a = 0100, and b = 0001,
then
a |= b changes a to 0101 and leaves b the same. b is usually called a mask

a tilde ~ in front of a value negates it:
a = 0110 1111
a = ~a changes a to 1001 0000

finally &= is just like |= except it's an AND instead of an OR:
a = 0110
b = 0100 and ~b = 1011
so
a &= ~b changes a to 0010. this is how you make sure that a pin is off.

Step 7: Draw a frame

the data is stored in arrays of unsigned chars, which are 8 bit numbers. PROGMEM forces the data to be stored in program memory, rather than allowing the avr to copy all of the data to ram. the purpose here is to reduce the number of steps involved and to maximize the amount of info that can be stored and quickly retrieved.

unsigned char green_vals[][8] PROGMEM = { { 0x01, 0xff, 0x80, 0xff, etc...unsigned char red_vals[][8] PROGMEM = { { 0x01, 0x02, 0x03, 0x04, etc...

remember that the matrix is only 8 leds across, meaning that each entry in those arrays corresponds to a complete description of an entire row. so looping through 8 of them in succession is a frame...

for (i=0; i<8; i++){  set_frame( red_vals[ 0 ][ i ], green_vals[ 0 ][ i ], (1<<i) );  show_frame( TIME_TO_SHOW_LINE );}

except that won't work, because of PROGMEM up there... just call pgm_read_byte() on red_vals and green_vals to fix it.

set_frame( pgm_read_byte( &red_vals[ 0 ][ i ] ), pgm_read_byte( &green_vals[ 0 ][ i ] ), (1<<i) );

the set_frame() function is pretty simple:
/* send frame line data to shift registers and set appropriate grounder pin */void set_frame ( unsigned char red, unsigned char green, unsigned char gnd ){	/* just a loop variable */	unsigned char i = 0;		/* set up red, loop through all 8 bits */	for (i=0; i<8; i++)	{		if ( red & (1<<i) ) PORTB |= red_ser;	// if it's a one then serial pin hi		else PORTB &= ~red_ser;			// otherwise make sure it's low		if ( green & (1<<i) )  PORTB |= green_ser;   // if it's a one then pin hi		else  PORTB &= ~green_ser; 	// otherwise make sure it's low		PORTB |= ser_sck;	// clock up		PORTB &= ~ser_sck;	// clock down         }        PORTB &= ~red_ser;		// be sure to leave red's ser line low	PORTB &= ~green_ser;		// leave green serial pin low	/* set the grounder pin for this frame line to low */	PORTD = ~gnd;		// upsidedown logic... }

Step 8: Great, but where's the data?

the led_matrix_formatted.py script is very simple thanks to the python imaging library.

since we want to change the palette of images the first thing to do is generate a palette array, into which we place the palette that will replace the palette of the soon to be paletted image. palette palette palette, palette palette image.
using some loops that array gets filled up with black, red, yellow, and green.

then we cycle through the command line args, which hopefully contain a bunch of images. each image is resized, converted to 'indexed' (palette) mode, and given the new palette that was generated above.

(btw, you can mess with that palette a great deal to achieve a variety of final looks)

then using more of the bit masking method seen in step 6, two long strings are formed and written to a file for copy/pasting.

Step 9: Python makes it easy...

Picture of python makes it easy...
calculating and entering in a bunch of binary data is for people who are living in the sixties. this is the oughts, so we let the computer do it for us!

first dig up a video file that you want to use ( i used Futurama s05e10 the Farnsworth Paradox )

second generate a bunch of jpegs. to do so type this is an empty directory:
mplayer -ss 00:17:20 -vo jpeg:quality=50 ~/tv/futurama.mpg
the '-ss 00:17:20' seeks to 17 minutes 20 seconds in the file (funny part) and the '-vo jpeg:quality=50' tells mplayer that you want to output mid quality jpegs instead of say, video on your screen. i never tested that quality setting, but given what comes next i don't think it matters.

third run this handy python script: `python ./led_matrix_formatted_data.py ./*.jpg` to create the "RGout.t" file, which is full of data to paste into the c code file.

fourth copy and paste the contents of RGout.t into led_matrix_template.c, and save it as matrix.c.

fifth compile and load the program onto your avr with a programmer. be sure to check the makefile to set the type of programmer you have! (btw i didn't write that makefile, i found it on google and modified it.)

sixth watch pixelly cartoons!

Step 10: Post scripts

Picture of post scripts
for people who build this i have included a couple of RGout.t 's for their viewing pleasure:

the intro to Futurama, the intro to Harvey Birdaman (including car chase!), and of course 00:17:20 from Farnsworth's Paradox.

as they are 64 pixel descriptions of tv, i assume that they fall under fair use at this point. the shows certainly aren't recoverable in any way from the data provided.


also, for people who don't build the device but would like to watch funny pixelly cartoons (or the tv news, whatever) anyhow, the python script contains commented out lines to make small bitmaps of the converted images.

typing `convert -delay 5 ./*.bmp Animated.gif` in the directory after running the uncommented script will produce an animated gif of the images which can then be played however you like, but i recommend `mplayer -fs Animated.gif` to get a fullscreen experience. ( you'll notice that the commented lines expand the images up to 256x256 pixels. this is not nearly as cool as watching the 8x8 versions blown up to fullscreen. check it out)


skeedes1 year ago
Hi, can the grounds also be driven using any shift register? BTW nice pencilmanship!
cool but don't u think it's misssing a arduino
jensenr304 years ago
what a mess! looks fun!
ha. I agree, i was like.. hmm? then stomach punch - bam got it! Thanks. We need you to write a dictionary for everything that needs an explanation. :)
eshneto5 years ago
 Really great explanation. Keep on going!
ReCreate6 years ago
What movie/show is that?
arduinoe6 years ago
does the display actually flicker like that or is that just a similar refresh rate to the camarea
probably the camera
taz6996 years ago
Awesome explanation. I wish you where my robotics teacher in high school. lol
I wish I had a robotics teacher.
lol mee 2
is that a whippet?
lol ur the second person to ask. no its not mine but its an odd mix breed. i dont remember what it is. but i suppose it looks sort of like that due to the angle i took the photo from.
I only asked because I saw the other post ,and I thought it would be funny and/or annoying if I asked too. I looked up whippets, an they do look similar, but I don't think it is a whippet.
haha lol
Yeah, It worked!
sparr6 years ago
You could add shades of color by storing more than 1 bit of data per subpixel per frame. That 5ms delay for each line is plenty of time to do some pseudo-PWM. It would make the data much larger though.
how would you go about making the screen a 8x6. Meaning that it would be 8 matrix's wide and 6 matrix's tall. How do you interface all the matrix's to act as one big screen
To simply scale this design up, you would need 48 of the matrixes, obviously. The circuit would be laid out as if you had one long 384x8-pixel matrix, even though you would arrange them physically in a rectangle. You would need an additional shift register for each matrix, and all the shift registers would need to be chained together to cascade. And you would need a row driver capable of putting out enough current to drive 384 LEDs at once.

That is not a particularly feasible design. The largest display I have seen like that was 4x2 * 8x8, and that was stretching it. You would probably want to build a 8x1 * 8x8 display, then get more creative in stacking those to avoid ridiculous input pin counts.
sethj (author)  alex_arseneau8 years ago
do you mean 64x48 pixels? you could do that by adding a few more shift registers and adjusting the code to notice them.
darkman1117 years ago
if anyone wants to watch futurama and other shows like american dad the boondocks and robot chicken all seasons and episodes from these show u should try http://newamericandadepisodes.com/ also has funny clips and pics
You could always buy a Zoombox. It's a much easier way to get a giant, crappy picture.
I think he wants SMALL crappy picture ;)
Wash0ut8 years ago
actually, if you pay close attention during the beginning you can see how "futurama" fans out and at the end you can make out a small outline of the tube the guy is sliding through. Nothing great but still distinctive. But who care it's still Awsome!
sethj (author) 8 years ago
has anyone noticed the animated gif?
naught101 sethj8 years ago
yep. took a while, but that's classic.
Bluemetal8 years ago
This was the best, most graphical and easiest to understand explanation of a shift register. :-)
sethj (author)  Bluemetal8 years ago
:)
robonut6258 years ago
Cool! Great description of the '595! lol
royalestel8 years ago
This is pretty cool. If you add a transparent LCD screen in front of it, you can make your own HDR display! Actually, that's something I've been kicking around for a while.
garydion8 years ago
Glad to see someone else using these displays! Should you be interested in a simpler circuit I am using an ATmega8 and a single 74HC373 to drive this display. Less hardware, but probably not quite as bright as I'm multiplexing red/green. I'm working with a friend to create a JAVA app that streams animations to the micro resulting in a very similar effect. Once downloaded to flash, we'll end up with some animated "amulets", much like the Christmas ornaments seen here recently. Great instructable!
sethj (author)  garydion8 years ago
thanks, this is my first instructable. this site is pretty cool! i'm wondering, how are you going about the streaming? i had considered having my python script dump straight into rs232 serial and putting a max232 on the board, but haven't gotten around to it yet... usb would be cooler.
Jacob S.8 years ago
thats pretty cool, I love projects like this, you know, with no practical usage. I didn't know they sold led matrixes like that, I'll have to get a few peace out
Should've done it for an intro with less happening in it. Otherwise, pretty good.
sethj (author)  inevitable_chaos8 years ago
thanks! i had wanted to do something easy like Lost with its big zooming "LOST" but i don't have any dvds of it. the code and everything is included here so if anyone wants to make a data set of something but not build the device, i can try try and load it onto mine and post the video... won't have sound though :)
PetervG8 years ago
It seems to me like the 8x8 matrix playing the Futurama intro was just flashing random things.
sethj (author)  PetervG8 years ago
yeah, it does look kind of random. looking at the code, though, you can see that it is in fact a direct resampling of the show...