Monday, 16 September 2013

Arduino 80x25 TV Video Output Library I2C Mode

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

I know I only updated the Arduino 80x25 text tv / video output library yesterday, but whilst I was doing that, a further improvement occurred to me. The original interface was 8 bit parallel with two handshaking lines. This is about as fast as it is going to get, but tricky if you don't have 10 I/O lines available. The recent update was to add 4 bit mode. This effectively halved the speed by splitting the data into two nibbles, but reduced the required I/O pins to 6 (4 bits plus two handshaking). Well. I thought I could take that a step further. It is again fewer pins, now only two are required, but it is slower than the parallel version.
My initial thought was to use serial, but the hardware UART on the is on two pins of port D, and the full 8 bits of port D are required to drive the shift register. Writing the character data to the shift register has to be accomplished in 8 processor instructions, so only a write to a complete 8 bit port is possible. The UART is also interrupt driven, and the timer interrupts need to be maintained for the display updates. The beauty of the 8 bit interface was that it could be polled in the deadspace between timer interrupts.
So what else is available? SPI is an option, but is also interrupt driven. The final thought was the I2C. The ATMega328P TWI (Two Wire Interface) is fully compatible with the Phillips I2C (I Squared C or Inter-Integrated Circuit) bus, and the terms TWI and I2C will be used interchangeably. It allows simple communication with up to 127 devices with only two pins. It can also be polled rather than interrupt driven for exactly the purpose of slow devices, or devices which are busy doing something else.  The two pins required are PC4 and PC5, analogue pins 4 and 5. One of these was used on the parallel version as the shift register load pin. That has been moved to PB1, but means there need to be two different versions of the video processor. Grant Searle's original with 4bit or 8bit parallel interface, and the new I2C only version.
The documentation on implementing an I2C slave was a bit minimal, most of the examples covering only master mode. But though it took quite a while to get it working, the actual code changes to the video processor boiled down to be quite minimal. Now it initialises itself as an I2C slave as address 1 (this can be changed in the code if required). In the main loop, instead of looking for new parallel data, it checks the I2C interface and reads new data if there is any. The changes at the Arduino end are a bit more complicated. The Wire library is used to setup the Arduino as a master device and data is sent though to the terminal. The wire library has a limit of 32 byte packets, so I split larger strings up before sending. I also found problems with packets of only a few bytes. This could be an issue in my code or the wire library, I'm not sure. I had to add a small (50uS) delay after sending small packets or it can loose every other packet sometimes. Below is a screenshot from a debug version which just printed the value of the character it received, it was being sent a sequence 00, 01, 02, 03 etc. up to FF and back to 00. As you can see, it starts ok, but where is 75, 77, 79 etc.? The delay seems to fix this and doesn't slow it down too much. 50uS may be a lot in terms of 16MHz processor clocks, but if all you're doing is echoing characters being typed, it's perfectly acceptable. As with the 4-bit mods, it can still update the screen much faster than it can be read.
The library has been updated to support I2C mode, and there is now a Hello World I2C sample with the character set in I2C mode. This was a good test as the characters and the spaces between are all sent individually, where as the two 80 character lines are sent as single text lines, and there are various control codes to position the slashes at the corners.
The new library can be downloaded here. This zip file includes the source and hex files and source for both versions of the video processor, and an updated version of the library which supports I2C mode.
It is possible to use the Video Processor in I2C mode without the library, just using the wire library.
  #include <Wire.h>

  void setup()
  {
    Wire.begin();
  
    Wire.beginTransmission(0x01);
    Wire.write("Hello, World!");
    Wire.endTransmission();
  }

  void loop()
  {
    // your code
  }
If you go for just the Wire library, you will need to deal with the issues of the 32 byte Wire buffer and small packets.