📄 lv2410x.c
字号:
* muted through a chip function like BOOL MuteStereoDecoderPll(BOOL bState) instead of driving the bit
* directly.
* - Function SetHwFeatureValue(IHCAP_BEEPSOURCE, byValue) can also be used to avoid accessing the LV2400x
* directly. byValue for LV2400x is: 0=beep off, 1=beep 500 Hz, 2=beep 1kHz, 3=beep 2kHz
* - Make sure that the LV2400x is in idle state before invoking this function.
* ************************************************************************************************
* Copyright (c) 2004. Semiconductor Ideas to the Market (ItoM) B.V. All rights reserved.
* ************************************************************************************************ */
void AudioFeedback(BYTE byType)
{
// Local equations
#define _AFB_DEMPLL ((BYTE)0x01)
#define _AFB_SDPLL ((BYTE)0x02)
#define _AFB_AUD_MUTE ((BYTE)0x04)
BYTE byOrgFlag, byCurVolume, byOrgBeep, byOrgBand;
// Do nothing if beep is not desired
if (g_byBeepVol==0)
return;
// Init local.
byOrgFlag = 0;
// Turn off radio band, enable beep source
byOrgBand = SetRegBits(IR01_RADIO_CTRL3_REG, (IR1_RCTL3_SE_FM|IR3_RCTL3_SE_AM|IR1_RCTL3_SE_BEEP), IR1_RCTL3_SE_BEEP);
// Turn on the stereo decoder PLL mute for stable beep frequency
if ( DriveBit(IR01_STEREO_CTRL_REG, IR1_STCTL_SD_PM, TRUE) )
byOrgFlag |= _AFB_SDPLL;
// Unmute audio if necessary
if ( GetHwFeatureValue(IHCAP_AMUTE) )
{
SetHwFeatureValue(IHCAP_AMUTE, 0); // Un-mute audio
byOrgFlag |= _AFB_AUD_MUTE;
}
// Set volume if necessary
byCurVolume = GetHwFeatureValue(IHCAP_VOLUME); // Determine current volume level
if (byCurVolume<g_byBeepVol)
SetHwFeatureValue(IHCAP_VOLUME, g_byBeepVol);
// turn on demodulator PLL mute to mute the radio
//@@ if (DriveBitNeg(IR01_RADIO_CTRL2_REG, IR1_RCTL2_IF_PM_L, TRUE) )
// byOrgFlag |= _AFB_DEMPLL;
if (byType == AUDFB_TYPE1)
{
// Beep at 500 Hz
byOrgBeep = SetRegBits(IR01_AUDIO_CTRL2_REG, IR1_ACTL2_BPFREQ, IR1_BEEP_500Hz);
DelayUs(DLT_20ms);
DelayUs(DLT_20ms);
}
else //if (byType == AUDFB_TYPE2)
{
// Beep at 2kHz
byOrgBeep = SetRegBits(IR01_AUDIO_CTRL2_REG, IR1_ACTL2_BPFREQ, IR1_BEEP_2KHz);
DelayUs(DLT_20ms);
DelayUs(DLT_20ms);
// Pause
SetRegBits(IR01_AUDIO_CTRL2_REG, IR1_ACTL2_BPFREQ, IR1_BEEP_OFF);
DelayUs(DLT_20ms);
DelayUs(DLT_20ms);
// Beep at 2kHz
SetRegBits(IR01_AUDIO_CTRL2_REG, IR1_ACTL2_BPFREQ, IR1_BEEP_2KHz);
DelayUs(DLT_20ms);
DelayUs(DLT_20ms);
}
// Restore everything
if (byCurVolume != g_byBeepVol) // Restore volume
SetHwFeatureValue(IHCAP_VOLUME, byCurVolume);
//@@@ if ( (byOrgFlag &_AFB_DEMPLL)==0 ) // Restore demodulator PLL mute
// DriveBitNeg(IR01_RADIO_CTRL2_REG, IR1_RCTL2_IF_PM_L, FALSE);
if ( byOrgFlag & _AFB_AUD_MUTE ) // Restore audio mute
SetHwFeatureValue(IHCAP_AMUTE, 1);
if ( (byOrgFlag & _AFB_SDPLL)==0 ) // Restore the stereo decoder PLL mute
DriveBit(IR01_STEREO_CTRL_REG, IR1_STCTL_SD_PM, FALSE);
// Restore beep frequency bits
SetRegBits(IR01_AUDIO_CTRL2_REG, IR1_ACTL2_BPFREQ, byOrgBeep);
// Restore radio band, beep source setting
SetRegBits(IR01_RADIO_CTRL3_REG, (IR1_RCTL3_SE_FM|IR3_RCTL3_SE_AM|IR1_RCTL3_SE_BEEP), byOrgBand);
} // End AudioFeedback
//-----------------------------------------------------------------------------
// Helper functions for switch between USB and stand-alone mode
// Placed here because of the shadow list/value array
//-----------------------------------------------------------------------------
#ifdef USE_USB
void RestoreShadowReg()
{
// Restore shadow register of LV2400x when switching from USB back to stand-alone
BYTE i;
g_byBlock = 0xFF; // Mark shadowed block select is dirty to force setting it the 1st time
for (i=0; i<LVSHADOW_LSIZE; i++)
WriteReg(g_Lv24ShadowList[i], g_byaShwRegValue[i]);
} // End RestoreShadowReg
#endif //USE_USB
//-----------------------------------------------------------------------------
// Registers shadowing function
//-----------------------------------------------------------------------------
void ShadowReg(WORD wRegAddress, BYTE byValue)
{
BYTE i;
for (i=0; i<LVSHADOW_LSIZE; i++)
{
if ( g_Lv24ShadowList[i] == wRegAddress )
{
g_byaShwRegValue[i] = byValue;
break;
}
}
g_byBlock = MSB(wRegAddress); // Save last access block
} // End ShadowReg
BYTE GetSwRegValue(WORD wRegAddress)
{
BYTE i;
for (i=0; i<LVSHADOW_LSIZE; i++)
{
if ( g_Lv24ShadowList[i] == wRegAddress )
return(g_byaShwRegValue[i]);
}
return(0); // not found
} // End GetSwRegValue
void SelRegBlock(BYTE byBlock)
{
// Skip selecting the block when it's already selected
if (g_byBlock != byBlock)
{
g_byBlock = byBlock; // Save block number for next time
IoWrite3W(byBlock, BLK_SEL); // Write the block number to BLK_SEL register
}
} // End SelRegBlock
/* ************************************************************************************************
*
* Function: IsFrequencyOk
*
* Authors: Hung van Le
* Purpose: Verify if wCurFreq is in range of wExpFreq +/- margin
* Input:
* wCurFreq: current frequency
* wExpFreq: the expected frequency
* dwPrecise: precise of the compare (max=1000000, 1000000 is exact comparing)
* Output:
* 0 : wCurFreq within the margin
* -1: wCurFreq too low (i.e. wCurFreq < (wExpFreq - margin)
* +1: wCurFreq too high (i.e. wCurFreq > (wExpFreq + margin)
* Comments: margin = (1000000 * DividerFactor) / dwPrecise
* Divider factor is dependant on current output select of the chip
*
* ************************************************************************************************
* Copyright (c) 2004. Semiconductor Ideas to the Market (ItoM) B.V. All rights reserved.
* ************************************************************************************************ */
int IsFrequencyOk(WORD wCurFreq, WORD wExpFreq, DWORD dwPrecise)
{
WORD wMargin;
DWORD dwFactor;
if (dwPrecise != 1000000)
{
switch ( GetOutputSelect() )
{
case CO_RF_OSC:
// wMargin = (1000000 * (DWORD)GetDividerFactor())/dwPrecise;
// wMargin /= 10000; // 10 KHz unit for RF
dwFactor = 100 * IMR01_FM_DIVIDER;
break;
case CO_IF_OSC:
// wMargin = (1000000 * (DWORD)GetDividerFactor())/dwPrecise;
// wMargin /= 10; // 10 Hz unit for IF
dwFactor = 100000;
break;
//case CO_SD_OSC:
default:
// wMargin = (1000000 * (DWORD)GetDividerFactor())/dwPrecise;
// wMargin /= 1; // 1 Hz unit for other freq
// 1 Hz unit for SD and other freq.
dwFactor = 1000000;
break;
}
}
else
dwFactor = 0;
if (dwPrecise < dwFactor)
wMargin = (WORD)(dwFactor / dwPrecise);
else
wMargin = 0;
if ( wCurFreq < (wExpFreq - wMargin) )
return(-1);
else if ( wCurFreq > (wExpFreq + wMargin) )
return(1);
else
return(0);
} // End IsFrequencyOk
BYTE CountPulse(DWORD dwMeasureTimeUs, PWORD pwFreq)
{
// Decide counter1/Counter2 usage here
#ifdef USE_EXTCLK
if ( ( g_bySwFlag1 & SF1_EXTCLK) == EXTCLK_12MHz ) // 12MHz is enabled
{
// Don't use counter 2 when measuring IF in lock mode
if ( (GetOutputSelect() != CO_IF_OSC) ||
((GetSwRegValue(IR01_RADIO_CTRL2_REG) & IR1_RCTL2_IF_PM_L) == 0 ) )
return(CountPulseCnt2(pwFreq)); // Use counter 2 (with swapping) for other cases
}
#endif //USE_EXTCLK
return(CountPulseCnt1(dwMeasureTimeUs, pwFreq));
} // End CountPulse
/* ************************************************************************************************
*
* Function: CountPulseCnt1
*
* Authors: Hung van Le
* Purpose: Counting the pulse (Measure frequencies) of the currently
* selected chip's output. Software is responsible for measuring interval
* Input:
* DWORD dwMeasureTimeUs: time to measure in us
* PDWORD pwFreq: buffer to receive the measured frequency (unit depends on chip output)
* Output: Status as defined in LvErr.h
* Comments: Frequencies (depend on current output select) are shadowed when this function is invoked
* This function prepares the chip for counting pulse (reset counter...) and uses timer 0 interrupt
* to do the time critical part (pulse NR_W low for counting).
* Then the counter is disabled and can be read back.
* The interrupt returns the extra overhead time sothat the frequency can be
* calculated.
*
* ************************************************************************************************
* Copyright (c) 2004. Semiconductor Ideas to the Market (ItoM) B.V. All rights reserved.
* ************************************************************************************************ */
BYTE CountPulseCnt1(DWORD dwMeasureTimeUs, PWORD pwFreq)
{
WORD wStart, wStop;
WORD wPulseCnt;
BYTE byTmp;
// Return value 0 means no pulses counted (chip removed?)
*pwFreq = 0;
// Reset counter
DriveBit(IR01_CNT_CTRL_REG, IR1_CCTL_CNT1_CLR, TRUE); // Drive Clear counter bit high
DriveBit(IR01_CNT_CTRL_REG, IR1_CCTL_CNT1_CLR, FALSE); // Drive Clear counter bit low
// Create the StartPattern (enable LV2400x counter) and StopPattern (disable LV2400x counter)
byTmp = GetSwRegValue(IR01_CNT_CTRL_REG);
byTmp |= IR1_CCTL_CNT_EN; // Enable counter pattern (start pattern)
wStart = MAKEWORD(byTmp, LSB(IR01_CNT_CTRL_REG));
byTmp &= (BYTE)(~IR1_CCTL_CNT_EN); // Disable counter pattern
wStop = MAKEWORD(byTmp, LSB(IR01_CNT_CTRL_REG));
// Start LV2400x counter and Pulse the NRW line
dwMeasureTimeUs = Pulse3wNRW(wStart, wStop, dwMeasureTimeUs);
// Read counter1 of LV2400x
wPulseCnt = ReadReg(IR01_CNT_H_REG); // High byte
wPulseCnt <<=8;
wPulseCnt |= ReadReg(IR01_CNT_L_REG); // Patch low byte
// Calculate measure frequency
*pwFreq = PulseToFrequency1(wPulseCnt, dwMeasureTimeUs);
return(LVLS_NO_ERROR);
} // End CountPulseCnt1
/* ************************************************************************************************
*
* Function: PulseToFrequency1
*
* Authors: Hung van Le
* Purpose: Convert 16 bit pulse count to frequency
* Input:
* wPulseCnt: 16 bit pulse count value
* dwMeasureTimeUs: measured time in us
* Output: The calculated frequency in Hz
* Comments: Use formula f = n * d / t
* where: f: frequency in Hz
* n: pulse count
* d: divider factor (fetched with GetDividerFactor-function)
* t: measured time in us
* This function is meant for measuring with counter 1 (software controlled timing)
* ************************************************************************************************
* Copyright (c) 2004. Semiconductor Ideas to the Market (ItoM) B.V. All rights reserved.
* ************************************************************************************************ */
/*
WORD PulseToFrequency1(WORD wPulseCnt, DWORD dwMeasureTimeUs)
{
DWORD dwFreqHz;
DWORD dwUnit;
switch ( GetOutputSelect() )
{
case CO_RF_OSC:
dwUnit=10000; // 10 KHz unit for RF
break;
case CO_IF_OSC:
dwUnit=10; // 10 Hz unit for IF
break;
//case CO_SD_OSC:
default:
dwUnit=1; // 1 Hz unit for SD and other freq.
break;
}
dwFreqHz = (DWORD)wPulseCnt * GetDividerFactor();
// Pure unsigned 32 bit variant
{
DWORD dwM, dwK, dwH;
DWORD dwTmp1, dwTmp2;
dwM = dwFreqHz/dwMeasureTimeUs; // First dividing gives MHz because t is in us
dwTmp1 = dwFreqHz%dwMeasureTimeUs; // Remainder of MHz
dwTmp2 = dwTmp1/1000; // Extract KHz
dwK = (dwTmp2 * 1000000)/dwMeasureTimeUs; // KHz
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
dwFreqHz = dwM*1000000 + dwK*1000 + dwH; // Total frequency
}
// MulDiv variant
//dwFreqHz = MulDiv(dwFreqHz, 1000000, dwMeasureTimeUs);
// Apply unit
dwFreqHz /= dwUnit;
// Shadow the measured frequency to simulates (frequency) read-registers
ShadowMeasuredFrequency(dwFreqHz);
return((WORD)dwFreqHz);
} // End PulseToFrequency1
*/
WORD PulseToFrequency1(WORD wPulseCnt, DWORD dwMeasureTimeUs)
{
DWORD dwFreq;
switch ( GetOutputSelect() )
{
case CO_RF_OSC:
dwFreq = (DWORD)wPulseCnt * IMR01_FM_DIVIDER;
dwFreq *= 100; // 10 KHz unit for RF
dwFreq/= dwMeasureTimeUs;
/*
// Round the measured frequency up to 10 kHz - this must also be done to all RF-usage (example. in FindFmStation)
dwFreq = (DWORD)wPulseCnt * IMR01_FM_DIVIDER;
dwFreq *= 1000; // RF: Calculate in kHz to round it up to 10 KHz unit later
dwFreq/= dwMeasureTimeUs; // RF freq is now in kHz
dwFreq = (dwFreq+5)/10; // 10 KHz unit for RF (with up rouding)
*/
break;
case CO_IF_OSC:
dwFreq = (DWORD)wPulseCnt * 100000; // 10 Hz unit for IF
dwFreq/= dwMeasureTimeUs;
break;
//case CO_SD_OSC:
default:
// 1 Hz unit for SD and other freq.
dwFreq = (DWORD)wPulseCnt;
// Pure unsigned 32 bit variant
{
DWORD dwM, dwK, dwH;
DWORD dwTmp1, dwTmp2;
dwM = dwFreq/dwMeasureTimeUs; // First dividing gives MHz because t is in us
dwTmp1 = dwFreq%dwMeasureTimeUs; // Remainder of MHz
dwTmp2 = dwTmp1/1000; // Extract KHz
dwK = (dwTmp2 * 1000000)/dwMeasureTimeUs; // KHz
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -