One thing that often confuses people poking at DVI/HDMI signals is the EDID. The EDID is the 'device identifier data' that lets the computer know what kind of monitor is attached. To make it simple, the EDID is stored on an i2c EEPROM. If you reprogram the EEPROM, you've changed around the EDID.

The TFP401 video decoder chip never reads or writes the EEPROM/EDID, it has NO IDEA what is stored in the EDID!

Which sounds kinda odd - how does the TFP401 know what resolution to display then? The answer is that the computer defines the resolution of the monitor, and bases the decision on the EDID contents.

Usually the EDID tells the computer about half a dozen or so resolution options. However, with the TFP401, ther's only one resolution you should use: the native resolution of TTL display. That's because the TFP401 does not contain a video scaler - if you set the computer resolution to 800x480 while it is connected to a 1024x600 TTL display, you'll only get video in the top left corner. If you set the computer resolution to 1024x600 while it is connected to a 800x480 display, you'll get video that is cut off, and does not include the top right or bottom left sections.

So, basically, make sure the EDID contains the resolution you'll be connecting! We assume you'll be going with the ultra-common 800x480. You can reprogram the EDID using an Arduino or (possibly) a computer using the HDMI/DVI port if you have software to write the EDID that way.

To reprogram the EEPROM, disconnect the HDMI connector, and connect

  • 5V pin to Arduino 5V
  • GND pin to Arduino GND
  • SCL to Arduino SCL (A5 on an Arduino Uno)
  • SDA to Arduino SDA (A4 on an Arduino Uno)

As of February 7, 2024, this board has been revised to include a plug-n-play Stemma QT connector for the EDID EEPROM. If you have that version, you can use a STEMMA QT cable.

and use the following code to update the EDID:

#include <Wire.h> //I2C library


/* 480x272 @ 25mhz

uint8_t PROGMEM eepromdat[128] = {
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x04, 0x81, 0x43, 0x00, 0x01, 0x00, 0x00, 0x00, 
0x0C, 0x17, 0x01, 0x03, 0x81, 0x0A, 0x06, 0x78, 0x8A, 0xA5, 0x8E, 0xA6, 0x54, 0x4A, 0x9C, 0x26, 
0x12, 0x45, 0x46, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xC4, 0x09, 0xE0, 0x33, 0x10, 0x10, 0x14, 0x10, 0x08, 0x05, 
0x4A, 0x00, 0x5F, 0x36, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x41, 0x44, 0x41, 
0x46, 0x52, 0x55, 0x49, 0x54, 0x20, 0x34, 0x33, 0x20, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42
};
*/
/* Adafruit breakout @ 800x480 ! */ 
uint8_t PROGMEM eepromdat[128] = {
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x04, 0x81, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x11, 0x01, 0x03, 0x80, 0x0F, 0x0A, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x80, 0x0C, 0x20, 0x80, 0x30, 0xE0, 0x2D, 0x10, 0x28, 0x30,
0xD3, 0x00, 0x6C, 0x44, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17,
};

// I2C eeprom dumper
byte i2c_eeprom_read_byte(uint8_t deviceaddress, uint16_t eeaddress );

#define EEPROMSIZE 256UL  // 0.5 Kb
#define ADDRESS_SIZE 8

byte i2c_eeprom_read_byte(uint8_t deviceaddress, uint16_t eeaddress ) {
    byte rdata = 0xFF;
#if (ADDRESS_SIZE == 16)
    Wire.beginTransmission(deviceaddress);
    Wire.write((eeaddress >> 8)); // MSB
#else
    //deviceaddress |= (eeaddress >> 8);
    Wire.beginTransmission(deviceaddress); // MSB
#endif
    Wire.write(eeaddress); // LSB
    Wire.endTransmission();
    Wire.requestFrom(deviceaddress, (uint8_t)1);
    while (!Wire.available()); 
    rdata = Wire.read();
    return rdata;
}

void i2c_eeprom_write_byte(uint8_t deviceaddress, uint16_t eeaddress, byte data ) {
#if (ADDRESS_SIZE == 16)
    Wire.beginTransmission(deviceaddress);
    Wire.write((eeaddress >> 8)); // MSB
#else
    //deviceaddress |= (eeaddress >> 8);
    Wire.beginTransmission(deviceaddress); // MSB
#endif
    Wire.write((byte)eeaddress); // LSB
    Wire.write((byte)data);
    Wire.endTransmission();
}
  

void setup() {
  Wire.begin(); // initialise the connection
  Serial.begin(9600);
  Serial.println(F("EEPROM WRITER"));
  Serial.print(F("EEPROM data size: "));
  Serial.println(sizeof(eepromdat));
  Serial.println(F("Hit any key & return to start"));
  while (!Serial.available());
  byte b;
  Serial.println("Starting");
  for (uint16_t addr = 0; addr < EEPROMSIZE; addr++) {
    if (addr < sizeof(eepromdat)) {
      b = pgm_read_byte(eepromdat+addr);
    } else {
      b = 0xFF;
    }
     i2c_eeprom_write_byte(0x50, addr, b);
     delay(5);
     if ((addr % 32) == 0)
       Serial.println();
     Serial.print("0x");
     if (b < 0x10) Serial.print('0');
     Serial.print(b, HEX); //print content to serial port
     Serial.print(", ");
  }
  Serial.println("\n\r========\n\rFinished!");
  for (uint16_t addr = 0; addr < EEPROMSIZE; addr++) {
    if (addr < sizeof(eepromdat)) {
      b = pgm_read_byte(eepromdat+addr);
    } else {
      b = 0xFF;
    }
    uint8_t d =  i2c_eeprom_read_byte(0x50, addr);
    if ((addr % 32) == 0)
      Serial.println();
    Serial.print("0x");
    if (d < 0x10) Serial.print('0');
    Serial.print(d, HEX); //print content to serial port
    Serial.print(", ");

    if (b != d) {
       Serial.print(F("verification failed at 0x")); Serial.println(addr);
       while (1);
     }
  }
  Serial.println(F("\n\r\n\rVerified!"));
}

void loop() {
}

You can see we have an example for 480x272 there, for 4.3" screens. The reason we don't recommend it, tho, is that it overclocks the screens a bit and more-over, 480x272 is smaller than the 'minimal' 640x480 that most HDMI drivers really want. So during boot up or whatever, you won't get a display.

If you want to generate your own EDIDs and customize them, which is a great way to seriously lose like 4 hours of your life, you can download EDID editor software such as Deltacast or whatever you find when you google for "EDID editor" You only need the first 128 bytes (there are longer detailed EDID's that have an extra 128 byte 'chunk' but this decoder doesn't support all that stuff anyways)

While we dont think you could damage the TFP401 or display with a really messed up EDID, we still think you should only edit/customize the EDID if you're comfortable with some intense hex editing and EEPROM programming, its not for the faint of heart

This guide was first published on Oct 24, 2014. It was last updated on Mar 08, 2024.

This page (Editing the EDID) was last updated on Mar 08, 2024.

Text editor powered by tinymce.