📄 lv2400x.c
字号:
/************************************************************************
*
* Copyright(c) 2004 ItoM BV
* All Rights Reserved.
*
* LV2400x evaluation kit: LC24001 specific code
* File name: Lv2400x.c
*
*************************************************************************/
#include <stdio.h>
#include "common.h"
#include "Lv24Ekit.h"
// ==============================================================================
#ifdef USE_LV2400x // The whole file can be discarded if LV2400x is not used
// ==============================================================================
#include "Lv2400xReg.h" // For register layout
/*-------------------------------------------------------------------
Local data
-------------------------------------------------------------------*/
typedef struct // Register address-value structure (for default register settings)
{
WORD wRegAddress;
BYTE byValue;
} I3W_REG_VALUES;
// ----- Default register value list of LV2400x
I3W_REG_VALUES _rom g_Lv2400xDefault[] =
{
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|
IR1_RCTL1_NA_H_4|
IR1_RCTL1_NA_H_1|
IR1_RCTL1_NA_H_0), // 0x202 - Radio control 1 - Enable AFC as default - keep reserved bit high
//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
};
#define LV2400X_DEFAULT_REG_LSIZE (sizeof(g_Lv2400xDefault)/sizeof(g_Lv2400xDefault[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
// (*): 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]) )
/*-------------------------------------------------------------------
LV24001 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, 1, // Radio source: 0=Radio off, 1=FM
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]))
/*-------------------------------------------------------------------
LV24001 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
g_byStnFlag = STNWRAP_ONCE; // Default options
g_byScanLevel = 4; // Default scan level
g_byBeepVol = 10; // Default beep volume
g_byDynBassBoost = 15; // Default: dynamic bass boost level is max.
// 1) Write the default values to the device
for (i=0; i<LV2400X_DEFAULT_REG_LSIZE; i++)
WriteReg(g_Lv2400xDefault[i].wRegAddress, g_Lv2400xDefault[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 FM 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
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;
}
// 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: GetOutputSelect
*
* Authors: Hung van Le
* Purpose: Select an output of IMR01 chip
* Input: Nothing
* Output: The output select
* Comments: The output select is virtualized.
*
* ************************************************************************************************
* Copyright (c) 2004. Semiconductor Ideas to the Market (ItoM) B.V. All rights reserved.
* ************************************************************************************************ */
BYTE GetOutputSelect(void)
{
BYTE byCurOutputSel;
// Get current measuring mask
byCurOutputSel = GetSwRegValue(IR01_MSRC_SEL_REG) & IR1_MSRCS_MSS_MASK;
if (byCurOutputSel == IR1_MSRCS_MSS_FM)
return(CO_RF_OSC); // RF frequency
else if (byCurOutputSel == IR1_MSRCS_MSS_IF)
return(CO_IF_OSC); // IF frequency
else if (byCurOutputSel == IR1_MSRCS_MSS_SD)
return(CO_SD_OSC); // SD frequency
else // other settings
return(CO_NONE);
} // End GetOutputSelect
/* ************************************************************************************************
*
* Function: SetOutputSelect
*
* Authors: Hung van Le
* Purpose: Select an output of IMR01 chip
* Input:
* WORD wOutputCfg: desired output (See SetUpChipMode in Lv24Ekit.h for possible outputs)
* Output: The original output select
* Comments: The output select is virtualized.
*
* ************************************************************************************************
* Copyright (c) 2004. Semiconductor Ideas to the Market (ItoM) B.V. All rights reserved.
* ************************************************************************************************ */
WORD SetOutputSelect(WORD wOutputCfg)
{
WORD wCurOutputCfg;
// Determine current chip output
wCurOutputCfg = GetOutputSelect();
// Do nothing if no change
if (wCurOutputCfg == wOutputCfg)
return(wCurOutputCfg);
// Output select change - update chip
switch (wOutputCfg)
{
case CO_NONE: // Disable all measurements
SetRegBits(IR01_MSRC_SEL_REG, IR1_MSRCS_MSS_MASK, 0);
break;
case CO_RF_OSC: // RF frequency
SetRegBits(IR01_MSRC_SEL_REG, IR1_MSRCS_MSS_MASK, IR1_MSRCS_MSS_FM);
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -