Thursday, March 27, 2014

First VHDL-attempts to remove DC from BladeRF-outputs

First VHDL-attempts to remove DC from BladeRF-outputs


Well, subject says it all.

Last few weeks I did study VHDL a lot and came up with the following change of the lms6002d.vhdl piece:

library ieee ;
    use ieee.std_logic_1164.all ;
    use ieee.numeric_std.all ;

-- modified to remove DC-component
-- March-2014 KdG
           
entity lms6002d is
  port (
    -- RX Controls
    rx_clock            :   in      std_logic ;
    rx_reset            :   in      std_logic ;
    rx_enable           :   in      std_logic ;

    -- RX Interface with LMS6002D
    rx_lms_data         :   in      signed(11 downto 0) ;
    rx_lms_iq_sel       :   in      std_logic ;
    rx_lms_enable       :   buffer  std_logic ;

    -- RX Sample Interface
    rx_sample_i         :   buffer  signed(11 downto 0) ;
    rx_sample_q         :   buffer  signed(11 downto 0) ;
    rx_sample_valid     :   buffer  std_logic ;

    -- TX Controls
    tx_clock            :   in      std_logic ;
    tx_reset            :   in      std_logic ;
    tx_enable           :   in      std_logic ;

    -- TX Sample Interface
    tx_sample_i         :   in      signed(11 downto 0) ;
    tx_sample_q         :   in      signed(11 downto 0) ;
    tx_sample_valid     :   in      std_logic ;

    -- TX Interface to the LMS6002D
    tx_lms_data         :   buffer  signed(11 downto 0) ;
    tx_lms_iq_sel       :   buffer  std_logic ;
    tx_lms_enable       :   buffer  std_logic
  ) ;
end entity ;

architecture arch of lms6002d is

signal rx_average_i, rx_average_q : signed(11 downto 0);
signal accum_i : signed(18 downto 0) ;
signal accum_q : signed(18 downto 0) ;

begin

    -------------
    -- Receive --
    -------------
    rx_sample : process(rx_clock, rx_reset)
    begin
        if( rx_reset = '1' ) then
            rx_sample_i <= (others =>'0') ;
            rx_sample_q <= (others =>'0') ;
                     rx_average_i <= (others => '0'); -- KdG
                     rx_average_q <= (others => '0');     -- KdG              
            rx_sample_valid <= '0' ;
            rx_lms_enable <= '0' ;
        elsif( rising_edge( rx_clock ) ) then
            if( rx_lms_iq_sel = '0' ) then
                rx_lms_enable <= rx_enable ;
            end if ;

            rx_sample_valid <= '0' ;
            if( rx_lms_enable = '1' ) then
                if(rx_lms_iq_sel = '1' ) then
                    -- rx_sample_i <= rx_lms_data;
                               rx_sample_i <= rx_lms_data - rx_average_i; -- KdG
                else
                    -- rx_sample_q <= rx_lms_data;
                                 rx_sample_q <= rx_lms_data - rx_average_q ; -- KdG
                    rx_sample_valid <= '1' ;
                end if ;
            end if ;
        end if ;
    end process ;

    --------------
    -- Transmit --
    --------------
    tx_sample : process(tx_clock, tx_reset)
        variable tx_q_reg   :   signed(11 downto 0) ;
    begin
        if( tx_reset = '1' ) then
            tx_lms_data <= (others =>'0') ;
            tx_lms_iq_sel <= '0' ;
            tx_lms_enable <= '0' ;
            tx_q_reg := (others =>'0') ;
        elsif( rising_edge( tx_clock ) ) then
            if( tx_lms_iq_sel = '0' ) then
                tx_lms_enable <= tx_enable ;
            end if ;

            if( tx_sample_valid = '1' ) then
                tx_lms_data <= tx_sample_i ;
                tx_q_reg := tx_sample_q ;
                tx_lms_iq_sel <= '0' ;
            elsif( tx_lms_enable = '1' ) then
                tx_lms_data <= tx_q_reg ;
                tx_lms_iq_sel <= '1' ;
            else
                tx_lms_data <= (others =>'0') ;
                tx_lms_iq_sel <= '0' ;
            end if ;
        end if ;
    end process ;
      
      average: process(rx_sample_valid)
          variable count : integer ;
    begin
          if( rising_edge( rx_sample_valid ) ) then
                if(rx_lms_iq_sel = '1' ) then
                       accum_i <= accum_i + rx_lms_data;
                     else
                    accum_q <= accum_q + rx_lms_data;
                     end if;  
                count := count + 1;
                     if ( count > 128 ) then
                         count := 0;
                           rx_average_i(11 downto 0) <= accum_i (18 downto 7);
                           rx_average_q(11 downto 0) <= accum_q (18 downto 7);
                           accum_i <= (others =>'0') ;
                           accum_q <= (others =>'0') ;
                     end if;
             end if;
      end process average;
      
end architecture ;

I declared some signals and calculate the average in a separate process.

I get some errors from Quartus:

Error (10028): Can't resolve multiple constant drivers for net "rx_average_i[11]" at lms6002d.vhd(114)
Error (10029): Constant driver at lms6002d.vhd(53)
Error (10028): Can't resolve multiple constant drivers for net "rx_average_i[10]" at lms6002d.vhd(114)
Error (10028): Can't resolve multiple constant drivers for net "rx_average_i[9]" at lms6002d.vhd(114)
Error (10028): Can't resolve multiple constant drivers for net "rx_average_i[8]" at lms6002d.vhd(114)
Error (10028): Can't resolve multiple constant drivers for net "rx_average_i[7]" at lms6002d.vhd(114)
Error (10028): Can't resolve multiple constant drivers for net "rx_average_i[6]" at lms6002d.vhd(114)
Error (10028): Can't resolve multiple constant drivers for net "rx_average_i[5]" at lms6002d.vhd(114)
Error (10028): Can't resolve multiple constant drivers for net "rx_average_i[4]" at lms6002d.vhd(114)
Error (10028): Can't resolve multiple constant drivers for net "rx_average_i[3]" at lms6002d.vhd(114)
Error (10028): Can't resolve multiple constant drivers for net "rx_average_i[2]" at lms6002d.vhd(114)
Error (10028): Can't resolve multiple constant drivers for net "rx_average_i[1]" at lms6002d.vhd(114)
Error (10028): Can't resolve multiple constant drivers for net "rx_average_i[0]" at lms6002d.vhd(114)
Error (10028): Can't resolve multiple constant drivers for net "rx_average_q[11]" at lms6002d.vhd(114)
Error (10028): Can't resolve multiple constant drivers for net "rx_average_q[10]" at lms6002d.vhd(114)
Error (10028): Can't resolve multiple constant drivers for net "rx_average_q[9]" at lms6002d.vhd(114)
Error (10028): Can't resolve multiple constant drivers for net "rx_average_q[8]" at lms6002d.vhd(114)
Error (10028): Can't resolve multiple constant drivers for net "rx_average_q[7]" at lms6002d.vhd(114)
Error (10028): Can't resolve multiple constant drivers for net "rx_average_q[6]" at lms6002d.vhd(114)

Thusfar I do not understand this error-messages.

Because it was a long time ago already that I posted something on my blog, this is a kind of “I am still alive message”.

I will dig into this problem, but I would LOVE to get some hints from VHDL-gurus!

Next time I hope to come up with a working VHDl-solution.

1 comment:

  1. HDL's only allow you to drive a signal from a single process so it understands from a very narrow context what the next value should be.

    The errors are just saying that you assign the signal 'rx_average_i' in two separate processes - one in the 'rx_sample' process, and the other in the 'average' process. You can use 'rx_average_i' in any process, but only assign to it in a single process.

    Also, your 'count' variable in the 'average' process is just an integer. By default, VHDL will make all integers 32 bits. You should constrain your integers if you know you won't be using them. To do that you type 'variable count : integer range 0 to 127;'. Also note that integer is signed, natural is 0 and higher, and positive is 1 and higher. They can all be compared to each other, but the extra limits may be helpful for you.

    In general, VHDL is a very strict language. You will get a lot of compilation errors before things will attempt to even simulate. Speaking of which, I highly recommend you get ModelSim from Altera and simulate your algorithm you plan on using. It's much, much easier in a simulation environment to verify it is doing what you expect.

    Good luck!

    ReplyDelete