📄 lv2410x.c
字号:
WORD wTmp;
// Positive IF osc (ie IF frequency increases when the osc value increases)
if (wIfOscValue > 0xFF)
return(LVLS_IFOSC_OUTOFLIMIT_ERR);
WriteReg(IR01_IF_OSC_REG, (BYTE)wIfOscValue);
// Program IF Center Frequency Oscillator and IF bandwidth according to the value of IF_OSC
WriteReg(IR01_IFCEN_OSC_REG, (BYTE)wIfOscValue); // IF center has the same value as IF DAC
// IF BW is 65% of IF DAC value
wTmp = (WORD)wIfOscValue*65;
wTmp /= 100;
WriteReg(IR01_IF_BW_REG, (BYTE)wTmp);
return(LVLS_NO_ERROR);
} // End WriteIfOsc
BYTE WriteSdOsc(WORD wSdOscValue)
{
// Positive Stereo decoder clock (ie SD frequency increases when the osc value increases)
if (wSdOscValue > 0xFF)
return(LVLS_STEREOSC_OUTOFLIMIT_ERR);
WriteReg(IR01_SD_OSC_REG, (BYTE)wSdOscValue);
return(LVLS_NO_ERROR);
} // End WriteSdOsc
BYTE WriteRfOsc(WORD wRfOscValue)
{
// Positive FM osc (ie FM frequency increases when the osc value increases)
if (wRfOscValue > 0xFF)
return(LVLS_RFOSC_OUTOFLIMIT_ERR);
WriteReg(IR01_FM_OSC_REG, (BYTE)wRfOscValue);
return(LVLS_NO_ERROR);
} // End WriteRfOsc
/* ************************************************************************************************
*
* Function: WriteRfCap
* Authors: Hung van Le
* Purpose: Virtualized register access to FM-capacitor bank switch
* Input:
* WORD wCapValue: the logical CAP value (will be converted to hardware value)
* Output: Status as defined in LvErr.h
* Comments:
* Write the CAP bank select - using software logical value to deal with 7.5 bits FM CAP
* Logical value Physical value
* 0...63 255...193
* 64..191 127...0
* Following conversions are used:
* - Hardware to software conversion:
* if hw<128
* sw=~(hw+64)
* else
* sw=~hw
* - Software to hardware conversion:
* if sw<64
* hw=~sw
* else
* hw=~sw-64
*
* ************************************************************************************************
* Copyright (c) 2004. Semiconductor Ideas to the Market (ItoM) B.V. All rights reserved.
* ************************************************************************************************ */
BYTE WriteRfCap(WORD wCapValue)
{
// Make sure value is valid
if ( wCapValue > QSS_MAX_RFCAP ) // Value exceeds limit
return(LVLS_RFCAP_OUTOFLIMIT_ERR);
// Convert the software value to hardware value before writing it
if (wCapValue < 64)
wCapValue = 255 - wCapValue;
else
wCapValue = 255 - wCapValue - 64;
// Write value to the chip
WriteReg(IR01_FM_CAP_REG, (BYTE)wCapValue);
return(LVLS_NO_ERROR);
} // End WriteRfCap
BYTE WriteAmCap(WORD wAmCapValue)
{
// Negative osc (ie frequency increases when the value decreases)
// So invert the value to have positive logic
if (wAmCapValue > IR3_AACAP_MASK)
return(LVLS_AACAP_OUTOFLIMIT_ERR);
// Invert the logical value
//@@@ wAmCapValue = IR3_AACAP_MASK - wAmCapValue;
WriteReg(IR03_AM_ACAPLOW_REG, (wAmCapValue&IR3_AACAP_LOW_MASK));
wAmCapValue>>=8;
SetRegBits(IR03_AM_FE_REG, IR3_AACAP_HIGH_MASK, (WORD)(wAmCapValue&IR3_AACAP_HIGH_MASK));
return(LVLS_NO_ERROR);
} // End WriteAmCap
BYTE GetRfCapValue(void)
{
// The shadow register contains the physical value, software expects logical value as return value.
// so convert the value
BYTE byLogicalCap, byCurCapValue;
byCurCapValue = GetSwRegValue(IR01_FM_CAP_REG);
byLogicalCap = 255 - byCurCapValue;
if ( byCurCapValue < 128 )
byLogicalCap -= 64;
return(byLogicalCap);
} // End GetRfCapValue
BYTE SetAFCMode(BYTE byEnable)
{
// Reset AFC bit = !EnableState
DriveBit(IR01_RADIO_CTRL1_REG, IR1_RCTL1_RST_AFC, !byEnable);
// Set IOSC_ON bit and return it previous state
return(DriveBit(IR01_RADIO_CTRL1_REG, IR1_RCTL1_EN_AFC, byEnable));
} // End SetAFCMode
BYTE SetDeemphasis(BYTE byDeemp)
{
return(DriveBit(IR01_AUDIO_CTRL2_REG, IR1_ACTL2_DEEMP75, byDeemp));
} // End SetDeemphasis
BYTE SetStereoMono(BOOL bStereo)
{
// Input:
// bStereo: TRUE: stereo - FALSE: mono
BYTE byResult;
// No error yet
byResult = LVLS_NO_ERROR;
if (bStereo) // stereo mode request
{
byResult = Set_SD_Freq(DEFAULT_SD_FREQ); // Set the stereo decoder clock
}
// Enable/Disable stereo according to input
if (byResult != LVLS_NO_ERROR)
bStereo = FALSE; // Force mono mode
SetChipStereo(bStereo);
return(byResult);
} // End SetStereoMono
BYTE SetChipStereo(BYTE byStereo)
{
BYTE byOrgValue;
byOrgValue = DriveBitNeg(IR01_STEREO_CTRL_REG, IR1_STCTL_STEREO_L, byStereo);
// Show value
CallBack(CRSN_MS_CHNG);
return(byOrgValue);
} // End SetChipStereo
BYTE GetChipVolume(void)
{
// The LV2400x has 4 bits volume and 1 volume shift bit.
// The logical levels are defined as follow:
// Level Vol[3:0] VolShiftBit Range
// 0...15 0...15 0 3...48 dB
// 16..19 12..15 1 51..60 dB
BYTE byVolLevel;
// Fetch the 4 bits volume
byVolLevel = GetSwRegValue(IR01_AUDIO_CTRL1_REG) & IR1_ACTL1_VOL_LVL;
// Volume bit is inverted @@@@
byVolLevel = 15 - byVolLevel;
// Determine the volume shift bit
if ( GetSwRegValue(IR01_RADIO_CTRL3_REG) & IR1_RCTL3_VOL_SHIFT )
byVolLevel += 4;
return(byVolLevel);
} // End GetChipVolume
void SetChipVolume(BYTE byLevel)
{
// Input: the logical volume level (0..19)
BYTE byRegValue;
BOOL bShiftVol;
if (byLevel<16)
{
bShiftVol = FALSE;
}
else
{
if (byLevel>19)
byLevel = 19; // Make sure we have valid level
byLevel -= 4;
bShiftVol = TRUE;
}
// IR01_AUDIO_CTRL1_REG has bit[7:4] as tone control, [3:0] as volume. We want to keep the tone control
// as same as the volume level until the dynamic bass boost level reached
byRegValue = (15-byLevel); // Volume value is the invertion of logical level (volume bits are inverted)
if (byLevel > g_byDynBassBoost) // Check tone level against dynamic bass boost
byLevel = g_byDynBassBoost; // If exceeds, wrap it back
byLevel = 15-byLevel; // The tone value is the invertion of tone level (tone bits are inverted)
byRegValue |= (byLevel<<4); // Shift tone value to its position and patch into volume value
// Update hardware
DriveBit(IR01_RADIO_CTRL3_REG, IR1_RCTL3_VOL_SHIFT, bShiftVol);
WriteReg(IR01_AUDIO_CTRL1_REG, byRegValue);
} // End SetChipVolume
/* ************************************************************************************************
*
* Function: SetChipAudioMute
*
* Authors: Hung van Le
* Purpose: Handle the sotware audio mute
* Input: BYTE byMute: new mute state
* BYTE byMuteSrc: mute source
* Output: Original (software) audio mute state
* Comments: Mute state: 0=no mute, 1=muted
*
* ************************************************************************************************
* Copyright (c) 2002-2004. Semiconductor Ideas to the Market (ItoM) B.V. All rights reserved.
* ************************************************************************************************ */
BYTE SetChipAudioMute(BYTE byMute, BYTE bySource)
{
BYTE byCurState;
// Determine current state (for returning it later)
if ( (g_bySwFlag1 & bySource)==0 )
byCurState = 0; // unmute
else
byCurState = 1; // mute
if (byMute) // mute request
{
// Mute the chip
DriveBitNeg(IR01_RADIO_CTRL3_REG, IR1_RCTL3_AUDIO_MUTE_L, 1);
g_bySwFlag1 |= bySource; // register mute source
}
else // unmute request
{
g_bySwFlag1 &= (~bySource); // register unmute source
if ( (g_bySwFlag1 & MUTESRC_MASK) == 0) // the chip comes in unmute mode
DriveBitNeg(IR01_RADIO_CTRL3_REG, IR1_RCTL3_AUDIO_MUTE_L, 0);
}
return(byCurState);
} // End SetChipAudioMute
BYTE GetFmFieldStrength(void)
{
BYTE byRegValue;
BYTE byOrgMode;
BYTE byFs;
// Make sure the chip is in measuring mode for measure field strenggth
byOrgMode = DriveBit(IR01_RADIO_CTRL1_REG, IR1_RCTL1_EN_MEAS, TRUE);
// Read Radio status register to determine field strength
byRegValue = ReadReg(IR01_RADIO_STAT_REG);
// Extract FieldStrength
byRegValue &= IR1_RSTAT_FS; // extract field strength bits
byRegValue ^= IR1_RSTAT_FS; // Invert field strength level (0 becomes 1)
byFs = 0; // field strength to be returned
while (byRegValue != 0)
{
if ( byRegValue & 1 )
byFs++;
byRegValue>>=1;
}
// Restore measure mode
DriveBit(IR01_RADIO_CTRL1_REG, IR1_RCTL1_EN_MEAS, byOrgMode);
return(byFs);
} // End GetFmFieldStrength
BYTE GetStereoState(void)
{
// Determine stereo state of LV2400x
// Return: GSS_MONO: mono mode
// GSS_STEREO: stereo is enabled but no stereo recieving
// GSS_STEREO_DET: stereo is enabled and stereo detected
// Determine stereo enable state
if ( (GetSwRegValue(IR01_STEREO_CTRL_REG) & IR1_STCTL_STEREO_L) == 0 ) // Stereo bit = 0: stereo is enabled
{
if (ReadReg(IR01_RADIO_STAT_REG) & IR1_RSTAT_STEREO) // Stereo state bit = 1 (Stereo)
return(GSS_STEREO_DET); // Stereo is detected by the chip
else
return(GSS_STEREO); // Stereo is enabled but not detected
}
else
return(GSS_MONO);
} // End GetStereoState
//////////////////////////////////////////////////////////////////////
// LV24xxx Interrupt functions
//////////////////////////////////////////////////////////////////////
void EnableLv2400xIrq(void)
{
// Enable interrupt of 3-wire bus 1 (INT5 (vector 1Bh) - rising edge trigger)
// We use following LV24xxx interrupts:
// - Field strength
// - Stereo/Mono
// - AFC out of range
// Clear any pending interrupt of LV24xxx
ReadReg(IR01_CTRL_STAT_REG); // Read IR01_CTRL_STAT_REG to clear AFC interrupt
ReadReg(IR01_RADIO_STAT_REG); // Read IR01_RADIO_STAT_REG to clear field strength, Stereo interrupt
// Program the LV24xxx interrupt level: high active, enable Mono/Stereo, fieldstrength and AFC interrupt
WriteReg(IR01_IRQ_MSK_REG, IR1_IRQM_ACT_HIGH|IR1_IRQM_EN_MS|IR1_IRQM_EN_FS|IR1_IRQM_EN_AFC);
// Write to IR01_IRQ_OUT_REG-register to select interrupt output of LV24xxx
WriteReg(IR01_IRQ_OUT_REG, 0);
// Enable system interrupt INT5
Enable3wIrq(TRUE);
// Mark chip interrupt is on
g_byLvIrqFlg |= IFL_CHIP_IRQ_EN;
} // End EnableLv2400xIrq
void DisableLv2400xIrq(void)
{
// Disable system interrupt INT5
Enable3wIrq(FALSE);
} // End DisableLv2400xIrq
void HandleLv2400xIrq(void)
{
// We handle following LV24xxx interrupts:
// - Field strength: Update LCD display
// - Stereo/Mono: Update LCD display
// - AFC out of range: re-tune the frequency
BYTE byEnMask, byIrqOcc, byTmp1;
// Fetch the interrupt enable mask
byEnMask = GetSwRegValue(IR01_IRQ_MSK_REG);
// Read the interrupt ID register (see what interrupt occurred)
byIrqOcc = ReadReg(IR01_IRQ_ID_REG);
// Handle the interrupts
if ( byIrqOcc & (IR1_IRQID_FS_MS) ) // Mono or fieldstrength
{
// Read IR01_RADIO_STAT_REG to clear field strength, Stereo interrupt
byTmp1 = ReadReg(IR01_RADIO_STAT_REG);
// Hanlde field strength interrupt
if (byEnMask & IR1_IRQM_EN_FS) // Was field strength interrupt enabled?
{
CallBack(CRSN_FS_CHNG);
} // End fieldstrength interrupt handling
// Hanlde Mono/Stereo interrupt
if (byEnMask & IR1_IRQM_EN_MS) // Was its interrupt enabled?
{
CallBack(CRSN_MS_CHNG);
} // End Mono/Stereo interrupt handling
} // EndIf Field strength/Mono-stereo
// AFC interrupt
if (byIrqOcc & IR1_IRQID_AFC) // AFC interrupt occurred?
{
if (byEnMask & IR1_IRQM_EN_AFC) // Was its interrupt enabled?
{
CallBack(CRSN_AFC_FAILED);
}
}
} // End HandleLc2400xIrq
/* ************************************************************************************************
*
* Function: AudioFeedback
*
* Authors: Hung van Le
* Purpose: Generate beep with the LV2400x
* Input: byType: pre-defined beep type
* AUDFB_TYPE1: tone 500 Hz for 40ms
* AUDFB_TYPE2: tone 2kHz for 40ms, pause 40ms, tone 2kHz for 40ms
* Comments: - This function accesses the registers of LV2400x directly. These accesses can be moved to
* chip specific layer when multiple chip support is needed. For example the Stereo decoder PLL can be
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -