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

📄 lv2400x.c

📁 LV24000的单片机DEMO程序
💻 C
📖 第 1 页 / 共 5 页
字号:
				if (byVolume < g_byDynBassBoost )	// Logical volume level doesn't exceed dynamic bass boost level
					byTone = byVolume;		// Let tone level follow volume level
				else					// Volume level exceeds dynamic bass boost
					byTone = g_byDynBassBoost;	// Keep tone level fixed at dynamic bass boost level
				byTone = 15 - byTone;			// Convert tone level to tone value (the 4 tone bits are inverted)
				byTone <<= 4;				// Shift tone to correction position
				SetRegBits(IR01_AUDIO_CTRL1_REG, IR1_ACTL1_TONE_LVL, byTone);
			}
		}
		break;

	case IHCAP_HPA:	// Headphone amplifier
		// Input: 0=off 1=on
		// Check if headphone support
		if ( g_byHwFlag1 & HF1_HP)
			DriveBit(IR01_PW_SCTRL_REG, IR2_PSCTL_HPA, byValue);
		break;
		
//	case IHCAP_CNT2:
//  		m_dwCnt2ExtClk = pValue->Cnt2.dwExtClock; // Save the external clock (in Hz) for later usage
//		break;

	// Software settings
	case IHCAP_SCANLVL:	// Scan level
		g_byScanLevel = byValue;
		break;

	case IHCAP_SCANWRP:	// Scan wrapping
		g_byStnFlag &= (~STN_WRAP_MODE);	// clear old setting
		g_byStnFlag |= (byValue & STN_WRAP_MODE);
		break;

	case IHCAP_REGION:	// Region
		byResult = SetRegion(byValue);
		break;

	case IHCAP_BEEPVOL:	// Audible feedback volume
		g_byBeepVol = byValue;

#ifdef USE_EXTCLK
	case IHCAP_EXTCLK:
		g_bySwFlag1 &= (BYTE)(~SF1_EXTCLK);
		g_bySwFlag1 |= (BYTE)(byValue & SF1_EXTCLK);
		break;
#endif //USE_EXTCLK

	default:
		byResult = LVLS_NSU_FEATURE_ERR;
		break;
	} // EndSwitch
	return(byResult);
} // End SetHwFeatureValue

void AdjustHwToneControl(void)
{
	// Control the ToneMute bit (IR1_RCTL3_TONE_MUTE_L of IR01_RADIO_CTRL3_REG)
	// Unmute the tone control if bass or treble is not 0
	BYTE byTmp;
	BOOL bState;
		
	byTmp = GetSwRegValue(IR01_AUDIO_CTRL2_REG);
	
	if (byTmp & (IR1_ATREBLE_MASK|IR1_ABASS_MASK)) // One or more tone bit is set
		bState = FALSE;	// Don't mute the tone
	else
		bState = TRUE;	// All tone bits are 0, mute the tone control
	DriveBitNeg(IR01_RADIO_CTRL3_REG, IR1_RCTL3_TONE_MUTE_L, bState);
} // End AdjustHwToneControl

//////////////////////////////////////////////////////////////////////
// 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 
 *		  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|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|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

// ==============================================================================
#endif //USE_LVC2400x 	// The whole file can be discarded if LV2400x is not used
// ==============================================================================

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -