⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vblank.c

📁 GM5621原代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
	$Workfile:   vblank.c  $
	$Revision:   1.17  $
	$Date:   Sep 19 2005 04:15:06  $
*/

#define __D_DDC2BI_C__
//******************************************************************************
//
//              Copyright (C) 2002.  GENESIS MICROCHIP INC.
//      All rights reserved.  No part of this program may be reproduced.
//
//     Genesis Microchip Inc., 165 Commerce Valley Dr. West
//     Thornhill, Ontario, Canada, L3T 7V8
//
//==============================================================================
//
// MODULE:      vblank.c
//
// USAGE:       This module contains functions running functions indide the
//              vertical blanking time.
//
//******************************************************************************

//******************************************************************************
//  I N C L U D E    F I L E S
//*****************************************************************************
#include "inc\all.h"
#include "system\mcu186.h"
#include "math.h"
#include "mem.h"
//******************************************************************************
//  L O C A L    D E F I N I T I O N S
//******************************************************************************
#if (USE_ADC_CALIBRATION_ISR)

#define ADC_CALIBRATION_ISR_IN_RAM		1 // 0: The code will be in ROM

#define DEBUG_VBLANK_ISR	0

#if DEBUG_VBLANK_ISR && DEBUG_MSG
	#define	msg(a,b)	gm_Print((const char far *)a,b)
#else
	#define msg(a,b)
#endif

//******************************************************************************
//  F U N C T I O N S
//******************************************************************************
//void InitCalValues(void)
//		Calucultates rgb_cal[] values and stores in NVRAM.
//void InitADCCalibration(BYTE integrity) based on 'integrity' either gets
//    rgb_cal[] values from NVRAM or calls gm_AutoAdcInitMain and then calls
//    InitCalVaues() above.
//void ADCCalibration(void)
//		Background routine which adjusts OFFSET2.
//void far ADCCalibrationISR(void)
//		Main body of ISR, collects rgb_tot[] values.
//void interrupt ext_VBlankISR(void)
//		New IRQ4 interrupt, it calls DDC2Bi is (old irq4) or ADCCalibrationISR
//		based on interrupt status.
//void InitADCCalibrationISR(BYTE integrity)
//		Main initialization, it sets up the new IRQ4 vector and calls
//		InitADCCalibration() above.


//******************************************************************************
//  S T A T I C    F U N C T I O N    P R O T O T Y P E S
//******************************************************************************
static void SaveOffset1Cal(void);
static gmt_RET_STAT LoadOffset1Cal(void);

//******************************************************************************
//  C O D E
//******************************************************************************

// Arrays below are for the offset1 moving average.  Just adjust
// OFFSET_ARRAY_SIZE to whatever average size you like.
#define OFFSET2_ARRAY_SIZE			64

// ADC_READINGS_PER_INTERRUPT is how many ADC readings will take place in
// one interrupt.  If this value is set equal to OFFSET2_ARRAY_SIZE, then
// all the readings will take place in one interrupt.  If the value is set
// to half of OFFSET2_ARRAY_SIZE, then it will take two interrups to
// get all the data.
#define ADC_READINGS_PER_INTERRUPT 	1

//The threshold value is how many counts the ADC value has to change
//before it adjusts the offset1 value.
#define ADC_THRESHOLD	  ((OFFSET2_ARRAY_SIZE * 8) / 10)

// DDC2Bi holdoff time is used to avoid servicing the VBlanking ADCCalibration
// routine if DDC2Bi traffic is found.  This will free up more processing time
// for the DDC2Bi handler which takes a big hit by having the IRQ4 hander
// out in external ROM.  Normally the DDC2Bi handler is in IROM.
// The units are in VBlank interrupts, a value of 100 means ADCCalibraion
// won't be called for 100 VBlanking intervals if DDC2Bi traffic is found.
#define VBLANK_DDC2BI_HOLDOFF		100

// Glitch threshold is used when reading the ADC directly.  The routines
// will read the ADC twice for each reading, and if the two readings
// are within the glitch threshold, then that value is considered good.
#define ADC_GLITCH_THRESHOLD			3

// ADC_GLITCH_RETRY is how many times to read the ADC channels if a glitch
// is encountered.  To high a value and you may spend to much time in the
// ISR resulting in garbage on the display.  The number is the combined
// reading of all 3 ADCs.
#define ADC_GLITCH_RETRY				9

// Values below are DAC, OFFSET2 and GAIN values to be programmed in when
// reading the ADC during blanking.  These values are held constant so we
// can monitor the ADC drift and adjust OFFSET1 accordingly.
#define ADC_TESTDAC_VALUE	0x18 			//0x80...ideally its better not to have this on edge for large transistions (7F -80)


WORD  rgb_cal[3];
SWORD rgb_tot[3];
volatile BYTE rgb_index;

//******************************************************************
// FUNCTION     :   void InitCalValues
// USAGE        :   This is where the actual computation for the
//                  calibration values is performed.  This function
//                  Is called during initialization if there is no
//                  calibration values in NVRAM.
//                  **NOTE** This function should be called whenever
//                  an gm_AutoColorBalance is performed.  The Auto
//                  Color balance routine will calculate new OFFSET2
//                  and Gain values for each ADC.  If this function isn't
//                  called to get new calibration values, then the ISR
//                  will just 'adjust' the OFFSET2 values back.
//******************************************************************
void InitCalValues(void)
{
	BYTE i,j,color,one,two,SysMask,Fas2;
	WORD W_Timeout;
	DWORD timeout;

	// turn off calibration ISR
	SysMask = gm_ReadRegByte(MISC_OCMMASK);
	// if rgb_index is zero, then routine is running, but background ADCCalibration
	// hasn't executed yet and interrupt will be off, so turn it back on.
	if(rgb_index == 0x00)
		SysMask |= D_VBLANK;
	gm_ClearRegBitsByte(MISC_OCMMASK, D_VBLANK);

	rgb_cal[0] = 0;
	rgb_cal[1] = 0;
	rgb_cal[2] = 0;

	for(j=0;j<OFFSET2_ARRAY_SIZE;j+= ADC_READINGS_PER_INTERRUPT)
	{
		timeout = 0UL;
		// clear vblank status bit.
		gm_WriteRegByte(DISPLAY_STATUS, D_VBLANK);
		// wait for vblank, otherwise you'll see a glitch in the display as this
		// calibration routine runs.
		do
      {
         timeout++;
      	if(timeout >= 0x500UL) //timeout within about 20ms
         	break;
      }while((gm_ReadRegByte(DISPLAY_STATUS) & D_VBLANK) == 0);

		gm_SetRegBitsByte(ADC_CONTROL, AC_COUPLE_EN | CLAMP_EN | ADC_ENABLE | ( gmvb_SogSensitivity << SOG_SENS_SHIFT));
		// set up DAC
		gm_WriteRegByte(ADC_TESTDAC, RED_ST | GRN_ST | BLU_ST); // Enable ADC Self Test for all RGB channels.
		gm_WriteRegByte(ADC_DAC_DATA, ADC_TESTDAC_VALUE);

		#ifdef ADC_B_PHASE
			Fas2 = gm_ReadRegByte(ADC_B_PHASE);
			gm_WriteRegByte(ADC_B_PHASE, 0x00); // Reduced the BW before calibration.
		#else
			Fas2 = gm_ReadRegByte(ADC_FAS2);
			gm_WriteRegByte(ADC_FAS2, 0x00); // Reduced the BW before calibration.
		#endif

		for(color=0; color < 3;color++)
		{
			i = ADC_READINGS_PER_INTERRUPT;
			W_Timeout = (ADC_READINGS_PER_INTERRUPT * 4);
			while(i && W_Timeout)
			{
				one = gm_ReadRegByte(ADC_DATA_RED + color);
				two = gm_ReadRegByte(ADC_DATA_RED + color);

				if(abs(one-two) < ADC_GLITCH_THRESHOLD)
				{
					rgb_cal[color] += (WORD)two;
					i--;
				}
				W_Timeout--;
			}

			// if timeout occurs, better to set calibration value to ADC_TESTDAC_VALUE than 0x00, it will
			// likely produce less color shift if all else is working fine.
			if(W_Timeout == 0)
			{
				msg("InitCalValues: timeout!!",0);
				rgb_cal[color] += (ADC_TESTDAC_VALUE * ADC_READINGS_PER_INTERRUPT);
			}

			// Round up! (add 0.5)
			#if (OFFSET2_ARRAY_SIZE > 1)
			rgb_cal[color] += (ADC_READINGS_PER_INTERRUPT / 2);
			#endif
		}
		// restore DAC
		// Turn off test ADC
		gm_WriteRegByte(ADC_TESTDAC, 0);
		// Restore BW
		#ifdef ADC_B_PHASE
			gm_WriteRegByte(ADC_B_PHASE, Fas2);
		#else
			gm_WriteRegByte(ADC_FAS2, Fas2);
		#endif

	}

	msg("**r_cal %x",(WORD)rgb_cal[0]);
	msg("**g_cal %x",(WORD)rgb_cal[1]);
	msg("**b_cal %x",(WORD)rgb_cal[2]);

	SaveOffset1Cal();
	// turn on calibration ISR
	rgb_index = OFFSET2_ARRAY_SIZE;
	rgb_tot[0] = rgb_cal[0];
	rgb_tot[1] = rgb_cal[1];
	rgb_tot[2] = rgb_cal[2];

  	gm_WriteRegByte(DISPLAY_STATUS, D_VBLANK);
	gm_WriteRegByte(MISC_OCMMASK, SysMask);

}

//******************************************************************
// FUNCTION     :   void InitADCCalibration
// USAGE        :   Based on 'integrity' the routine will either
//                  Read the calibration values from NVRAM or
//                  compute new values.  If generating new
//                  calibration values, then first multiple
//                  OFFSET1 calibrations are perfromed (gm_AutoADCInitMain())
//                  and averaged together to get a real 'average'
//                  OFFSET1 value.
//******************************************************************
void InitADCCalibration(BYTE integrity)
{
	BYTE i;
	WORD red, grn, blu;

	// First see if OFFSET1 values are saved in NVRAM.
	if(integrity && (LoadOffset1Cal() == gmd_OK))
	{
		msg("offset1 values restored from NVRAM",0);
		msg("red %x",(WORD)gm_ReadRegByte(RED_OFFSET1));
		msg("grn %x",(WORD)gm_ReadRegByte(GRN_OFFSET1));
		msg("blu %x",(WORD)gm_ReadRegByte(BLU_OFFSET1));
		msg("r_cal %x",rgb_cal[0]);
		msg("g_cal %x",rgb_cal[1]);
		msg("b_cal %x",rgb_cal[2]);
      gm_SetRegBitsByte(ADC_MODULATION,CAL_TRIG);
      gm_ClearRegBitsByte(ADC_MODULATION,CAL_TRIG);
		return;
	}
   else
	{
		#define AUTO_ADC_INIT_AVG 16
      red = grn = blu = 0;
		for(i=0;i<AUTO_ADC_INIT_AVG;i++)
      {
         gm_AutoADCInitMain();

         red += gm_ReadRegByte(RED_OFFSET1);
         grn += gm_ReadRegByte(GRN_OFFSET1);
         blu += gm_ReadRegByte(BLU_OFFSET1);
      }

      red += AUTO_ADC_INIT_AVG / 2;
      grn += AUTO_ADC_INIT_AVG / 2;
      blu += AUTO_ADC_INIT_AVG / 2;

		red /= AUTO_ADC_INIT_AVG;
      grn /= AUTO_ADC_INIT_AVG;
      blu /= AUTO_ADC_INIT_AVG;
	}

	gm_WriteRegByte(RED_OFFSET1,red);
	gm_WriteRegByte(GRN_OFFSET1,grn);
	gm_WriteRegByte(BLU_OFFSET1,blu);

	InitCalValues();
}

//******************************************************************
// FUNCTION     :   void ADCQuickCalibrate
// USAGE        :   Function performs the same actions the calibration
//                  ISR and ADCCalibrate() perform, except it counts
//                  on the display being disabled, and thus doesn't
//                  have to wait for the vblanking time, it can
//                  run continousely until offset2 stabalizes.
//******************************************************************
void ADCQuickCalibrate(void)
{
	BYTE color, Fas2;
	BYTE B_Adc[3];
	BYTE B_rgboff2[3];
	WORD W_Done = (OFFSET2_ARRAY_SIZE * 0x3F); // maximum timeout.
	#define STABLE_DONE_COUNT	3 // how many times offset2 has to be stable to be declared finished.
	BYTE B_StableDone = STABLE_DONE_COUNT;

	// set up DAC
	gm_WriteRegWord(ADC_TESTDAC,(((WORD)ADC_TESTDAC_VALUE << 8) |  RED_ST | GRN_ST | BLU_ST));

	#ifdef ADC_B_PHASE
		Fas2 = gm_ReadRegByte(ADC_B_PHASE);
		gm_WriteRegByte(ADC_B_PHASE, 0x00); // Reduced the BW before calibration.
	#else
		Fas2 = gm_ReadRegByte(ADC_FAS2);
		gm_WriteRegByte(ADC_FAS2, 0x00); // Reduced the BW before calibration.
	#endif

	rgb_tot[0] = rgb_cal[0];
	rgb_tot[1] = rgb_cal[1];
	rgb_tot[2] = rgb_cal[2];

	do
	{
		B_Adc[0] = gm_ReadRegByte(ADC_DATA_RED);
		if(abs(B_Adc[0] - gm_ReadRegByte(ADC_DATA_RED)) > ADC_GLITCH_THRESHOLD)
			continue;

		B_Adc[1] = gm_ReadRegByte(ADC_DATA_GRN);
		if(abs(B_Adc[1] - gm_ReadRegByte(ADC_DATA_GRN)) > ADC_GLITCH_THRESHOLD)
			continue;
	
		B_Adc[2] = gm_ReadRegByte(ADC_DATA_BLU);
		if(abs(B_Adc[2] - gm_ReadRegByte(ADC_DATA_BLU)) > ADC_GLITCH_THRESHOLD)
			continue;

		// if no glitch adjust the rgb_tot values.
		rgb_tot[0] -= (SWORD)B_Adc[0];
		rgb_tot[1] -= (SWORD)B_Adc[1];
		rgb_tot[2] -= (SWORD)B_Adc[2];
		rgb_index--;

		if(rgb_index == 0x00)
		{// when reach end run ADCCalibration()
			// get current offset2 values.
			B_rgboff2[0] = gm_ReadRegByte(RED_OFFSET2);
			B_rgboff2[1] = gm_ReadRegByte(GRN_OFFSET2);
			B_rgboff2[2] = gm_ReadRegByte(BLU_OFFSET2);
			// adjust offset2.
			// if new total is greater than the calibrated value, decrease the offset2,
			// else increase it.  rgb_tot[0] and red_cal haven't been divided by
			// OFFSET2_ARRAY_SIZE to scale them back down, so instead ADC_THRESHOLD
			// if multipied by OFFSET2_ARRAY_SIZE so we don't have to do the division
			// (or shift)
			for(color=0;color<3;color++)
			{
				BYTE adj;
				// Round up! (add 0.5)
				#if (OFFSET2_ARRAY_SIZE > 1)
				rgb_tot[color] -= (OFFSET2_ARRAY_SIZE / 2);
				#endif

				// use a proportional control to speedup the calibration.
				adj = abs(rgb_tot[color]) / ADC_THRESHOLD;

				if(rgb_tot[color] < -(ADC_THRESHOLD))
				{
					B_StableDone = STABLE_DONE_COUNT; // if any change, reset stable done count
					B_rgboff2[color]-= adj;
					// check we didn't wrap around.
					if(B_rgboff2[color] > 0x7F)
						B_rgboff2[color] = 0x00;
				}
				if(rgb_tot[color] > (ADC_THRESHOLD))
				{
					B_StableDone = STABLE_DONE_COUNT; // if any change, reset stable done count.
					B_rgboff2[color]+= adj;
					// check we didn't wrap around.
					if(B_rgboff2[color] > 0x7F)
						B_rgboff2[color] = 0x7F;

				}
				// reset rgb_tot
				rgb_tot[color] = rgb_cal[color];
			}// for color
		
			// restore offset2
			gm_WriteRegByte(RED_OFFSET2,B_rgboff2[0]);
			gm_WriteRegByte(GRN_OFFSET2,B_rgboff2[1]);
			gm_WriteRegByte(BLU_OFFSET2,B_rgboff2[2]);
			gm_WriteRegByte(HOST_CONTROL, IPFORCE_UPDATE);
		
			rgb_index = OFFSET2_ARRAY_SIZE;
			if((B_StableDone--) == 0)
				break;
		}// if index == 0
	}while(W_Done--);

	// restore DAC
	gm_WriteRegWord(ADC_TESTDAC,0x00);
	// Restore BW
	#ifdef ADC_B_PHASE
		gm_WriteRegByte(ADC_B_PHASE, Fas2);
	#else
		gm_WriteRegByte(ADC_FAS2, Fas2);
	#endif
}

//******************************************************************
// FUNCTION     :   void ADCCalibration
// USAGE        :   Function looks at the rgb_tot values compared
//                  to saved ADC calibration values (rgb_cal), if
//                  the values are different, then the offset2
//                  registers should be adjusted to make these values
//                  equal.
//******************************************************************
void ADCCalibration(void)
{
	BYTE color;
	BYTE B_rgboff2[3];
	WORD adj;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -