⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lv2410x.c

📁 LV24000的单片机DEMO程序
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 + -