mirror of
https://github.com/Nuand/bladeRF-wiphy.git
synced 2024-12-20 22:23:48 +00:00
222 lines
7.1 KiB
VHDL
222 lines
7.1 KiB
VHDL
|
-- This file is part of bladeRF-wiphy.
|
||
|
--
|
||
|
-- Copyright (C) 2020 Nuand, LLC.
|
||
|
--
|
||
|
-- 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, Fifth Floor, Boston, MA 02110-1301 USA.
|
||
|
|
||
|
library ieee ;
|
||
|
use ieee.std_logic_1164.all ;
|
||
|
use ieee.numeric_std.all ;
|
||
|
use ieee.math_real.all ;
|
||
|
|
||
|
entity wlan_agc is
|
||
|
port (
|
||
|
-- 40MHz clock and async asserted, sync deasserted reset
|
||
|
clock : in std_logic ;
|
||
|
reset : in std_logic ;
|
||
|
|
||
|
agc_hold_req : in std_logic ;
|
||
|
|
||
|
gain_inc_req : out std_logic ;
|
||
|
gain_dec_req : out std_logic ;
|
||
|
gain_rst_req : out std_logic ;
|
||
|
gain_ack : in std_logic ;
|
||
|
gain_nack : in std_logic ;
|
||
|
gain_max : in std_logic ;
|
||
|
|
||
|
rst_gains : out std_logic ;
|
||
|
burst : out std_logic ;
|
||
|
|
||
|
sample_i : in signed(15 downto 0 ) ;
|
||
|
sample_q : in signed(15 downto 0 ) ;
|
||
|
sample_valid : in std_logic
|
||
|
) ;
|
||
|
end entity ;
|
||
|
|
||
|
architecture arch of wlan_agc is
|
||
|
|
||
|
type wlan_sample_t is record
|
||
|
i : signed(15 downto 0) ;
|
||
|
q : signed(15 downto 0) ;
|
||
|
valid : std_logic ;
|
||
|
end record ;
|
||
|
|
||
|
signal iir : signed( 31 downto 0 ) ;
|
||
|
signal ptemp : signed( 31 downto 0 ) ;
|
||
|
signal burst_cnt: signed( 7 downto 0 ) ;
|
||
|
|
||
|
function run_iir( x : signed( 31 downto 0); y : signed ( 31 downto 0) )
|
||
|
return signed
|
||
|
is
|
||
|
variable amrea : signed(31 downto 0) ;
|
||
|
begin
|
||
|
amrea := resize( x - shift_right(x, 6) + shift_right(y, 6), 32 );
|
||
|
return amrea;
|
||
|
end;
|
||
|
|
||
|
type fsm_t is (IDLE, SETTLE, ATTACK, WAIT_GAIN_ACK, WAIT_GAIN_ACK_1, HOLD) ;
|
||
|
|
||
|
type state_t is record
|
||
|
fsm : fsm_t ;
|
||
|
inc_req : std_logic ;
|
||
|
dec_req : std_logic ;
|
||
|
rst_req : std_logic ;
|
||
|
timer : unsigned( 10 downto 0 ) ;
|
||
|
end record ;
|
||
|
|
||
|
function NULL_STATE return state_t is
|
||
|
variable rv : state_t ;
|
||
|
begin
|
||
|
rv.fsm := IDLE ;
|
||
|
rv.inc_req := '0' ;
|
||
|
rv.dec_req := '0' ;
|
||
|
rv.rst_req := '0' ;
|
||
|
rv.timer := ( others => '0' );
|
||
|
return rv ;
|
||
|
end function ;
|
||
|
|
||
|
signal current, future : state_t := NULL_STATE ;
|
||
|
signal sample, sample_out : wlan_sample_t ;
|
||
|
begin
|
||
|
sample.i <= sample_i;
|
||
|
sample.q <= sample_q;
|
||
|
sample.valid <= sample_valid;
|
||
|
|
||
|
gain_inc_req <= current.inc_req ;
|
||
|
gain_dec_req <= current.dec_req ;
|
||
|
gain_rst_req <= current.rst_req ;
|
||
|
|
||
|
process( clock )
|
||
|
begin
|
||
|
if( reset = '1' ) then
|
||
|
rst_gains <= '0' ;
|
||
|
burst <= '0' ;
|
||
|
elsif( rising_edge( clock )) then
|
||
|
if( ( gain_max = '1' and iir < 4200 ) or current.fsm = SETTLE ) then
|
||
|
rst_gains <= '1' ;
|
||
|
else
|
||
|
rst_gains <= '0' ;
|
||
|
end if ;
|
||
|
|
||
|
if( gain_max = '0' or iir > 150000 ) then
|
||
|
burst <= '1' ;
|
||
|
burst_cnt <= to_signed(18, burst_cnt'length) ;
|
||
|
else
|
||
|
if( ptemp > 300000 ) then
|
||
|
burst <= '1' ;
|
||
|
burst_cnt <= to_signed(6, burst_cnt'length) ;
|
||
|
else
|
||
|
if( burst_cnt > 0 ) then
|
||
|
burst <= '1' ;
|
||
|
burst_cnt <= burst_cnt - 1 ;
|
||
|
else
|
||
|
burst <= '0' ;
|
||
|
end if ;
|
||
|
end if ;
|
||
|
end if ;
|
||
|
end if ;
|
||
|
end process ;
|
||
|
|
||
|
process( clock )
|
||
|
begin
|
||
|
if( reset = '1' ) then
|
||
|
iir <= ( others => '0' ) ;
|
||
|
ptemp <= (others => '0' ) ;
|
||
|
elsif( rising_edge( clock )) then
|
||
|
if( current.timer = 18 ) then
|
||
|
iir <= ptemp ;
|
||
|
elsif( sample.valid = '1') then
|
||
|
ptemp <= sample.i * sample.i + sample.q * sample.q ;
|
||
|
iir <= run_iir(iir, ptemp) ;
|
||
|
end if ;
|
||
|
end if ;
|
||
|
end process ;
|
||
|
|
||
|
sync : process(clock, reset)
|
||
|
begin
|
||
|
if( reset = '1' ) then
|
||
|
current <= NULL_STATE ;
|
||
|
elsif( rising_edge(clock) ) then
|
||
|
current <= future ;
|
||
|
end if ;
|
||
|
end process ;
|
||
|
|
||
|
comb : process(all)
|
||
|
begin
|
||
|
future <= current ;
|
||
|
future.inc_req <= '0' ;
|
||
|
future.dec_req <= '0' ;
|
||
|
future.rst_req <= '0' ;
|
||
|
|
||
|
case current.fsm is
|
||
|
when IDLE =>
|
||
|
future.fsm <= SETTLE ;
|
||
|
|
||
|
when SETTLE =>
|
||
|
if( current.timer > 32 ) then -- 50 looks good 70 is overkill
|
||
|
future.timer <= ( others => '0' ) ;
|
||
|
future.fsm <= ATTACK ;
|
||
|
else
|
||
|
if( current.timer < 400 ) then
|
||
|
future.timer <= current.timer + 1 ;
|
||
|
end if ;
|
||
|
end if ;
|
||
|
|
||
|
when ATTACK =>
|
||
|
if( rst_gains = '1' ) then
|
||
|
future.timer <= ( others => '0' ) ;
|
||
|
elsif( current.timer < 1000 ) then
|
||
|
future.timer <= current.timer + 1 ;
|
||
|
end if ;
|
||
|
|
||
|
if( agc_hold_req = '1' ) then
|
||
|
future.fsm <= HOLD ;
|
||
|
else
|
||
|
-- 405000, -48dBm to enter mid, -28dBm to enter low
|
||
|
if( current.timer < 24 and iir > 485000 ) then --335000
|
||
|
-- I = Q = sqrt(2048*2048/10)=657, IIR = I^2 + Q^2= 845000
|
||
|
future.fsm <= WAIT_GAIN_ACK ;
|
||
|
future.dec_req <= '1' ;
|
||
|
elsif( current.timer > 300 and iir < 1000 ) then
|
||
|
--elsif( iir < 5000 ) then
|
||
|
-- I = Q = 50, IIR = I^2 + Q^2= 5000
|
||
|
future.inc_req <= '1' ;
|
||
|
future.fsm <= WAIT_GAIN_ACK ;
|
||
|
end if ;
|
||
|
end if ;
|
||
|
|
||
|
when WAIT_GAIN_ACK =>
|
||
|
future.fsm <= WAIT_GAIN_ACK_1 ;
|
||
|
when WAIT_GAIN_ACK_1 =>
|
||
|
if( gain_ack = '1' ) then
|
||
|
future.fsm <= SETTLE ;
|
||
|
future.timer <= ( others => '0' ) ;
|
||
|
end if ;
|
||
|
if( gain_nack = '1' ) then
|
||
|
future.fsm <= ATTACK ;
|
||
|
end if ;
|
||
|
|
||
|
when HOLD =>
|
||
|
if( iir < 5000 ) then
|
||
|
-- I = Q = 50, IIR = I^2 + Q^2= 5000
|
||
|
future.rst_req <= '1' ;
|
||
|
future.fsm <= WAIT_GAIN_ACK ;
|
||
|
end if ;
|
||
|
|
||
|
end case ;
|
||
|
end process ;
|
||
|
|
||
|
end architecture ;
|