📄 auto.c
字号:
Histogram |= (uint32)RdScalarReg(rP0FB);
Sum += Histogram;
if(Sum >= ExtraBlackPixel) break;
}
if(area==0){
TheChannelFineTuneOk = 1; //next channel
WrScalarReg(9-(channel*3), RdScalarReg(9-(channel*3))+Offset);
}
else{
WrScalarReg(9-(channel*3), RdScalarReg(9-(channel*3))+area);
}
}
}
}
uint8 code MaskWin[4] = {
0x00, // rP02A Horizontal Mask Window Begin
24, // rP02B Horizontal Mask Window End
0x00, // rP02C Vertical Mask Window Begin
0x00, // rP02D Vertical Mask Window End
};
/*
********************************************************************************
* 函 数 名: AutoTunePorc
* 功能描述: 自动校正位置,时钟和相位, 如果画面是满屏的就进行完整的调整,如果
* 画面是不满屏的,那么就只进行相位的调整
* 输 入: 无
* 返 回: 无
* 注 意: 对于客户的特殊要求,这里并没有进行处理,所以客户对特定画面或者
* 显示模式的要求,需要根据实际需求进行调整
********************************************************************************
*/
uint8 AutoTuneProc(void)
{
uint8 result = AUTO_CONTINUE;
uint8 Reg06A;
Flg_NonFullScreen = FALSE;
Reg06A = RdScalarReg(rP06A); // 该寄存器用于抖动校正控制
WrScalarReg(rP06A, 0x00); // 清除该寄存器原来的设置
WrScalarBytes(rP02A, 4, MaskWin); // 设置Mask Window
result = AutoTunePos();
//if (result == AUTO_FAIL) {
// ModePar.htotal = ModeAttr[ModePar.mode].Htotal;
// AdcSetPll(ModePar.htotal);
// AutoTuneClock();
// }
//result = AutoTunePos();
// 对不满屏画面的AUTO处理
if (result == AUTO_FAIL) {
if (Flg_NonFullScreen) {
AutoTuneClockByPhase();
result = AutoTunePhaseFine();
goto auto_exit;
}
else goto auto_exit;
}
// 对满屏画面的AUTO处理
else {
Flg_NonFullScreen = FALSE;
result = AutoTuneClock();
if (result == AUTO_FAIL) goto auto_exit;
result = AutoTuneClockByPhase();
if (result == AUTO_FAIL) goto auto_exit;
result = AutoTunePhaseFine();
if (result == AUTO_FAIL) goto auto_exit;
result = AutoTunePos();
}
auto_exit:
WrScalarReg(rP06A, Reg06A);
if (result == AUTO_OK) {
ModePar.hoffset = 0;
ModePar.voffset = 0;
}
AdjClock(HIDE, 0);
AdjPhase(HIDE, 0);
AdjHpos(HIDE, 0);
AdjVpos(HIDE, 0);
return result;
}
/*
********************************************************************************
* 函 数 名: AutoTunePos
* 功能描述: 自动校正水平和垂直的位置,采用的是SCALAR自身的方法,过程也十分
* 简单明了。
* 输 入: 无
* 返 回: 返回调整的结果: AUTO_OK或者是AUTO_FAIL
********************************************************************************
*/
uint8 AutoTunePos(void)
{
uint16 xdata temph,tempv;
uint16 xdata H_Active, V_Active;
uint16 xdata InputVactive;
if (SyncGetIntState()) return AUTO_FAIL;
// 设置初始的参数
//WrScalarBytes(rP02A, 4, MaskWin); // 设置Mask Window
WrScalarReg(rP107, NOISE_MARGIN); // 设置门限值
AutoGetHmask();
// 启动自动校正过程
WrScalarReg(rP106, 0x00);
WrScalarReg(rP106, AUTO_MASK + 0x01);
// 等待自动校正结束
SysTmr = 200/SYSTMR_PRIO;
while ((RdScalarReg(rP106) & BIT_0) && SysTmr != 0) {
ClearWatchDog();
if (SyncGetIntState()) {
return AUTO_FAIL;
}
}
if (SysTmr != 0) { // 对没有超时的情况进行处理
V_Active = RdScalarWord(rP10C) & 0x07FF;
H_Active = RdScalarWord(rP110) & 0x07FF;
if (Flg_Interlace) InputVactive = DispModeHeight<<1;
else InputVactive = DispModeHeight;
tempv = abs(InputVactive - V_Active);
if(tempv < 5) {
temph = abs(DispModeWidth - H_Active);
if(temph > (DispModeWidth >> 2)) { // Check HTotal range.
Flg_NonFullScreen = TRUE;
return AUTO_FAIL;
}
}
else {
Flg_NonFullScreen = TRUE;
return AUTO_FAIL;
}
tempv = RdScalarWord(rP108) & 0x07FF;
temph = RdScalarWord(rP10E) & 0x07FF;
if(tempv < 1 || temph < 1) return AUTO_FAIL;
if((tempv > 0xff) || (temph > (ModePar.htotal - H_Active))) {
Flg_NonFullScreen = TRUE;
return AUTO_FAIL;
}
else {
if(V_Active != InputVactive) {
if(V_Active==400 || V_Active==350) {
tempv = tempv - (InputVactive - V_Active)/2;
}
}
ModePar.hstart = temph;
ModePar.vstart = tempv;
SarHpos(ModePar.hstart);
SarVpos(ModePar.vstart);
return AUTO_OK;
}
}
return AUTO_FAIL; // 如果超时表示自动位置调整失败
}
/*
********************************************************************************
* 函 数 名: AutoCheckPhaseData
* 功能描述: 按步长为4输出相位值,将所有值输出一遍。在输出的同时启动检测功能,
* 记录检测值的最大值和最小值,返回这两个值的差值,同时检验值SOD最大
* 时的相位值记录在MaxSOD_Phase,SOD最小的相位值记录在MinSOD_Phase
* 输 入: 无
* 返 回: 返回最大检测值和最小检测值的差
* 注 意: 不破坏AdcPar.phase的值
********************************************************************************
*/
static uint32 AutoCheckPhaseData(void)
{
uint32 xdata Value,MinValueTemp,MaxValueTemp;
uint8 ADC_Phase;
MaxValueTemp = 0;
MinValueTemp = 0xFFFFFFFF;
for(ADC_Phase = 0; ADC_Phase < 0x40; ADC_Phase += 4) {
AdcSetPhase(ADC_Phase);
WrScalarReg(rP106, AUTO_MASK + 0x02);
SysTmr = 200/SYSTMR_PRIO;
while((RdScalarReg(rP106) & BIT_1) && SysTmr != 0) {
ClearWatchDog();
if (SyncGetIntState()) return 0;
}
Value = RdScalarWord(rP115);
Value <<= 16;
Value += RdScalarWord(rP113);
if(Value < MinValueTemp) {
MinValueTemp = Value;
MinSOD_Phase = ADC_Phase;
}
if(Value > MaxValueTemp) {
MaxValueTemp = Value;
MaxSOD_Phase = ADC_Phase;
}
}
Value = MaxValueTemp - MinValueTemp;
return Value;
}
/*
********************************************************************************
* 函 数 名: AutoTuneClock
* 功能描述: 自动校正ADC采样时钟, 同时会影响标志Flg_NonFullScreen
* 输 入: 无
* 返 回: 返回调整的结果: AUTO_OK或者是AUTO_FAIL
********************************************************************************
*/
static uint8 AutoTuneClock(void)
{
uint8 H_Difference,i,Compare;
uint16 xdata H_Act, TempClock;
WrScalarBytes(rP02A, 4, MaskWin); // 设置Mask Window
TempClock = ModePar.htotal;
if(DispModeWidth >= TempClock) {
TempClock = DispModeWidth + ModePar.hstart;
AdcSetPll(TempClock);
}
WrScalarWord(rP117, DispModeWidth);
for(i = 0; i < 20; i++) {
AutoGetHmask();
WrScalarReg(rP106, AUTO_MASK + 0x01);
SysTmr = 200/SYSTMR_PRIO;
while((RdScalarReg(rP106) & 0x01) && SysTmr != 0) {
ClearWatchDog();
if (SyncGetIntState()) return AUTO_FAIL;
}
H_Act = RdScalarWord(rP110) & 0x0FFF;
H_Difference = RdScalarReg(rP119);
Compare = (H_Difference & 0xC0) >> 6;
H_Difference &= 0x3F;
if(Compare == 0x00) break;
if(Compare == 0x01) {
TempClock += H_Difference;
//if(TempClock > 3072) {
if(TempClock > (DispModeWidth + (DispModeWidth>>1))) {
i = 0xFF;
break;
}
}
if(Compare > 0x01) {
TempClock -= H_Difference;
if(TempClock < DispModeWidth) {
i = 0xFF;
break;
}
}
AdcSetPll(TempClock);
}
if(i == 0xFF || i == 20) {
Flg_NonFullScreen = 1;
AdcSetPll(ModePar.htotal);
return AUTO_FAIL;
}
else {
ModePar.htotal = TempClock;
// ModePar.htotal = (TempClock + 2) & 0xFFFC;
AdcSetPll(ModePar.htotal);
return AUTO_OK;
}
}
/*
********************************************************************************
* 函 数 名: AutoTuneClockByPhase
* 功能描述: 在当前采样时钟的基础上(该基础时钟是通过在此之前执行的AutoTuneClock
* 所得到的),往前或者往后调整2步,通过相位校正的方式来细调当前的时钟
* 是否准确。
* 输 入: 无
* 返 回: 返回调整的结果: AUTO_OK或者是AUTO_FAIL
* 注 意: 判断的原则是相位检测值的差是否是最大的。
********************************************************************************
*/
static uint8 AutoTuneClockByPhase(void)
{
uint8 k,MinTmpPh,MaxTmpPh;
uint16 Clk;
uint32 xdata MaxMin,Value;
Clk = ModePar.htotal - 1;
MaxMin = 0;
for(k = 0; k < 3; k++) { // find tune clock +/- 1
AdcSetPll(Clk);
Value = AutoCheckPhaseData();
if(MaxMin < Value) {
ModePar.htotal = Clk;
MaxMin = Value;
MinTmpPh = MinSOD_Phase;
MaxTmpPh = MaxSOD_Phase;
}
Clk++;
}
AdcSetPll(ModePar.htotal);
// 通过设定这个条件来判断画面是锐利的还是平滑的
//Value = (uint32)DispModeWidth * DispModeHeight * 256;
if (Flg_Interlace) Value = (uint32)DispModeWidth * DispModeHeight * 128;
else Value = (uint32)DispModeWidth * DispModeHeight * 64;
// 画面是平滑的,因此最佳Phase应该出现在反向180度的地方,其实应该要加
// 32才对,但是需要往前推8个点,所以是加24
if(MaxMin < Value) {
ModePar.phase = (MinTmpPh + 24) & 0x3F;
PhaseSearchRange = 32;
}
// 画面是锐利的,因此最佳Phase应该出现在最大值的附近,往前推8个点为后面
// 的搜寻服务
else {
ModePar.phase = (MaxTmpPh - 8) & 0x3F;
PhaseSearchRange = 16;
}
AdcSetPhase(ModePar.phase);
return AUTO_OK;
}
/*
********************************************************************************
* 函 数 名: AutoTunePhaseFine
* 功能描述: 自动校正ADC采样时钟的相位
* 输 入: 无
* 返 回: 返回调整的结果: AUTO_OK或者是AUTO_FAIL
* 注 意: 这个函数的使用要在一定的基础上进行,否则不能得到正确的结果
********************************************************************************
*/
static uint8 AutoTunePhaseFine(void)
{
uint8 GoodPhase,yy, Phase;
uint32 xdata Phase_0, Phase_1, Phase_2, Phase_Pre3, Phase_Now3, Phase_Delta;
Phase_1 = 0x00000000; // (i-1)
Phase_2 = 0x00000000; // (i-2)
Phase_Pre3 = 0x00000000; // (pre sum)->(delta)->(now sum)
Phase_Delta = 0xFFFFFFFF; // (min delta)
for(yy = 0; yy < PhaseSearchRange; yy++) {
Phase = (ModePar.phase + yy) & 0x3F;
AdcSetPhase(Phase);
WrScalarReg(rP106, AUTO_MASK + 0x02);
SysTmr = 200/SYSTMR_PRIO;
while((RdScalarReg(rP106) & 0x02) && SysTmr != 0) {
ClearWatchDog();
if (SyncGetIntState()) return AUTO_FAIL;
}
Phase_Now3 = RdScalarWord(rP115);
Phase_Now3 <<= 16;
Phase_Now3 += RdScalarWord(rP113);
Phase_2 = Phase_1; // Shift
Phase_1 = Phase_0;
Phase_0 = Phase_Now3;
Phase_Now3 = (Phase_0>>1) + (Phase_1>>1) + (Phase_2>>2); // Phase_Now3
if(yy < 3) Phase_Pre3 = Phase_Now3; // Phase_Pre3 = Phase_Now3
else {
if(Phase_Now3 > Phase_Pre3) Phase_Pre3 = Phase_Now3 - Phase_Pre3;
else Phase_Pre3 = Phase_Pre3 - Phase_Now3; // Phase_Pre3=delta
if(Phase_Pre3 < Phase_Delta) {
GoodPhase = Phase;
Phase_Delta = Phase_Pre3;
}
Phase_Pre3 = Phase_Now3; // Phase_Pre3 = Phase_Now3
}
}
// 这个范围是+/- 2, 具体的数值将取决于实际的PCB设计
//ModePar.phase = (GoodPhase - 2) & 0x3F;
ModePar.phase = (GoodPhase - 1) & 0x3F;
AdcSetPhase(ModePar.phase);
return AUTO_OK;
}
/*
================================================================================
= 说明: 这个函数还需要调整,因为在640 * 480的分辨率下自动调整不成功
================================================================================
*/
static void AutoGetHmask(void)
{
#if 0
uint16 mask, hw;
uint8 sw;
float temp;
WrScalarReg(rP02A, 0x10);
sw = RdScalarReg(rP1B1);
hw = RdScalarWord(rP19B) & 0x1FFF;
temp = ((float)ModePar.htotal * sw * 8)/hw;
mask = (uint8)(temp * 11/10 + 0.5);
if (mask > 0xFF) mask = 0xFF;
hw = ModePar.htotal - DispModeWidth - ModePar.hstart;
if (mask > hw) mask = hw;
WrScalarReg(rP02B, mask);
#endif
}
/*
********************************************************************************
* 文 件 结 束 *
********************************************************************************
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -