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

📄 vp310_driver.c

📁 嵌入式软件VP310tuner驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/* vp310_driver.c*/
/* Mitel Semiconductor */
/* Date : 12 February 1999 */
/* This program contains C functions to control the VP310 and the Tuner front-end */

#include <stdio.h>
#include <math.h>
#include <time.h>
#include <windows.h>

#include "stblib.h"
#include "stbhead.h"
#include "chchead.h"
#include "vp310_i2c_routines.h"
#include "vp310.h"


/* Global variables */
static	BYTE			tuner_device_id;
static	BYTE			synth_byte4;
static	UINT			VP310_KHz_sys_clk;

/*-----------------------------------------------------------------------------------------------*/
/*  VP310 primary initialisation			                                                     */
/*-----------------------------------------------------------------------------------------------*/
VP310_STATUS 
VP310_configure(UINT KHz_LNB_offset_lim, BYTE VP310_PLL_ratio )
{
	VP310_BOOLEAN		agc_slope_positive;
	VP310_STATUS		status;
	BYTE				buffer[10], config_reg_value;

	/* Define tuner parameters */
	if (DIRECT_CONVERSION)
	{
		tuner_device_id		= SP5769_DEVICE_ID;
		agc_slope_positive	= VP310_FALSE;
		synth_byte4			= SP5769_BYTE4;
	}
	else /* IF conversion */
	{
		tuner_device_id		= SP5659_DEVICE_ID;
		agc_slope_positive	= VP310_TRUE;
		synth_byte4			= SP5659_BYTE4;
	}

	/* Write Configuration Register to enable VP310 */
	config_reg_value = 128;
	switch (VP310_PLL_ratio)
	{
		case 3 : config_reg_value = config_reg_value;			break;
		case 4 : config_reg_value = config_reg_value + 4;		break;
		case 6 : config_reg_value = config_reg_value + 8;		break;
		case 9 : config_reg_value = config_reg_value + 12;		break;
		default : return VP310_INVALID_PLL_RATIO;
	}
	VP310_KHz_sys_clk = VP310_PLL_ratio * KHZ_XTAL_FREQ;
	buffer[0] = config_reg_value;
	if ((status = VP310_Write_Registers(VP310_CONFIG, buffer, 1, VP310_FALSE)) != VP310_NO_ERROR)
		return status;

	/* Wait for 1 ms (200 microseconds adequate) for the clock PLL to settle */
	go_to_sleep(VP310_INIT_DELAY);

	/* Write RESET Register to perform a FULL reset */
	buffer[0] = 128;
	if ((status = VP310_Write_Registers(VP310_RESET, buffer, 1, VP310_FALSE)) != VP310_NO_ERROR)
		return status;

	/* Read VP310 Configuration register as a check on whether the system is O.K. */
	if ((status = VP310_Read_Registers(VP310_CONFIG, buffer, 1, VP310_FALSE)) != VP310_NO_ERROR)
		return status;
	if (buffer[0] != config_reg_value)
		return VP310_CONFIG_REG_ERROR;

	/* Write SNR High Threshold Register */
	buffer[0] = VP310_SNR_THS_HIGH_DEFAULT;
	if ((status = VP310_Write_Registers(VP310_SNR_THS_HIGH, buffer, 1, VP310_FALSE)) != VP310_NO_ERROR)
		return status;

	/* Write Viterbi Setup and Reference Bytes 0-6*/
	buffer[0] = VP310_VIT_SETUP_DEFAULT;
	buffer[1] = VP310_VIT_REF0_DEFAULT;
	buffer[2] = VP310_VIT_REF1_DEFAULT;
	buffer[3] = VP310_VIT_REF2_DEFAULT;
	buffer[4] = VP310_VIT_REF3_DEFAULT;
	buffer[5] = VP310_VIT_REF4_DEFAULT;
	buffer[6] = VP310_VIT_REF5_DEFAULT;
	buffer[7] = VP310_VIT_REF6_DEFAULT;
	if ((status = VP310_Write_Registers(VP310_VIT_SETUP, buffer, 8, VP310_FALSE)) != VP310_NO_ERROR)
		return status;

	/* Default LNB offset setting within VP310 is +/-6000 kHz */
	/* The following is to convert from KHz to MHz and then multiply by 8 */
    buffer[0] = (KHz_LNB_offset_lim * 33) >> 12;
	if (buffer[0] != 48)
		if ((status = VP310_Write_Registers(VP310_FR_LIM, buffer, 1, VP310_FALSE)) != VP310_NO_ERROR)
			return status;

	/* Write AGC_CTRL register if agc slope is positive */
	buffer[0] = 39;
	if (agc_slope_positive)
		if ((status = VP310_Write_Registers(VP310_RESET, buffer, 1, VP310_FALSE)) != VP310_NO_ERROR)
			return status;

	/* Write 3 to MON_CTRL to read locked symbol rate from MONITOR register */
	buffer[0] = 3;
	if ((status = VP310_Write_Registers(VP310_MON_CTRL, buffer, 1, VP310_FALSE)) != VP310_NO_ERROR)
		return status;

	return VP310_NO_ERROR;
	/* Write to SYS_CLK register, the system clock freq in MHz multiplied by 2
	   if the crystal is not 10 or 15 MHz. */
}

/*----------------------------------------------------------------------------------------------*/
/*  Tune to a channel				     														*/
/*----------------------------------------------------------------------------------------------*/
VP310_STATUS 
VP310_acquire_channel(	ULONG					KHz_tuner_freq,
						VP310_LNB_PARAMS		lnb_params,
						VP310_KBD_PARAMS		kbd_params,
						VP310_CODE_RATE			code_rate,
						VP310_IQ_MODE			iq_mode,
						VP310_BOOLEAN			AFC_on,
						VP310_BOOLEAN			set_diseqc,
						UINT					qpsk_lock_time_lim_ms,
						UINT					fec_lock_time_lim_ms,
						BYTE					*sym_rate_index,
						int						*KHz_freq_offset,
						VP310_CHANNEL_PARAMS	*channel_params, 
						ULONG					*qpsk_acq_time_ms,
						ULONG					*acq_time_ms)

{
	BYTE					curr_sym_index, end_sym_index, nr_sym_indices, curr_vit_mode_reg;
	BYTE					freq_end_cnt, baud_end_cnt;
	USHORT					iq_swap_per_ms;
	UINT					kbd_rate, kbd_diff, elapsed_time, i;
	VP310_BOOLEAN			qpsk_lock, fec_lock;
	clock_t					start_time, current_time, acq_start_time, swap_time;
	VP310_STATUS			status;
	BYTE					buffer[8], qpsk_ctrl;
	VP310_CHANNEL_PARAMS	channel_params_init = {	1000000, CODE_3_4, 27500, IQ_NORMAL,
													POL_VERTICAL, TONE_OFF};

	
	*channel_params = channel_params_init;
	*sym_rate_index = 0;
	*KHz_freq_offset = 0;
	*qpsk_acq_time_ms = 0;
	*acq_time_ms = 0;
	channel_params->KHz_tuner_freq = KHz_tuner_freq;
	/* Note that the acquire channel program does NOT include the offset frequency in
	the channel_params.  channel_params will have the given KHz_tuner_freq as this is the
	frequency to which the tuner is currently tuned. */

	/* QPSK Control for fats freq search */
	if (AFC_on)
		qpsk_ctrl = 4 + IQ_WIRES_CROSSED;
	else
		qpsk_ctrl = IQ_WIRES_CROSSED;
	/* Set the LNB Polarisation and 22KHz tone, if set_diseqc is TRUE */
	if (set_diseqc)
	{
		if (lnb_params.enTone == TONE_ON)
			buffer[0] = 1;
		else
			buffer[0] = 0;
		if (lnb_params.enPolar == POL_HORIZONTAL)
			buffer[0] += 64;
		if ((status = VP310_Write_Registers(VP310_DISEQC_MODE, buffer, 1, VP310_FALSE)) != VP310_NO_ERROR) 
			return status;
	}

	/* Program the tuner */
	if ((status = VP310_program_tuner(KHz_tuner_freq, qpsk_lock_time_lim_ms)) != VP310_NO_ERROR)
		return status;

	/* Symbol Rate */
	if (kbd_params.sweep_on)
	{
		curr_sym_index	= 0;
		end_sym_index	= 0;
		nr_sym_indices	= 1;
		if ((status = make_sym_sweep_regs(kbd_params, buffer)) != VP310_NO_ERROR)
			return status;
	}
	else
	{
		curr_sym_index	= kbd_params.start_index;
		end_sym_index	= kbd_params.end_index;
		nr_sym_indices	= end_sym_index - curr_sym_index + 1;
		if (nr_sym_indices <= 0)
			return VP310_SYM_INDEX_ERROR;
	}
	
	/* Form code rate register */
	/* If iq_mode is AUTO this will set it to NORMAL at this point.  Toggled later */
	curr_vit_mode_reg = make_vit_mode_reg(code_rate, iq_mode);

	acq_start_time = clock();

	qpsk_lock = fec_lock = VP310_FALSE;
	/* Get QPSK Lock */
	while ( (curr_sym_index <= end_sym_index) && (!fec_lock) )
	{
		if (!(kbd_params.sweep_on))
		{
			/* If no sweep, load symbol rate info */
			kbd_rate = kbd_params.KBd_sym_table[curr_sym_index];
			/* To convert from KBaud to MBaud, and multiply by 256 */
			kbd_rate = (kbd_rate * 131) >> 9;
			buffer[0]= (BYTE) ((kbd_rate >> 8) & 0xFF);
			buffer[1]= (BYTE) (kbd_rate & 0xFF);
		}
		/* Viterbi code rate */
		buffer[2]= curr_vit_mode_reg;
		/* AFC */
		buffer[3] = qpsk_ctrl;
		/* GO pulse */
		buffer[4] = 1;
		/* Load symbol rate, code rate and QPSK_CTRL registers and Apply GO */
		if ((status = VP310_Write_Registers(VP310_SYM_RATE_H, buffer, 5, VP310_FALSE)) != VP310_NO_ERROR)
			return status;
		/* Wait for QPSK to lock */
		freq_end_cnt = 0;
		baud_end_cnt = 0;
		start_time = clock();
		current_time = start_time;
		elapsed_time = (UINT) (current_time - start_time);
		qpsk_lock	= VP310_FALSE;
		fec_lock	= VP310_FALSE; 
		while (	!( 	( (freq_end_cnt > FREQ_END_CNT_LIM) && (!(kbd_params.sweep_on)) ) ||
					( (baud_end_cnt > BAUD_END_CNT_LIM) && ((kbd_params.sweep_on))  ) ||		
					( (elapsed_time) > (qpsk_lock_time_lim_ms)	) ||
					( (qpsk_lock)													)	)	)
		{
			/* Read the first 5 registers */
			if ((status = VP310_Read_Registers(VP310_QPSK_INT_H, buffer, 7, VP310_FALSE)) != VP310_NO_ERROR)
				return status;

			/* Test for QPSK lock  */
			if ( (buffer[4] & 2) != 0) /* QPSK is in lock */
			{
				qpsk_lock = VP310_TRUE;
				/* Test FEC lock as well */
				if ( (buffer[6] & 12) == 12)
					fec_lock = VP310_TRUE;
				break;
			}
			/* Test for and Frequency end hit */
			if ( ( buffer[2] & 64) != 0) /* Frequency range end */
				freq_end_cnt++;
			/* Test for and Symbol rate end hit (will happen only in the event of a symbol rate sweep) */
			if ( ( buffer[2] & 32) != 0) /* Baud range end */
				baud_end_cnt++;
			go_to_sleep(DELTA_LOCK_DET_MS);
			current_time = clock();
			elapsed_time = (UINT) (current_time - start_time);
		}

		*qpsk_acq_time_ms = current_time - acq_start_time;
		/* If there is no qpsk lock and then increment curr_sym_index */
		if (!qpsk_lock)
		{
			curr_sym_index++;
			if (curr_sym_index > end_sym_index)
				return VP310_NO_QPSK_LOCK;
		}
		else if (!fec_lock) /* QPSK has locked, but can go out of lock while FEC is locking */
		{
			current_time = clock();
			if (iq_mode == IQ_AUTO)
			{
			/*	To resolve spectral inversion we need to know how long to stay in each spectral mode.
				This depends on symbol rate and on code rate and on wheter there is a code rate search.  
				So we read symbol rate first. */
				if ((status = VP310_Read_Registers(VP310_MONITOR_H, buffer, 1, VP310_FALSE)) != VP310_NO_ERROR)
					return status;
				if (buffer[0] & 128)		/* Symbol rate greater than 32 MBaud */
					iq_swap_per_ms = 22;
				else if (buffer[0] & 64)	/* Symbol rate betwee 16 and 32 MBaud */
					iq_swap_per_ms = 44;
				else if (buffer[0] & 32)	/* Symbol rate betwee 8 and 16 MBaud */
					iq_swap_per_ms = 88;
				else if (buffer[0] & 16)	/* Symbol rate betwee 4 and 8 MBaud */
					iq_swap_per_ms = 176;
				else if (buffer[0] & 8)		/* Symbol rate betwee 2 and 4 MBaud */
					iq_swap_per_ms = 352;
				else
					iq_swap_per_ms = 704;
				if (code_rate != CODE_AUTO)
					iq_swap_per_ms = iq_swap_per_ms >> 2;
			}

			/* Lock FEC */
			start_time = clock();
			swap_time = current_time = start_time;
			elapsed_time = (UINT) (current_time - start_time);
			while ( ((elapsed_time) < fec_lock_time_lim_ms) && (!fec_lock) )
			{
			/* Read the FEC status registers */
				if ( (status = VP310_Read_Registers(VP310_FEC_STATUS, buffer, 1, VP310_FALSE)) != VP310_NO_ERROR)
					return status;
				if ((buffer[0] & 12) == 12) /* FEC has locked */
				{
					fec_lock = VP310_TRUE;
					break;
				}
				else
				{
					go_to_sleep(DELTA_LOCK_DET_MS);
					current_time = clock();
					elapsed_time = (UINT) (current_time - start_time);
					if (iq_mode == IQ_AUTO)
					{
						if ((current_time - swap_time) > iq_swap_per_ms)
						{
							swap_time = current_time;
							/* Change polarity of the IQ-swap bit */
							buffer[0] = curr_vit_mode_reg = curr_vit_mode_reg ^ 64;
							if ((status = VP310_Write_Registers(VP310_VIT_MODE, buffer, 1, VP310_FALSE)) != VP310_NO_ERROR)
								return status;
						}
					}
				}
			}
			/* Time allowed for the FEC to lock after QPSK has locked, has elapsed. */
			if (!fec_lock)
			{
				curr_sym_index++;
				if (curr_sym_index > end_sym_index)
					return VP310_NO_FEC_LOCK;
			}
		}
	}
	/* The program will get here only if there is fec lock */
	*acq_time_ms = clock() - acq_start_time;
	/* go_to_sleep(10000); */
	status = VP310_get_channel_status(KHz_tuner_freq, channel_params, KHz_freq_offset);
	if (nr_sym_indices > 1)
	{
		/* Although the chip may have locked onto one symbol rate index, the correct
		index may be different */
		kbd_diff = 100000;
		for (i = kbd_params.start_index ; i <= kbd_params.end_index; i++)
			if (kbd_diff < (kbd_params.KBd_sym_table[i] - channel_params->KBd_rate))
			{
				kbd_diff = (kbd_params.KBd_sym_table[i] - channel_params->KBd_rate);
				*sym_rate_index = i;
			}
			else if (kbd_diff < (channel_params->KBd_rate - kbd_params.KBd_sym_table[i]))
			{
				kbd_diff = (channel_params->KBd_rate - kbd_params.KBd_sym_table[i]);
				*sym_rate_index = i;
			}
	}
	else
		*sym_rate_index = curr_sym_index;
	return status;
}

/*-----------------------------------------------------------------------------------------------*/
/*  Form registers	for symbol rate sweep			                                             */
/*-----------------------------------------------------------------------------------------------*/
VP310_STATUS
make_sym_sweep_regs(VP310_KBD_PARAMS kbd_params, BYTE *buffer)
{
	UINT			lo_lim, hi_lim;
	USHORT			ext_dr_low, ext_dr_high;
	BYTE			dec_ratio;
	USHORT			sub_ranges;
	BYTE			i;

⌨️ 快捷键说明

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