Project - VideoOut Module using Plain NETMF

I just posted VideoOut Module using Plain NETMF on Codeshare. Feel free to discuss and make suggestions here.

4 Likes

Very nice! :clap:

How long did it take to figure this one out?

@ Architect - It was actually pretty quick once I busted out the logic analyzer. It just took me a while to put the project in a form fit for sharing.

1 Like

The power of reverse engineering :slight_smile: Well done.

Think you could point me in the right direction for setting 640x480?

@ Skewworks - Well, if you want to stick to my reverse-engineered hack, the pointers for trying a different setting are in the comments, namely:

 
/// <summary>
/// Configures LCD RGB sockets to be compatible with the GHI VideoOut Module.
/// These settings were acquired by first using a Gadgeteer project to initialize the VideoOut Module at a resolution of 800x600 VGA.
/// The persistent LCD settings that were automatically set by Gadgeteer was then extracted using GHI's FEZ Config tool, so that
/// they can be reproduced here in plain NETMF. A similar reverse-engineering approach can be used if other resolutions are desired.
/// </summary>

And


/// <summary>
/// Transmits I2C commands to configure the VideoOut Module for VGA output at 800x600 resolution.
/// A Gadgeteer project was created to configure the VideoOut Module for 800x600 VGA output.
/// A logic analyzer then snooped on the I2C data being sent to the VideoOut Module as it was being initialized.
/// A similar approach can be used to capture the configuration data needed to initialize the VideoOut Module
/// if other resolutions or output formats are desired.
/// </summary>

In plain English:
Create a Gadgeteer project, and use the Gadgeteer driver properties/methods for the VideoOut Module to configure the module for 640x480. These will be written to the SOM’s configuration, and use FEZ Config to read-back that configuration on a future power cycle. Also, during a future reboot, use a logic analyzer connected to the I2C pins of the Chrontel chip to see what data is sent by Gadgeteer to configure the chip with your settings. The data is in Chrontel (register address + register value) pairs. I used a Saelae Logic16 for this.

–OR–

If GHI is nice, they can give you the driver source code and you can figure it out from there without all this hokey mucking around :slight_smile:

If I had a logic analyzer I’d stick with your approach. :wink:

I tried going over the docs you included but couldn’t really find an area that covered setting the resolution with I2C. I’m using the 800x600 for now on my project but if GHI wanted to share I wouldn’t mind being able to update my native VideoOut driver to handle different resolutions. :smiley:

Unfortunately we can’t share the code. It was even more if a nightmare trying to get any info from the chip manufacture.

@ Skewworks - Maybe this will be of any help: linux-2.6.32.9/ch7025_composite.c at master · rabeeh/linux-2.6.32.9 · GitHub

2 Likes

I think it just might. I’ll try it later and let you know. Thanks! :smiley:

Unfortunately this doesn’t work. Even looking at the 800*600 map things don’t quite line up.

Found It. I just need to do a little fiddling with the H&V Offset values. I’m very close. Post the code when it’s done.

Here you go

        private void VideoOutConfigVGA640x480()
        {
            OutputPort RESETB = new OutputPort(_socket.Pin3, true);                // Assign RESETB pin and set it high.
            SoftwareI2CBus i2cBus = new SoftwareI2CBus(_socket.Pin4, _socket.Pin5);   // Assign I2C SCL and SDA pins (corresponds to socket Pin 4 and 5 respectively if using Gadgeteer Socket Type X)

            // Chrontel CH7026's factory-assigned I2C device address is 0x76 (decimal 118), and its I2C bus operates at 100 kHz.
            SoftwareI2CBus.I2CDevice i2cDevice = i2cBus.CreateI2CDevice(0x76, 100);

            // Initialization sequence
            i2cDevice.Write(new byte[] { 0x02, 0x01 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x02, 0x03 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x03, 0x00 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x04, 0x39 }, 0, 2);

            //i2cDevice.Write(new byte[] { 0x06, 0x6B }, 0, 2);
            i2cDevice.Write(new byte[] { 0x08, 0x08 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x09, 0x80 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x0C, 0xD2 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x0D, 0x08 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x0F, 0x1A }, 0, 2);   // Combines for 640x800 (horizontal input / output)
            i2cDevice.Write(new byte[] { 0x10, 0x80 }, 0, 2);   // 80   last 8 bytes of 640
            i2cDevice.Write(new byte[] { 0x11, 0x3E }, 0, 2);   // 20   last 8 bytes of 800
            i2cDevice.Write(new byte[] { 0x12, 0x40 }, 0, 2);   // HSync & Offset
            i2cDevice.Write(new byte[] { 0x13, 0xAA }, 0, 2);   // H Offset
            i2cDevice.Write(new byte[] { 0x14, 0x60 }, 0, 2);   // HSync
            i2cDevice.Write(new byte[] { 0x15, 0x11 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x16, 0xE0 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x17, 0x0D }, 0, 2);   // Vertical combine
            i2cDevice.Write(new byte[] { 0x19, 0x19 }, 0, 2);   // Input height
            i2cDevice.Write(new byte[] { 0x1A, 0x02 }, 0, 2);   // Output height
            i2cDevice.Write(new byte[] { 0x1B, 0x23 }, 0, 2);   // Sync combine
            i2cDevice.Write(new byte[] { 0x1C, 0x20 }, 0, 2);   // Offset
            i2cDevice.Write(new byte[] { 0x1D, 0x20 }, 0, 2);   // Sync
            i2cDevice.Write(new byte[] { 0x1F, 0x28 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x20, 0x80 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x21, 0x12 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x22, 0x58 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x23, 0x74 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x25, 0x01 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x26, 0x04 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x37, 0x20 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x39, 0x20 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x3B, 0x20 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x41, 0x9A }, 0, 2);
            i2cDevice.Write(new byte[] { 0x4D, 0x03 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x4E, 0xC5 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x4F, 0x7F }, 0, 2);
            i2cDevice.Write(new byte[] { 0x50, 0x7B }, 0, 2);
            i2cDevice.Write(new byte[] { 0x51, 0x59 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x52, 0x12 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x53, 0x13 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x55, 0xE5 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x5E, 0x80 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x69, 0x64 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x77, 0x03 }, 0, 2);

            // Finalize sequence
            i2cDevice.Write(new byte[] { 0x7D, 0x62 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x04, 0x38 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x06, 0x71 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x03, 0x00 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x03, 0x00 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x03, 0x00 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x03, 0x00 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x03, 0x00 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x06, 0x68 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x02, 0x02 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x02, 0x03 }, 0, 2);
            i2cDevice.Write(new byte[] { 0x04, 0x00 }, 0, 2);

            byte registerAddressToRead = 0x00;      // Address for Chrontel CH7026 "Device ID Register".
            byte[] registerContents = new byte[1];  // Chrontel CH7026 should return a Device ID of 0x54 (decimal 84).
            int numWritten, numRead;                // Number of bytes written and read

            // Read the value stored in the Chrontel Device ID Register:
            i2cDevice.WriteRead(new byte[] { registerAddressToRead }, 0, 1, registerContents, 0, registerContents.Length, out numWritten, out numRead);

            i2cBus.Dispose();
        }

Also a minor change to the LCDConfig

                        lcdConfig.OutputEnableIsFixed = false;
                        lcdConfig.OutputEnablePolarity = false;
4 Likes

Collaboration at its finest! :slight_smile:

1 Like

Cool.

Can we get it to do more ? The CH7026 is capable of 720p or 1080i :slight_smile:

1 Like

Yes, I plan on adding more support. VideoOut will be added to my native gadgeteer collection with as many resolutions as I can manage.

1 Like

OK, looks like 1024x768 won’t happen. Even the Raptor gets ticked just telling the board to be that high a resolution. I’ll get the 320x240 up though.

I’ve also modified the IDisplayHAL interface to allow for selecting from multiple resolutions.

@ Skewworks - The maximum resolution for our boards is currently 800x600. We can look into increasing that at some point on the G400 given how much memory it has.

1 Like

@ John - the processor itself maxes out at 800x600

@ Gus - Looking at the datasheet, that is correct.

@ Skewworks - Looks like 800x600 is the max then.

@ Gus - We need a faster mainboard then 8)