From a7caaac7a41ca7f8765fa062170ef51a7d09d7c6 Mon Sep 17 00:00:00 2001 From: Kyle Keen Date: Sat, 2 Aug 2014 13:15:17 -0400 Subject: [PATCH] r82xx: tejeez's if/bw filters --- include/rtl-sdr.h | 4 + include/tuner_r82xx.h | 5 +- src/librtlsdr.c | 49 ++++++-- src/tuner_r82xx.c | 254 +++++++++++++++--------------------------- 4 files changed, 138 insertions(+), 174 deletions(-) diff --git a/include/rtl-sdr.h b/include/rtl-sdr.h index 22da878..656c55b 100644 --- a/include/rtl-sdr.h +++ b/include/rtl-sdr.h @@ -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. * diff --git a/include/tuner_r82xx.h b/include/tuner_r82xx.h index 5ec500d..8068205 100644 --- a/include/tuner_r82xx.h +++ b/include/tuner_r82xx.h @@ -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 diff --git a/src/librtlsdr.c b/src/librtlsdr.c index b5c1da7..2b0759e 100644 --- a/src/librtlsdr.c +++ b/src/librtlsdr.c @@ -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); diff --git a/src/tuner_r82xx.c b/src/tuner_r82xx.c index a557c0d..4611d99 100644 --- a/src/tuner_r82xx.c +++ b/src/tuner_r82xx.c @@ -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;