Thursday, May 15, 2014

FT800 with Streaming Video

I like to check out the thrift stores in my area for one of a kind technical gems to add to my collection. A few years ago I came across a Connectix QuickCam. This is one of the earliest webcams that didn't require a separate video capture card. Due to how easy it was to install, it was incredibly popular. So much so that Logitech ended up buying Connectix out and forking the product under their own brand.

Connectix QuickCam
When I saw it in the store I really had no idea what it was aside from the fact that it was a webcam and it had a parallel port. My first instinct was that a parallel port is simply a collection of TTL lines that I could emulate with a modern microcontroller. I finally had some time to put it into action and decided to stream video frames from the camera to a Gameduino 2 and the FT800 video processor that it uses.



The results were great, aside from the low image quality of the camera. This experiment proves the concept of using an FT800 to composite motion video with other visual elements. A better image sensor would provide a really cool experience.

Keep reading to see how I did it!

The Camera


The first step was to write a driver for the camera. The camera is very well documented by the original manufacturer, Connectix. Unfortunately the specification is still protected by an NDA. If you search hard enough, you can find it ;] The designers obviously had some ulterior motives when designing the protocol. In numerous sections of the specification there are references to using the camera with a non-parallel port interface.

QuickCam with FT800
There is a PIC microcontroller embedded in the connector of the QuickCam that implements a protocol for communicating with the camera.

QuickCam Guts :]
The entire protocol is handshake-driven. The host platform puts a word on the data bus of the parallel port and raises and lowers a line to indicate that it is ready for the camera to read it. The camera raises and lowers another line to indicate that it has read the data. This sequence is used to issue commands to the camera.

Gameduino 2
Below is the code for the send byte routine. I usually define a struct to model devices like this to make it independent of pinout. I decided that this was just an experiment and went for hard-coded pins. I had some skew issues and had to insert a short delay after placing data on the bus. I corrected this with a short delay.
void QuickCam_SendByte(uint8_t byte)
{
    SystemGpioC.Output.Port &= 0xFC03;
    SystemGpioC.Output.Port |= (byte << 2);
    for(volatile int i = 0; i < 5; i++);

    QuickCam_ReadByte();
}

uint8_t QuickCam_ReadByte()
{
    SystemGpioA.Output.P11 = true;
    while(!(SystemGpioA.Input.P8));
    
    uint8_t byte = ((SystemGpioC.Input.Port >> 10) & 0x0F) << 4;

    SystemGpioA.Output.P11 = false;
    while(SystemGpioA.Input.P8);

    byte |= ((SystemGpioC.Input.Port >> 10) & 0x0F);
    byte ^= 0x88;
    
    return byte;
}

The FT800


While I was brainstorming for this experiment I had to implement a few of the commands for dealing with bitmaps. I realized that a bitmap is very loosely defined in the context of the FT800. You simply give it a pointer and tell it the image format,  stride and height. The FT800 assumes that everything you are telling it is correct and starts to render pixel data on the screen. If the pointer is not valid you will get garbage rendered onto the screen.

I wondered what would happen if a bitmap handle was modified after being rendered to the screen. The results were exactly as I had expected: the screen updates! Best of all, the screen updates without emitting a new display list. This effectively gives you a framebuffer that you can treat like a sprite. The graphics processor has 256kB of video RAM. This is more than enough room for a 320x240 RGB565 image. This is very cool and gives a reason to get excited about the compositing nature of the FT800 device.

The QuickCam can generate a test pattern. This is useful for validating endianness and color order (RGB, BGR).

QuickCam Test Pattern!
The FT800 supports bilinear scaling and there is no cost to this.  Below is a sample rendering four scaled-down versions of myself. This has no impact on system performance!

QuickCam Tiling

Hardware Interface


The hardware interface is simple enough. I used some female-to-female cables to connect to the MORPHO connector on the Nucleo board. These fit nicely on the male pins of the QuickCam parallel port connector.

Nucleo Interface
I also needed a way to power the QuickCam. The camera sniffs power from the PS/2 bus using a wedge. I created a small patch cable to power it from USB.

USB to PS/2 Power Adapter

A Note About Performance


The QuickCam is an incredibly antiquated device. The FT800 in this demo is clocked at 21MHz. This would permit a 320x240 RGB565 frame to be transmitted in 58ms. This would give a framerate of around 17fps. The FT800 can be clocked faster, but the camera cannot.  I would love to get my hands on a more modern camera module and try this out again. Some camera modules these days even support hardware JPEG encoding. The FT800 supports hardware JPEG decoding! This would give an incredible framerate while transferring a low amount of data.

Conclusion


The more I use the FT800, the more I realize how powerful it is. With some clever tricks you can convince it to do some very interesting acrobatics. I would be interested in an FT800 with more graphics memory. You could create a memory protected compositing window manager by simply allowing applications to only paint data into their data region. The individual frame buffers would be shown and hidden by the various UI elements. Interesting stuff.

I hope you have enjoyed reading this article! As always, leave your thoughts in the comments!

2 comments :

  1. Is that a Nucleo board you are using to drive the Gameduino 2? Did you get the Gameduino 2 library to run on a Nucleo?

    ReplyDelete
    Replies
    1. That's correct, I am using the Nucleo board to drive the Gameduino 2. I wrote my own Gameduino 2 library (and driver framework for the STM32 processor).

      Delete