r82xx: tejeez's if/bw filters

pull/6/head
Kyle Keen 2014-08-02 13:15:17 -04:00
rodzic 3f2632dcaf
commit a7caaac7a4
4 zmienionych plików z 138 dodań i 174 usunięć

Wyświetl plik

@ -144,6 +144,10 @@ RTLSDR_API int rtlsdr_read_eeprom(rtlsdr_dev_t *dev, uint8_t *data,
RTLSDR_API int rtlsdr_set_center_freq(rtlsdr_dev_t *dev, uint32_t freq);
RTLSDR_API int rtlsdr_set_if_freq(rtlsdr_dev_t *dev, uint32_t freq);
RTLSDR_API int rtlsdr_set_if_bandwidth(rtlsdr_dev_t *dev, int bw);
/*!
* Get actual frequency the device is tuned to.
*

Wyświetl plik

@ -32,7 +32,8 @@
#define R82XX_CHECK_ADDR 0x00
#define R82XX_CHECK_VAL 0x69
#define R82XX_IF_FREQ 3570000
#define R82XX_DEFAULT_IF_FREQ 6000000
#define R82XX_DEFAULT_IF_BW 2000000
#define REG_SHADOW_START 5
#define NUM_REGS 30
@ -118,5 +119,7 @@ int r82xx_set_freq(struct r82xx_priv *priv, uint32_t freq);
int r82xx_set_gain(struct r82xx_priv *priv, int set_manual_gain, int gain);
int r82xx_set_nomod(struct r82xx_priv *priv);
int r82xx_set_dither(struct r82xx_priv *priv, int dither);
int r82xx_set_bw(struct r82xx_priv *priv, uint32_t bw);
int r82xx_set_if_freq(struct r82xx_priv *priv, uint32_t freq);
#endif

Wyświetl plik

@ -64,6 +64,7 @@ typedef struct rtlsdr_tuner_iface {
int (*set_gain)(void *, int gain /* tenth dB */);
int (*set_if_gain)(void *, int stage, int gain /* tenth dB */);
int (*set_gain_mode)(void *, int manual);
int (*set_if_freq)(void *, uint32_t freq /* Hz */);
} rtlsdr_tuner_iface_t;
enum rtlsdr_async_status {
@ -123,6 +124,7 @@ struct rtlsdr_dev {
int dev_lost;
int driver_active;
unsigned int xfer_errors;
int tuner_initialized;
};
void rtlsdr_set_gpio_bit(rtlsdr_dev_t *dev, uint8_t gpio, int val);
@ -238,7 +240,17 @@ int r820t_set_freq(void *dev, uint32_t freq) {
rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;
return r82xx_set_freq(&devt->r82xx_p, freq);
}
int r820t_set_bw(void *dev, int bw) { return 0; }
int r820t_set_bw(void *dev, int bw) {
rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;
return r82xx_set_bw(&devt->r82xx_p, bw);
}
int r820t_set_if_freq(void *dev, uint32_t freq) {
rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;
return r82xx_set_if_freq(&devt->r82xx_p, freq);
}
int r820t_set_gain(void *dev, int gain) {
rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;
return r82xx_set_gain(&devt->r82xx_p, 1, gain);
@ -251,37 +263,37 @@ int r820t_set_gain_mode(void *dev, int manual) {
/* definition order must match enum rtlsdr_tuner */
static rtlsdr_tuner_iface_t tuners[] = {
{
NULL, NULL, NULL, NULL, NULL, NULL, NULL /* dummy for unknown tuners */
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL /* dummy for unknown tuners */
},
{
e4000_init, e4000_exit,
e4000_set_freq, e4000_set_bw, e4000_set_gain, e4000_set_if_gain,
e4000_set_gain_mode
e4000_set_gain_mode, NULL
},
{
_fc0012_init, fc0012_exit,
fc0012_set_freq, fc0012_set_bw, _fc0012_set_gain, NULL,
fc0012_set_gain_mode
fc0012_set_gain_mode, NULL
},
{
_fc0013_init, fc0013_exit,
fc0013_set_freq, fc0013_set_bw, _fc0013_set_gain, NULL,
fc0013_set_gain_mode
fc0013_set_gain_mode, NULL
},
{
fc2580_init, fc2580_exit,
_fc2580_set_freq, fc2580_set_bw, fc2580_set_gain, NULL,
fc2580_set_gain_mode
fc2580_set_gain_mode, NULL
},
{
r820t_init, r820t_exit,
r820t_set_freq, r820t_set_bw, r820t_set_gain, NULL,
r820t_set_gain_mode
r820t_set_gain_mode, r820t_set_if_freq
},
{
r820t_init, r820t_exit,
r820t_set_freq, r820t_set_bw, r820t_set_gain, NULL,
r820t_set_gain_mode
r820t_set_gain_mode, r820t_set_if_freq
},
};
@ -662,6 +674,7 @@ int rtlsdr_deinit_baseband(rtlsdr_dev_t *dev)
rtlsdr_set_i2c_repeater(dev, 1);
r = dev->tuner->exit(dev); /* deinitialize tuner */
rtlsdr_set_i2c_repeater(dev, 0);
dev->tuner_initialized = 0;
}
/* poweroff demodulator and ADCs */
@ -693,6 +706,14 @@ int rtlsdr_set_if_freq(rtlsdr_dev_t *dev, uint32_t freq)
tmp = if_freq & 0xff;
r |= rtlsdr_demod_write_reg(dev, 1, 0x1b, tmp, 1);
/* Tell the R820T driver which IF frequency we are currently using
* so that it can choose the optimal IF filter settings.
* Works for normal tuning as well as no-mod direct sampling! */
if(dev->tuner_initialized && dev->tuner && dev->tuner->set_if_freq) {
rtlsdr_set_i2c_repeater(dev, 1);
dev->tuner->set_if_freq(dev, freq);
rtlsdr_set_i2c_repeater(dev, 0);
}
return r;
}
@ -1144,6 +1165,7 @@ int rtlsdr_set_direct_sampling(rtlsdr_dev_t *dev, int on)
rtlsdr_set_i2c_repeater(dev, 1);
r = dev->tuner->exit(dev);
rtlsdr_set_i2c_repeater(dev, 0);
dev->tuner_initialized = 0;
}
}
@ -1153,6 +1175,7 @@ int rtlsdr_set_direct_sampling(rtlsdr_dev_t *dev, int on)
fprintf(stderr, "Tuning E4000 to 3708 MHz\n");
rtlsdr_set_i2c_repeater(dev, 1);
dev->tuner->init(dev);
dev->tuner_initialized = 1;
dev->tuner->set_freq(dev, 3708000000u);
e4000_set_bw(dev, 15000000);
rtlsdr_set_i2c_repeater(dev, 0);
@ -1161,6 +1184,7 @@ int rtlsdr_set_direct_sampling(rtlsdr_dev_t *dev, int on)
rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;
rtlsdr_set_i2c_repeater(dev, 1);
dev->tuner->init(dev);
dev->tuner_initialized = 1;
r82xx_set_nomod(&devt->r82xx_p);
rtlsdr_set_i2c_repeater(dev, 0);
}
@ -1190,11 +1214,12 @@ int rtlsdr_set_direct_sampling(rtlsdr_dev_t *dev, int on)
rtlsdr_set_i2c_repeater(dev, 1);
r |= dev->tuner->init(dev);
rtlsdr_set_i2c_repeater(dev, 0);
dev->tuner_initialized = 1;
}
if ((dev->tuner_type == RTLSDR_TUNER_R820T) ||
(dev->tuner_type == RTLSDR_TUNER_R828D)) {
r |= rtlsdr_set_if_freq(dev, R82XX_IF_FREQ);
r |= rtlsdr_set_if_freq(dev, R82XX_DEFAULT_IF_FREQ);
/* enable spectrum inversion */
r |= rtlsdr_demod_write_reg(dev, 1, 0x15, 0x01, 1);
@ -1585,7 +1610,7 @@ found:
/* the R82XX use 3.57 MHz IF for the DVB-T 6 MHz mode, and
* 4.57 MHz for the 8 MHz mode */
rtlsdr_set_if_freq(dev, R82XX_IF_FREQ);
rtlsdr_set_if_freq(dev, R82XX_DEFAULT_IF_FREQ);
/* enable spectrum inversion */
rtlsdr_demod_write_reg(dev, 1, 0x15, 0x01, 1);
@ -1598,8 +1623,10 @@ found:
break;
}
if (dev->tuner->init)
if (dev->tuner->init) {
r = dev->tuner->init(dev);
dev->tuner_initialized = 1;
}
rtlsdr_set_i2c_repeater(dev, 0);

Wyświetl plik

@ -760,104 +760,29 @@ static int r82xx_sysfreq_sel(struct r82xx_priv *priv, uint32_t freq,
return 0;
}
static int r82xx_set_tv_standard(struct r82xx_priv *priv,
static int r82xx_init_tv_standard(struct r82xx_priv *priv,
unsigned bw,
enum r82xx_tuner_type type,
uint32_t delsys)
{
/* everything that was previously done in r82xx_set_tv_standard
* and doesn't need to be changed when filter settings change */
int rc, i;
uint32_t if_khz, filt_cal_lo;
uint8_t data[5];
uint8_t filt_gain, img_r, filt_q, hp_cor, ext_enable, loop_through;
uint8_t data[5], val;
uint8_t filt_gain, img_r, ext_enable, loop_through;
uint8_t lt_att, flt_ext_widest, polyfil_cur;
int need_calibration;
if (delsys == SYS_ISDBT) {
if_khz = 4063;
filt_cal_lo = 59000;
filt_gain = 0x10; /* +3db, 6mhz on */
img_r = 0x00; /* image negative */
filt_q = 0x10; /* r10[4]:low q(1'b1) */
hp_cor = 0x6a; /* 1.7m disable, +2cap, 1.25mhz */
ext_enable = 0x40; /* r30[6], ext enable; r30[5]:0 ext at lna max */
loop_through = 0x00; /* r5[7], lt on */
lt_att = 0x00; /* r31[7], lt att enable */
flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
polyfil_cur = 0x60; /* r25[6:5]:min */
} else {
if (bw < 6) {
/* narrowest bandwidth? */
if_khz = 3570;
filt_cal_lo = 56000; /* 52000->56000 */
filt_gain = 0x10; /* +3db, 6mhz on */
img_r = 0x00; /* image negative */
filt_q = 0x10; /* r10[4]:low q(1'b1) */
hp_cor = 0x6a; /* 1.7m disable, +2cap, 1.25mhz */
ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
loop_through = 0x00; /* r5[7], lt on */
lt_att = 0x00; /* r31[7], lt att enable */
flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
polyfil_cur = 0x60; /* r25[6:5]:min */
} else if (bw == 6) {
if_khz = 3570;
filt_cal_lo = 56000; /* 52000->56000 */
filt_gain = 0x10; /* +3db, 6mhz on */
img_r = 0x00; /* image negative */
filt_q = 0x10; /* r10[4]:low q(1'b1) */
hp_cor = 0x6b; /* 1.7m disable, +2cap, 1.0mhz */
ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
loop_through = 0x00; /* r5[7], lt on */
lt_att = 0x00; /* r31[7], lt att enable */
flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
polyfil_cur = 0x60; /* r25[6:5]:min */
} else if (bw == 7) {
#if 0
/*
* There are two 7 MHz tables defined on the original
* driver, but just the second one seems to be visible
* by rtl2832. Keep this one here commented, as it
* might be needed in the future
*/
if_khz = 4070;
filt_cal_lo = 60000;
filt_gain = 0x10; /* +3db, 6mhz on */
img_r = 0x00; /* image negative */
filt_q = 0x10; /* r10[4]:low q(1'b1) */
hp_cor = 0x2b; /* 1.7m disable, +1cap, 1.0mhz */
ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
loop_through = 0x00; /* r5[7], lt on */
lt_att = 0x00; /* r31[7], lt att enable */
flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
polyfil_cur = 0x60; /* r25[6:5]:min */
#endif
/* 7 MHz, second table */
if_khz = 4570;
filt_cal_lo = 63000;
filt_gain = 0x10; /* +3db, 6mhz on */
img_r = 0x00; /* image negative */
filt_q = 0x10; /* r10[4]:low q(1'b1) */
hp_cor = 0x2a; /* 1.7m disable, +1cap, 1.25mhz */
ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
loop_through = 0x00; /* r5[7], lt on */
lt_att = 0x00; /* r31[7], lt att enable */
flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
polyfil_cur = 0x60; /* r25[6:5]:min */
} else {
if_khz = 4570;
filt_cal_lo = 68500;
filt_gain = 0x10; /* +3db, 6mhz on */
img_r = 0x00; /* image negative */
filt_q = 0x10; /* r10[4]:low q(1'b1) */
hp_cor = 0x0b; /* 1.7m disable, +0cap, 1.0mhz */
ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
loop_through = 0x00; /* r5[7], lt on */
lt_att = 0x00; /* r31[7], lt att enable */
flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
polyfil_cur = 0x60; /* r25[6:5]:min */
}
}
if_khz = R82XX_DEFAULT_IF_FREQ/1000;
filt_cal_lo = 56000; /* 52000->56000 */
filt_gain = 0x10; /* +3db, 6mhz on */
img_r = 0x00; /* image negative */
ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
loop_through = 0x00; /* r5[7], lt on */
lt_att = 0x00; /* r31[7], lt att enable */
flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
polyfil_cur = 0x60; /* r25[6:5]:min */
/* Initialize the shadow registers */
memcpy(priv->regs, r82xx_init_array, sizeof(r82xx_init_array));
@ -881,72 +806,6 @@ static int r82xx_set_tv_standard(struct r82xx_priv *priv,
}
priv->int_freq = if_khz * 1000;
/* Check if standard changed. If so, filter calibration is needed */
/* as we call this function only once in rtlsdr, force calibration */
need_calibration = 1;
if (need_calibration) {
for (i = 0; i < 2; i++) {
/* Set filt_cap */
rc = r82xx_write_reg_mask(priv, 0x0b, hp_cor, 0x60);
if (rc < 0)
return rc;
/* set cali clk =on */
rc = r82xx_write_reg_mask(priv, 0x0f, 0x04, 0x04);
if (rc < 0)
return rc;
/* X'tal cap 0pF for PLL */
rc = r82xx_write_reg_mask(priv, 0x10, 0x00, 0x03);
if (rc < 0)
return rc;
rc = r82xx_set_pll(priv, filt_cal_lo * 1000);
if (rc < 0 || !priv->has_lock)
return rc;
/* Start Trigger */
rc = r82xx_write_reg_mask(priv, 0x0b, 0x10, 0x10);
if (rc < 0)
return rc;
// usleep_range(1000, 2000);
/* Stop Trigger */
rc = r82xx_write_reg_mask(priv, 0x0b, 0x00, 0x10);
if (rc < 0)
return rc;
/* set cali clk =off */
rc = r82xx_write_reg_mask(priv, 0x0f, 0x00, 0x04);
if (rc < 0)
return rc;
/* Check if calibration worked */
rc = r82xx_read(priv, 0x00, data, sizeof(data));
if (rc < 0)
return rc;
priv->fil_cal_code = data[4] & 0x0f;
if (priv->fil_cal_code && priv->fil_cal_code != 0x0f)
break;
}
/* narrowest */
if (priv->fil_cal_code == 0x0f)
priv->fil_cal_code = 0;
}
rc = r82xx_write_reg_mask(priv, 0x0a,
filt_q | priv->fil_cal_code, 0x1f);
if (rc < 0)
return rc;
/* Set BW, Filter_gain, & HP corner */
rc = r82xx_write_reg_mask(priv, 0x0b, hp_cor, 0xef);
if (rc < 0)
return rc;
/* Set Img_R */
rc = r82xx_write_reg_mask(priv, 0x07, img_r, 0x80);
if (rc < 0)
@ -985,11 +844,79 @@ static int r82xx_set_tv_standard(struct r82xx_priv *priv,
/* Store current standard. If it changes, re-calibrate the tuner */
priv->delsys = delsys;
priv->type = type;
priv->bw = bw;
return 0;
}
static int r82xx_set_if_filter(struct r82xx_priv *priv, int hpf, int lpf) {
int rc, i;
uint8_t filt_q, hp_cor;
int cal;
filt_q = 0x10; /* r10[4]:low q(1'b1) */
if(lpf <= 2500) {
hp_cor = 0xE0; /* 1.7m enable, +2cap */
cal = 16*(2500-lpf) / (2500-2000);
} else if(lpf <= 3100) {
hp_cor = 0xA0; /* 1.7m enable, +1cap */
cal = 16*(3100-lpf) / (3100-2200);
} else if(lpf <= 3900) {
hp_cor = 0x80; /* 1.7m enable, +0cap */
cal = 16*(3900-lpf) / (3900-2600);
} else if(lpf <= 7100) {
hp_cor = 0x60; /* 1.7m disable, +2cap */
cal = 16*(7100-lpf) / (7100-5300);
} else if(lpf <= 8700) {
hp_cor = 0x20; /* 1.7m disable, +1cap */
cal = 16*(8700-lpf) / (8700-6300);
} else {
hp_cor = 0x00; /* 1.7m disable, +0cap */
cal = 16*(11000-lpf) / (11000-7500);
}
if(hpf >= 4700) hp_cor |= 0x00; /* 5 MHz */
else if(hpf >= 3800) hp_cor |= 0x01; /* 4 MHz */
else if(hpf >= 3000) hp_cor |= 0x02; /* -12dB @ 2.25 MHz */
else if(hpf >= 2800) hp_cor |= 0x03; /* -8dB @ 2.25 MHz */
else if(hpf >= 2600) hp_cor |= 0x04; /* -4dB @ 2.25 MHz */
else if(hpf >= 2400) hp_cor |= 0x05; /* -12dB @ 1.75 MHz */
else if(hpf >= 2200) hp_cor |= 0x06; /* -8dB @ 1.75 MHz */
else if(hpf >= 2000) hp_cor |= 0x07; /* -4dB @ 1.75 MHz */
else if(hpf >= 1800) hp_cor |= 0x08; /* -12dB @ 1.25 MHz */
else if(hpf >= 1600) hp_cor |= 0x09; /* -8dB @ 1.25 MHz */
else if(hpf >= 1400) hp_cor |= 0x0A; /* -4dB @ 1.25 MHz */
else hp_cor |= 0x0B;
if(cal < 0) cal = 0;
else if(cal > 15) cal = 15;
priv->fil_cal_code = cal;
fprintf(stderr, "Setting IF filter for %d...%d kHz: hp_cor=0x%02x, fil_cal_code=%d\n", hpf, lpf, hp_cor, cal);
rc = r82xx_write_reg_mask(priv, 0x0a,
filt_q | priv->fil_cal_code, 0x1f);
if (rc < 0)
return rc;
/* Set BW, Filter_gain, & HP corner */
rc = r82xx_write_reg_mask(priv, 0x0b, hp_cor, 0xef);
if (rc < 0)
return rc;
return 0;
}
int r82xx_set_bw(struct r82xx_priv *priv, uint32_t bw) {
priv->bw = bw;
return r82xx_set_if_filter(priv, ((int)priv->int_freq - (int)bw/2)/1000, ((int)priv->int_freq + (int)bw/2)/1000);
}
int r82xx_set_if_freq(struct r82xx_priv *priv, uint32_t freq) {
priv->int_freq = freq;
return r82xx_set_if_filter(priv, ((int)freq - (int)priv->bw/2)/1000, ((int)freq + (int)priv->bw/2)/1000);
}
static int r82xx_read_gain(struct r82xx_priv *priv)
{
uint8_t data[4];
@ -1127,9 +1054,9 @@ int r82xx_set_nomod(struct r82xx_priv *priv)
fprintf(stderr, "Using R820T no-mod direct sampling mode\n");
rc = r82xx_set_tv_standard(priv, 8, TUNER_DIGITAL_TV, 0);
/*rc = r82xx_set_bw(priv, 1000000);
if (rc < 0)
goto err;
goto err;*/
/* experimentally determined magic numbers
* needs more experimenting with all the registers */
@ -1275,11 +1202,14 @@ int r82xx_init(struct r82xx_priv *priv)
rc = r82xx_write(priv, 0x05,
r82xx_init_array, sizeof(r82xx_init_array));
rc = r82xx_set_tv_standard(priv, 3, TUNER_DIGITAL_TV, 0);
if (rc < 0)
goto err;
rc |= r82xx_init_tv_standard(priv, 3, TUNER_DIGITAL_TV, 0);
rc = r82xx_sysfreq_sel(priv, 0, TUNER_DIGITAL_TV, SYS_DVBT);
priv->bw = R82XX_DEFAULT_IF_BW;
priv->int_freq = R82XX_DEFAULT_IF_FREQ;
/* r82xx_set_bw will always be called by rtlsdr_set_sample_rate,
so there's no need to call r82xx_set_if_filter here */
rc |= r82xx_sysfreq_sel(priv, 0, TUNER_DIGITAL_TV, SYS_DVBT);
priv->init_done = 1;