Professional Documents
Culture Documents
[ +1]
=1
x[n] = represent the noisy filter input,
define the properties of the filter, and are calculated as the inverse Fourier transform
of the desired frequency characteristics of the desired filter.
FIR Filter parameters calculation:
ADC data out rate: 4.68Mhz
ADC takes 21 clock cycles to convert one sample So the sampling rate calculated:
4680000/21 = 222857 samples per secondThe cutoff frequencies will be decoded
by the input signal frequencies:
The analog input signal to at the Vref pin of the ADC is:
The Frequency content of the signal can be viewed by the Fourier transform:
The signal has low frequencies, so we need to apply a low pass filter.
Analysis of a 60 order Low pass FIR filter with cutoff 10000Hz and 2000Hz
frequency.
fc = 0.0448718; % 100000Hz cutoff
N = 60; % number of taps
n = -(N/2):(N/2);
n = n+(n==0)*eps;
[h] = sin(n*2*pi*fc)./(n*pi);
[w] = 0.54 + 0.46*cos(2*pi*n/N);
d = h.*w;
int_coefficient = 32767*d;
freqz(d,1,99901,222857);
for i = 1:61
coefficients(i) = floor(int_coefficient(i)');
end
The filter coefficients are converted to the integer values for the calculations in fpga using q
word notation of numbers.The plot of those coefficient is as follows
22 28 33 38 41 40 33 17 -9 -48 -98 -155 -216
-272 -315 -333 -316 -255 -142 27 254 533 856 1208 1574
1932 2262 2543 2759 2894 2940 2894 2759 2543 2262 1932 1574
1208 856 533 254 27 -142 -255 -316 -333 -315 -272 -216
-155 -98 -48 -9 17 33 40 41 38 33 28 22
And the filter input and output in simulation is of 60 order filter are
Above graph shows the input to the FIR filter i.e the feedback voltage received.
Filtered output is shown above which has less jumps.
20 order FIR calculations
fc = 0.0089600; % 2000Hz cutoff
%fc = 0.044871 ; % 10000 Hz cutoff
N = 20; % number of taps
n = -(N/2):(N/2);
n = n+(n==0)*eps;
[h] = sin(n*2*pi*fc)./(n*pi);
[w] = 0.54 + 0.46*cos(2*pi*n/N);
d = h.*w;
int_coefficient = 32767*d;
freqz(d,1,99901,222857);
for i = 1:21
coefficients (i) = floor(int_coefficient(i)');
end
23 29 48 78 116 158 199 237 267 286 293 286 267
237 199 158 116 78 48 29 23
Plot of coefficients
Filter response of 20
th
order in the two cases
1. 2000 Hz frequency cutoff
The db magnitude at zero frequency in this case is -14.28db which will give an inverse gain of
=
1
10
14.28
20
= 5.1761
So the filter output will be reduced in magnitude by this factor which needs to be compensated
to compare between the input and output.
2. 10000Hz frequency cutoff
In this case the factor is =
1
10
2
20
= 1.2589
The input and output for 20 order filter at 2000Hz cutoff of Lowpass
filter
The input and the filtered result output is shown above using a 20 order FIR filter.
The input and the output results of FIR filter using 20
th
order and 10000Hz cutoff frequency.
and the coefficients are: 26 67 169 369 686 1111 1606 2108 2542 2836
2940 2836 2542 2108 1606 1111 686 369 169 67 26
Above graph is the plot of coefficients of 20 order filter.
FPGA implementation of the filters:
60 Order FIR filter.
#
# pin constraints
#
NET adc_cs LOC = "B11";
NET adc_miso LOC = "F18";
NET adc_sclk LOC = "A11";
NET bit_out LOC = "F17";
NET "CLK_IN" LOC = "C10";
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 14:54:15 03/12/2014
-- Design Name:
-- Module Name: fir - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
--use ieee.std_logic_arith.all;
--use ieee.std_logic_unsigned.all;
use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity fir is
port
(
-- ADD USER PORTS BELOW THIS LINE ------------------
adc_miso : in std_logic;
adc_sclk : out std_logic;
adc_cs : out std_logic;
CLK_IN : in std_logic;
bit_out : out std_logic
);
end fir;
architecture Behavioral of fir is
signal input : signed(15 downto 0) := (others => '0');
signal p : unsigned(4 downto 0) := (others => '0');
signal k : unsigned(4 downto 0) := (others => '0');
signal index2 : unsigned(4 downto 0) := (others => '0');
signal q : unsigned(5 downto 0) := (others => '0');
signal index : unsigned(3 downto 0) := (others => '0');
signal data_buffer : std_logic_vector(15 downto 0) := (others => '0');
signal clk_slow : std_logic := '0';
signal clk_slow_out : std_logic := '0';
signal cs_select : unsigned(1 downto 0) := (others => '0');
signal count_2_bits : unsigned(1 downto 0) := (others => '0');
type array_signed1 is array(60 downto 0) of signed(15 downto 0);
signal H : array_signed1 := (others => "0000000000000000");
signal slv_reg0 : std_logic_vector(15 downto 0);
signal slv_reg1 : std_logic_vector(31 downto 0);
type MULT_TYPE is array(60 downto 0) of signed(31 downto 0);
signal mult_array : MULT_TYPE := (others => "00000000000000000000000000000000");
type ADD_TYPE is array(60 downto 0) of signed(31 downto 0);
signal ADD_array : ADD_TYPE := (others => "00000000000000000000000000000000");
constant ZERO : signed(31 downto 0) := (others => '0');
begin
H(0) <= to_signed(22,16);
H(1) <= to_signed(28,16);
H(2) <= to_signed(33,16);
H(3) <= to_signed(38,16);
H(4) <= to_signed(41,16);
H(5) <= to_signed(40,16);
H(6) <= to_signed(33,16);
H(7) <= to_signed(17,16);
H(8) <= to_signed(-9,16);
H(9) <= to_signed(-48,16);
H(10) <= to_signed(-98,16);
H(11) <= to_signed(-155,16);
H(12) <= to_signed(-216,16);
H(13) <= to_signed(-272,16);
H(14) <= to_signed(-315,16);
H(15) <= to_signed(-333,16);
H(16) <= to_signed(-316,16);
H(17) <= to_signed(-255,16);
H(18) <= to_signed(-142,16);
H(19) <= to_signed(27,16);
H(20) <= to_signed(254,16);
H(21) <= to_signed(533,16);
H(22) <= to_signed(856,16);
H(23) <= to_signed(1208,16);
H(24) <= to_signed(1574,16);
H(25) <= to_signed(1932,16);
H(26) <= to_signed(2262,16);
H(27) <= to_signed(2543,16);
H(28) <= to_signed(2759,16);
H(29) <= to_signed(2894,16);
H(30) <= to_signed(2940,16);
H(31) <= to_signed(2894,16);
H(32) <= to_signed(2759,16);
H(33) <= to_signed(2543,16);
H(34) <= to_signed(2262,16);
H(35) <= to_signed(1932,16);
H(36) <= to_signed(1574,16);
H(37) <= to_signed(1208,16);
H(38) <= to_signed(856,16);
H(39) <= to_signed(533,16);
H(40) <= to_signed(254,16);
H(41) <= to_signed(27,16);
H(42) <= to_signed(-142,16);
H(43) <= to_signed(-255,16);
H(44) <= to_signed(-316,16);
H(45) <= to_signed(-333,16);
H(46) <= to_signed(-315,16);
H(47) <= to_signed(-272,16);
H(48) <= to_signed(-216,16);
H(49) <= to_signed(-155,16);
H(50) <= to_signed(-98,16);
H(51) <= to_signed(-48,16);
H(52) <= to_signed(-9,16);
H(53) <= to_signed(17,16);
H(54) <= to_signed(33,16);
H(55) <= to_signed(40,16);
H(56) <= to_signed(41,16);
H(57) <= to_signed(38,16);
H(58) <= to_signed(33,16);
H(59) <= to_signed(28,16);
H(60) <= to_signed(22,16);
-------------------------------clock_divide-----------------------------------------------------
process ( CLK_IN ) is
begin
if CLK_IN'event and CLK_IN = '1' then
q <= q + 1;
clk_slow <= q(3);
clk_slow_out <= q(2);
adc_sclk <= clk_slow;
end if;
end process;
-------------------------------clock_divide-----------------------------------------------------
process( clk_slow ) is
begin
if falling_edge(clk_slow) then
Case cs_select is
when "00" =>
adc_cs <= '0';
case count_2_bits is
when "10" =>
data_buffer(to_integer(index)) <= adc_miso;
index <= index + 1;
if ( index = "1111" ) then
index <= "0000";
slv_reg0 <= data_buffer;
for i in 0 to 60 loop
mult_array(i) <= signed(slv_reg0)*H(60-i);
if i = 0 then
ADD_array(i) <= ZERO + mult_array(0);
else
ADD_array(i) <= mult_array(i) + ADD_array(i-1);
end if;
end loop;
slv_reg1 <= std_logic_vector(ADD_array(60));
cs_select <= cs_select + 1;
count_2_bits <= "00";
end if;
when others =>
count_2_bits <= count_2_bits + 1;
end case;
when others =>
adc_cs <= '1';
cs_select <= cs_select + 1;
end case;
end if;
end process;
Process_bit_out_clk_fast : process(clk_slow_out)
begin
if(falling_edge(clk_slow_out)) then
bit_out <= slv_reg1(to_integer(index2));
index2 <= index2 + 1;
end if;
end process;
end Behavioral;
Signals can be view on the oscilloscope:
ADC_CS :
In adc_cs signal pulses have been created at the fixed intervals. When adc_cs is
low ADC is in output mode and outputs the digital code of the analog voltage whil
a high value is necessary between two conversions.
ADC_MISO : Dout signal
The output of the filter is show below: ( 60 order low pass FIR filter, cutoff 10000
Hz)
Filter implementation in EDK as a peripheral to the soft core processor:
We have already seen how to make a project in EDk, in the case of ADC converter.
Now we need to make a user defined peripheral.
1. Select from the menu Hardware->Create or Import Peripheral. Click
Next.
2. Select Create templates for a new peripheral and click Next.
We must now decide where to place the files for the peripheral. They can be
placed within this project, or they can be made accessible to other projects. Select
To an XPS project. Click Next.
On the Name and Version page, type fir for the peripheral name. Click Next.
On the Bus Interface page, select AXI4-lite and click Next.
The the created Peripheral fir needs modification in the design.
The Low pass FIR filter has order 20 and cutoff frequency 10000Hz.
Select from the menu File->Open and browse to pcores\fir_v1_00_a\hdl\vhdl
from the project folder.
There are two source files : fir.vhd and user_logic.vhd.
Open the fir.vhd file.
1. Find the line of code that says ADD USER PORTS BELOW THIS LINE and add these
lines of code:
adc_miso : in std_logic;
adc_sclk : out std_logic;
adc_cs : out std_logic;
Find the line of code that says MAP USER PORTS BELOW THIS LINE and add these two
lines of code:
adc_miso => adc_miso,
adc_sclk => adc_sclk,
adc_cs => adc_cs,
Save and close fir.vhd
Now open the user_logic.vhd file.
Replace the ieee libraries with these
library ieee;
use ieee.std_logic_1164.all;
use IEEE.NUMERIC_STD.ALL;
Add following lines where -- ADD USER PORTS BELOW THIS LINE ----is written
adc_miso : in std_logic;
adc_sclk : out std_logic;
adc_cs : out std_logic;
The part where --USER signal declarations added here, as needed for user logic is given write :
signal input : signed(15 downto 0) := (others => '0');
signal q : unsigned(5 downto 0) := (others => '0');
signal index : unsigned(3 downto 0) := (others => '0');
signal data_buffer : signed(15 downto 0) := (others => '0');
signal clk_slow : std_logic := '0';
signal cs_select : unsigned(1 downto 0) := (others => '0');
signal count_2_bits : unsigned(1 downto 0) := (others => '0');
type array_signed1 is array(20 downto 0) of signed(15 downto 0);
signal H : array_signed1 := (others => "0000000000000000");
type MULT_TYPE is array(20 downto 0) of signed(31 downto 0);
signal mult_array : MULT_TYPE := (others => "00000000000000000000000000000000");
type ADD_TYPE is array(20 downto 0) of signed(31 downto 0);
signal ADD_array : ADD_TYPE := (others => "00000000000000000000000000000000");
constant ZERO : signed(31 downto 0) := (others => '0');
After this Add the following code in the User logic implementation:
H(0) <= to_signed(26,16);
H(1) <= to_signed(67,16);
H(2) <= to_signed(169,16);
H(3) <= to_signed(369,16);
H(4) <= to_signed(686,16);
H(5) <= to_signed(1111,16);
H(6) <= to_signed(1606,16);
H(7) <= to_signed(2108,16);
H(8) <= to_signed(2542,16);
H(9) <= to_signed(2836,16);
H(10) <= to_signed(2940,16);
H(11) <= to_signed(2836,16);
H(12) <= to_signed(2542,16);
H(13) <= to_signed(2108,16);
H(14) <= to_signed(1606,16);
H(15) <= to_signed(1111,16);
H(16) <= to_signed(686,16);
H(17) <= to_signed(369,16);
H(18) <= to_signed(169,16);
H(19) <= to_signed(67,16);
H(20) <= to_signed(26,16);
process ( Bus2IP_Clk ) is
begin
if Bus2IP_Clk'event and Bus2IP_Clk = '1' then
q <= q + 1;
clk_slow <= q(4); --- 75000000/2^4 = 4.6875Mhz
adc_sclk <= clk_slow;
end if;
end process;
-------------------------------clock_divide-----------------------------------------------------
process( clk_slow ) is
begin
if falling_edge(clk_slow) then
Case cs_select is
when "00" =>
adc_cs <= '0';
case count_2_bits is
when "10" =>
data_buffer(to_integer(index)) <= adc_miso;
index <= index + 1;
if ( index = "1111" ) then
index <= "0000";
input <= data_buffer;
slv_reg0(15 downto 0) <= std_logic_vector(input);
for i in 0 to 20 loop
mult_array(i) <= input*H(20-i);
if i = 0 then
ADD_array(i) <= ZERO + mult_array(0);
else
ADD_array(i) <= mult_array(i) + ADD_array(i-1);
end if;
end loop;
slv_reg1 <= std_logic_vector(ADD_array(20));
cs_select <= cs_select + 1;
count_2_bits <= "00";
end if;
when others =>
count_2_bits <= count_2_bits + 1;
end case;
when others =>
adc_cs <= '1';
cs_select <= cs_select + 1;
end case;
end if;
end process;
Now Delete the process named SLAVE_REG_WRITE_PROC.
Save the file and close it.
Now Again goto the Hardware -> create and import peripheral and this time
select import peripheral.
Now select same name by which we created the peripheral i.e fir. And click yes.
In the source file type window click Next tick HDL source files only
Now the HDL source file window Locate the .pao file for the project.
Now Click next in the HDL analysis window if there is no error in the HDL source
file next window will appear.
Select the options shown in the above figure.
Now in the Register space window select the address from C_BASEADDR to
C_HIGHADDR.
After this click next in the next three windows.
Add the Design to the microblaze by double click the peripheral created.
Make the Ports on the peripheral external.
The cpu.ucf file
NET uart_tx LOC = "F13";
NET uart_rx LOC = "E13";
NET uart_switch LOC = "C15";
NET adc_cs LOC = "B11";
NET adc_miso LOC = "F18";
NET adc_sclk LOC = "A11";
NET "CLK_IN" LOC = "C10";
Now generate the Top entity in the ISE for the created hardware design.
Next step : Synthesize -> implement -> generate programming file.
On synthesize we get the information about the Logic used in fpga.
The systhesize report explains detail wise how many types of logical resources we
have used.
The logical resources used here can be decreased by using a sequential algorithm
probably involving state machine model, doing only one multiplication and
addition per clock.
Here we are producing an output sample as soon as we are receiving, one output
sample only in one clock cycle the throughput in this parallel algorithm is more.
After Implementation and bit file generation is complete the design needs to be
exported to the SDK for application development on the developed drivers.
In the screen shot the option to export the design to sdk is visible, right click that
and run. Select a location for the SDK.
EDK Memory addresses:
The address for user designed peripheral registers are from 0x7AA00000 to
0x7AA0FFFF
In the SDK go to file->new application project as shown in the image below.
In the next dialogue box enter the name of the project click next then select a
hello world program and finish.
Now the c program to print the received bit values of fir datain and FIR dataout:
#include <stdio.h>
#include "platform.h"
#include "platform.h"
#include "xparameters.h"
#include "xil_io.h"
void print(char *str);
int main()
{
init_platform();
unsigned int DataRead;
unsigned int reversedNum;
unsigned int reversedNum1;
unsigned int dataout;
unsigned int f;
unsigned int f1;
while(1){
DataRead = Xil_In16(0x7AA00000);
dataout = Xil_In32(0x7AA00004);
reversedNum = reverse_bits_recursive(DataRead, 16);
reversedNum1 = reverse_bits_recursive(dataout, 32);
// f1 = (32768-reversedNum)*100*5/32768;
// f = (2147483648-reversedNum1)*1000000*5/2147483648;
// xil_printf("reversed: %d \n\r", reversedNum);
xil_printf("FIR_datain: %d FIR_dataout: %d \n\r",reversedNum,
reversedNum1);
};
return 0;
}
int reverse_bits_recursive(unsigned int num, unsigned int numBits)
{
unsigned int reversedNum;
unsigned int mask = 0;
mask = (0x1 << (numBits/2)) - 1;
if (numBits == 1) return num;
reversedNum = reverse_bits_recursive(num >> numBits/2, numBits/2) |
reverse_bits_recursive((num & mask), numBits/2) <<
numBits/2;
return reversedNum;}
From the received values the voltages can be plotted as in the case of ADC conversion earlier.
The feedback signal its in oscilloscope analog converted to digital signal
The FIR DataOUT bits Order 20, cutoff frequency 10000Hz, Low pass fir filter.
The input and the output results of FIR filter using 20
th
order and 10000Hz cutoff
frequency.
and the coefficients are: 26 67 169 369 686 1111 1606 2108 2542 2836
2940 2836 2542 2108 1606 1111 686 369 169 67 26
Conclusion:
In the report we saw the implementation of 60 order FIR on fpga in Xilinx ISE by a
parallel filter output computing algorithm and while using the Microblaze the
limitations for the filter order are only 20 due to the limitations of the resources.
By the graph of the filter output we can see that filtering is smoothing out the
signal also it is removing the extreme peaks.
Now to increase the order of the filter we will have to change the filter algorithm
from parallel to a state machine implementation which involves less
multiplication and adders per clock cycle so that limited logic resources get used.