user15072: I am working on a project where i emulate the EDID of a screen to force a source into sending data on a certain resolution.
I read the original EDID code of a screen and change the timings into the resolution I want to force the source in, i send this changed EDID code to the source with an Arduino uno when the source gives a read on address 0x50 (where the EDID located, see handshake). We have an HDMI in/out with the data lines connected thru and the DDC lines (source) connected to the Arduino that we can send the changed EDID to the source (i²c protocol).
I can change the resolution successfully on some sources, and on some it doesn’t change. The attached screen doesn’t find a source. I use the same code for both scenarios.
#include <DTWI.h>
#include <Wire.h>         //BUFFER_LENGTH = 256

uint8_t edid[256] = {
 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x4C, 0x2D, 0xF4, 0x0C, 0x45, 0x52, 0x46, 0x31, 0x15, 0x19, 0x01, 0x03, 0x80, 0x3C, 0x22, 0x78, 0x2A, 0x52, 0x95, 0xA5, 0x56, 0x54, 0x9D, 0x25, 0x0E, 0x50, 0x54, 0xBF, 0xEF, 0x80, 0x71, 0x4F, 0x81, 0xC0, 0x81, 0x00, 0x81, 0x80, 0x95, 0x00, 0xA9, 0xC0, 0xB3, 0x00, 0x01, 0x01, 0x02, 0x3A, 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C, 0x45, 0x00, 0x56, 0x50, 0x21, 0x00, 0x00, 0x1E, 0x01, 0x1D, 0x00, 0x72, 0x51, 0xD0, 0x1E, 0x20, 0x6E, 0x28, 0x55, 0x00, 0x56, 0x50, 0x21, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x32, 0x4B, 0x1E, 0x51, 0x11, 0x00, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x53, 0x32, 0x37, 0x45, 0x33, 0x37, 0x30, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x62, 0x02, 0x03, 0x1B, 0xF1, 0x46, 0x90, 0x04, 0x1F, 0x13, 0x03, 0x12, 0x67, 0x03, 0x0C, 0x00, 0x10, 0x00, 0x80, 0x22, 0x23, 0x09, 0x07, 0x07, 0x83, 0x01, 0x00, 0x00, 0x01, 0x1D, 0x00, 0xBC, 0x52, 0xD0, 0x1E, 0x20, 0xB8, 0x28, 0x55, 0x40, 0x56, 0x50, 0x21, 0x00, 0x00, 0x1E, 0x8C, 0x0A, 0xD0, 0x90, 0x20, 0x40, 0x31, 0x20, 0x0C, 0x40, 0x55, 0x00, 0x56, 0x50, 0x21, 0x00, 0x00, 0x18, 0x8C, 0x0A, 0xD0, 0x8A, 0x20, 0xE0, 0x2D, 0x10, 0x10, 0x3E, 0x96, 0x00, 0x56, 0x50, 0x21, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3D
};  

void receiveEvent(int receivedByte)
{
    if (receivedByte == 1)          //If there is 1 byte received
    {
      int receivedValue = Wire.read() << 1;
      receivedValue |= Wire.read();
      Serial.print("Read byte: ");
      Serial.print(receivedValue); 
      Serial.println();
    }
    else
    {
        Serial.println("Not the amount of bytes that was expected: ");
        Serial.print(receivedByte); 
    }  

    while(Wire.available())
    {
        Wire.read();
    }
    return;
}

void requestEvent()
{  
      Serial.println();

     for (int i = 0; i < 256; i++){
            Wire.write(edid[i]);               //Write EDID
            Serial.print(edid[i], HEX);      //Print EDID
            Serial.print(",");  
     }

    Serial.println(); 
    Serial.println("Finished");      //Write is complete

}  

void setup()
{
  Serial.begin(9600); 
  Serial.println("**** HDMI ****");
  pinMode(2, OUTPUT);          //Hot plug detection
  Wire.begin(0x50);  
  digitalWrite(2, LOW); 
  delay(20);
  digitalWrite(2, HIGH);         //Source knows that a screen is attached and want to read the edid of the screen

  Wire.onReceive(receiveEvent);  
  Wire.onRequest(requestEvent); 
}

void loop()
{

}

The following attached pictures are the EDID handshakes without the Arduino involved. 
Handshake 1: This is an HDMI 1.4 device 
Handshake 2: This is another HDMI 1.4 device
You can see that the handshakes are the same. 
My code only works on handshake 1.
Does anyone have an idea why it doesn't work on the other devices ?
Does it has to do with the Start/Restart ?
Regards !

user15498: I'm not an expert in HDMI/DDC, but I have some theories to remove potential problems:

"Wire.onRequest/Wire.onReceive" could be before "digitalWrite(2, HIGH)", to really represent "OK, you can send me data now" (Arduino isn't the fastest HW, and Arduino libs add extra overhead - lots of condition races can occur);
You could use "Write.write(did, 256)", instead of writing one byte to I2C then another via serial (again, racing conditions, specially since serial writing is slow);
If I'm not misunderstanding, the byte received from HDMI means the byte you should start transmitting EDID (ex: for "0", do a "Wire.write(edid, 128)", for "0x80", do a "Wire.write(edid + 0x80)"). This is a common approach for reading from PROM chips. HDMI have a 5V pin to allow PROM reading from turned-off devices, and byte 127 from EDID means "I may have more 128 bytes for you".
Are you doing simple tests, with unmodified data? Ex: read EDID from device X, test that same EDID, then test with modified data?


15072: <p>I am working on a project where i emulate the EDID of a screen to force a source into sending data on a certain resolution.</p>

<p>I read the original EDID code of a screen and change the timings into the resolution I want to force the source in, i send this changed EDID code to the source with an Arduino uno when the source gives a read on address 0x50 (where the EDID located, see handshake). We have an HDMI in/out with the data lines connected thru and the DDC lines (source) connected to the Arduino that we can send the changed EDID to the source (i²c protocol).</p>

<p>I can change the resolution successfully on some sources, and on some it doesn’t change. The attached screen doesn’t find a source. I use the same code for both scenarios.</p>

<pre><code>#include &lt;DTWI.h&gt;
#include &lt;Wire.h&gt;         //BUFFER_LENGTH = 256

uint8_t edid[256] = {
 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x4C, 0x2D, 0xF4, 0x0C, 0x45, 0x52, 0x46, 0x31, 0x15, 0x19, 0x01, 0x03, 0x80, 0x3C, 0x22, 0x78, 0x2A, 0x52, 0x95, 0xA5, 0x56, 0x54, 0x9D, 0x25, 0x0E, 0x50, 0x54, 0xBF, 0xEF, 0x80, 0x71, 0x4F, 0x81, 0xC0, 0x81, 0x00, 0x81, 0x80, 0x95, 0x00, 0xA9, 0xC0, 0xB3, 0x00, 0x01, 0x01, 0x02, 0x3A, 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C, 0x45, 0x00, 0x56, 0x50, 0x21, 0x00, 0x00, 0x1E, 0x01, 0x1D, 0x00, 0x72, 0x51, 0xD0, 0x1E, 0x20, 0x6E, 0x28, 0x55, 0x00, 0x56, 0x50, 0x21, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x32, 0x4B, 0x1E, 0x51, 0x11, 0x00, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x53, 0x32, 0x37, 0x45, 0x33, 0x37, 0x30, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x62, 0x02, 0x03, 0x1B, 0xF1, 0x46, 0x90, 0x04, 0x1F, 0x13, 0x03, 0x12, 0x67, 0x03, 0x0C, 0x00, 0x10, 0x00, 0x80, 0x22, 0x23, 0x09, 0x07, 0x07, 0x83, 0x01, 0x00, 0x00, 0x01, 0x1D, 0x00, 0xBC, 0x52, 0xD0, 0x1E, 0x20, 0xB8, 0x28, 0x55, 0x40, 0x56, 0x50, 0x21, 0x00, 0x00, 0x1E, 0x8C, 0x0A, 0xD0, 0x90, 0x20, 0x40, 0x31, 0x20, 0x0C, 0x40, 0x55, 0x00, 0x56, 0x50, 0x21, 0x00, 0x00, 0x18, 0x8C, 0x0A, 0xD0, 0x8A, 0x20, 0xE0, 0x2D, 0x10, 0x10, 0x3E, 0x96, 0x00, 0x56, 0x50, 0x21, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3D
};  

void receiveEvent(int receivedByte)
{
    if (receivedByte == 1)          //If there is 1 byte received
    {
      int receivedValue = Wire.read() &lt;&lt; 1;
      receivedValue |= Wire.read();
      Serial.print("Read byte: ");
      Serial.print(receivedValue); 
      Serial.println();
    }
    else
    {
        Serial.println("Not the amount of bytes that was expected: ");
        Serial.print(receivedByte); 
    }  

    while(Wire.available())
    {
        Wire.read();
    }
    return;
}

void requestEvent()
{  
      Serial.println();

     for (int i = 0; i &lt; 256; i++){
            Wire.write(edid[i]);               //Write EDID
            Serial.print(edid[i], HEX);      //Print EDID
            Serial.print(",");  
     }

    Serial.println(); 
    Serial.println("Finished");      //Write is complete

}  

void setup()
{
  Serial.begin(9600); 
  Serial.println("**** HDMI ****");
  pinMode(2, OUTPUT);          //Hot plug detection
  Wire.begin(0x50);  
  digitalWrite(2, LOW); 
  delay(20);
  digitalWrite(2, HIGH);         //Source knows that a screen is attached and want to read the edid of the screen

  Wire.onReceive(receiveEvent);  
  Wire.onRequest(requestEvent); 
}

void loop()
{

}
</code></pre>

<p>The following attached pictures are the EDID handshakes without the Arduino involved. </p>

<p>Handshake 1: This is an HDMI 1.4 device <a href="https://i.stack.imgur.com/8YSMW.png" rel="noreferrer"><img src="https://i.stack.imgur.com/8YSMW.png" alt="HDMI 1.4 device"></a></p>

<p>Handshake 2: This is another HDMI 1.4 device<a href="https://i.stack.imgur.com/HXRxR.png" rel="noreferrer"><img src="https://i.stack.imgur.com/HXRxR.png" alt="Another HDMI 1.4 device"></a></p>

<p>You can see that the handshakes are the same. 
My code only works on handshake 1.</p>

<p>Does anyone have an idea why it doesn't work on the other devices ?</p>

<p>Does it has to do with the Start/Restart ?</p>

<p>Regards !</p>
 15498: <p>I'm not an expert in HDMI/DDC, but I have some theories to remove potential problems:</p>

<ol>
<li>"Wire.onRequest/Wire.onReceive" could be before "digitalWrite(2, HIGH)", to really represent "OK, you can send me data now" (Arduino isn't the fastest HW, and Arduino libs add extra overhead - lots of condition races can occur);</li>
<li>You could use "Write.write(did, 256)", instead of writing one byte to I2C then another via serial (again, racing conditions, specially since serial writing is slow);</li>
<li>If I'm not misunderstanding, the byte received from HDMI means the byte you should start transmitting EDID (ex: for "0", do a "Wire.write(edid, 128)", for "0x80", do a "Wire.write(edid + 0x80)"). This is a common approach for reading from PROM chips. HDMI have a 5V pin to allow PROM reading from turned-off devices, and byte 127 from EDID means "I may have more 128 bytes for you".</li>
<li>Are you doing simple tests, with unmodified data? Ex: read EDID from device X, test that same EDID, then test with modified data?</li>
</ol>
