DIY TinyMarquee: an Attiny24 based scrolling marquee

Ever looked at a scrolling LED marquee, displaying news headlines and other worldly information, and thought, "I need that"? Well, as a little project we've built one from the ground up, hardware, firmware, software and all. This was conducted as an educational exercise in  PCB design, charlieplexing, software serial on AVRs, and web scraping.

I humbly present these notes in hope that they will provide some direction if you embark on a similar project. The source code and design files are up on a git repository. (All of this work is done and tested on Linux.) Edit: I made the python scripts more modular, but they are now interdependent, so if you're poking around with this, grab the entire Git repository to avoid missing functions, &c.

This is hardly the first DIY Marquee project out there in the wild. Here is a large one that appears to be all hand-routed on protoboard.  Here is one made from Christmas lights. Here is a network enabled one. One using ping-pong balls. And here is one implemented in the rear window of a car. To the best of my knowledge, this DIY project is unique in using charlieplexing and software serial to push the capabilities of the AtTiny24.

A terminal stock ticker

The python module ystockquote can pull stock prices and other information from Yahoo finance. With this library, grabbing a stock price is as easy as "get_price(stockname)". So, we have a short python script to download stock prices, format them, and save to a local file. There is also a less well tested news headline scraper.

Bitmap fonts 

We need to translate text into a format that we can send to a scrolling marquee. We send raw pixels to the marquee ( so that we can adjust fonts and graphics without re-loading the firmware ). To accomplish this, we send new columns as 5-bit integers over serial. But before we get to that, we need to make a 5-pixel high font. I used Gimp to draw a font and a short Jython script to convert it into bit-packed integers representing columns of pixels for each letter.*

To test converting text to the bitmap font, the script "scroll" takes the scraped data and scrolls it across a simulated marquee in the terminal ( there is also the short "terminal_marquee" script which scrolls indefinitely, but updates intermittently in the background )


The hardware consists of 90 3mm LEDs arranged in a 5x18 grid. These are driven by 10 IO lines of an AtTiny24. The remaining free IO line is used to poll and listen for serial data. There is also a 10K pull-up resistor on the AtTiny's reset pin, and a 0.1μF decoupling capacitor near the power pins. The surface mount AtTiny bridges one row of the LED pins. This is mildly annoying to solder but not prohibitively difficult if you are already practiced in SMT soldering. Thats it! not much to it. The marquee gets power and data from a USB to TTL serial adapter.


Charlieplexing is a way to drive tons of LEDs form only a few pins. Since LEDs only light up when current is passed in one direction, you can place two LEDs for every unique pair of IO lines at your disposal. This lets you drive N*(N-1) LEDs from N IO pins.**

PCB design

Update : I apologize for the lack of schematic. None exists. The layout was done entirely within Eagle's board editor without a schematic step -- this is all I have.

While it is possible to wire up the grid of LEDs by hand, I would not recommend it. Instead of going through this tedium, you can design a custom board and get it professionally fabricated. I use the free version of Eagle Cad to design and prepare boards for manufacture. A full Eagle tutorial is beyond the scope of this writeup, but numerous tutorials can be found elsewhere online. The Eagle design files for this project can be found here.

Exporting gerber files for board fabrication

One you have finalized a board, you need to prepare design files for fabrication. PCB designs get exported to so called "Gerber" files, which are like the PDFs of circuit board design. Once you have these files you can send them off to a fab house for production. My favorite tutorial for this is on Hackaday.

For one-off boards, BatchPCB is the go-to place. For small runs, consider Advanced Circuits or Seeed studio's Fusion PCB service. For larger runs (more than 30), depending on board size, Goldphoenix is the place to go. Depending on which service you choose, you should get boards in a few days to five weeks. I used Seeed because it is relatively cheap, and it took about a month to ship to the US.

Part sourcing 

For cheap LEDs I use Ebay. For all other components ( especially the AVR microcontollers ), I source from Mouser or Digikey. For a low cost USB to Serial adaptor, look for "USB To RS232 TTL PL2303HX" on Ebay . These are cheaper than, say, an FTDI cable from Sparkfun, and have worked great for me. I'd hoped to save a few bucks by using charlieplexing and the AtTiny14 in the design -- the total cost of each board, shipping and USB-TTL converter included, from a lot of 10, is about $7.50:
10   boards     $30   
1000 LEDs       $10   
10   AtTiny     $14   
50   Resistors  $ 1   
10   Capacitors $ 1   
10   Headers    $ 1   
10   USB-TTL    $18   
       /10      $ 7.50

Cleaning the boards 

After you're finished soldering, remove any solder flux adhered to the board. Apart from being unsightly, flux can be conductive and corrosive and damage the board over time. Hackaday has a good tutorial on this. We filled an old jar with 90% Isopropanol, dunked the boards in there, and shook them around for a while -- it worked wonderfully.

Software serial 

The Attiny24 does not have hardware support for serial ( UART ), so we'll have to make a software implementation. For information about the RS-232 communication protocol, see the wiki. I used polling at twice the serial rate (4800Hz) to monitor incoming serial data, which is works for transmitting five bit packets. Further details about the firmware can be found in the C source file.

Compiling with avr-gcc 

I never remember the commands to compile and upload firmware, so here are the commands for future reference.

#compile source to a file a.o targeting the AtTiny24
avr-gcc -Os -mmcu=attiny24 ./display_serial.c -o a.o 

#extract the text and data sections to make a binary for the AVR
avr-objcopy -j .text -j .data -O binary a.o a.bin 

# check the size ( this should be smaller than the amount of available flash )
du -b ./a.bin

# upload the binary to ( in this case ) the AtTiny24 
avrdude -c avrispmkII -p t24 -B4 -P /dev/ttyUSB1 -U flash:w:a.bin 

So, now what?

I'm not sure. I guess these will probably just sit in my desk for a while. The news was getting depressing and I honestly don't care about stock prices, so for now it's just a marquee clock. I'm open to suggestions for cool applications of this hardware.


*If you don't have Jython or a working JVM installed, it may be easier for you to re-enter the font as text data and write a short conversion routine in python.

**If you're familiar with multiplexing there's a simple way to conceptualize board layout for charlieplexing. When you multiplex an NxN grid of LEDs, you use N IO lines to control power to the (-) ends of the LEDs, and N IO lines to control power to the (+) ends of the LEDs.  To go from multiplexing to charlieplexing, note that microcontroller pins can take on three sates : Low (-), High (+), and Off ("high impedence"). Each IO line can serve as both a (+) line and a (-) line. What happens if we use the same N pins to drive both the (-) and the (+) a multiplexed display? Everything works fine, as long as we use the "off" state to stop current. One problem: there some LEDs along the diagonal of the matrix that have their (+) and (-) driven by the same IO pin -- there is no way to make these light up. But, no worries, since we are laying out our own board, we can just delete these LEDs, or connect their (+) terminals to a reserved IO pin to regain control of them! Charlieplexed PCB design can be relatively simple: lay out a grid of LEDs as if you were to multiplex them, but connect the N anodes to the N cathodes, and either delete the N LEDs that end up being connected to the same IO line at both ends, or wire these up to a separate IO pin to finish things off.