📄 si47xxfmrx.c
字号:
//-----------------------------------------------------------------------------
//
// si47xxFMRX.c
//
// Contains the FM radio functions with the exceptions of autoseek and rds.
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include <c8051f320.h>
#include <stddef.h>
#include "typedefs.h"
#include "portdef.h"
#include "commanddefs.h"
#include "propertydefs.h"
#include "si47xxFMRX.h"
//-----------------------------------------------------------------------------
// Defines
//-----------------------------------------------------------------------------
#define POWERUP_TIME 110 // Powerup delay in milliseconds
//-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------
extern bit WaitSTCInterrupt;
extern bit PoweredUp;
extern bit SeekTuneInProc;
extern u8 idata cmd[8];
extern u8 idata rsp[13];
extern u8 chipFunction;
// This variables are used by the status commands. Make sure to call those
// commands (fmRsqStatus, fmTuneStatus, or fmRdsStatus) prior to access.
extern u8 xdata Status;
extern u8 xdata RsqInts;
extern u8 xdata STC;
extern u8 xdata SMUTE;
extern u8 xdata BLTF;
extern u8 xdata AFCRL;
extern u8 xdata Valid;
extern u8 xdata Pilot;
extern u8 xdata Blend;
extern u16 xdata Freq;
extern u8 xdata RSSI;
extern u8 xdata ASNR;
extern u16 xdata AntCap;
extern u8 xdata FreqOff;
u8 xdata RdsInts;
u8 xdata RdsSync;
u8 xdata GrpLost;
u8 xdata RdsFifoUsed;
u16 xdata BlockA;
u16 xdata BlockB;
u16 xdata BlockC;
u16 xdata BlockD;
u8 xdata BleA;
u8 xdata BleB;
u8 xdata BleC;
u8 xdata BleD;
typedef enum {USA, EUROPE, JAPAN} country_enum; // Could be expanded
//-----------------------------------------------------------------------------
// Function prototypes
//-----------------------------------------------------------------------------
void wait_ms(u16 ms);
void si47xx_command(u8 cmd_size, u8 idata *cmd, u8 reply_size, u8 idata *reply);
void si47xx_reset(void);
u8 getIntStatus(void);
void fmTuneFreq(u16 frequency);
static void fmSeekStart(u8 seekUp, u8 wrap);
static void fmTuneStatus(u8 cancel, u8 intack);
static void fmRsqStatus(u8 intack);
//-----------------------------------------------------------------------------
// Take the Si47xx out of powerdown mode.
//-----------------------------------------------------------------------------
void si47xxFMRX_powerup(void)
{
// Check if the device is already powered up.
if (PoweredUp) {
} else {
// Put the ID for the command in the first byte.
cmd[0] = POWER_UP;
// Enable the GPO2OEN on the part because it will be used to determine
// RDS Sync timing.
cmd[1] = POWER_UP_IN_GPO2OEN;
// The device is being powered up in FM RX mode.
cmd[1] |= POWER_UP_IN_FUNC_FMRX;
// The opmode needs to be set to analog mode
cmd[2] = POWER_UP_IN_OPMODE_RX_ANALOG;
// Powerup the device
si47xx_command(3, cmd, 8, rsp);
wait_ms(POWERUP_TIME); // wait for si47xx to powerup
// Since we did not boot the part in query mode the result will not
// contain the part information.
PoweredUp = 1;
}
}
//-----------------------------------------------------------------------------
// Place the Si47xx into powerdown mode.
//-----------------------------------------------------------------------------
void si47xxFMRX_powerdown(void)
{
// Check to see if the device is powered up. If not do not do anything.
if(PoweredUp)
{
// Set the powered up variable to 0
PoweredUp = 0;
// Put the ID for the command in the first byte.
cmd[0] = POWER_DOWN;
// Invoke the command
si47xx_command(1, cmd, 1, rsp);
}
}
//-----------------------------------------------------------------------------
// This function will set up some general items on the hardware like
// initializing the RDS and STC interrupts.
//
// Note:
// * RDS is only available on certain parts. Please refer to the data
// sheet for your part to determine if your part supports RDS.
//-----------------------------------------------------------------------------
static void si47xxFMRX_hardware_cfg(void)
{
// Enable the RDS and STC interrupt here
si47xx_set_property(GPO_IEN, GPO_IEN_STCIEN_MASK | GPO_IEN_RDSIEN_MASK);
}
//-----------------------------------------------------------------------------
// Set up general configuration properties:
// Soft Mute Rate, Soft Mute Max Attenuation, Soft Mute SNR Threshold,
// Blend Mono Threshold, Blend Stereo Threshold, Max Tune Error,
// Seek Tune SNR Threshold, Seek Tune RSSI Threshold
//
// Note:
// * RDS is only available on certain parts. Please refer to the data
// sheet for your part to determine if your part supports RDS.
//-----------------------------------------------------------------------------
static void si47xxFMRX_general_cfg(void)
{
// Typically the settings used for stereo blend are determined by the
// designer and not exposed to the end user. They should be adjusted here.
// If the user wishes to force mono set both of these values to 127.
// si47xx_set_property(FM_BLEND_MONO_THRESHOLD, 30);
// si47xx_set_property(FM_BLEND_STEREO_THRESHOLD, 49);
// The softmute feature can be disabled, but it is normally left on.
// The softmute feature is disabled by setting the attenuation property
// to zero.
// si47xx_set_property(FM_SOFT_MUTE_RATE, 64);
// si47xx_set_property(FM_SOFT_MUTE_MAX_ATTENUATION, 16);
// si47xx_set_property(FM_SOFT_MUTE_SNR_THRESHOLD, 4);
// The max tune error is normally left in its default state. The designer
// can change if desired.
// si47xx_set_property(FM_MAX_TUNE_ERROR, 30);
// Typically the settings used for seek are determined by the designer
// and not exposed to the end user. They should be adjusted here.
si47xx_set_property(FM_SEEK_TUNE_SNR_THRESHOLD, 3);
si47xx_set_property(FM_SEEK_TUNE_RSSI_THRESHOLD, 20);
}
//-----------------------------------------------------------------------------
// Set up regional configuration properties including:
// Seek Band Bottom, Seek Band Top, Seek Freq Spacing, Deemphasis
//
// Inputs:
// country
//
// Note:
// * RDS is only available on certain parts. Please see the part's
// datasheet for more information.
//-----------------------------------------------------------------------------
static void si47xxFMRX_regional_cfg(country_enum country)
{
// Typically the settings used for stereo blend are determined by the
// designer and not exposed to the end user. They should be adjusted here.
// If the user wishes to force mono set both of these values to 127.
// si47xx_set_property(FM_BLEND_MONO_THRESHOLD, 30);
// si47xx_set_property(FM_BLEND_STEREO_THRESHOLD, 49);
// Depending on the country, set the de-emphasis, band, and space settings
// Also optionally enable RDS for countries that support it
switch (country) {
case USA :
// This interrupt will be used to determine when RDS is available.
si47xx_set_property(FM_RDS_INTERRUPT_SOURCE,
FM_RDS_INTERRUPT_SOURCE_SYNCFOUND_MASK); // RDS Interrupt
// Enable the RDS and allow all blocks so we can compute the error
// rate later.
si47xx_set_property(FM_RDS_CONFIG, FM_RDS_CONFIG_RDSEN_MASK |
(3 << FM_RDS_CONFIG_BLETHA_SHFT) |
(3 << FM_RDS_CONFIG_BLETHB_SHFT) |
(3 << FM_RDS_CONFIG_BLETHC_SHFT) |
(3 << FM_RDS_CONFIG_BLETHD_SHFT));
si47xx_set_property(FM_DEEMPHASIS, FM_DEEMPH_75US); // Deemphasis
// Band is already set to 87.5-107.9MHz (US)
// Space is already set to 200kHz (US)
break;
case JAPAN :
si47xx_set_property(FM_RDS_CONFIG, 0); // Disable RDS
si47xx_set_property(FM_DEEMPHASIS, FM_DEEMPH_50US); // Deemphasis
si47xx_set_property(FM_SEEK_BAND_BOTTOM, 7600); // 76 MHz Bottom
si47xx_set_property(FM_SEEK_BAND_TOP, 9000); // 90 MHz Top
si47xx_set_property(FM_SEEK_FREQ_SPACING, 10); // 100 kHz Spacing
break;
case EUROPE :
default:
// This interrupt will be used to determine when RDS is available.
si47xx_set_property(FM_RDS_INTERRUPT_SOURCE,
FM_RDS_INTERRUPT_SOURCE_SYNCFOUND_MASK); // RDS Interrupt
// Enable the RDS and allow all blocks so we can compute the error
// rate later.
si47xx_set_property(FM_RDS_CONFIG, FM_RDS_CONFIG_RDSEN_MASK |
(3 << FM_RDS_CONFIG_BLETHA_SHFT) |
(3 << FM_RDS_CONFIG_BLETHB_SHFT) |
(3 << FM_RDS_CONFIG_BLETHC_SHFT) |
(3 << FM_RDS_CONFIG_BLETHD_SHFT));
si47xx_set_property(FM_DEEMPHASIS, FM_DEEMPH_50US); // Deemphasis
// Band is already set to 87.5-107.9MHz (Europe)
si47xx_set_property(FM_SEEK_FREQ_SPACING, 10); // 100 kHz Spacing
break;
}
}
//-----------------------------------------------------------------------------
// Configures the device for normal operation
//-----------------------------------------------------------------------------
void si47xxFMRX_configure(void)
{
// Configure all other registers
si47xxFMRX_hardware_cfg();
si47xxFMRX_general_cfg();
si47xxFMRX_regional_cfg(USA);
// Turn on the Headphone Amp and analog out.
M_INPUT_AD = 1;
M_OUTPUT_AD = 0;
GP1 = 1;
}
//-----------------------------------------------------------------------------
// Resets the part and initializes registers to the point of being ready for
// the first tune or seek.
//-----------------------------------------------------------------------------
void si47xxFMRX_initialize(void)
{
// Zero status registers.
PoweredUp = 0;
// Perform a hardware reset, power up the device, and then perform the
// initial configuration.
si47xx_reset();
si47xxFMRX_powerup();
si47xxFMRX_configure();
}
//-----------------------------------------------------------------------------
// Set the volume and mute/unmute status
//
// Inputs:
// volume: a 6-bit volume value
//
// Note: It is assumed that if the volume is being adjusted, the device should
// not be muted.
//-----------------------------------------------------------------------------
void si47xxFMRX_set_volume(u8 volume)
{
// Turn off the mute
si47xx_set_property(RX_HARD_MUTE, 0);
// Set the volume to the passed value
si47xx_set_property(RX_VOLUME, (u16)volume & RX_VOLUME_MASK);
}
//-----------------------------------------------------------------------------
// Mute/unmute audio
//
// Inputs:
// mute: 0 = output enabled (mute disabled)
// 1 = output muted
//-----------------------------------------------------------------------------
void si47xxFMRX_mute(u8 mute)
{
if(mute)
si47xx_set_property(RX_HARD_MUTE,
RX_HARD_MUTE_RMUTE_MASK | RX_HARD_MUTE_LMUTE_MASK);
else
si47xx_set_property(RX_HARD_MUTE, 0);
}
//-----------------------------------------------------------------------------
// Tunes to a station number using the current band and spacing settings.
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -