📄 vp310_driver.c
字号:
/* 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 + -