Hi All,

I created a patch which adds a shift_iq setting to the usrp2.
This can shift the output of dsp_core_rx by 0 to 3 bits.
(= Multiply by 1, 2, 4 or 8)

It does proper rounding and clipping.

With the shift_iq setting in combination with the already existing
scale_iq you can optimize the dynamic range so that the samples going to
the PC always use the full 16 bit [-32768 to + 32767]

In practice this means a dynamic range increase of 6 dB or more.

Of course, if you set the shift to high you will get clipping.

The patch changes the fpga verilog, fpga firmware, usrp2, and gr-usrp
sources.


I did several icarus verilog simulations which came out OK.

I also created a python testscript which uses the actual usrp2. It
generates a 200 kHz signal on TX and receives it with RX.
(you need to loopback TX to RX using basicRX/TX or LFTX/RX boards.)
With the GUI you can set scale_iq and shift_iq.

I generated a new u2_rev3.bin and txrx.bin which seem to work fine.
Note that this firmware is based on my current git checkout.
So if you want to have this feature with the lastest code, you have to
apply my patch to the latest tree and generate new firmware yourself.

I created this patch on request, so it would be great if it were added
to the official tree. (So the default firmware can be used in the future
to have this function)

Patch and a testscript at:
http://www.olifantasia.com/projects/gnuradio/mdvh/usrp2_add_shift_iq/


Martin Dudok van Heel

diff --git a/gr-usrp2/src/usrp2.i b/gr-usrp2/src/usrp2.i
index 3197402..e960372 100644
--- a/gr-usrp2/src/usrp2.i
+++ b/gr-usrp2/src/usrp2.i
@@ -72,6 +72,7 @@ public:
   bool set_center_freq(double frequency, usrp2::tune_result *r);
   bool set_decim(int decimation_factor);
   bool set_scale_iq(int scale_i, int scale_q);
+  bool set_shift_iq(int shift_q, int shift_i);
   int decim();
   %rename(_real_adc_rate) adc_rate;
   bool adc_rate(long *rate);
diff --git a/gr-usrp2/src/usrp2_source_base.cc b/gr-usrp2/src/usrp2_source_base.cc
index 0ad7008..12fcd88 100644
--- a/gr-usrp2/src/usrp2_source_base.cc
+++ b/gr-usrp2/src/usrp2_source_base.cc
@@ -76,6 +76,12 @@ usrp2_source_base::set_scale_iq(int scale_i, int scale_q)
   return d_u2->set_rx_scale_iq(scale_i, scale_q);
 }
 
+bool 
+usrp2_source_base::set_shift_iq(int shift_q, int shift_i)
+{
+  return d_u2->set_rx_shift_iq(shift_q, shift_i);
+}
+
 int
 usrp2_source_base::decim()
 {
diff --git a/gr-usrp2/src/usrp2_source_base.h b/gr-usrp2/src/usrp2_source_base.h
index 2e2d51f..d318ad9 100644
--- a/gr-usrp2/src/usrp2_source_base.h
+++ b/gr-usrp2/src/usrp2_source_base.h
@@ -61,11 +61,24 @@ public:
   bool set_decim(int decimation_factor);
 
   /*!
-   * \brief Set receive IQ scale factors
+   * \brief Set receive IQ input scale factors
    */
   bool set_scale_iq(int scale_i, int scale_q);
 
   /*!
+   * \brief Set receive IQ output shift
+   * shift 0 (default) scales by 1
+   * shift 1 scales by 2
+   * shift 2 scales by 4
+   * shift 3 scales by 8
+   * Note that with a shift >0 overflow and clipping can occur.
+   * This can be resolved by reducing scale_iq to below the default 1024.
+   * By using a shift of 1 or 2 and reducing scale_iq,
+   * the full 16 bit output range (-32768 to +32767) can be used
+   */
+  bool set_shift_iq(int shift_q, int shift_i);
+
+  /*!
    * \brief Get receive decimation rate
    */
   int decim();
diff --git a/usrp2/firmware/apps/app_common_v2.c b/usrp2/firmware/apps/app_common_v2.c
index 036d0ba..54bef3f 100644
--- a/usrp2/firmware/apps/app_common_v2.c
+++ b/usrp2/firmware/apps/app_common_v2.c
@@ -272,6 +272,9 @@ config_rx_v2_cmd(const op_config_rx_v2_t *p,
   if (p->valid & CFGV_SCALE_IQ){
     dsp_rx_regs->scale_iq = p->scale_iq;
   }
+  if (p->valid & CFGV_SHIFT_IQ){
+    dsp_rx_regs->shift_iq = p->shift_iq;
+  }
 
   // Build reply subpacket
 
diff --git a/usrp2/firmware/include/usrp2_eth_packet.h b/usrp2/firmware/include/usrp2_eth_packet.h
index 63d4b3a..b1db5ac 100644
--- a/usrp2/firmware/include/usrp2_eth_packet.h
+++ b/usrp2/firmware/include/usrp2_eth_packet.h
@@ -283,6 +283,7 @@ typedef struct {
   uint32_t	freq_lo;	// low  32-bits of 64-bit fxpt_freq (Q44.20)
   uint32_t	decim;		// desired decimation factor (NOT -1)
   uint32_t	scale_iq;	// (scale_i << 16) | scale_q [16.0 format]
+  uint32_t	shift_iq;	// (shift_i <<  4) | shift_q  [0, 1, 2 or 3]
 } _AL4 op_config_rx_v2_t;
 
 // bitmask for "valid" field.  If the bit is set, there's
@@ -292,7 +293,7 @@ typedef struct {
 #define	CFGV_FREQ		0x0002	// target_freq field is valid
 #define	CFGV_INTERP_DECIM	0x0004	// interp or decim is valid
 #define	CFGV_SCALE_IQ		0x0008	// scale_iq is valid
-
+#define	CFGV_SHIFT_IQ		0x0010	// shift_iq is valid
 /*!
  * \brief Reply to receiver configuration
  */
diff --git a/usrp2/firmware/lib/memory_map.h b/usrp2/firmware/lib/memory_map.h
index 0d0cf04..14b5f7b 100644
--- a/usrp2/firmware/lib/memory_map.h
+++ b/usrp2/firmware/lib/memory_map.h
@@ -500,6 +500,32 @@ typedef struct {
    */
   volatile uint32_t gpio_stream_enable;
 
+  /*!
+   * \brief arithmic shift rx samples 0, 1, 2 or 3 bits to the left
+   * This can increasy dynamic range
+   * Every shift left corresponds to 6 dB
+   * Default is shift_iq is {0,0} (and scale_iq={1024,1024])
+   * With optimal combination of shift_iq and scale_iq the output samples can use the entire 16 bit range of -32768 to 32767.
+   * Max output range is shift=2, scale_iq around {578,578}
+   * shifts >0 will experience overflow and clipping if you don't scale_down scale_iq below the default 1024
+   * At the moment the maximum shift is 3, but this may be increased to 15 in the future.
+   * <pre>
+   * shift_iq value:
+   *
+   *    3                   2                   1                       
+   *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+   * +-------+-------+-------+-------+-------+-------+-------+-------+
+   * |                                               | shiftQ| shiftI|
+   * +-------+-------+-------+-------+-------+-------+-------+-------+
+   *
+   * Each 4-bit shiftI field is either 0000 (shift 0), 0001 (shift 1), 0010 (shift 2) or 0011 (shift 3)
+   * Each 4-bit shiftQ field is either 0000 (shift 0), 0001 (shift 1), 0010 (shift 2) or 0011 (shift 3)
+   *
+   * The default value is 0
+   * </pre>
+   */
+  volatile uint32_t	shift_iq;	// {shift_q,shift_i}
+
 } dsp_rx_regs_t;
   
 #define dsp_rx_regs ((dsp_rx_regs_t *) DSP_RX_BASE)
diff --git a/usrp2/fpga/sdr_lib/dsp_core_rx.v b/usrp2/fpga/sdr_lib/dsp_core_rx.v
index af4f0b9..ece6fc5 100644
--- a/usrp2/fpga/sdr_lib/dsp_core_rx.v
+++ b/usrp2/fpga/sdr_lib/dsp_core_rx.v
@@ -63,6 +63,12 @@ module dsp_core_rx
      (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
       .in(set_data),.out(gpio_ena),.changed());
 
+   wire [3:0] shift_i;
+   wire [3:0] shift_q;
+   setting_reg #(.my_addr(`DSP_CORE_RX_BASE+10)) sr_10
+     (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+      .in(set_data),.out({shift_q,shift_i}),.changed());
+
    // The TVRX connects to what is called adc_b, thus A and B are
    // swapped throughout the design.
    //
@@ -155,8 +161,11 @@ module dsp_core_rx
      (.clk(clk),.rst(rst),.bypass(~enable_hb2),.run(run),.cpi(cpi_hb),
       .stb_in(strobe_hb1),.data_in(q_hb1),.stb_out(),.data_out(q_hb2));
 
-   round #(.bits_in(18),.bits_out(16)) round_iout (.in(i_hb2),.out(i_out));
-   round #(.bits_in(18),.bits_out(16)) round_qout (.in(q_hb2),.out(q_out));
+   //round #(.bits_in(18),.bits_out(16)) round_iout (.in(i_hb2),.out(i_out));
+   //round #(.bits_in(18),.bits_out(16)) round_qout (.in(q_hb2),.out(q_out));
+
+   clip_and_round_configurable #(.bits_in(18),.bits_out(16)) round_iout (.in(i_hb2),.out(i_out),.clip_bits(shift_i[1:0]));
+   clip_and_round_configurable #(.bits_in(18),.bits_out(16)) round_qout (.in(q_hb2),.out(q_out),.clip_bits(shift_q[1:0]));
 
    // Streaming GPIO
    //
diff --git a/usrp2/fpga/top/u2_rev3/Makefile b/usrp2/fpga/top/u2_rev3/Makefile
index 4358d7c..c04ef15 100644
--- a/usrp2/fpga/top/u2_rev3/Makefile
+++ b/usrp2/fpga/top/u2_rev3/Makefile
@@ -159,6 +159,8 @@ sdr_lib/dsp_core_tx.v \
 sdr_lib/hb_dec.v \
 sdr_lib/hb_interp.v \
 sdr_lib/round.v \
+sdr_lib/clip_and_round.v \
+sdr_lib/clip_and_round_configurable.v \
 sdr_lib/round_reg.v \
 sdr_lib/rx_control.v \
 sdr_lib/rx_dcoffset.v \
diff --git a/usrp2/host/include/usrp2/usrp2.h b/usrp2/host/include/usrp2/usrp2.h
index 2d9e2a4..9e45934 100644
--- a/usrp2/host/include/usrp2/usrp2.h
+++ b/usrp2/host/include/usrp2/usrp2.h
@@ -159,6 +159,13 @@ namespace usrp2 {
     bool set_rx_scale_iq(int scale_i, int scale_q);
 
     /*!
+     * Set receiver IQ left shift (1 shift left is a scaling by 2)
+     * Note that overflow and clipping can occur if shift >0 and scale_iq is the default 1024
+     * With optimum scaling and shifting the entire 16 bit output dynamic range can be used
+     */
+    bool set_rx_shift_iq(int shift_i, int shift_q);
+
+    /*!
      * Set received sample format
      *
      *    domain: complex or real
diff --git a/usrp2/host/lib/usrp2.cc b/usrp2/host/lib/usrp2.cc
index 801a436..6e7cf70 100644
--- a/usrp2/host/lib/usrp2.cc
+++ b/usrp2/host/lib/usrp2.cc
@@ -236,6 +236,12 @@ namespace usrp2 {
   }
 
   bool
+  usrp2::set_rx_shift_iq(int shift_i, int shift_q)
+  {
+    return d_impl->set_rx_shift_iq(shift_i, shift_q);
+  }
+
+  bool
   usrp2::start_rx_streaming(unsigned int channel, unsigned int items_per_frame)
   {
     return d_impl->start_rx_streaming(channel, items_per_frame);
diff --git a/usrp2/host/lib/usrp2_impl.cc b/usrp2/host/lib/usrp2_impl.cc
index b19c6ec..b7bc5f8 100644
--- a/usrp2/host/lib/usrp2_impl.cc
+++ b/usrp2/host/lib/usrp2_impl.cc
@@ -46,6 +46,7 @@
 #endif
 
 static const int DEFAULT_RX_SCALE = 1024;
+static const int DEFAULT_RX_SHIFT = 0;
 
 namespace usrp2 {
 
@@ -203,6 +204,10 @@ namespace usrp2 {
     // set workable defaults for scaling
     if (!set_rx_scale_iq(DEFAULT_RX_SCALE, DEFAULT_RX_SCALE))
       std::cerr << "usrp2::ctor set_rx_scale_iq failed\n";
+
+    // set workable defaults for schift
+    if (!set_rx_shift_iq(DEFAULT_RX_SHIFT, DEFAULT_RX_SHIFT))
+      std::cerr << "usrp2::ctor set_rx_shift_iq failed\n";
   }
 
   usrp2::impl::~impl()
@@ -614,6 +619,24 @@ namespace usrp2 {
   }
 
   bool
+  usrp2::impl::set_rx_shift_iq(int shift_i, int shift_q)
+  {
+    op_config_rx_v2_cmd cmd;
+    op_config_rx_reply_v2_t reply;
+
+    init_config_rx_v2_cmd(&cmd);
+    cmd.op.valid = htons(CFGV_SHIFT_IQ);
+    cmd.op.shift_iq = htonl(((shift_i & 0x3) << 4) | (shift_q & 0x3));
+
+    pending_reply p(cmd.op.rid, &reply, sizeof(reply));
+    if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+      return false;
+
+    bool success = (ntohx(reply.ok) == 1);
+    return success;
+  }
+
+  bool
   usrp2::impl::start_rx_streaming(unsigned int channel, unsigned int items_per_frame)
   {
     if (channel > MAX_CHAN) {
@@ -814,6 +837,7 @@ namespace usrp2 {
       success = transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
       success = success && (ntohx(reply.ok) == 1);
       d_channel_rings[channel].reset();
+      d_rx_seqno=-1;
       //fprintf(stderr, "usrp2::stop_rx_streaming:  success = %d\n", success);
       return success;
     }
diff --git a/usrp2/host/lib/usrp2_impl.h b/usrp2/host/lib/usrp2_impl.h
index d78a00d..782dbcf 100644
--- a/usrp2/host/lib/usrp2_impl.h
+++ b/usrp2/host/lib/usrp2_impl.h
@@ -137,6 +137,7 @@ namespace usrp2 {
     bool set_rx_decim(int decimation_factor);
     int rx_decim() { return d_rx_decim; }
     bool set_rx_scale_iq(int scale_i, int scale_q);
+    bool set_rx_shift_iq(int shift_i, int shift_q);
     bool set_gpio_ddr(int bank, uint16_t value, uint16_t mask);
     bool set_gpio_sels(int bank, std::string src);
     bool enable_gpio_streaming(int bank, int enable);
diff -urN a/usrp2/fpga/sdr_lib/clip_and_round_configurable.v b/usrp2/fpga/sdr_lib/clip_and_round_configurable.v
--- a/usrp2/fpga/sdr_lib/clip_and_round_configurable.v	1970-01-01 01:00:00.000000000 +0100
+++ b/usrp2/fpga/sdr_lib/clip_and_round_configurable.v	2010-07-08 20:03:59.000000000 +0200
@@ -0,0 +1,116 @@
+// -*- verilog -*-
+//
+//  USRP - Universal Software Radio Peripheral
+//
+//  Copyright (C) 2010 Matt Ettus, Martin Dudok van Heel
+//
+//  This program is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin Street, Boston, MA  02110-1301  USA
+//
+
+// Clipping "macro", keeps the bottom bits, clips out the requested amount of bits (left shift) and rounds
+//
+// clip_bits is a 3 bit input, not a parameter,
+// so this can be dynamically configured.
+// clip_bits can be set to 0, 1, 2, or 3
+// Note: Due to the use of arithmic shift, only works with tools which understand verilog 2001
+// This could be resolved by coding out all 4 shift cases
+
+module clip_and_round_configurable
+  #(parameter bits_in=0,
+    parameter bits_out=0)
+    (input [bits_in-1:0] in,
+     output [bits_out-1:0] out,
+     input [1:0] clip_bits);
+
+   wire [bits_out-1:0] clip3;
+   wire [bits_out-1:0] clip2;
+   wire [bits_out-1:0] clip1;
+   wire [bits_out-1:0] clip0; 
+
+   clip #(.bits_in(bits_in+1),.bits_out(bits_out)) round_3 (.in({in,1'b0}),.out(clip3));
+   clip #(.bits_in(bits_in),.bits_out(bits_out)) round_2 (.in({in}),.out(clip2));
+   clip_and_round #(.bits_in(bits_in),.bits_out(bits_out),.clip_bits(1)) round_1 (.in(in),.out(clip1));
+   round #(.bits_in(bits_in),.bits_out(bits_out)) round_0 (.in(in),.out(clip0));
+
+   assign out=
+    (clip_bits==3'd3)? clip3:
+    (clip_bits==3'd2)? clip2:
+    (clip_bits==3'd1)? clip1:
+                       clip0; //default case, no clipping     
+
+/*
+   parameter max_clip_bits=3;//must be 3, used as a constant here
+
+   wire [bits_out-1:0] 	   rounded;
+
+   //   rounded0 = in[bits_in-1:bits_in-bits_out] + (in[bits_in-1] & |in[bits_in-bits_out-1:0]);
+   //   rounded1 = in[bits_in-1-1:bits_in-1-bits_out] + (in[bits_in-1-1] & |in[bits_in-1-bits_out-1:0]);
+   //   rounded2 = in[bits_in-1-2:bits_in-2-bits_out] + (in[bits_in-2-1] & |in[bits_in-2-bits_out-1:0]);
+   //   rounded3 = in[bits_in-1-3:bits_in-3-bits_out] + (in[bits_in-3-1] & |in[bits_in-3-bits_out-1:0]);
+
+
+   wire [max_clip_bits-1:0] mask = (clip_bits==2'd0)?3'b000:
+                                  (clip_bits==2'd1)?3'b100:
+                                  (clip_bits==2'd2)?3'b110:
+                                                    3'b111;
+
+
+   //Note, uses arithmic shift, only available in verilog 2001
+   wire [bits_in-1:0] tmp1  = $signed(in) >>> clip_bits;
+   wire [bits_out-1:0] tmp2 = tmp1[bits_out-1:0];
+   wire [bits_in-1:0] tmp3 = in<<clip_bits;
+   wire tmp4               = tmp3[bits_in-1];
+   //assign rounded = {$signed(in) >>> clip_bits}[bits_out-1:0] +
+   //               {in<<clip_bits}[bits_in-1] & | (
+   assign rounded = tmp2 +
+               tmp4 & | (
+               (clip_bits==2'd0)?in[bits_in - 0 - bits_out-1:0]:
+               (clip_bits==2'd1)?in[bits_in - 1 - bits_out-1:0]:
+               (clip_bits==2'd2)?in[bits_in - 2 - bits_out-1:0]:
+                                 in[bits_in - 3 - bits_out-1:0]  )  ;
+   
+
+   assign rounded = tmp2 +
+               tmp4 & | (in[bits_in - 0 - bits_out-1:0] & (~mask)
+
+//parameter N = 4; 
+//genvar i;
+//
+//  generate for ( i = 0; i <= N-1; i = i+1 )
+//    begin: inst
+//      sum sum_i ( .in1(a[8*i+7:i*8]),
+//                  .in2(b[8*i+7:i*8]),
+//                  .out(out[8*i+7:i*8]) );
+//    end
+//  endgenerate 
+
+   // clip_bits==0 => mask=000
+   // clip_bits==1 => mask=100
+   // clip_bits==2 => mask=110
+   // clip_bits==3 => mask=111
+
+
+
+// overflow0=0
+// overflow1=(in[bits_in-1] | in[bits_in-2] ) &  ~ (in[bits_in-1] & in[bits_in-2])
+// overflow2=(in[bits_in-1] | in[bits_in-2] | in[bits_in-3] ) & ~(in[bits_in-1] & in[bits_in-2] & in[bits_in-3])
+
+   wire 		   overflow = | (in[bits_in-1:bits_in-max_clip_bits-1] & mask) & ~(&(in[bits_in-1:bits_in-max_clip_bits-1] | (~mask)));
+   
+   assign 		   out = overflow ? 
+			   (in[bits_in-1] ? {1'b1,{(bits_out-1){1'b0}}} : {1'b0,{(bits_out-1){1'b1}}}) :
+			   rounded;
+ */  
+endmodule // clip_and_round_configurable
_______________________________________________
Patch-gnuradio mailing list
Patch-gnuradio@gnu.org
http://lists.gnu.org/mailman/listinfo/patch-gnuradio

Reply via email to