Friday, 6 September 2013

Arduino 80x25 TV Video Output Library

[Update: Please see the new version which supports multiple fonts and 'medium resolution' graphics]

Arduino TV Out has been around for a while, but you can't get many characters on the screen and uses a lot of the Arduino's resource. This is a library which will let you generate an 80x25 text screen on a TV or monitor from an Ardiuno. Well I say from an Arduino, it's more like two Arduinos, or to be precise, an Arduino and a second ATMega328P as a video processor, and one additional TTL chip.
The video processing work is all done by the second ATMega328P, the video processor. This leaves the main processor (the ATMega328P on the Arduino) to do whatever you like. There is a simple 8 bit data transfer whenever a new character is to be added to the display, in a similar way to driving an LCD display. The concept comes from Grant Searles Monitor and Keyboard interface, itself an update of code by Daryl Rictor (40x25 display using an ATmega8). The code in the second chip is unmodified from Grant's (download from his page above). I've completely rewritten the Arduino code, now in the form of a library to make it easier to use.

           Shift Register --> Char Data
               /                   \ 
Arduino <==> Video Processor        + ==> Video
               \                   /
                   Composite Sync

The idea is basically this, the Arduino (the first ATMega328P) has an 8 bit output port and two control lines. This interfaces to the video processor (the second ATMega328P). This has an 8 bit output port and 1 control line which is fed to a 74LS165 or 74HCT166 shift register (the pinouts are different, but they can both provide the necessary functionality, you may have more luck finding the 165) [Update: the 166 is preferable, and the HCT version should be used if possible]. The output of the shift register is the character video output data. There is also a composite sync is output from video processor. The composite sync and video data are combined via two resistors and this forms the composite video output. This composite video output is suitable to drive a modern LCD TV or an old CRT TV or monitor.
OK, so how do you do it? Well first you need to program the second microcontroller. This is written in assembler and does not use the Arduino bootloader, so needs to be uploaded via a programmer. There are many options, use an external programmer, use something like the USBTiny ISP to program in circuit, or use the Ardunio as an ISP.
If using an external programmer, such as the MiniPro, select ATMega328P, set the fuses to E6 D9 FF and select Grant's SBCVideo.hex file.
Alternatively, since there is already going to be an Arduino and a second ATMega328P, Arduino as ISP can be used. Wire up the circuit as per the Arduino as ISP demo (leave some space for the 74LS165). Here is an excellent tutorial on Arduino as ISP, and more info on avrdude.
Once built up, you can test it in the Arduino environment by selecting Arduino As ISP from the Programmer menu, As a test, load up the 'blink' example and use 'Upload using Programmer' to upload it. If all is well, the LED on digital pin 13 will blink. This is running from the second ATMega328P (their pin 13's are connected together). You can easily test this if you remove the wire and see it stop flashing. If it keeps flashing, you've reporgrammed the Arduino instead, try again. The fuses need to be set, and a hex file uploaded. This cannot be done from the Arduino environment, so you need to use avrdude on the command line to program the device. The commands required are as follows (change the com port as necessary)

  1. avrdude -P COM3 -b 19200 -c avrisp -p m328p -n
  2. avrdude -P COM3 -b 19200 -c avrisp -p m328p -U lfuse:w:0xe6:m
  3. avrdude -P COM3 -b 19200 -c avrisp -p m328p -U hfuse:w:0xd9:m
  4. avrdude -P COM3 -b 19200 -c avrisp -p m328p -U efuse:w:0xff:m
  5. avrdude -P COM3 -b 19200 -c avrisp -p m328p -U flash:w:SBCVideo.hex

Once the video processor is programmed, wire it up as per the circuit diagram. The pins on the video processor should remain the same (unless you want to modify the source). The pins on the Arduino end can be any. I chose the nearest ones. The only exception was choosing digital pin 13 as the Ack pin. This just shows activity on the LED on the Arduino for diagnostic purposes. The pin connections are:

  • Video Data In 0: Arduino D12 - ATMega328P pin 15
  • Video Data In 1: Arduino D11 - ATMega328P pin 16
  • Video Data In 2: Arduino D10 - ATMega328P pin 17
  • Video Data In 3: Arduino D9 - ATMega328P pin 18
  • Video Data In 4: Arduino D8 - ATMega328P pin 19 
  • Video Data In 5: Arduino D7 - ATMega328P pin 23 
  • Video Data In 6: Arduino D6 - ATMega328P pin 24 
  • Video Data In 7: Arduino D5 - ATMega328P pin 25
  • Video Available: Arduino D4 - ATMega328P pin 26 
  • Video Ack: Arduino D13 - ATMega328P pin 27
  • Reset: Arduino Reset - ATMega328P pin 1
  • 16 MHz Crystal to ATMega328P pins 9 and 10
  • 22pf capacitors from ATMega328P pins 9 and 10 to GND
  • Video Data Out 0: ATMega328P pin 2 - 74LS165 pin 11
  • Video Data Out 1: ATMega328P pin 3 - 74LS165 pin 12
  • Video Data Out 2: ATMega328P pin 4 - 74LS165 pin 13
  • Video Data Out 3: ATMega328P pin 5 - 74LS165 pin 14
  • Video Data Out 4: ATMega328P pin 6 - 74LS165 pin 3
  • Video Data Out 5: ATMega328P pin 11 - 74LS165 pin 4
  • Video Data Out 6: ATMega328P pin 12 - 74LS165 pin 5
  • Video Data Out 7: ATMega328P pin 13 - 74LS165 pin 6
  • Shift Register Load: ATMega328P pin 28 - 74LS165 pin 1
  • Shift Register Clock 1: ATMega328P pin 10 - 74LS165 pin 2
  • Shift Register Clock 2: GND - Shift Register pin 15
  • Shift Register Serial Load: GND - Shift Register 10
  • Composite Sync Out: ATMega328P pin 14 via 1K to Composite Video Out
  • Video Out: 74LS165 pin 9 via 470R resistor to Composite Video Out

The breadboard wiring is as follows:
It should probably look neater than this.
Once that is built, you can get on with the coding. Download the Terminal library, unzip it and copy the 'terminal' folder into the library folder in your Arduino workspace. You should then be able to include the terminal.h file in your projects.
There are a number of examples provided, these show using the library to generate things like a BBC Micro startup screen.
Or from a Commodore Pet  (notice different cursor options are available):
Since the work is now being done by the video processor, it leaves most of the Arduino free to do something more useful. For example, with a slight modification to Mike Field's Tiny BASIC, it can use the terminal as an output.
The input is from the serial terminal. It is left as an exercise for the reader to provide a keyboard of some sort. The I2C, and half of the input pins are still available, and SPI could be freed up so there are lots of choices.
Since the sync and video are available separately, it can even drive something odd like an Amstrad GT 65 green screen monitor which has separate sync and video inputs
The sync and video are wired to the monitor inputs directly. The the resistors can be removed if the composite video is not required.
The whole reason for doing all this is to drive a Commodore Pet monitor, as part of my Pet Project.
However, that turned out to be a lot more complicated. More on that later....