apply frequency correction value on the xtal clock directly

by using this approach both, the tuning frequency and the sample rate
should be corrected at the same time.
This commit is contained in:
Dimitri Stolnikov 2012-07-08 15:52:59 +02:00
parent 7dc15d9fd7
commit f9b5d7b0a6
2 changed files with 59 additions and 29 deletions

View File

@ -60,9 +60,9 @@ RTLSDR_API int rtlsdr_close(rtlsdr_dev_t *dev);
*
* Usually both ICs use the same clock. Changing the clock may make sense if
* you are applying an external clock to the tuner or to compensate the
* frequency (and samplerate) error caused by the original cheap crystal.
* frequency (and samplerate) error caused by the original (cheap) crystal.
*
* NOTE: Call this function only if you know what you are doing.
* NOTE: Call this function only if you fully understand the implications.
*
* \param dev the device handle given by rtlsdr_open()
* \param rtl_freq frequency value used to clock the RTL2832 in Hz
@ -109,8 +109,21 @@ RTLSDR_API int rtlsdr_set_center_freq(rtlsdr_dev_t *dev, uint32_t freq);
*/
RTLSDR_API uint32_t rtlsdr_get_center_freq(rtlsdr_dev_t *dev);
/*!
* Set the frequency correction value for the device.
*
* \param dev the device handle given by rtlsdr_open()
* \param ppm correction value in parts per million (ppm)
* \return 0 on success
*/
RTLSDR_API int rtlsdr_set_freq_correction(rtlsdr_dev_t *dev, int ppm);
/*!
* Get actual frequency correction value of the device.
*
* \param dev the device handle given by rtlsdr_open()
* \return correction value in parts per million (ppm)
*/
RTLSDR_API int rtlsdr_get_freq_correction(rtlsdr_dev_t *dev);
enum rtlsdr_tuner {

View File

@ -91,7 +91,7 @@ void rtlsdr_set_gpio_bit(rtlsdr_dev_t *dev, uint8_t gpio, int val);
int e4000_init(void *dev) {
rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;
devt->e4k_s.i2c_addr = E4K_I2C_ADDR;
devt->e4k_s.vco.fosc = devt->tun_xtal;
devt->e4k_s.vco.fosc = devt->tun_xtal; /* no need to correct it here */
devt->e4k_s.rtl_dev = dev;
return e4k_init(&devt->e4k_s);
}
@ -540,10 +540,7 @@ int rtlsdr_set_xtal_freq(rtlsdr_dev_t *dev, uint32_t rtl_freq, uint32_t tuner_fr
(rtl_freq < MIN_RTL_XTAL_FREQ || rtl_freq > MAX_RTL_XTAL_FREQ))
return -2;
if (dev->rtl_xtal != rtl_freq) {
if (0 == rtl_freq)
rtl_freq = DEF_RTL_XTAL_FREQ;
if (rtl_freq > 0 && dev->rtl_xtal != rtl_freq) {
dev->rtl_xtal = rtl_freq;
/* update xtal-dependent settings */
@ -553,9 +550,13 @@ int rtlsdr_set_xtal_freq(rtlsdr_dev_t *dev, uint32_t rtl_freq, uint32_t tuner_fr
if (dev->tun_xtal != tuner_freq) {
if (0 == tuner_freq)
tuner_freq = dev->rtl_xtal;
dev->tun_xtal = dev->rtl_xtal;
else
dev->tun_xtal = tuner_freq;
dev->tun_xtal = tuner_freq;
/* read corrected clock value into e4k structure */
if (rtlsdr_get_xtal_freq(dev, NULL, &dev->e4k_s.vco.fosc))
return -3;
/* update xtal-dependent settings */
if (dev->freq)
@ -570,12 +571,13 @@ int rtlsdr_get_xtal_freq(rtlsdr_dev_t *dev, uint32_t *rtl_freq, uint32_t *tuner_
if (!dev)
return -1;
*rtl_freq = dev->rtl_xtal;
#define APPLY_PPM_CORR(val,ppm) (((val) * (1.0 + (ppm) / 1e6)))
if (!dev->tuner)
return -2;
if (rtl_freq)
*rtl_freq = (uint32_t) APPLY_PPM_CORR(dev->rtl_xtal, dev->corr);
*tuner_freq = dev->tun_xtal;
if (tuner_freq)
*tuner_freq = (uint32_t) APPLY_PPM_CORR(dev->tun_xtal, dev->corr);
return 0;
}
@ -624,16 +626,13 @@ int rtlsdr_get_usb_strings(rtlsdr_dev_t *dev, char *manufact, char *product,
int rtlsdr_set_center_freq(rtlsdr_dev_t *dev, uint32_t freq)
{
int r = -1;
double f = (double) freq;
if (!dev || !dev->tuner)
return -1;
if (dev->tuner->set_freq) {
f *= 1.0 + dev->corr / 1e6;
rtlsdr_set_i2c_repeater(dev, 1);
r = dev->tuner->set_freq(dev, (uint32_t) f);
r = dev->tuner->set_freq(dev, freq);
rtlsdr_set_i2c_repeater(dev, 0);
if (!r)
@ -647,7 +646,7 @@ int rtlsdr_set_center_freq(rtlsdr_dev_t *dev, uint32_t freq)
uint32_t rtlsdr_get_center_freq(rtlsdr_dev_t *dev)
{
if (!dev || !dev->tuner)
if (!dev)
return 0;
return dev->freq;
@ -655,25 +654,32 @@ uint32_t rtlsdr_get_center_freq(rtlsdr_dev_t *dev)
int rtlsdr_set_freq_correction(rtlsdr_dev_t *dev, int ppm)
{
int r;
int r = 0;
if (!dev || !dev->tuner)
if (!dev)
return -1;
if (dev->corr == ppm)
return -1;
return -2;
dev->corr = ppm;
/* retune to apply new correction value */
r = rtlsdr_set_center_freq(dev, dev->freq);
/* read corrected clock value into e4k structure */
if (rtlsdr_get_xtal_freq(dev, NULL, &dev->e4k_s.vco.fosc))
return -3;
if (dev->rate) /* reset sample rate to apply new correction value */
r |= rtlsdr_set_sample_rate(dev, dev->rate);
if (dev->freq) /* retune to apply new correction value */
r |= rtlsdr_set_center_freq(dev, dev->freq);
return r;
}
int rtlsdr_get_freq_correction(rtlsdr_dev_t *dev)
{
if (!dev || !dev->tuner)
if (!dev)
return 0;
return dev->corr;
@ -752,7 +758,7 @@ int rtlsdr_set_tuner_gain(rtlsdr_dev_t *dev, int gain)
int rtlsdr_get_tuner_gain(rtlsdr_dev_t *dev)
{
if (!dev || !dev->tuner)
if (!dev)
return 0;
return dev->gain;
@ -796,6 +802,7 @@ int rtlsdr_set_sample_rate(rtlsdr_dev_t *dev, uint32_t samp_rate)
uint16_t tmp;
uint32_t rsamp_ratio;
double real_rate;
uint32_t rtl_freq;
if (!dev)
return -1;
@ -804,10 +811,14 @@ int rtlsdr_set_sample_rate(rtlsdr_dev_t *dev, uint32_t samp_rate)
if (samp_rate > MAX_SAMP_RATE)
samp_rate = MAX_SAMP_RATE;
rsamp_ratio = (dev->rtl_xtal * TWO_POW(22)) / samp_rate;
/* read corrected clock value */
if (rtlsdr_get_xtal_freq(dev, &rtl_freq, NULL))
return -2;
rsamp_ratio = (rtl_freq * TWO_POW(22)) / samp_rate;
rsamp_ratio &= ~3;
real_rate = (dev->rtl_xtal * TWO_POW(22)) / rsamp_ratio;
real_rate = (rtl_freq * TWO_POW(22)) / rsamp_ratio;
if ( ((double)samp_rate) != real_rate )
fprintf(stderr, "Exact sample rate is: %f Hz\n", real_rate);
@ -1089,7 +1100,7 @@ found:
}
dev->tuner = &tuners[dev->tuner_type];
dev->tun_xtal = dev->rtl_xtal;
dev->tun_xtal = dev->rtl_xtal; /* use the rtl clock value by default */
if (dev->tuner->init)
r = dev->tuner->init(dev);
@ -1313,10 +1324,16 @@ int rtlsdr_cancel_async(rtlsdr_dev_t *dev)
uint32_t rtlsdr_get_tuner_clock(void *dev)
{
uint32_t tuner_freq;
if (!dev)
return 0;
return ((rtlsdr_dev_t *)dev)->tun_xtal;
/* read corrected clock value */
if (rtlsdr_get_xtal_freq((rtlsdr_dev_t *)dev, NULL, &tuner_freq))
return 0;
return tuner_freq;
}
int rtlsdr_i2c_write_fn(void *dev, uint8_t addr, uint8_t *buf, int len)