📄 lv2410x.c
字号:
/************************************************************************
*
* Copyright(c) 2004 ItoM BV
* All Rights Reserved.
*
* LV2400x evaluation kit: LC24001 specific code
* File name: Lv2410x.c
*
*************************************************************************/
#include <stdio.h>
#include "common.h"
#include "Lv24Ekit.h"
// ==============================================================================
#ifdef USE_LV2410x // The whole file can be discarded if LC2410x is not used
// ==============================================================================
#include "Lv2410xReg.h" // For register layout
/*-------------------------------------------------------------------
Global data for this module
-------------------------------------------------------------------*/
BYTE g_byFmStereo;
BYTE g_byFmRegion;
WORD g_wLastFmFreq;
BYTE g_byAmRegion;
WORD g_wLastAmFreq;
WORD g_wFmRfLo;
WORD g_wFmRfHi;
WORD g_wAmRfLo;
WORD g_wAmRfHi;
/*-------------------------------------------------------------------
Local data
-------------------------------------------------------------------*/
typedef struct // Register address-value structure (for default register settings)
{
WORD wRegAddress;
BYTE byValue;
} I3W_REG_VALUES;
// ----- Default register value list of LV2410x
I3W_REG_VALUES _rom g_Lv2410xDefault[] =
{
IR01_MSRC_SEL_REG, 0, // 0x0102 - Measure source select: nothing selected
//IR01_FM_OSC_REG, 0, // 0x0103 - should be tuned
//IR01_SD_OSC_REG, 0x80, // 0x0104 - should be tuned
//IR01_IF_OSC_REG, 0, // 0x0105 - should be tuned
//IR01_FM_CAP_REG, 0, // 0x0109 - should be tuned
IR01_CNT_CTRL_REG, IR1_CCTL_SWP_CNT_L, // 0x0106 - Counter control: select counter 1, no counter swapping
IR01_IRQ_MSK_REG, IR1_IRQM_ACT_LOW, // 0x0108 - Interrupt mask: IRQ active low
IR01_RADIO_CTRL1_REG, (IR1_RCTL1_EN_AFC|
IR3_RCTL1_AM_CD2|
IR3_RCTL1_AM_CD1|
IR3_RCTL1_AM_CD0), // 0x202 - Radio control 1 - Enable AFC as default - AM clock divider bits = 1 for FM
//IR01_IFCEN_OSC_REG, xx, // 0x0203 - IF Center Frequency Oscillator: init when setting IF
//IR01_IF_BW_REG, xx, // 0x0205 - IF Bandwidth: init when setting IF
IR01_RADIO_CTRL3_REG, (IR1_RCTL3_SE_FM|
IR1_RCTL3_AGC_SETLVL),// 0x0207 - Radio Control 3: mute audio, mute tone, select FM source, Set AGC level for FM (V4)
IR01_STEREO_CTRL_REG, IR1_DEF_CS_VAL|
IR1_STCTL_AUTO_SLEWRATE|
IR1V6_CANCEL_PILOT, // 0x0208 - Stereo Control: Mono, SD PLL mute off, set default CS value, auto slew rate on
IR01_AUDIO_CTRL1_REG, 0x77, // 0x0209 - Audio Control 1: default volume level
IR01_AUDIO_CTRL2_REG, IR1_BEEP_HIGH, // 0x020A - Audio Control 2: treble/bass setting, don't enable the beep output
IR01_RADIO_CTRL2_REG, IR1_RCTL2_IF_PM_L|
IR1_RCTL2_AGC_SPD, // 0x0206 - Radio Control 2: VREF2/VREF on, IF PLL mute off, Turn on AGC speed for quick fieldstrength measuring
IR01_PW_SCTRL_REG, (IR1_PSCTL_PW_RAD|
IR1_DEF_SOFT_ST|
IR1_DEF_SOFT_MUTE), // 0x020B - Power and soft control: turn on FM. Set default soft mute, soft stereo
// AM part
IR03_AM_ACAPLOW_REG, 0, // 0x0302 - AM antenna capacitor (low byte)
IR03_AM_FE_REG, IR3_AFE_AGCSP, // 0x0303 - AM front end control & AA cap high
IR03_AM_CTRL_REG, (IR3_AMCTL_AGC3_1|
IR3_AMCTL_AGC3_0), // 0x0304 - AM control register AGC3=3
};
#define LV2410X_DEFAULT_REG_LSIZE (sizeof(g_Lv2410xDefault)/sizeof(g_Lv2410xDefault[0]))
/*-------------------------------------------------------------------
Register address list to be shadowed
(Only save the necessary registers to reduce RAM usage)
-------------------------------------------------------------------*/
WORD _rom g_Lv24ShadowList[] =
{
IR01_MSRC_SEL_REG, // 0x0102 Block 1- Reg02 (W): Measure source select
IR01_FM_OSC_REG, // (*) 0x0103 Block 1- Reg03 (W): DAC control for FM-RF oscillator
IR01_SD_OSC_REG, // (*) 0x0104 Block 1- Reg04 (W): DAC control for stereo decoder oscillator
IR01_IF_OSC_REG, // (*) 0x0105 Block 1- Reg05 (W): DAC control for IF oscillator
IR01_CNT_CTRL_REG, // 0x0106 Block 1- Reg06 (W): Counter control
IR01_IRQ_MSK_REG, // 0x0108 Block 1- Reg08 (W): Interrupt mask
IR01_FM_CAP_REG, // 0x0109 Block 1- Reg09 (W): CAP bank control for RF-frequency
IR01_RADIO_CTRL1_REG, // 0x0202 Block 2- Reg02 (W): Radio control 1
IR01_IFCEN_OSC_REG, // (*) 0x0203 Block 2- Reg03 (W): IF Center Frequency Oscillator
IR01_IF_BW_REG, // (*) 0x0205 Block 1- Reg05 (W): IF Bandwidth
IR01_RADIO_CTRL2_REG, // 0x0206 Block 2- Reg06 (W): Radio Control 2
IR01_RADIO_CTRL3_REG, // 0x0207 Block 2- Reg07 (W): Radio Control 3
IR01_STEREO_CTRL_REG, // 0x0208 Block 2- Reg08 (W): Stereo Control
IR01_AUDIO_CTRL1_REG, // 0x0209 Block 2- Reg09 (W): Audio Control 1
IR01_AUDIO_CTRL2_REG, // 0x020A Block 2- Reg0A (W): Audio Control 2
IR01_PW_SCTRL_REG, // 0x020B Block 2- Reg0B (W): Power and soft control
// Additional registers for AM
IR03_AM_ACAPLOW_REG, // (*) 0x0302 Block 3-Reg02 (W): AM antenna capacitor (low byte)
IR03_AM_FE_REG, // 0x0303 Block 3-Reg03 (W): AM front end control & AA cap high
IR03_AM_CTRL_REG, // 0x0304 Block 3-Reg04 (W): AM control register
// (*): not required if stand-alone mode only.
// These registers are shadowed for retoring them when switching from USB to stand alone mode
};
#define LVSHADOW_LSIZE (sizeof(g_Lv24ShadowList)/sizeof(g_Lv24ShadowList[0]))
// Global for this module
BYTE g_byaShwRegValue[LVSHADOW_LSIZE]; // array to hold the shadowed value
/*-------------------------------------------------------------------
Treble/Bass converting table
-------------------------------------------------------------------*/
BYTE _rom g_Lv24001Treble[]=
{
IR1_ACTL2_TREB_N, // Logical level 0
0, // Logical level 1
IR1_ACTL2_TREB_P, // Logical level 2
};
#define IMR1_TREBLE_LSIZE (sizeof(g_Lv24001Treble)/sizeof(g_Lv24001Treble[0]) )
BYTE _rom g_Lv24001Bass[]=
{
//IR1_ACTL2_BASS_N|IR1_ACTL2_BASS_LVL, // Logical level 0: invalid combination!
IR1_ACTL2_BASS_N, // 0 // Logical level 0
0, // 1 // Logical level 1
IR1_ACTL2_BASS_P, // 2 // Logical level 2
IR1_ACTL2_BASS_P|IR1_ACTL2_BASS_LVL, // 3 // Logical level 3
};
#define IMR1_BASS_LSIZE (sizeof(g_Lv24001Bass)/sizeof(g_Lv24001Bass[0]) )
/*-------------------------------------------------------------------
LV2410x feature limit
-------------------------------------------------------------------*/
typedef struct
{
BYTE byFeatureId;
BYTE byUpperLimit;
} LV_FEAT_LIMIT;
LV_FEAT_LIMIT _rom g_Lv2400xFeatLimit[] =
{
IHCAP_TUNERPWR, 1, // Tuner's power: 0=off, 1= On
IHCAP_VOLUME, 20, // Volume level
IHCAP_AMUTE, 1, // Audio mute: 0=audio, 1= muted
IHCAP_ATREBLE, (IMR1_TREBLE_LSIZE-1), // Audio treble
IHCAP_ABASS, (IMR1_BASS_LSIZE-1), // Audio bass
IHCAP_DYNBASSBOOST, 15, // Dynamic bass boost
IHCAP_SMUTE, 7, // Audio soft mute
IHCAP_STEREO, 1, // Stereo: 0=mono, 1=stereo
IHCAP_SOFT_ST, 7, // Soft stereo
IHCAP_RADIOSOURCE, 2, // (LV2410x) Radio source: 0=Radio off, 1=FM, 2=AM
IHCAP_EXTSOURCE, 1, // External source: 0=off, 1=on
IHCAP_BEEPSOURCE, 3, // Beep tone: 0=off, 1=Freq1, 2=Freq2, 3=Freq3
//IHCAP_AFC 1, // Bit 14: AFC (automatic frequency control) supported
IHCAP_HPA, 1, // Bit 15: Hardware headphone amplifier presents
// Software features
IHCAP_SCANLVL, 7, // Scan level (0...7)
IHCAP_SCANWRP, 2, // 0=no wrap, 1=wrap once, 2=wrap continue
IHCAP_REGION, 4, // Region: 0=None, 1=Europe, 2=Japan, 3=USA, 4=JapanWide
IHCAP_BEEPVOL, 20, // Beep volume - same limit as IHCAP_VOLUME
#ifdef USE_EXTCLK
IHCAP_EXTCLK, 1, // 0= no external clock, 1= 12MHz, 2=32kHz
#endif //USE_EXTCLK
};
#define LV2400X_FEATLIMIT_LSIZE (sizeof(g_Lv2400xFeatLimit)/sizeof(g_Lv2400xFeatLimit[0]))
// ----- FM-RF to AM-RF divider table
typedef struct
{
BYTE byRegValue; // Register value to select the divider factor
BYTE byDivFac; // The divider factor tab value
} REG_DIVFAC_STRUCT;
REG_DIVFAC_STRUCT _rom g_IR03ES1AmDivider[]=
{
IR3_AMDIV_48, 48, // 0
IR3_AMDIV_64, 64, // 1
IR3_AMDIV_80, 80, // 2
IR3_AMDIV_96, 96, // 3
IR3_AMDIV_128, 128, // 4
IR3_AMDIV_160, 160, // 5
IR3_AMDIV_192, 192, // 6
//IR3_AMDIV_OFF, 1, // 7 (Divider off)
};
#define IMR3ES1_AMDIVTAB_SIZE (sizeof(g_IR03ES1AmDivider)/sizeof(g_IR03ES1AmDivider[0]) )
/*-------------------------------------------------------------------
LV2410x routines
-------------------------------------------------------------------*/
BYTE InitLv2400xChip(void)
{
BYTE byResult;
BYTE i;
// Init software
g_byBlock = 0xFF; // Mark no block is selected yet
g_byHwFlag1 = HF1_NEG_IF_PHASE; // LV2400x has negative IF phase
g_byRegion = REGION_EUROPE; // Default region for FM
g_byAmRegion = REGION_EUROPE; // Default region for AM
g_byStnFlag = STNWRAP_ONCE; // Default options
g_byScanLevel = 4; // Default scan level
g_byDynBassBoost = 15; // Default: dynamic bass boost level is max.
g_byBeepVol = 10; // Default beep volume
g_byFmStereo = TRUE; // Default is stereo mode
g_wLastAmFreq = 0; // Default: no AM frequency set yet
// 1) Write the default values to the device
for (i=0; i<LV2410X_DEFAULT_REG_LSIZE; i++)
WriteReg(g_Lv2410xDefault[i].wRegAddress, g_Lv2410xDefault[i].byValue);
// 2) Set the prefered IF frequency
byResult = Set_IF_Freq(DEFAULT_IF_FREQ);
// 3) Init tuning system
if (byResult == LVLS_NO_ERROR)
byResult = InitTuningRfCapOsc();
// 4) Set region to initialise Radio band limits
if (byResult == LVLS_NO_ERROR)
byResult = SetRegion(g_byRegion);
// 5) Set the prefered Stereo Decode clock
Set_SD_Freq(DEFAULT_SD_FREQ); // This step can be postboned until stereo is enabled
// Additional step: read the chip ID to determine chip specific features (in case the wrong chip is connected)
switch (ReadReg(IR01_CHIP_ID_REG))
{
case LV24102_ID: // AM and headphone supported
g_byHwFlag1 |= HF1_AM;
// Fall through
case LV24002_ID: // Headphone supported
g_byHwFlag1 |= HF1_HP;
break;
case LV24101_ID: // AM supported
g_byHwFlag1 |= HF1_AM;
break;
//case LV24001_ID:
default:
break;
}
// Extra init for AM
{
DWORD dwTmp;
g_wFmRfLo = g_wHwRfLow; // FM RF limit (10 kHz unit)
g_wFmRfHi = g_wHwRfHigh;
dwTmp = g_wHwRfLow; // FM-RF in 10 kHz
dwTmp = dwTmp * 10; // Convert FM-RF to 1kHz.
g_wAmRfLo = dwTmp/g_IR03ES1AmDivider[IMR3ES1_AMDIVTAB_SIZE-1].byDivFac; // Minimal AM_RF freq = Min. FM_RF/Max.divider
dwTmp = g_wHwRfHigh; // FM-RF in 10 kHz
dwTmp = dwTmp * 10; // Convert FM-RF to 1 kHz
g_wAmRfHi = dwTmp/g_IR03ES1AmDivider[0].byDivFac; // Maximal AM_RF freq = Max. FM_RF/Min.divider
}
// The chip is now ready - remember that it's still muted
return(byResult);
}// End InitLv2400xChip
void DeInitLv2400xChip(void)
{
// Disable interrupt
DisableLv2400xIrq();
// Mute the audio
SetChipAudioMute(TRUE, MUTESRC_APPLICATION);
// Turn off the chip power
//DriveBit(IR01_PW_SCTRL_REG, IR1_PSCTL_PW_RAD, FALSE); // Skip to avoid noise on speaker
} // End DeInitLv2400xChip
/* ************************************************************************************************
*
* Function: Set_IF_Freq
* Authors: Hung van Le
* Purpose: Set the IF frequency to specified dwInputIF
* Input:
* DWORD dwInputIF: the IF frequency to be set in Hz
* Output: Status as defined in LvErr.h
* Comments: None
*
* ************************************************************************************************
* Copyright (c) 2004. Semiconductor Ideas to the Market (ItoM) B.V. All rights reserved.
* ************************************************************************************************ */
BYTE Set_IF_Freq(WORD wInputIF)
{
BYTE byResult;
BYTE byOrgDemState;
WORD wCfg;
// turn on demodulator PLL mute to set the IF
byOrgDemState = DriveBitNeg(IR01_RADIO_CTRL2_REG, IR1_RCTL2_IF_PM_L, TRUE);
// Select correct oscillator output and enable measuring mode
wCfg = SetUpChipMode(CO_IF_OSC|CHIP_MEASURE_MODE);
// Do the tuning
byResult = LinTuneDac(wInputIF, LV_MSR_TIME_32ms, WriteIfOsc, 50, 150, 1);
// Tuning done - restore status
DriveBitNeg(IR01_RADIO_CTRL2_REG, IR1_RCTL2_IF_PM_L, byOrgDemState);
// Restore chip config
SetUpChipMode(wCfg);
return(byResult);
} // End Set_IF_Freq
/* ************************************************************************************************
*
* Function: Set_SD_Freq
* Authors: Hung van Le
* Purpose: Set the stereo decoder clock frequency to specified dwInputSC
* Input:
* DWORD dwInputSC: the stereo decoder clock frequency to be set in Hz
* Output: Status as defined in LvErr.h
* Comments: the set SC will be shadowed in m_dwStereoClock
*
* ************************************************************************************************
* Copyright (c) 2004. Semiconductor Ideas to the Market (ItoM) B.V. All rights reserved.
* ************************************************************************************************ */
BYTE Set_SD_Freq(WORD wInputSC)
{
BYTE byResult;
BOOL bOrgPllState;
WORD wCfg;
WORD wCurFreq;
// turn on the stereo PLL mute measure the stereo decoder clock
bOrgPllState = DriveBit(IR01_STEREO_CTRL_REG, IR1_STCTL_SD_PM, TRUE);
// Select correct oscillator output and enable measuring mode
wCfg = SetUpChipMode(CO_SD_OSC|CHIP_MEASURE_MODE);
// Get current stereo clock
byResult = CountPulse(LV_MSR_TIME_100ms, &wCurFreq);
// Skip tuning if the frequency is already good
if (byResult == LVLS_NO_ERROR)
{
if ( IsFrequencyOk(wCurFreq, DEFAULT_SD_FREQ, LV_MSR_TIME_100ms) != 0 )
byResult = LVLS_NO_ERROR+1;
}
// Do the tuning - Some device has dead point below StereoOsc<20, so interpolate between 50-150
if (byResult != LVLS_NO_ERROR)
byResult = LinTuneDac(wInputSC, LV_MSR_TIME_100ms, WriteSdOsc, 50, 150, 1);
// Tuning done - restore status
DriveBit(IR01_STEREO_CTRL_REG, IR1_STCTL_SD_PM, bOrgPllState);
SetUpChipMode(wCfg);
return(byResult);
} // End Set_SD_Freq
/* ************************************************************************************************
*
* Function: Virtualize register access to the hardware
* WriteIfOsc (adjust the DAC of IF PLL )
* WriteSdOsc (adjust the DAC of Stereo decoder clock)
* WriteRfOsc (adjust the DAC of RF varicap)
* Authors: Hung van Le
* Purpose: These functions provide access to registers of the device which are used for setting frequencies
* Comments: None
*
* ************************************************************************************************
* Copyright (c) 2004. Semiconductor Ideas to the Market (ItoM) B.V. All rights reserved.
* ************************************************************************************************ */
BYTE WriteIfOsc(WORD wIfOscValue)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -