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

📄 lv2410x.c

📁 LV24000的单片机DEMO程序
💻 C
📖 第 1 页 / 共 5 页
字号:
/************************************************************************
*
*   Copyright(c) 2004 ItoM BV
*   All Rights Reserved.
*
*   LV2400x evaluation kit: LC24001 specific code
*   File name:	Lv2410x.c
*
*************************************************************************/

#include <stdio.h>
#include "common.h"
#include "Lv24Ekit.h"

// ==============================================================================
#ifdef USE_LV2410x 	// The whole file can be discarded if LC2410x is not used
// ==============================================================================
#include "Lv2410xReg.h"		// For register layout

/*-------------------------------------------------------------------
        Global data for this module
-------------------------------------------------------------------*/
BYTE g_byFmStereo;
BYTE g_byFmRegion;
WORD g_wLastFmFreq;
BYTE g_byAmRegion;
WORD g_wLastAmFreq;

WORD g_wFmRfLo;
WORD g_wFmRfHi;
WORD g_wAmRfLo;
WORD g_wAmRfHi;
/*-------------------------------------------------------------------
        Local data
-------------------------------------------------------------------*/
typedef struct	// Register address-value structure (for default register settings)
{
	WORD wRegAddress;
	BYTE byValue;
} I3W_REG_VALUES;

// ----- Default register value list of LV2410x
I3W_REG_VALUES _rom g_Lv2410xDefault[] = 
{
	IR01_MSRC_SEL_REG,	0,			// 0x0102 - Measure source select: nothing selected

	//IR01_FM_OSC_REG,	0,			// 0x0103 - should be tuned
	//IR01_SD_OSC_REG,	0x80,			// 0x0104 - should be tuned
	//IR01_IF_OSC_REG,	0,			// 0x0105 - should be tuned
	//IR01_FM_CAP_REG,	0,			// 0x0109 - should be tuned
	IR01_CNT_CTRL_REG,	IR1_CCTL_SWP_CNT_L,	// 0x0106 - Counter control: select counter 1, no counter swapping
	IR01_IRQ_MSK_REG,	IR1_IRQM_ACT_LOW,	// 0x0108 - Interrupt mask: IRQ active low

	IR01_RADIO_CTRL1_REG,	(IR1_RCTL1_EN_AFC|
				 IR3_RCTL1_AM_CD2|
				 IR3_RCTL1_AM_CD1|
				 IR3_RCTL1_AM_CD0),	// 0x202 - Radio control 1 - Enable AFC as default - AM clock divider bits = 1 for FM
	//IR01_IFCEN_OSC_REG,	xx,			// 0x0203 - IF Center Frequency Oscillator: init when setting IF 
	//IR01_IF_BW_REG,	xx,			// 0x0205 - IF Bandwidth: init when setting IF

	IR01_RADIO_CTRL3_REG,	(IR1_RCTL3_SE_FM|
				IR1_RCTL3_AGC_SETLVL),// 0x0207	- Radio Control 3: mute audio, mute tone, select FM source, Set AGC level for FM (V4)

	IR01_STEREO_CTRL_REG,	IR1_DEF_CS_VAL|
				IR1_STCTL_AUTO_SLEWRATE|
				IR1V6_CANCEL_PILOT,	// 0x0208 - Stereo Control: Mono, SD PLL mute off, set default CS value, auto slew rate on
	IR01_AUDIO_CTRL1_REG,	0x77,			// 0x0209 - Audio Control 1: default volume level
	IR01_AUDIO_CTRL2_REG,	IR1_BEEP_HIGH,		// 0x020A - Audio Control 2: treble/bass setting, don't enable the beep output

	IR01_RADIO_CTRL2_REG,	IR1_RCTL2_IF_PM_L|	
		 		IR1_RCTL2_AGC_SPD,	// 0x0206 - Radio Control 2: VREF2/VREF on, IF PLL mute off, Turn on AGC speed for quick fieldstrength measuring
	IR01_PW_SCTRL_REG,	(IR1_PSCTL_PW_RAD|
				IR1_DEF_SOFT_ST|
				IR1_DEF_SOFT_MUTE),	// 0x020B - Power and soft control: turn on FM. Set default soft mute, soft stereo
	// AM part
	IR03_AM_ACAPLOW_REG,	0, 			// 0x0302 - AM antenna capacitor (low byte)
	IR03_AM_FE_REG,		IR3_AFE_AGCSP,		// 0x0303 - AM front end control & AA cap high
	IR03_AM_CTRL_REG,	(IR3_AMCTL_AGC3_1|
				 IR3_AMCTL_AGC3_0),	// 0x0304 - AM control register  AGC3=3
};
#define LV2410X_DEFAULT_REG_LSIZE (sizeof(g_Lv2410xDefault)/sizeof(g_Lv2410xDefault[0]))

/*-------------------------------------------------------------------
        Register address list to be shadowed
	(Only save the necessary registers to reduce RAM usage)
-------------------------------------------------------------------*/
WORD _rom g_Lv24ShadowList[] = 
{
	IR01_MSRC_SEL_REG,	// 0x0102 Block 1- Reg02 (W): Measure source select
	IR01_FM_OSC_REG,	// (*) 0x0103 Block 1- Reg03 (W): DAC control for FM-RF oscillator
	IR01_SD_OSC_REG,	// (*) 0x0104 Block 1- Reg04 (W): DAC control for stereo decoder oscillator
	IR01_IF_OSC_REG,	// (*) 0x0105 Block 1- Reg05 (W): DAC control for IF oscillator
	IR01_CNT_CTRL_REG,	// 0x0106 Block 1- Reg06 (W): Counter control
	IR01_IRQ_MSK_REG,	// 0x0108 Block 1- Reg08 (W): Interrupt mask
	IR01_FM_CAP_REG,	// 0x0109 Block 1- Reg09 (W): CAP bank control for RF-frequency

	IR01_RADIO_CTRL1_REG,	// 0x0202 Block 2- Reg02 (W): Radio control 1
	IR01_IFCEN_OSC_REG,	// (*) 0x0203 Block 2- Reg03 (W): IF Center Frequency Oscillator
	IR01_IF_BW_REG,		// (*) 0x0205 Block 1- Reg05 (W): IF Bandwidth
	IR01_RADIO_CTRL2_REG,	// 0x0206 Block 2- Reg06 (W): Radio Control 2
	IR01_RADIO_CTRL3_REG,	// 0x0207 Block 2- Reg07 (W): Radio Control 3
	IR01_STEREO_CTRL_REG,	// 0x0208 Block 2- Reg08 (W): Stereo Control	
	IR01_AUDIO_CTRL1_REG,	// 0x0209 Block 2- Reg09 (W): Audio Control 1
	IR01_AUDIO_CTRL2_REG,	// 0x020A Block 2- Reg0A (W): Audio Control 2
	IR01_PW_SCTRL_REG,	// 0x020B Block 2- Reg0B (W): Power and soft control
	// Additional registers for AM
	IR03_AM_ACAPLOW_REG,	// (*) 0x0302 Block 3-Reg02 (W): AM antenna capacitor (low byte)
	IR03_AM_FE_REG,		// 0x0303 Block 3-Reg03 (W): AM front end control & AA cap high
	IR03_AM_CTRL_REG,	// 0x0304 Block 3-Reg04 (W): AM control register 
				// (*): not required if stand-alone mode only. 
				//      These registers are shadowed for retoring them when switching from USB to stand alone mode
};
#define LVSHADOW_LSIZE (sizeof(g_Lv24ShadowList)/sizeof(g_Lv24ShadowList[0]))

// Global for this module
BYTE g_byaShwRegValue[LVSHADOW_LSIZE];	// array to hold the shadowed value

/*-------------------------------------------------------------------
	Treble/Bass converting table
-------------------------------------------------------------------*/
BYTE _rom g_Lv24001Treble[]=
{
	IR1_ACTL2_TREB_N,	// Logical level 0
	0,			// Logical level 1
	IR1_ACTL2_TREB_P,	// Logical level 2
};
#define IMR1_TREBLE_LSIZE (sizeof(g_Lv24001Treble)/sizeof(g_Lv24001Treble[0]) )

BYTE _rom g_Lv24001Bass[]=
{
	//IR1_ACTL2_BASS_N|IR1_ACTL2_BASS_LVL,	// Logical level 0: invalid combination!
	IR1_ACTL2_BASS_N,			// 0	// Logical level 0
	0,					// 1	// Logical level 1
	IR1_ACTL2_BASS_P,			// 2	// Logical level 2
	IR1_ACTL2_BASS_P|IR1_ACTL2_BASS_LVL,	// 3	// Logical level 3
};
#define IMR1_BASS_LSIZE (sizeof(g_Lv24001Bass)/sizeof(g_Lv24001Bass[0]) )

/*-------------------------------------------------------------------
        LV2410x feature limit
-------------------------------------------------------------------*/
typedef struct
{
	BYTE byFeatureId;
	BYTE byUpperLimit;
} LV_FEAT_LIMIT;

LV_FEAT_LIMIT _rom g_Lv2400xFeatLimit[] = 
{
	IHCAP_TUNERPWR,		1,	// Tuner's power: 0=off, 1= On
	IHCAP_VOLUME,		20, 	// Volume level
	IHCAP_AMUTE,		1,	// Audio mute: 0=audio, 1= muted
	IHCAP_ATREBLE,		(IMR1_TREBLE_LSIZE-1),	// Audio treble
	IHCAP_ABASS,		(IMR1_BASS_LSIZE-1),	// Audio bass
	IHCAP_DYNBASSBOOST,	15, 	// Dynamic bass boost
	IHCAP_SMUTE,		7, 	// Audio soft mute

	IHCAP_STEREO,		1, 	// Stereo: 0=mono, 1=stereo
	IHCAP_SOFT_ST,		7, 	// Soft stereo

	IHCAP_RADIOSOURCE,	2, 	// (LV2410x) Radio source: 0=Radio off, 1=FM, 2=AM
	IHCAP_EXTSOURCE,	1, 	// External source: 0=off, 1=on
	IHCAP_BEEPSOURCE,	3, 	// Beep tone: 0=off, 1=Freq1, 2=Freq2, 3=Freq3
	//IHCAP_AFC	       	1,	// Bit 14: AFC (automatic frequency control) supported
	IHCAP_HPA,		1,	// Bit 15: Hardware headphone amplifier presents

	// Software features
	IHCAP_SCANLVL,		7,	// Scan level (0...7)
	IHCAP_SCANWRP,		2,	// 0=no wrap, 1=wrap once, 2=wrap continue
	IHCAP_REGION,		4,	// Region: 0=None, 1=Europe, 2=Japan, 3=USA, 4=JapanWide
	IHCAP_BEEPVOL,		20,	// Beep volume - same limit as IHCAP_VOLUME
#ifdef USE_EXTCLK
	IHCAP_EXTCLK,		1,	// 0= no external clock, 1= 12MHz, 2=32kHz
#endif //USE_EXTCLK
};
#define LV2400X_FEATLIMIT_LSIZE (sizeof(g_Lv2400xFeatLimit)/sizeof(g_Lv2400xFeatLimit[0]))

// ----- FM-RF to AM-RF divider table
typedef struct
{
	BYTE byRegValue;	// Register value to select the divider factor
	BYTE byDivFac;		// The divider factor tab value
} REG_DIVFAC_STRUCT;

REG_DIVFAC_STRUCT _rom g_IR03ES1AmDivider[]=
{
	IR3_AMDIV_48,	 48,	// 0
	IR3_AMDIV_64,	 64,	// 1
	IR3_AMDIV_80,	 80,	// 2
	IR3_AMDIV_96,	 96,	// 3
	IR3_AMDIV_128,	128,	// 4
	IR3_AMDIV_160,	160,	// 5
	IR3_AMDIV_192,	192,	// 6
	//IR3_AMDIV_OFF, 1,		// 7 (Divider off)
};
#define IMR3ES1_AMDIVTAB_SIZE (sizeof(g_IR03ES1AmDivider)/sizeof(g_IR03ES1AmDivider[0]) )

/*-------------------------------------------------------------------
        LV2410x routines
-------------------------------------------------------------------*/
BYTE InitLv2400xChip(void) 
{
	BYTE byResult;
	BYTE i;

	// Init software
	g_byBlock = 0xFF;		// Mark no block is selected yet
	g_byHwFlag1 = HF1_NEG_IF_PHASE;	// LV2400x has negative IF phase
	g_byRegion = REGION_EUROPE;	// Default region for FM
	g_byAmRegion = REGION_EUROPE;	// Default region for AM
	g_byStnFlag = STNWRAP_ONCE;	// Default options
	g_byScanLevel = 4;		// Default scan level
	g_byDynBassBoost = 15;		// Default: dynamic bass boost level is max.
	g_byBeepVol = 10;		// Default beep volume
	g_byFmStereo = TRUE;		// Default is stereo mode
	g_wLastAmFreq = 0;		// Default: no AM frequency set yet

	// 1) Write the default values to the device
	for (i=0; i<LV2410X_DEFAULT_REG_LSIZE; i++)
		WriteReg(g_Lv2410xDefault[i].wRegAddress, g_Lv2410xDefault[i].byValue);

	// 2) Set the prefered IF frequency
	byResult = Set_IF_Freq(DEFAULT_IF_FREQ);

	// 3) Init tuning system
	if (byResult == LVLS_NO_ERROR)
		byResult = InitTuningRfCapOsc(); 

	// 4) Set region to initialise Radio band limits
	if (byResult == LVLS_NO_ERROR)
		byResult = SetRegion(g_byRegion);

	// 5) Set the prefered Stereo Decode clock
	Set_SD_Freq(DEFAULT_SD_FREQ);	//  This step can be postboned until stereo is enabled

	// Additional step: read the chip ID to determine chip specific features (in case the wrong chip is connected)
	switch (ReadReg(IR01_CHIP_ID_REG))
	{
	case LV24102_ID:	// AM and headphone supported
		g_byHwFlag1 |= HF1_AM;
		// Fall through
	case LV24002_ID:	// Headphone supported
		g_byHwFlag1 |= HF1_HP;
		break;

	case LV24101_ID:	// AM supported
		g_byHwFlag1 |= HF1_AM;
		break;
	//case LV24001_ID:
	default:
		break;
	}

	// Extra init for AM
	{
		DWORD dwTmp;

		g_wFmRfLo = g_wHwRfLow;		// FM RF limit (10 kHz unit)
		g_wFmRfHi = g_wHwRfHigh;

		dwTmp = g_wHwRfLow;		// FM-RF in 10 kHz
		dwTmp = dwTmp * 10;		// Convert FM-RF to 1kHz.
		g_wAmRfLo = dwTmp/g_IR03ES1AmDivider[IMR3ES1_AMDIVTAB_SIZE-1].byDivFac; // Minimal AM_RF freq = Min. FM_RF/Max.divider

		dwTmp = g_wHwRfHigh;		// FM-RF in 10 kHz
		dwTmp = dwTmp * 10;		// Convert FM-RF to 1 kHz
		g_wAmRfHi = dwTmp/g_IR03ES1AmDivider[0].byDivFac; // Maximal AM_RF freq = Max. FM_RF/Min.divider
	}

	// The chip is now ready - remember that it's still muted
	return(byResult);
}// End InitLv2400xChip

void DeInitLv2400xChip(void)
{
	// Disable interrupt
	DisableLv2400xIrq();

	// Mute the audio
	SetChipAudioMute(TRUE, MUTESRC_APPLICATION);

	// Turn off the chip power
	//DriveBit(IR01_PW_SCTRL_REG, IR1_PSCTL_PW_RAD, FALSE); // Skip to avoid noise on speaker
} // End DeInitLv2400xChip

/* ************************************************************************************************
 *
 *  Function:   Set_IF_Freq
 *  Authors:    Hung van Le
 *  Purpose:    Set the IF frequency to specified dwInputIF
 *  Input:		
 *			DWORD dwInputIF: the IF frequency to be set in Hz
 *  Output:     Status as defined in LvErr.h
 *  Comments:	None
 *
 * ************************************************************************************************
 * Copyright (c) 2004. Semiconductor Ideas to the Market (ItoM) B.V. All rights reserved.
 * ************************************************************************************************ */
BYTE Set_IF_Freq(WORD wInputIF)
{
	BYTE byResult;
	BYTE byOrgDemState;
	WORD wCfg;

	// turn on demodulator PLL mute to set the IF
	byOrgDemState = DriveBitNeg(IR01_RADIO_CTRL2_REG, IR1_RCTL2_IF_PM_L, TRUE);

	// Select correct oscillator output and enable measuring mode
	wCfg = SetUpChipMode(CO_IF_OSC|CHIP_MEASURE_MODE);

	// Do the tuning 
	byResult = LinTuneDac(wInputIF, LV_MSR_TIME_32ms, WriteIfOsc, 50, 150, 1);

	// Tuning done - restore status
	DriveBitNeg(IR01_RADIO_CTRL2_REG, IR1_RCTL2_IF_PM_L, byOrgDemState);

	// Restore chip config
	SetUpChipMode(wCfg);

	return(byResult);
} // End Set_IF_Freq

/* ************************************************************************************************
 *
 *  Function:   Set_SD_Freq
 *  Authors:    Hung van Le
 *  Purpose:    Set the stereo decoder clock frequency to specified dwInputSC
 *  Input:		
 *		DWORD dwInputSC: the stereo decoder clock frequency to be set in Hz
 *  Output:     Status as defined in LvErr.h
 *  Comments:	the set SC will be shadowed in m_dwStereoClock
 *
 * ************************************************************************************************
 * Copyright (c) 2004. Semiconductor Ideas to the Market (ItoM) B.V. All rights reserved.
 * ************************************************************************************************ */
BYTE Set_SD_Freq(WORD wInputSC)
{
	BYTE byResult;
	BOOL bOrgPllState;
	WORD wCfg;
	WORD wCurFreq;

	// turn on the stereo PLL mute measure the stereo decoder clock
	bOrgPllState = DriveBit(IR01_STEREO_CTRL_REG, IR1_STCTL_SD_PM, TRUE);

	// Select correct oscillator output and enable measuring mode
	wCfg = SetUpChipMode(CO_SD_OSC|CHIP_MEASURE_MODE);
		
	// Get current stereo clock
	byResult = CountPulse(LV_MSR_TIME_100ms, &wCurFreq);

	// Skip tuning if the frequency is already good
	if (byResult == LVLS_NO_ERROR)
	{
		if ( IsFrequencyOk(wCurFreq, DEFAULT_SD_FREQ, LV_MSR_TIME_100ms) != 0 )
			byResult = LVLS_NO_ERROR+1;
	}

	// Do the tuning - Some device has dead point below StereoOsc<20, so interpolate between 50-150
	if (byResult != LVLS_NO_ERROR)
		byResult = LinTuneDac(wInputSC, LV_MSR_TIME_100ms, WriteSdOsc, 50, 150, 1);

	// Tuning done - restore status
	DriveBit(IR01_STEREO_CTRL_REG, IR1_STCTL_SD_PM, bOrgPllState);
	SetUpChipMode(wCfg);

	return(byResult);
} // End Set_SD_Freq

/* ************************************************************************************************
 *
 *  Function:   Virtualize register access to the hardware
 *			WriteIfOsc (adjust the DAC of IF PLL )
 *			WriteSdOsc (adjust the DAC of Stereo decoder clock)
 *			WriteRfOsc (adjust the DAC of RF varicap)
 *  Authors:    Hung van Le
 *  Purpose:    These functions provide access to registers of the device which are used for setting frequencies
 *  Comments:   None
 *
 * ************************************************************************************************
 * Copyright (c) 2004. Semiconductor Ideas to the Market (ItoM) B.V. All rights reserved.
 * ************************************************************************************************ */
BYTE WriteIfOsc(WORD wIfOscValue) 
{

⌨️ 快捷键说明

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