IT66121 ic HDMI成帧器

IT66121 ic HDMI framer

我在让这个 IC 在我的硬件上工作时遇到了一些麻烦。使用 Arduino 发送 I2C 命令,当我将 IC 用作 "pass-thru" 发送我的同步和数据启用信号时,我可以获得 IC 响应甚至一些视频。

但我无法掌握显示内置模式生成器或生成同步的 IC 等基础知识。

#include "Wire.h"

#define HDMI_ADDRESS 0x4c

byte zero = 0x00; 

typedef struct structRegSetEntry 
{
    byte offset ;
    byte invAndMask ;
    byte OrMask ;
} RegSetEntry;

static RegSetEntry HDMITX_Init_Table[] = 
{
    {0x0F, 0x40, 0x00}, // Enable GRCLK (for i2c)

    {0x62, 0x08, 0x00}, // XP_RESETB
    {0x64, 0x04, 0x00},  // IP_RESETB
    {0x01,0x00,0x00},   //idle(100);

    {0x04, 0x20, 0x20}, //RESET HDMI
    {0x04, 0x1D, 0x1D}, // Set to wait for function enable
    {0x01,0x00,0x00},   //idle(100);

    {0x0F, 0x01, 0x00}, // bank 0 ;


    //low clock       
    {0x62, 0x90, 0x10}, // TMDS clk <80Mhz
    {0x64, 0x89, 0x09}, // PCLKIN <80MHz
    {0x68, 0x10, 0x10}, // TMDS clk <80Mhz
    {0x00, 0x00, 0x00} // End of Table
};

static RegSetEntry HDMITX_DefaultVideo_Table[] = 
{
    ////////////////////////////////////////////////////
    // Config default output format.
    ////////////////////////////////////////////////////
    {0x72, 0xff, 0x00},
    {0x70, 0xff, 0x00},

    // 2012/12/20 added by Keming's suggestion test
    {0x88, 0xF0, 0x00},

    //~jauchih.tseng@ite.com.tw
    {0x04, 0x08, 0x00}, //clear the RESET flag
    {0,0,0}
};

static RegSetEntry HDMITX_SetHDMI_Table[] = 
{
    ////////////////////////////////////////////////////
    // Config default HDMI Mode
    ////////////////////////////////////////////////////
    {0xC0, 0x01, 0x01}, // HDMI mode
 // {0xC0, 0x01, 0x00}, // DVI mode

    {0xC1, 0x03, 0x00}, // avmute (not muted) 
    {0xC6, 0x03, 0x03}, // Enable General Control packet, one for each field
    {0,0,0}
};

static RegSetEntry HDMITX_PwrOn_Table[] = 
{
    {0x0F, 0x78, 0x38},   // PwrOn GRCLK
    {0x05, 0x01, 0x00},   // PwrOn PCLK

    // PLL PwrOn
    {0x61, 0x20, 0x00},   // PwrOn DRV
    {0x62, 0x44, 0x00},   // PwrOn XPLL
    {0x64, 0x40, 0x00},   // PwrOn IPLL

    // PLL Reset OFF
    {0x61, 0x10, 0x00},   // DRV_RST
    {0x62, 0x08, 0x08},   // XP_RESETB
    {0x64, 0x04, 0x04},   // IP_RESETB
    {0x0F, 0x78, 0x18},   // PwrOn IACLK
    {0x00, 0x00, 0x00} // End of Table
};

byte HDMITX_ReadI2C_Byte(byte RegAddr)
{
     byte value;

    Wire.beginTransmission(HDMI_ADDRESS);
    Wire.write(RegAddr);
    Wire.endTransmission();
    Wire.requestFrom(HDMI_ADDRESS, 1);

    if (Wire.available())
    {
      value=Wire.read();
    }

    Wire.endTransmission();

    return value;
}

void HDMITX_WriteI2C_Byte(byte RegAddr, byte data)
{           
    Wire.beginTransmission(HDMI_ADDRESS);
    Wire.write(RegAddr);
    Wire.write(data);
    Wire.endTransmission();
}

void HDMITX_SetI2C_Byte(byte Reg, byte Mask, byte Value)
{
    byte Temp;

    if( Mask != 0xFF )
    {
      Temp=HDMITX_ReadI2C_Byte(Reg);
      Temp&=(~Mask);
      Temp|=Value&Mask;
    }
    else
    {
      Temp=Value;
    }

    HDMITX_WriteI2C_Byte(Reg, Temp);
}

void hdmitx_LoadRegSetting(RegSetEntry table[])
{
    int i ;

    for( i = 0 ;  ; i++ )
    {
        if( table[i].offset == 0 && table[i].invAndMask == 0 && table[i].OrMask == 0 )
        {
            return ;
        }
        else if( table[i].invAndMask == 0 && table[i].OrMask == 0 )
        {
            delay(table[i].offset);
        }
        else if( table[i].invAndMask == 0xFF )
        {
              HDMITX_WriteI2C_Byte(table[i].offset,table[i].OrMask);
        }
        else
        {
              HDMITX_SetI2C_Byte(table[i].offset,table[i].invAndMask,table[i].OrMask);
        }
    }
}



void setPatternGen()
{
        unsigned int HTotal, HDES, VTotal, VDES;
        unsigned int HDEW, VDEW, HFP, HSW, VFP, VSW;
        unsigned int HRS, HRE;
        unsigned int VRS, VRE;
        unsigned int H2ndVRRise;
        unsigned int VRS2nd, VRE2nd;
        byte Pol;



  //  // fmt   HActive VActive HTotal VTotal  H_FBH  H_SyncW   H_BBH V_FBH V_SyncW  V_BBH Scan VPolarity HPolarity
//    {  1,    640,    480,    800,   525,    16,    96,       48,   10,   2,       33,   PROG Vneg,     Hneg},// 640x480@60Hz         - CEA Mode [ 1]

        HTotal  = 800;// TimingTable[fmt_index].HTotal;
        HDEW    = 640;//TimingTable[fmt_index].HActive;
        HFP     = 16;//TimingTable[fmt_index].H_FBH;
        HSW     = 96;//TimingTable[fmt_index].H_SyncW;
        HDES    = HSW+ 48;//TimingTable[fmt_index].H_BBH;
        VTotal  = 525;//TimingTable[fmt_index].VTotal;
        VDEW    = 480;//TimingTable[fmt_index].VActive;
        VFP     = 10;//TimingTable[fmt_index].V_FBH;
        VSW     = 2;//TimingTable[fmt_index].V_SyncW;
        VDES    = VSW+ 33;//TimingTable[fmt_index].V_BBH;
/*
//   fmt HActive  VActive HTotal  VTotal    H_FBH  H_SyncW    H_BBH V_FBH   V_SyncW  V_BBH    Scan    VPolarity   HPolarity
//{  2,  720,     480,    858,    525,      16,    62,        60,   9,      6,        30,      PROG,  Vneg,       Hneg},// 720x480@60Hz         - CEA Mode [ 2]


        HTotal  = 858;// TimingTable[fmt_index].HTotal;
        HDEW    = 720;//TimingTable[fmt_index].HActive;
        HFP     = 16;//TimingTable[fmt_index].H_FBH;
        HSW     = 62;//TimingTable[fmt_index].H_SyncW;
        HDES    = HSW+ 60;//TimingTable[fmt_index].H_BBH;
        VTotal  = 525;//TimingTable[fmt_index].VTotal;
        VDEW    = 480;//TimingTable[fmt_index].VActive;
        VFP     = 9;//TimingTable[fmt_index].V_FBH;
        VSW     = 6;//TimingTable[fmt_index].V_SyncW;
        VDES    = VSW+ 30;//TimingTable[fmt_index].V_BBH;
 */

        HRS = HFP - 2;
        HRE = HRS + HSW;
        H2ndVRRise = HRS+ HTotal /2;

        VRS = VFP;
        VRE = VRS + VSW;

        VRS2nd = 0xFFF;
        VRE2nd = 0x3F;

        HDMITX_SetI2C_Byte(0x90, 0x06, 0x00); //polarity

        // write H2ndVRRise
        HDMITX_SetI2C_Byte(0x90, 0xF0, (H2ndVRRise&0x0F)<<4);
        HDMITX_WriteI2C_Byte(0x91, (H2ndVRRise&0x0FF0)>>4);
 //     HDMITX_SetI2C_Byte(0x90, 0xF0, 0xF0); //progressive HTOTAL = 0xFFF
 //     HDMITX_WriteI2C_Byte(0x91, 0xFF);


        // write HRS/HRE
        HDMITX_WriteI2C_Byte(0x95, HRS&0xFF);
        HDMITX_WriteI2C_Byte(0x96, HRE&0xFF);
        HDMITX_WriteI2C_Byte(0x97, ((HRE&0x0F00)>>4)+((HRS&0x0F00)>>8));

        // write VRS/VRE
        HDMITX_WriteI2C_Byte(0xa0, VRS&0xFF);
        HDMITX_WriteI2C_Byte(0xa1, ((VRE&0x0F)<<4)+((VRS&0x0F00)>>8));
        HDMITX_WriteI2C_Byte(0xa2, VRS2nd&0xFF);
        HDMITX_WriteI2C_Byte(0xa6, (VRE2nd&0xF0)+((VRE&0xF0)>>4));
        HDMITX_WriteI2C_Byte(0xa3, ((VRE2nd&0x0F)<<4)+((VRS2nd&0xF00)>>8));
        HDMITX_WriteI2C_Byte(0xa4, H2ndVRRise&0xFF);
        HDMITX_SetI2C_Byte(0xa5, 0x0f, ((H2ndVRRise>>8)&0x0f));
        HDMITX_SetI2C_Byte(0xb1, 0x51, ((HRE&0x1000)>>6)+((HRS&0x1000)>>8)+((HDES&0x1000)>>12));
        HDMITX_SetI2C_Byte(0xb2, 0x05, ((H2ndVRRise&0x1000)>>10)+((H2ndVRRise&0x1000)>>12));

      //HDMITX_SetI2C_Byte(0x90, 0x08, 0x08); //Enable Sync gen 

      //HDMITX_SetI2C_Byte(0xa5, 0x20, 0x20); //Enable DEOnly - ignore V/H sync

        HDMITX_SetI2C_Byte(0xa9, 0x40, 0x40); // pattern generator mux
        HDMITX_WriteI2C_Byte(0xad, 0x00);
        HDMITX_WriteI2C_Byte(0xae, 0x00);

        HDMITX_SetI2C_Byte(0xa8, 0x01, 0x01); //Enable pattern generator
        HDMITX_SetI2C_Byte(0x69, 0x80, 0x80); //release reset pattern generator


}

void setup()
{
  Wire.begin();
  Serial.begin(9600);
}

void loop()
{
      Serial.println("init...");


      //ID OK!!!
      Serial.println("reading ID");
      Serial.println(HDMITX_ReadI2C_Byte(0x00),HEX);
      Serial.println(HDMITX_ReadI2C_Byte(0x01),HEX);
      Serial.println(HDMITX_ReadI2C_Byte(0x02),HEX);
      Serial.println(HDMITX_ReadI2C_Byte(0x03),HEX);
      Serial.println("done ID");

      hdmitx_LoadRegSetting(HDMITX_Init_Table);

      hdmitx_LoadRegSetting(HDMITX_DefaultVideo_Table);
      hdmitx_LoadRegSetting(HDMITX_SetHDMI_Table);

      // enable DE
    //HDMITX_SetI2C_Byte(0x90, 0x01, 0x00);

     //Use DE Only
     //When Reg_DEOnlyIn=1 , don’t care input vsync and hsync
     //setDEOnly();

     setPatternGen();

     hdmitx_LoadRegSetting(HDMITX_PwrOn_Table);

     Serial.println("done");

     while(1){}
}

如果我注释掉“setPatternGen();”并将我自己的视频信号发送到 IC 输入,我会得到视频输出,但我的目标是使用 IC 来 "format" 非-如此标准的视频输入到 HDMI,但正如我所说,我现在连模式发生器都没有。

我已经浏览了一些我找到的IT66121代码(大部分代码来自那里),我得到了datasheet和this IC programmer's guide,但是都很肤浅,没有详细解释操作(即使是基础知识)。

经过多次尝试和代码更改后,我终于让模式生成器开始工作了。 希望这个片段对某人有用

#include "Wire.h"

#define HDMI_ADDRESS 0x4c

byte zero = 0x00; 

typedef struct structRegSetEntry 
{
    byte offset ;
    byte invAndMask ;
    byte OrMask ;
} RegSetEntry;

static RegSetEntry HDMITX_Init_Table[] = 
{
    {0x0F, 0x40, 0x00}, // Enable GRCLK (for i2c)

    {0x62, 0x08, 0x00}, // XP_RESETB
    {0x64, 0x04, 0x00},  // IP_RESETB
    {0x01,0x00,0x00},   //idle(100);

    {0x04, 0x20, 0x20}, //RESET HDMI
    {0x04, 0x1D, 0x1D}, // Set to wait for function enable
    {0x01,0x00,0x00},   //idle(100);

    {0x0F, 0x01, 0x00}, // bank 0 ;

    //low clock       
    {0x62, 0x90, 0x10}, // TMDS clk <80Mhz
    {0x64, 0x89, 0x09}, // PCLKIN <80MHz
    {0x68, 0x10, 0x10}, // TMDS clk <80Mhz
    {0x00, 0x00, 0x00} // End of Table
};

static RegSetEntry HDMITX_DefaultVideo_Table[] = 
{
    ////////////////////////////////////////////////////
    // Config default output format.
    ////////////////////////////////////////////////////
    {0x72, 0xff, 0x00}, // no color conversion
    {0x70, 0xff, 0x00}, // RGB mode

    // 2012/12/20 added by Keming's suggestion test
 //   {0x88, 0xF0, 0x00},
    //~jauchih.tseng@ite.com.tw
    {0x04, 0x08, 0x00}, //clear the RESET flag
    {0,0,0}
};

static RegSetEntry HDMITX_SetHDMI_Table[] = 
{
    ////////////////////////////////////////////////////
    // Config default HDMI Mode
    ////////////////////////////////////////////////////
    {0xC0, 0x01, 0x01}, // HDMI mode
 //   {0xC0, 0x01, 0x00}, // DVI mode

    {0xC1, 0x03, 0x00}, // avmute (not muted) 
    {0xC6, 0x03, 0x03}, // Enable General Control packet, one for each field
    {0,0,0}
};

static RegSetEntry HDMITX_PwrOn_Table[] = 
{
    {0x0F, 0x78, 0x38},   // PwrOn GRCLK
    {0x05, 0x01, 0x00},   // PwrOn PCLK

    // PLL PwrOn
    {0x61, 0x20, 0x00},   // PwrOn DRV
    {0x62, 0x44, 0x00},   // PwrOn XPLL
    {0x64, 0x40, 0x00},   // PwrOn IPLL

    // PLL Reset OFF
    {0x61, 0x10, 0x00},   // DRV_RST
    {0x62, 0x08, 0x08},   // XP_RESETB
    {0x64, 0x04, 0x04},   // IP_RESETB
    {0x0F, 0x78, 0x18},   // PwrOn IACLK
    {0x00, 0x00, 0x00} // End of Table
};

byte HDMITX_ReadI2C_Byte(byte RegAddr)
{
     byte value;

    Wire.beginTransmission(HDMI_ADDRESS);
    Wire.write(RegAddr);
    Wire.endTransmission();
    Wire.requestFrom(HDMI_ADDRESS, 1);

    if (Wire.available())
    {
      value=Wire.read();
    }

    Wire.endTransmission();

    return value;
}

void HDMITX_WriteI2C_Byte(byte RegAddr, byte data)
{           
    Wire.beginTransmission(HDMI_ADDRESS);
    Wire.write(RegAddr);
    Wire.write(data);
    Wire.endTransmission();
}

void HDMITX_SetI2C_Byte(byte Reg, byte Mask, byte Value)
{
    byte Temp;

    if( Mask != 0xFF )
    {
      Temp=HDMITX_ReadI2C_Byte(Reg);
      Temp&=(~Mask);
      Temp|=Value&Mask;
    }
    else
    {
      Temp=Value;
    }

    HDMITX_WriteI2C_Byte(Reg, Temp);
}

void hdmitx_LoadRegSetting(RegSetEntry table[])
{
    int i ;

    for( i = 0 ;  ; i++ )
    {
        if( table[i].offset == 0 && table[i].invAndMask == 0 && table[i].OrMask == 0 )
        {
            return ;
        }
        else if( table[i].invAndMask == 0 && table[i].OrMask == 0 )
        {
            delay(table[i].offset);
        }
        else if( table[i].invAndMask == 0xFF )
        {
              HDMITX_WriteI2C_Byte(table[i].offset,table[i].OrMask);
        }
        else
        {
              HDMITX_SetI2C_Byte(table[i].offset,table[i].invAndMask,table[i].OrMask);
        }
    }
}

void setPatternGen()
{

        unsigned int HTotal, VTotal;
        unsigned int HDES, HDEE;
        unsigned int HDEW, VDEW, HFP, HSW, VFP, VSW;
        unsigned int HRS, HRE;
        unsigned int VRS, VRE;
        unsigned int VRS2nd, VRE2nd;
        unsigned int VDES, VDEE;
        unsigned int VDES2, VDEE2;
        unsigned int HBP, VBP;

        HTotal  = 858;
        HDEW    = 720;
        HFP     = 16;
        HSW     = 62;
        HBP    =  60;
        VTotal  = 525;
        VDEW    = 480;
        VFP     = 9;
        VSW     = 6;
        VBP    =  30;

        HRS = HFP;          // Horizontal Sync Start
        HRE = HRS + HSW;    // Horizontal Sync End = PGHRS + HSYNC width   
        HDES = HRE + HBP;   // PGHRE + Horizontal Back Porch
        HDEE = HDES + HDEW; // PGHDE start + Horizontal Clocks of Active Video

        VRS = VFP;   // Vertical Sync Start
        VRE = (VRS + VSW) % 16;  // Vertical Sync End = (PGVRS + VSYNC witdh) % 16
        VRS2nd = 0xFFF;   // 2nd field Vertical Sync Start
        VRE2nd = 0xFFF;   // 2nd field Vertical Sync End

        VDES = VRS + VSW + VFP; // Vertical Display Start = VRS + VSYNC width + Vertical Front Porch
        VDEE = VDES + VDEW;     // Vertical Display End = VDES + Active Vertical Line per field
        VDES2 = 0xFFF;    // 2nd field Vertical Display Start
        VDEE2 = 0xFFF;    // 2nd field Vertical Display End


        HDMITX_SetI2C_Byte(0x0F, 0x03, 0x00); //Set bank 0

        // write HTotal
        HDMITX_SetI2C_Byte(0x90, 0xF0, (HTotal&0x0F)<<4);
        HDMITX_WriteI2C_Byte(0x91, (HTotal&0x0FF0)>>4);


        // write HRS/HRE
        HDMITX_WriteI2C_Byte(0x95, HRS & 0xFF);
        HDMITX_WriteI2C_Byte(0x96, HRE & 0xFF);
        HDMITX_WriteI2C_Byte(0x97, ( (HRE&0x0F00)>>4) + ((HRS&0x0F00)>>8) );


        // write HDES/HDEE
        HDMITX_WriteI2C_Byte(0x92, HDES & 0xFF);
        HDMITX_WriteI2C_Byte(0x93, HDEE & 0xFF);
        HDMITX_WriteI2C_Byte(0x94, ( (HDEE&0x0F00)>>4) + ((HDES&0x0F00)>>8) );

        // write VTotal
        HDMITX_WriteI2C_Byte(0x98, VTotal & 0xFF); 
        HDMITX_WriteI2C_Byte(0x99, ((VTotal&0x0F00)>>8));

        // write VRS/VRE/VRS2/VRE2
        HDMITX_WriteI2C_Byte(0xa0, VRS&0xFF);
        HDMITX_WriteI2C_Byte(0xa1, ((VRE&0x0F)<<4)+((VRS&0x0F00)>>8));
        HDMITX_WriteI2C_Byte(0xa2, VRS2nd&0xFF);
        HDMITX_WriteI2C_Byte(0xa6, (VRE2nd&0xF0)+((VRE&0xF0)>>4));
        HDMITX_WriteI2C_Byte(0xa3, ((VRE2nd&0x0F)<<4)+((VRS2nd&0xF00)>>8));

        // write VDES/VDEE
        HDMITX_WriteI2C_Byte(0x9a, VDES & 0xFF);
        HDMITX_WriteI2C_Byte(0x9b, VDEE & 0xFF);
        HDMITX_WriteI2C_Byte(0x9C, ( (VDEE&0x0F00)>>4) + ((VDES&0x0F00)>>8) );

        // write VDES2/VDEE2
        HDMITX_WriteI2C_Byte(0x9D, VDES2 & 0xFF);
        HDMITX_WriteI2C_Byte(0x9E, VDEE2 & 0xFF);
        HDMITX_WriteI2C_Byte(0x9F, ( (VDEE2&0x0F00)>>4) + ((VDES2&0x0F00)>>8) );

        // write extra bits
        HDMITX_SetI2C_Byte(0xb1, 0x55, ((HRE&0x1000)>>6) + ((HRS&0x1000)>>8) + ((HDEE&0x1000)>>10) + ((HDES&0x1000)>>12));
        HDMITX_SetI2C_Byte(0xb2, 0x05, 0x00);

        //Disable DE and Sync gen, since the pattern generates this signals too
        HDMITX_SetI2C_Byte(0x90, 0x09, 0x00); //disable DE gen

         HDMITX_SetI2C_Byte(0xa9, 0xFF, 0x00); // select pattern generated value
         HDMITX_SetI2C_Byte(0xaf, 0xFF, 0xa0); // Hor increment in gradient
         HDMITX_SetI2C_Byte(0xb0, 0xFF, 0x00); // Ver increment in gradient

         HDMITX_SetI2C_Byte(0xa8, 0x01, 0x01); //Enable pattern generator   
}

void setup()
{
  Wire.begin();
  Serial.begin(9600);
}

void loop()
{
      Serial.println("init...");


      //ID OK!!!
      Serial.println("reading ID");
      Serial.println(HDMITX_ReadI2C_Byte(0x00),HEX);
      Serial.println(HDMITX_ReadI2C_Byte(0x01),HEX);
      Serial.println(HDMITX_ReadI2C_Byte(0x02),HEX);
      Serial.println(HDMITX_ReadI2C_Byte(0x03),HEX);
      Serial.println("done ID");

      hdmitx_LoadRegSetting(HDMITX_Init_Table);
      hdmitx_LoadRegSetting(HDMITX_DefaultVideo_Table);
      setPatternGen();
      hdmitx_LoadRegSetting(HDMITX_SetHDMI_Table);
      hdmitx_LoadRegSetting(HDMITX_PwrOn_Table);

      Serial.println("done");

      while(1){}
}