📄 lv2410x.c
字号:
dwH = (dwTmp2 * 1000000)%dwMeasureTimeUs; // Remainder of KHz
dwH = (dwH *1000)/dwMeasureTimeUs; // Hz from KHz
dwTmp2 = dwTmp1%1000; // Hz from MHz
dwH += ((dwTmp2 * 1000000)/dwMeasureTimeUs); // Total Hz
dwFreq = dwM*1000000 + dwK*1000 + dwH; // Total frequency
}
// MulDiv variant
//dwFreqHz = MulDiv(dwFreq, 1000000, dwMeasureTimeUs);
break;
}
// Shadow the measured frequency to simulates (frequency) read-registers
ShadowMeasuredFrequency(dwFreq);
return((WORD)dwFreq);
} // End PulseToFrequency1
/* ************************************************************************************************
*
* Function: CountPulseCnt2
*
* Authors: Hung van Le
* Purpose: Counting the pulse (Measure frequencies) of the currently
* selected chip's output. Measuring interval is made with external clock
* Input:
* PWORD pwFreq: buffer to receive the measured frequency (unit depends on chip output)
* Output: Status as defined in LvErr.h
* Comments: See also CountPulseCnt1
* The code is fixed for 12MHz external clock (counter swapping enabled)
* Counter 2 usage
* RF (100 MHz): IR1_CTAB_128, 128 (measuring time 0.66ms - 127ppm)
* RF (100 MHz): IR1_CTAB_512, 512 (measuring time 2.62ms - 32ppm)
*
* IF (45 kHz): IR1_CTAB_128, 128 (overflow !)
* IF (100 kHz): IR1_CTAB_128, 128 (measuring time 2.56ms - 33ppm)
*
* IF (45 kHz): IR1_CTAB_32, 32 (measuring time 1.42ms - 59ppm)
* IF (100 kHz): IR1_CTAB_32, 32 (measuring time 0.64ms - 130ppm)
*
* SD (38 kHz): IR1_CTAB_32, 32 (measuring time 1.68ms - 49ppm)
*
* RDS(57 kHz): IR1_CTAB_32, 32 (measuring time 1.12ms - 74ppm)
*
* Because of short measuring time, this method is not suitable for measuring IF/SD/RDS PLL
* in lock mode.
* In free running mode (calibration mode), this method can be used.
*
* RF is not PLL, so this methode always works
* We use following:
* RF 128
* IF/SD in free running mode: 32
* IF in lock mode: software window
*
* ************************************************************************************************
* Copyright (c) 2004. Semiconductor Ideas to the Market (ItoM) B.V. All rights reserved.
* ************************************************************************************************ */
#ifdef USE_EXTCLK
BYTE CountPulseCnt2(PWORD pwFreq)
{
BYTE byResult;
WORD wPulseCnt1, wPulseCnt2;
BYTE byTab;
BOOL bSwapState, bCntSelState;
// Return value 0 means no pulses counted (chip removed?)
//*pwFreqHz = 0;
byResult = LVLS_NO_ERROR;
if (GetOutputSelect() == CO_RF_OSC)
{
byTab = IR1_CTAB_128; // Register value
wPulseCnt2 = 128 *IMR01_CNT2_PRESCALER; // Pulses for counter 2
}
else
{
byTab = IR1_CTAB_32; // Register value
wPulseCnt2 = 32 *IMR01_CNT2_PRESCALER; // Pulses for counter 2
}
// Reset counter 1
DriveBit(IR01_CNT_CTRL_REG, IR1_CCTL_CNT1_CLR, TRUE); // Drive Clear counter bit of high
DriveBit(IR01_CNT_CTRL_REG, IR1_CCTL_CNT1_CLR, FALSE); // Drive Clear counter bit of low
// Program swap counter bit, tab bit, select counter 2
bSwapState = DriveBitNeg(IR01_CNT_CTRL_REG, IR1_CCTL_SWP_CNT_L, TRUE); // Swap counter
bCntSelState = DriveBit(IR01_CNT_CTRL_REG, IR1_CCTL_CNT_SEL, TRUE); // Select counter 2
SetRegBits(IR01_CNT_CTRL_REG, IR1_CCTL_CNT_TAB, byTab); // counter Tab setting
// Enable counter to start counting
DriveBit(IR01_CNT_CTRL_REG, IR1_CCTL_CNT_EN, TRUE);
// Wait counting done - Poll register for counting done
wPulseCnt1 = 1500; // Temporary use wPulseCnt1 as loop counter
do
{
if (ReadReg(IR01_IRQ_ID_REG) & IR1_IRQID_CNT2) // Counting done bit set
break;
wPulseCnt1--;
DelayUs(DLT_100us);
} while (wPulseCnt1>0);
// Counting done - Disable the counter (also clear IR1_IRQID_CNT2 bit)
DriveBit(IR01_CNT_CTRL_REG, IR1_CCTL_CNT_EN, FALSE);
// Check timeout
if (wPulseCnt1 == 0)
{
byResult = LVLS_POLLING_CNT_TIMEOUT;
}
else
{
// Read counter1 of LV2400x
wPulseCnt1 = ReadReg(IR01_CNT_H_REG); // High byte
wPulseCnt1 <<= 8;
wPulseCnt1 |= ReadReg(IR01_CNT_L_REG); // Patch low byte
}
// restore swap bit, counter select bit
DriveBitNeg(IR01_CNT_CTRL_REG, IR1_CCTL_SWP_CNT_L, bSwapState);
DriveBit(IR01_CNT_CTRL_REG, IR1_CCTL_CNT_SEL, bCntSelState);
// Formula to calculate frequency from pulse counts
// if NoSwapping
// f = (N1 * fext * DividerFactor)/N2
// if Swapping
// f = (N2 * fext * DividerFactor)/N1
// (N2 is value of counter 2 = TabValue * CNT2_div_factor)
*pwFreq = PulseToFrequency2(wPulseCnt2, wPulseCnt1);
return(byResult);
} // End CountPulseCnt2
#endif //USE_EXTCLK
#ifdef USE_EXTCLK
WORD PulseToFrequency2(WORD wCntA, WORD wCntB)
{
DWORD dwFreq;
// Avoid dividing by zero
if (wCntB == 0)
{
dwFreq = 0;
}
else
{
switch ( GetOutputSelect() )
{
case CO_RF_OSC:
dwFreq = (DWORD)wCntA * IMR01_FM_DIVIDER;
dwFreq *= (EXT_CLK_12MHZ/10000); // 10 KHz unit for RF
break;
case CO_IF_OSC:
dwFreq = (DWORD)wCntA * (EXT_CLK_12MHZ/10); // 10 Hz unit for IF
break;
//case CO_SD_OSC:
default:
dwFreq = (DWORD)wCntA * (EXT_CLK_12MHZ); // 1 Hz unit for other frequency
break;
}
dwFreq /= wCntB;
}
// Shadow the measured frequency to simulates (frequency) read-registers
ShadowMeasuredFrequency(dwFreq);
return((WORD)dwFreq);
} // End PulseToFrequency2
#endif //USE_EXTCLK
/* ************************************************************************************************
*
* Function: GetDividerFactor
*
* Authors: Hung van Le
* Purpose: Determine the (internal) divider factor by current chip output select
* Input: None
* Output: The divider factor belongs to current chip output
* Comments: For this device: the divider factor is 256 for FM output, 1 for other outputs
*
* ************************************************************************************************
* Copyright (c) 2004. Semiconductor Ideas to the Market (ItoM) B.V. All rights reserved.
* ************************************************************************************************ */
WORD GetDividerFactor(void)
{
if ( GetOutputSelect() == CO_RF_OSC )
return(IMR01_FM_DIVIDER); // usualy 256
else
return(1);
} // End GetDividerFactor
/* ************************************************************************************************
*
* Function: ShadowMeasuredFrequency
*
* Authors: Hung van Le
* Purpose: Simulates some (frequency) read-registers which are missing in the chip
* Input:
* DWORD dwFreqHz: frequency (in Hz) to be shadowed
* Output: None
* Comments: Use GetOutputSelect to determine the frequency source
*
* ************************************************************************************************
* Copyright (c) 2002-2004. Semiconductor Ideas to the Market (ItoM) B.V. All rights reserved.
* ************************************************************************************************ */
void ShadowMeasuredFrequency(DWORD dwFreqHz)
{
// Only save the RF frequency
if ( GetOutputSelect() == CO_RF_OSC)
{
g_wLastMsrRF = dwFreqHz;
}
} // End ShadowMeasuredFrequency
BYTE SetRfFrequency(WORD wRfFreq)
{
BYTE byResult;
BYTE byOrgAudioMute, byOrgAudioMode;
WORD wCfg;
WORD wCap, wOsc;
// Check limit
{
WORD wRfBandLo, wRfBandHi;
wRfBandHi = DisplayFreqToRf(g_wDisplayBandHigh);
wRfBandLo = DisplayFreqToRf(g_wDisplayBandLow);
byResult = CheckRfLimit(&wRfFreq, wRfBandLo, wRfBandHi, 2);
if (byResult != LVLS_NO_ERROR)
return(byResult);
}
// No valid station by a frequency set
g_byStnFlag &= (~STN_VALID);
// Save the new RF frequency
g_wLastSetRF = wRfFreq;
// Select correct oscillator output and enable measuring mode
wCfg = SetUpChipMode(CO_RF_OSC|CHIP_MEASURE_MODE|CHIP_AFC_OFF);
// Mute audio and force mono mode
byOrgAudioMute = SetChipAudioMute(TRUE, MUTESRC_OPERATION);
byOrgAudioMode = SetChipStereo(FALSE);
// Quick frequency set
CalculateRfCapOsc(wRfFreq, &wCap, &wOsc, QSSF_PRECISION_MED);
//WriteRfCap(wCap); // Will be done in FineTuneRfOsc
byResult = FineTuneRfOsc(wRfFreq, LV_MSR_TIME_32ms, wOsc, FALSE);
// Do finetuning if frequency is set
//if ( (dwResult == LVLS_NO_ERROR) && (dwOption & SETSTN_FINETUNE) )
// FineTuneFmToIF(&m_bValidStation);
// Restore chip config
SetUpChipMode(wCfg);
// Restore status
SetChipAudioMute(byOrgAudioMute, MUTESRC_OPERATION);
SetChipStereo(byOrgAudioMode);
return(byResult);
} // End SetRfFrequency
BYTE GetHwFeatureLimit(BYTE byFeatureId)
{
// Return upper limit of a feature (lower limit is always 0)
// Upper limit 0 means feature is not supported
BYTE i;
// Headphone amplifier: depends on hardware capapbility
if (byFeatureId == IHCAP_HPA)
{
if ( (g_byHwFlag1 & HF1_HP)==0 )
return(0); // Not supported by hardware
}
// Headphone amplifier: depends on hardware capapbility
if (byFeatureId == IHCAP_RADIOSOURCE)
{
if ( (g_byHwFlag1 & HF1_AM)==0 )
return(1); // Not supported by hardware - Only Off/FM
}
if (byFeatureId == IHCAP_REGION)
{
if ( (g_byStnFlag & STN_AM_MODE) == STN_AM_MODE )
return(3); // Only 0=None, 1=Europe, 2=Japan, 3=USA for AM mode (no JapanWide)
}
for (i=0; i<LV2400X_FEATLIMIT_LSIZE; i++)
{
if ( g_Lv2400xFeatLimit[i].byFeatureId == byFeatureId)
return(g_Lv2400xFeatLimit[i].byUpperLimit);
}
return(0); // Not support - no upper limit
} // End GetHwFeatureLimit
BYTE GetHwFeatureValue(BYTE byFeatureId)
{
// Return current value of a feature
BYTE byTmp, byValue;
// Default returned value
byValue=0;
switch (byFeatureId)
{
case IHCAP_TUNERPWR:
byTmp = GetSwRegValue(IR01_PW_SCTRL_REG);
if ( byTmp & IR1_PSCTL_PW_RAD ) // FM power on bit = 1: power is on
byValue = 1;
break;
case IHCAP_AMUTE:
if ( g_bySwFlag1 & MUTESRC_APPLICATION )
byValue = 1; // Muted
break;
case IHCAP_VOLUME:
byValue = GetChipVolume();
if ( (g_bySwFlag1 & MUTESRC_VOLUME)==0 )
byValue++; // Convert hardware level to logical level (add 1 when we are not muted)
break;
case IHCAP_STEREO:
byTmp = GetSwRegValue(IR01_STEREO_CTRL_REG);
if ( (byTmp & IR1_STCTL_STEREO_L) == 0) // Stereo bit = 0: stereo is enabled
byValue=1;
break;
// case IHCAP_DEEMP:
// wTmp = GetSwRegValue(IR01_AUDIO_CTRL2_REG);
// if ( wTmp & IR1_ACTL2_DEEMP75 ) // Deemphasis bit = 1: 75us
// pValue->State.bState = DEEMP_75;
// else
// pValue->State.bState = DEEMP_50;
// break;
case IHCAP_SMUTE: // Soft mute
// Soft mute is in bit [4:2] of IR01_PW_SCTRL_REG
byTmp = (BYTE)(GetSwRegValue(IR01_PW_SCTRL_REG) & IR1_PSCTL_SOFT_MUTE);
byValue = byTmp>>2; // Shift to logical level
break;
case IHCAP_SOFT_ST: // Soft stereo
// Soft stereo is in bit [7:5] of IR01_PW_SCTRL_REG
byTmp = (BYTE)(GetSwRegValue(IR01_PW_SCTRL_REG) & IR1_PSCTL_SOFT_ST);
byValue = byTmp>>5; // Shift to logical level
break;
// case IHCAP_AFC: // AFC (automatic frequency control)
// byTmp = GetSwRegValue(IR01_RADIO_CTRL1_REG);
// if (byTmp & IR1_RCTL1_EN_AFC)
// byValue = 1;
// break;
case IHCAP_ATREBLE: // Audio treble
// Fetch current setting
byTmp = (BYTE)(GetSwRegValue(IR01_AUDIO_CTRL2_REG) & IR1_ATREBLE_MASK);
// Return the logical level
byValue = SearchInByteArray(byTmp, g_Lv24001Treble, IMR1_TREBLE_LSIZE);
break;
case IHCAP_ABASS: // Audio bass
// Fetch current setting
byTmp = (BYTE)(GetSwRegValue(IR01_AUDIO_CTRL2_REG) & IR1_ABASS_MASK);
// Return the logical level
byValue = SearchInByteArray(byTmp, g_Lv24001Bass, IMR1_BASS_LSIZE);
break;
case IHCAP_RADIOSOURCE:
// Return: 0: off, 1: FM, 2: AM
byTmp = GetSwRegValue(IR01_RADIO_CTRL3_REG);
if (byTmp & IR1_RCTL3_SE_FM)
byValue = 1; // FM mode
else if (byTmp & IR3_RCTL3_SE_AM) // (LV2410X)
byValue = 2; // AM mode
break;
case IHCAP_EXTSOURCE:
// Input: on/off (true/false)
byTmp = GetSwRegValue(IR01_RADIO_CTRL3_REG);
if (byTmp & IR1_RCTL3_SE_EXT)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -