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){}
}
我在让这个 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){}
}