Hello Guys,
First of all: I am amazed by your project - many ideas come up in my head what can be done with this tiny cheap SDR.
I have tested rtl_sdr with a linux-vm on my Mac successfully but wanted to run it on my raspberry pi.
Unfortunately and thithout an explainable reason to me the tools detect an E4000 instead of the soldered FC0013 on my stick - but only on the PI.
To fix this issue I have changed the detection order in librtlsdr.c:
diff --git a/src/librtlsdr.c b/src/librtlsdr.c index 3a67b53..cb34f1d 100644 --- a/src/librtlsdr.c +++ b/src/librtlsdr.c @@ -1073,13 +1073,6 @@ int rtlsdr_open(rtlsdr_dev_t **out_dev, uint32_t index) /* Probe tuners */ rtlsdr_set_i2c_repeater(dev, 1);
- reg = rtlsdr_i2c_read_reg(dev, E4K_I2C_ADDR, E4K_CHECK_ADDR); - if (reg == E4K_CHECK_VAL) { - fprintf(stderr, "Found Elonics E4000 tuner\n"); - dev->tuner_type = RTLSDR_TUNER_E4000; - goto found; - } - reg = rtlsdr_i2c_read_reg(dev, FC0013_I2C_ADDR, FC0013_CHECK_ADDR); if (reg == FC0013_CHECK_VAL) { fprintf(stderr, "Found Fitipower FC0013 tuner\n"); @@ -1088,6 +1081,13 @@ int rtlsdr_open(rtlsdr_dev_t **out_dev, uint32_t index) goto found; }
+ reg = rtlsdr_i2c_read_reg(dev, E4K_I2C_ADDR, E4K_CHECK_ADDR); + if (reg == E4K_CHECK_VAL) { + fprintf(stderr, "Found Elonics E4000 tuner\n"); + dev->tuner_type = RTLSDR_TUNER_E4000; + goto found; + } + /* initialise GPIOs */ rtlsdr_set_gpio_output(dev, 5);
After compiling the lib the FC0013 is detected and the sticks works great on my Pi.
Of course this is not a perfect solution and I will figure out later in depth WHY the E4K_CHECK_VAL comes out of the FC0013.
Anybody else who has or had the same problems?
the Hardware used is: Bus 001 Device 004: ID 0ccd:00b3 TerraTec Electronic GmbH NOXON DAB/DAB+ Stick
regards
Christoph
Hi,
On 09.08.2012 14:13, Christoph Gommel wrote:
Unfortunately and thithout an explainable reason to me the tools detect an E4000 instead of the soldered FC0013 on my stick - but only on the PI.
I could reproduce this issue on my raspberry pi and pushed a fix. The I2C reads failed as expected at the E4K address, but due to a uninitialized variable (which unluckily had the value 0x40 - the same as the expected E4K check value) the tuner was mis-detected.
Regards, Steve
Perhaps someone can experiment with slowing down the stream of commands from the ExtIO to the tuner Stick so it remains stable.
After applying ExtIO to WinRAD and 2 different Tuner Sticks with the E4000/RTL2832, the same unwanted behavior is exhibited by both. The unwanted behavior is the Tuner Stick crashing as reported in the ExtIO: ezcap... Log as "While setting frequency: _I2CWriteArray:..." To get the Tuner Stick back, I have to unplug it, quit WinRAD, plug in the Tuner Stick, relaunch WinRAD.
This seems to be a consistent problem, not with the Tuner Stick but with the ExtIO script. While I am not familiar with the ExtIO Script, it seems the Tuner Stick is not able to receive wide or rapid changes in frequency.
Hi All,
The e4000 tuner is flexible in that it allows different gain distributions that optimize it for usage in different environments.
With high gain near the antenna and low gain after the filters one can get a low noise figure and a good dynamic range for close range interference. The bad side is that the early stages can become saturated by signals at large frequency separations. If the user adds a bandpass filter for a narrow frequency range, this mode gives the best performance.
With low gain near the antenna and high gain after the filters one can tolerate stronger signals at large frequency separation at the expense of a lower dynamic range for close spaced signals. This is useful when using the tuner without any filters.
Besides the standard gain distribution which is a compromise I have added two more gain modes in Linrad. The function set_tuner_gain_mode() accepts values from 0 to 3 where 0 and 1 are identical to the original settings. The AGC mode does not work quite ok, it was better some months ago, but it does work with the batch below since it is no longer totally disabled. Always disabling the AGC in the rtl2832 chip may or may not be a good idea.
The noise figures and points of saturation are similar at full gain in all modes. The table shows performance with the tuner set to 144.2 MHz with Linrad set to receive 144.5 MHz. The columns with a frequency show the signal level in dBm at each frequency that can be applied without A/D saturation or significant loss of S/N:
Mode Gain NF 143.8 145.5 154.2 1 42 7.9 -53 -44 -43 2 25 8.3 -56 -44 -20 3 25 7.0 -59 -48 -20
Note what happens for 10 MHz separation. Better performance at wide range leads to worse performance at close range. In mode 2 there is a 3 dB dynamic range loss at close range.
When the attenuator is set for a NF of about 17 dB (10 dB below optimum sensitivity for the desired signal, these data are obtained:
Mode Gain NF 143.8 145.5 154.2 1 24 17 -41 -29 -30 2 10 20 -41 -30 -8 3 0 17 -34 -26 -16
The above was performed applying the pattc below to the library downloaded a couple of days ago. I do not think the changes will affect any other software that uses the library. The set_tuner_gain_mode() function now returns the gain mode or the highest allowed gain mode if the user tries to set a too high one. Before, the function always returned zero so there was no reason to check the return value.
The patch is included below. If the basic principle is accepted for the osmocom library I guess defines should be moved to the header file and the global variable put into the dev structure.
Regards
Leif / SM5BSZ
diff ../rtl-sdr-ref/src/librtlsdr.c src/librtlsdr.c 93a94,102
// Sept 24 2012 SM5BSZ. Gain modes. // Note that these things are used in tuner_e4k.c also. // The routine using them should be moved to tuner_e4k.c extern int e4k_gain_mode; #define E4K_GAIN_MODE_OLD 1 #define E4K_GAIN_MODE_LINEARITY 2 #define E4K_GAIN_MODE_SENSITIVITY 3 #define MAX_E4K_GAIN_MODES 3
127c136,140 < if(e4k_set_lna_gain(&devt->e4k_s, min(300, gain - mixgain * 10)) == -EINVAL) ---
// SM5BSZ Sept24 2012: Use only (the modified) set_lna_gain if the user // asked for linearity or sensitivity. if(e4k_gain_mode <= E4K_GAIN_MODE_OLD) { if(e4k_set_lna_gain(&devt->e4k_s, min(300, gain - mixgain * 10)) == -EINVAL)
129c142 < if(e4k_mixer_gain_set(&devt->e4k_s, mixgain) == -EINVAL) ---
if(e4k_mixer_gain_set(&devt->e4k_s, mixgain) == -EINVAL)
130a144
// SM5BSZ: enhanced gain should affect how the AGC turns down the gain
132c146 < if(enhgain >= 0) ---
if(enhgain >= 0)
136c150,153 < return 0; ---
return 0; }e4k_set_lna_gain(&devt->e4k_s, gain); return 0;
137a155
141a160
785a805,807
// Sept 2012 SM5BSZ: Add standard gains const int e4k_std_gains[] = { -250, -200, -150, -100, -50, 0, 50, 100, 150, 200, 250};
802c824,832 < ptr = (int *)e4k_gains; len = sizeof(e4k_gains); ---
// Sept 2012 SM5BSZ: Use standard gains (5 dB step) if gain is mode above 1. if(e4k_gain_mode < 2) { ptr = (int *)e4k_gains; len = sizeof(e4k_gains); } else { ptr= (int *)e4k_std_gains; len = sizeof(e4k_std_gains); }
879a910,922
// SM5BSZ Oct 17 2012 Reconfigure the rtl if(mode) { /* enable SDR mode, disable DAGC (bit 5) */ rtlsdr_demod_write_reg(dev, 0, 0x19, 0x05, 1); } else { /* enable AGC */ rtlsdr_demod_write_reg(dev, 0, 0x19, 0x25, 1); }
diff ../rtl-sdr-ref/src/tuner_e4k.c src/tuner_e4k.c 41a42,49
// Sept 24 2012 SM5BSZ. Gain modes. // Note that these things are used in librtlsdr.c also. int e4k_gain_mode; #define E4K_GAIN_MODE_OLD 1 #define E4K_GAIN_MODE_LINEARITY 2 #define E4K_GAIN_MODE_SENSITIVITY 3 #define MAX_E4K_GAIN_MODES 3
659a668,671
// SM5BSZ Sept 24 2012: Use all gain controls if gain mode // is above 1 if(e4k_gain_mode <= E4K_GAIN_MODE_OLD) {
666a679,935
} if(e4k_gain_mode == E4K_GAIN_MODE_LINEARITY) { switch (gain) { case -250: e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 0); e4k_mixer_gain_set(e4k, 4); e4k_if_gain_set(e4k, 1, -3); e4k_if_gain_set(e4k, 2, 0); e4k_if_gain_set(e4k, 3, 0); e4k_if_gain_set(e4k, 4, 0); e4k_if_gain_set(e4k, 5, 9); e4k_if_gain_set(e4k, 6, 6); break;
case -200: e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 0); e4k_mixer_gain_set(e4k, 4); e4k_if_gain_set(e4k, 1, -3); e4k_if_gain_set(e4k, 2, 0); e4k_if_gain_set(e4k, 3, 0); e4k_if_gain_set(e4k, 4, 1); e4k_if_gain_set(e4k, 5, 12); e4k_if_gain_set(e4k, 6, 9); break; case -150: e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 0); e4k_mixer_gain_set(e4k, 4); e4k_if_gain_set(e4k, 1, -3); e4k_if_gain_set(e4k, 2, 6); e4k_if_gain_set(e4k, 3, 0); e4k_if_gain_set(e4k, 4, 0); e4k_if_gain_set(e4k, 5, 12); e4k_if_gain_set(e4k, 6, 9); break; case -100: e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 0); e4k_mixer_gain_set(e4k, 12); e4k_if_gain_set(e4k, 1, -3); e4k_if_gain_set(e4k, 2, 3); e4k_if_gain_set(e4k, 3, 0); e4k_if_gain_set(e4k, 4, 1); e4k_if_gain_set(e4k, 5, 12); e4k_if_gain_set(e4k, 6, 9); break; case -50: e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 0); e4k_mixer_gain_set(e4k, 12); e4k_if_gain_set(e4k, 1, -3); e4k_if_gain_set(e4k, 2, 6); e4k_if_gain_set(e4k, 3, 0); e4k_if_gain_set(e4k, 4, 0); e4k_if_gain_set(e4k, 5, 12); e4k_if_gain_set(e4k, 6, 12); break; case 0: e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 4); e4k_mixer_gain_set(e4k, 12); e4k_if_gain_set(e4k, 1, -3); e4k_if_gain_set(e4k, 2, 6); e4k_if_gain_set(e4k, 3, 0); e4k_if_gain_set(e4k, 4, 0); e4k_if_gain_set(e4k, 5, 12); e4k_if_gain_set(e4k, 6, 12); break; case 50: e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 6); e4k_mixer_gain_set(e4k, 12); e4k_if_gain_set(e4k, 1, -3); e4k_if_gain_set(e4k, 2, 6); e4k_if_gain_set(e4k, 3, 0); e4k_if_gain_set(e4k, 4, 0); e4k_if_gain_set(e4k, 5, 12); e4k_if_gain_set(e4k, 6, 12); break; case 100: e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 8); e4k_mixer_gain_set(e4k, 12); e4k_if_gain_set(e4k, 1, -3); e4k_if_gain_set(e4k, 2, 6); e4k_if_gain_set(e4k, 3, 0); e4k_if_gain_set(e4k, 4, 0); e4k_if_gain_set(e4k, 5, 12); e4k_if_gain_set(e4k, 6, 12); break; case 150: e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 10); e4k_mixer_gain_set(e4k, 12); e4k_if_gain_set(e4k, 1, -3); e4k_if_gain_set(e4k, 2, 6); e4k_if_gain_set(e4k, 3, 0); e4k_if_gain_set(e4k, 4, 0); e4k_if_gain_set(e4k, 5, 12); e4k_if_gain_set(e4k, 6, 12); break; case 200: e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 12); e4k_mixer_gain_set(e4k, 12); e4k_if_gain_set(e4k, 1, -3); e4k_if_gain_set(e4k, 2, 6); e4k_if_gain_set(e4k, 3, 0); e4k_if_gain_set(e4k, 4, 0); e4k_if_gain_set(e4k, 5, 12); e4k_if_gain_set(e4k, 6, 12); break; case 250: e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 14); e4k_mixer_gain_set(e4k, 12); e4k_if_gain_set(e4k, 1, -3); e4k_if_gain_set(e4k, 2, 6); e4k_if_gain_set(e4k, 3, 0); e4k_if_gain_set(e4k, 4, 0); e4k_if_gain_set(e4k, 5, 12); e4k_if_gain_set(e4k, 6, 12); break; }} if(e4k_gain_mode == E4K_GAIN_MODE_SENSITIVITY) { switch (gain) { case -250: e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 6); e4k_mixer_gain_set(e4k, 4); e4k_if_gain_set(e4k, 1, -3); e4k_if_gain_set(e4k, 2, 0); e4k_if_gain_set(e4k, 3, 0); e4k_if_gain_set(e4k, 4, 1); e4k_if_gain_set(e4k, 5, 6); e4k_if_gain_set(e4k, 6, 3); break;
case -200: e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 8); e4k_mixer_gain_set(e4k, 4); e4k_if_gain_set(e4k, 1, -3); e4k_if_gain_set(e4k, 2, 0); e4k_if_gain_set(e4k, 3, 0); e4k_if_gain_set(e4k, 4, 1); e4k_if_gain_set(e4k, 5, 6); e4k_if_gain_set(e4k, 6, 3); break; case -150: e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 10); e4k_mixer_gain_set(e4k, 4); e4k_if_gain_set(e4k, 1, -3); e4k_if_gain_set(e4k, 2, 0); e4k_if_gain_set(e4k, 3, 0); e4k_if_gain_set(e4k, 4, 1); e4k_if_gain_set(e4k, 5, 6); e4k_if_gain_set(e4k, 6, 3); break; case -100: e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 12); e4k_mixer_gain_set(e4k, 4); e4k_if_gain_set(e4k, 1, -3); e4k_if_gain_set(e4k, 2, 0); e4k_if_gain_set(e4k, 3, 0); e4k_if_gain_set(e4k, 4, 1); e4k_if_gain_set(e4k, 5, 6); e4k_if_gain_set(e4k, 6, 3); break; case -50: e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 14); e4k_mixer_gain_set(e4k, 4); e4k_if_gain_set(e4k, 1, -3); e4k_if_gain_set(e4k, 2, 0); e4k_if_gain_set(e4k, 3, 0); e4k_if_gain_set(e4k, 4, 1); e4k_if_gain_set(e4k, 5, 6); e4k_if_gain_set(e4k, 6, 3); break; case 0: e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 14); e4k_mixer_gain_set(e4k, 12); e4k_if_gain_set(e4k, 1, -3); e4k_if_gain_set(e4k, 2, 0); e4k_if_gain_set(e4k, 3, 0); e4k_if_gain_set(e4k, 4, 2); e4k_if_gain_set(e4k, 5, 3); e4k_if_gain_set(e4k, 6, 3); break; case 50: e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 14); e4k_mixer_gain_set(e4k, 12); e4k_if_gain_set(e4k, 1, -3); e4k_if_gain_set(e4k, 2, 3); e4k_if_gain_set(e4k, 3, 0); e4k_if_gain_set(e4k, 4, 1); e4k_if_gain_set(e4k, 5, 6); e4k_if_gain_set(e4k, 6, 3); break; case 100: e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 14); e4k_mixer_gain_set(e4k, 12); e4k_if_gain_set(e4k, 1, 6); e4k_if_gain_set(e4k, 2, 0); e4k_if_gain_set(e4k, 3, 0); e4k_if_gain_set(e4k, 4, 0); e4k_if_gain_set(e4k, 5, 6); e4k_if_gain_set(e4k, 6, 3); break; case 150: e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 14); e4k_mixer_gain_set(e4k, 12); e4k_if_gain_set(e4k, 1, 6); e4k_if_gain_set(e4k, 2, 0); e4k_if_gain_set(e4k, 3, 0); e4k_if_gain_set(e4k, 4, 2); e4k_if_gain_set(e4k, 5, 9); e4k_if_gain_set(e4k, 6, 3); break; break; case 200: fprintf(stderr,"\nCASE 200"); e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 14); e4k_mixer_gain_set(e4k, 12); e4k_if_gain_set(e4k, 1, 6); e4k_if_gain_set(e4k, 2, 3); e4k_if_gain_set(e4k, 3, 0); e4k_if_gain_set(e4k, 4, 1); e4k_if_gain_set(e4k, 5, 9); e4k_if_gain_set(e4k, 6, 6); break; case 250: e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 14); e4k_mixer_gain_set(e4k, 12); e4k_if_gain_set(e4k, 1, 6); e4k_if_gain_set(e4k, 2, 6); e4k_if_gain_set(e4k, 3, 0); e4k_if_gain_set(e4k, 4, 0); e4k_if_gain_set(e4k, 5, 9); e4k_if_gain_set(e4k, 6, 9); break; }} return gain;
694a964,969
// Sept 24 2012 SM5BSZ. Add a flag for more gain modes and return it // so we know the library has this feature. e4k_gain_mode=manual; if(e4k_gain_mode > MAX_E4K_GAIN_MODES)e4k_gain_mode=MAX_E4K_GAIN_MODES; return e4k_gain_mode;
695a971
e4k_gain_mode=0;
701a978
Hi,
Thanks for the tests and reporting.
Some comments purely about the patch form and not the functionality itself (I'll leave that for the rtl-sdr maintainer to decide):
// SM5BSZ Sept24 2012: Use only (the modified) set_lna_gain if the user // asked for linearity or sensitivity.
Don't put comment logs in the code ... if you want to document what the code does it's fine, but the commit message is there for the date/name/change recording.
Also, I think /* */ rather than // is the comment style in that project.
switch (gain) { case -250: e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 0); e4k_mixer_gain_set(e4k, 4); e4k_if_gain_set(e4k, 1, -3); e4k_if_gain_set(e4k, 2, 0); e4k_if_gain_set(e4k, 3, 0); e4k_if_gain_set(e4k, 4, 0); e4k_if_gain_set(e4k, 5, 9); e4k_if_gain_set(e4k, 6, 6); break;
That giant swith is just plain aweful. Either find a formula, or use tables.
Cheers,
Sylvain