add support for direct sampling mode

This commit adds the function rtlsdr_set_direct_sampling()
which can be used to enable/disable a mode where the
RTL2832 acts as a direct sampling receiver.

This mode disables the tuner, and by attaching a long
wire, or better, a 50Ω to 200Ω transformer and a lowpass-
filter to the In-phase ADC input (pin 1 or 2 of the RTL2832,
whereas pin 1 is at the molded dot) it is possible to listen to
shortwave radio stations. The coupling capacitors can be
left in place, but for better results they should be removed.

Tuning in this mode is done with the DDC, and since the
ADC samples with 28.8 MHz, tuning is possible from 0 to
28.8 MHz.

Signed-off-by: Steve Markgraf <steve@steve-m.de>
This commit is contained in:
Steve Markgraf 2012-09-13 21:53:51 +02:00
parent 1533422f98
commit fc5881d4cd
3 changed files with 84 additions and 12 deletions

View File

@ -229,6 +229,18 @@ RTLSDR_API int rtlsdr_set_testmode(rtlsdr_dev_t *dev, int on);
*/ */
RTLSDR_API int rtlsdr_set_agc_mode(rtlsdr_dev_t *dev, int on); RTLSDR_API int rtlsdr_set_agc_mode(rtlsdr_dev_t *dev, int on);
/*!
* Enable or disable the direct sampling mode. When enabled, the IF mode
* of the RTL2832 is activated, and rtlsdr_set_center_freq() will control
* the IF-frequency of the DDC, which can be used to tune from 0 to 28.8 MHz
* (xtal frequency of the RTL2832).
*
* \param dev the device handle given by rtlsdr_open()
* \param direct sampling mode, 1 means enabled, 0 disabled
* \return 0 on success
*/
RTLSDR_API int rtlsdr_set_direct_sampling(rtlsdr_dev_t *dev, int on);
/* streaming functions */ /* streaming functions */
RTLSDR_API int rtlsdr_reset_buffer(rtlsdr_dev_t *dev); RTLSDR_API int rtlsdr_reset_buffer(rtlsdr_dev_t *dev);

View File

@ -5,6 +5,8 @@
#define R820T_CHECK_ADDR 0x00 #define R820T_CHECK_ADDR 0x00
#define R820T_CHECK_VAL 0x69 #define R820T_CHECK_VAL 0x69
#define R820T_IF_FREQ 3570000
//*************************************************************** //***************************************************************
//* INCLUDES.H //* INCLUDES.H
//*************************************************************** //***************************************************************

View File

@ -79,6 +79,7 @@ struct rtlsdr_dev {
/* rtl demod context */ /* rtl demod context */
uint32_t rate; /* Hz */ uint32_t rate; /* Hz */
uint32_t rtl_xtal; /* Hz */ uint32_t rtl_xtal; /* Hz */
int direct_sampling;
/* tuner context */ /* tuner context */
enum rtlsdr_tuner tuner_type; enum rtlsdr_tuner tuner_type;
rtlsdr_tuner_iface_t *tuner; rtlsdr_tuner_iface_t *tuner;
@ -562,11 +563,19 @@ int rtlsdr_deinit_baseband(rtlsdr_dev_t *dev)
int rtlsdr_set_if_freq(rtlsdr_dev_t *dev, uint32_t freq) int rtlsdr_set_if_freq(rtlsdr_dev_t *dev, uint32_t freq)
{ {
uint32_t rtl_xtal;
int32_t if_freq; int32_t if_freq;
uint8_t tmp; uint8_t tmp;
int r; int r;
if_freq = ((freq * TWO_POW(22)) / dev->rtl_xtal) * (-1); if (!dev)
return -1;
/* read corrected clock value */
if (rtlsdr_get_xtal_freq(dev, &rtl_xtal, NULL))
return -2;
if_freq = ((freq * TWO_POW(22)) / rtl_xtal) * (-1);
tmp = (if_freq >> 16) & 0x3f; tmp = (if_freq >> 16) & 0x3f;
r = rtlsdr_demod_write_reg(dev, 1, 0x19, tmp, 1); r = rtlsdr_demod_write_reg(dev, 1, 0x19, tmp, 1);
@ -679,17 +688,19 @@ int rtlsdr_set_center_freq(rtlsdr_dev_t *dev, uint32_t freq)
if (!dev || !dev->tuner) if (!dev || !dev->tuner)
return -1; return -1;
if (dev->tuner->set_freq) { if (dev->direct_sampling) {
r = rtlsdr_set_if_freq(dev, freq);
} else if (dev->tuner && dev->tuner->set_freq) {
rtlsdr_set_i2c_repeater(dev, 1); rtlsdr_set_i2c_repeater(dev, 1);
r = dev->tuner->set_freq(dev, freq); r = dev->tuner->set_freq(dev, freq);
rtlsdr_set_i2c_repeater(dev, 0); rtlsdr_set_i2c_repeater(dev, 0);
if (!r)
dev->freq = freq;
else
dev->freq = 0;
} }
if (!r)
dev->freq = freq;
else
dev->freq = 0;
return r; return r;
} }
@ -751,6 +762,7 @@ int rtlsdr_get_tuner_gains(rtlsdr_dev_t *dev, int *gains)
const int fc0013_gains[] = { -63, 71, 191, 197 }; const int fc0013_gains[] = { -63, 71, 191, 197 };
const int fc2580_gains[] = { 0 /* no gain values */ }; const int fc2580_gains[] = { 0 /* no gain values */ };
const int r820t_gains[] = { 0 /* no gain values */ }; const int r820t_gains[] = { 0 /* no gain values */ };
const int unknown_gains[] = { 0 /* no gain values */ };
int *ptr = NULL; int *ptr = NULL;
int len = 0; int len = 0;
@ -775,7 +787,7 @@ int rtlsdr_get_tuner_gains(rtlsdr_dev_t *dev, int *gains)
ptr = (int *)r820t_gains; len = sizeof(r820t_gains); ptr = (int *)r820t_gains; len = sizeof(r820t_gains);
break; break;
default: default:
fprintf(stderr, "Invalid tuner type %d\n", dev->tuner_type); ptr = (int *)unknown_gains; len = sizeof(unknown_gains);
break; break;
} }
@ -923,6 +935,52 @@ int rtlsdr_set_agc_mode(rtlsdr_dev_t *dev, int on)
return rtlsdr_demod_write_reg(dev, 0, 0x19, on ? 0x25 : 0x05, 1); return rtlsdr_demod_write_reg(dev, 0, 0x19, on ? 0x25 : 0x05, 1);
} }
int rtlsdr_set_direct_sampling(rtlsdr_dev_t *dev, int on)
{
int r = 0;
if (!dev)
return -1;
if (on) {
if (dev->tuner && dev->tuner->exit) {
rtlsdr_set_i2c_repeater(dev, 1);
r = dev->tuner->exit(dev);
rtlsdr_set_i2c_repeater(dev, 0);
}
/* disable Zero-IF mode */
r |= rtlsdr_demod_write_reg(dev, 1, 0xb1, 0x1a, 1);
/* disable spectrum inversion */
r |= rtlsdr_demod_write_reg(dev, 1, 0x15, 0x00, 1);
fprintf(stderr, "Enabled direct sampling mode\n");
dev->direct_sampling = 1;
} else {
if (dev->tuner && dev->tuner->init) {
rtlsdr_set_i2c_repeater(dev, 1);
r |= dev->tuner->init(dev);
rtlsdr_set_i2c_repeater(dev, 0);
}
if (dev->tuner_type == RTLSDR_TUNER_R820T) {
r |= rtlsdr_set_if_freq(dev, R820T_IF_FREQ);
/* enable spectrum inversion */
r |= rtlsdr_demod_write_reg(dev, 1, 0x15, 0x01, 1);
} else {
/* Enable Zero-IF mode */
rtlsdr_demod_write_reg(dev, 1, 0xb1, 0x1b, 1);
}
fprintf(stderr, "Disabled direct sampling mode\n");
dev->direct_sampling = 0;
}
return r;
}
static rtlsdr_dongle_t *find_known_device(uint16_t vid, uint16_t pid) static rtlsdr_dongle_t *find_known_device(uint16_t vid, uint16_t pid)
{ {
unsigned int i; unsigned int i;
@ -1137,7 +1195,7 @@ int rtlsdr_open(rtlsdr_dev_t **out_dev, uint32_t index)
/* the R820T uses 3.57 MHz IF for the DVB-T 6 MHz mode, and /* the R820T uses 3.57 MHz IF for the DVB-T 6 MHz mode, and
* 4.57 MHz for the 8 MHz mode */ * 4.57 MHz for the 8 MHz mode */
rtlsdr_set_if_freq(dev, 3570000); rtlsdr_set_if_freq(dev, R820T_IF_FREQ);
/* enable spectrum inversion */ /* enable spectrum inversion */
rtlsdr_demod_write_reg(dev, 1, 0x15, 0x01, 1); rtlsdr_demod_write_reg(dev, 1, 0x15, 0x01, 1);
@ -1169,8 +1227,8 @@ int rtlsdr_open(rtlsdr_dev_t **out_dev, uint32_t index)
found: found:
if (dev->tuner_type == RTLSDR_TUNER_UNKNOWN) { if (dev->tuner_type == RTLSDR_TUNER_UNKNOWN) {
r = -1; fprintf(stderr, "No supported tuner found\n");
goto err; rtlsdr_set_direct_sampling(dev, 1);
} }
dev->tuner = &tuners[dev->tuner_type]; dev->tuner = &tuners[dev->tuner_type];
@ -1204,7 +1262,7 @@ int rtlsdr_close(rtlsdr_dev_t *dev)
while (RTLSDR_INACTIVE != dev->async_status) while (RTLSDR_INACTIVE != dev->async_status)
usleep(10); usleep(10);
rtlsdr_deinit_baseband(dev); rtlsdr_deinit_baseband(dev);
libusb_release_interface(dev->devh, 0); libusb_release_interface(dev->devh, 0);
libusb_close(dev->devh); libusb_close(dev->devh);