Fpga Implementation of Fir Filter

72
FPGA IMPLEMENTATION OF FIR FILTER AND USING IT AS A PERIPHERAL TO SOFT PROCESSOR MICROBLAZE FOR INCREASED USER SOFTWARE FUNCTIONALITIES

description

Fpga Implementation of Fir Filter

Transcript of Fpga Implementation of Fir Filter

FPGA IMPLEMENTATION OF FIR FILTER AND USING IT AS A

PERIPHERAL TO SOFT PROCESSOR MICROBLAZE FOR

INCREASED USER SOFTWARE FUNCTIONALITIES

Content

1. Introduction

2. Analog to Digital conversion

3. Filter and it’s parameter caculations

4. FPGA Implementation directly and as a peripheral to soft core

processor microblaze

5. Conclusion and Next objectives

Introduction:

It is necessary in control system to precisely measure the feedback signal. The

analog feedback signal gets affected by the noises so the A/D converted digital

bits have errors. After the filter in analog domain it is recommended to use a

digital filter to remove the ground noises in the signal. Generally the more is the

order of the filter more sharper are the frequency cutoffs but higher orders

requires higher number of logical resources from the FPGA so the filter

characteristics should be decided optimally using optimal logical resources by

considering the full design.

In this paper FIR filter algorithm has been developed and implemented on fpga.

The input data for the filter has been taken from A/D converter which digitizes

the feedback of measured force. Data received from the A/D and the filtered

output has been displayed on the Teraterm software PC, for uart communication

to PC fpga soft core processor microblaze has been used. In Microblaze via AXI

protocol communication between the FIR peripheral and the uart peripheral is

possible and both can be used simultaneously to receive, process and display the

feedback data on Teraterm, This increases the use of logical resources of fpga so

the order of filter is being chosen accordingly.

The report is organized as follows: first the analog to digital converter then the fir

filter calculations and matlab results using the coefficients. Finally after getting

satisfactory results in matlab filters have been implemented on fpga and applied

to the signal. In the end conclusions from the study and future objectives have

been included.

Analog to Digital converter and Data Reception:

Serial number Pin Function Range

1. Vref +0.5v to Va

2. +IN and -IN Differential input, The effective input voltage that is digitized is (+IN) − (−IN).

3. 4 and 5 GND

4. Va Analog power +4.5 v to +5.5v

5. Vio Digital input/output power +2.7v to +5.5v

6. SCLK ADC clock 1Mhz to 5Mhz

7. Dout Serial data out

8. 𝐶𝑆 Chip select

The range of sclk at which the A/D outputs digital data is 1 to 5 Mhz. The 𝐶𝑆 chip

select signal is used to set the adc in enable and disable modes, when it is high

the A/D converter does the converters the analog data into digital and when it is

low it sends the output bits at the clock cycle, while using the ADC one needs to

maintain a proper timing structure for the 𝐶𝑆 signal. The Dout pin output the

digital bits at the clock rate.

Some features of the ADC161S626

The ADC161S626 is a 16-bit, 50 kSPS to 250 kSPS sampling Analog-to-Digital (A/D)

converter.

Ensured performance from 50 to 250 kSPS

ADC161S626 supoorts following input operations:

Differential Input Operation

Single-Ended Input Operation

Input Common Mode Voltage

CMRR

For our application we are using the single mode operation:

For single-ended operation, the non-inverting input (+IN) of the ADC161S626 can

be driven with a signal that has a peak-to-peak range that is equal to or less than

(2 x VREF). The inverting input (−IN) should be biased at a stable VCM that is

halfway between these maximum and minimum values. In order to utilize the

entire dynamic range of the ADC161S626, VREF is limited to (VA / 2).

In our case the VA ~ 5v and Vref is limited to 2.5v so the range of voltage of ADC

with the cutoff Vcm = 2.5 is from 0 to 5v.

Timings Diagram of ADC:

DOUT is enabled on the second falling edge of SCLK after the assertion of CS and

is disabled on the rising edge of CS. If CS is raised prior to the 18th falling edge of

SCLK, the current conversion is aborted and DOUT will go into its high impedance

state. A new conversion will begin when CS is driven LOW.

Making a project in Xilinx ISE + EDK and SDK for xc6slx9 fpga to receive the data

bits from Dout and printing them on Teraterm.

Step 1 : Start the ISE 14.4

File -> New Project : Enter a name and set Top-level source type: HDL.

In the next window set the fpga as in the following picture then click next and

finish.

Now that we have started with a project.

Next step is to add a new source that is microblaze embedded processor.click

Next and finish.

Now Creating the EDK project and Adding uart Peripheral to it.

After adding the soft processor to the project new window opens.

Click yes, and ok in the next wondow.

Set the processor frequency (27 Mhz which is available on the board) and select

the reset polarity to high. Use area optimization strategy.

Here you can select the processor frequency and local memory size, one should

be careful while selecting the processor frequency it should be feasible to be

generated from the reference clock frequency click finish.

Now, steps to add uart driver to our soft core processor design.

Right click in the AXI UART (LITE) in the IP catalog tab of the EDK project and click

on ADD IP and click yes.

In the uart window the baud rate, data bits format, parity can be changed and

then select the processor we created, with which we are associating the uart

driver.

Now, in the system assembly view in the Ports tab the name of the ports can be

changed. In our design we are not using differential clock scheme but microblaze

has created driver of the differential clk system. We can change it in the Mhs file

as we are using single ended clock.

The Mhs file is shown below we need to add one manual port for the transmission

of data from board to pc put it in high (net_vcc) mode.

Now, Add a new user peripheral by the create and import peripheral in hardware

option

Click next.

select the AXI-4Lite interface.

Selected 1 register as per requirement.

Generate BFM selection select only if you want,

Now in the IPcores there are 2 Logic vhdl files are created where the logic for

receiving the data from the ADC can be written.

Goto : pcores -> datarec_v1_00_a->hdl-> vhdl and Open datarec and user_logic

files.

In the datarec file add ports below the line -- ADD USER PORTS BELOW THIS LINE -

------ adc_miso : in std_logic;

adc_sclk : out std_logic;

adc_cs : out std_logic;

and search for -- MAP USER PORTS BELOW THIS LINE ----

and write adc_miso => adc_miso,

adc_sclk => adc_sclk,

adc_cs => adc_cs,

save the datarec file and close it.

Now Open the user_logic file :

Relace the top libraries

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;

below the line -- ADD USER PORTS BELOW THIS LINE -------

adc_miso : in std_logic;

adc_sclk : out std_logic;

adc_cs : out std_logic;

Now in the user signal declaration part add ,

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');

Search for the --USER logic implementation added here—

And below this line add

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_end-----------------------------------------------------

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(15 downto 0) <= std_logic_vector(data_buffer);

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;

Search for the SLAVE_REG_WRITE_PROC and delete it.

Now save the file and close it.

Go to the Hardware in menu and create and import peripheral, click next

Click next and reach to

Next and in the next dialogue box select HDL source type then Locate the .pao file

In the next dialogue box select the options as shown below in the image

In the register space set the parameter high address as C_HIGHADDR.

And click next.

After clicking finish, Add the peripheral to the microblaze design.

Make the ports external.

The ucf file is shown below.

#

# pin constraints

#

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";

#

# additional constraints

#

#NET "CLK" TNM_NET = sys_clk_pin;

NET "CLK_IN" LOC = "C10";

#TIMESPEC TS_sys_clk_pin = PERIOD sys_clk_pin 27000 kHz;

Save the files and generate the top vhdl entity in Xilinx ISE.

The logical resources can be seen by synthesizing the project:

Export the project to SDK and create an empty application and replace the code with the below code. #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 offset;

unsigned int deviation_value100;

unsigned int reversedoffset;

offset = Xil_In16(0x7AA00000);

reversedoffset = reverse_bits_recursive(offset, 16);

while (1){

DataRead = Xil_In16(0x7AA00000);

reversedNum = reverse_bits_recursive(DataRead, 16);

if ( reversedNum >= 22000 && reversedNum <= reversedoffset )

{

/// negative voltage case

deviation_value100 = (reversedoffset- reversedNum)*5*100/ 32768;

xil_printf("voltage 1 : %c%c%d and number %d offset %d\n\r",0x2D

,0x2E,deviation_value100,reversedNum,reversedoffset );

}

else if ( reversedNum >= reversedoffset && reversedNum < 32768 )

{

deviation_value100 = ( reversedNum -

reversedoffset)*5*100/32768;

xil_printf("voltage 2 : %c%c%d and number %d offset

%d\n\r",0x2B ,0x2E,deviation_value100,reversedNum,reversedoffset );

}

else if ( reversedNum >= 0 && reversedNum <= 22000)

{

deviation_value100 = (32768-reversedoffset)*5*100/32768 +

reversedNum*5*100/32768;

xil_printf("voltage 3 : %c%c%d and number %d offset %d\n\r",0x2B

,0x2E,deviation_value100,reversedNum,reversedoffset );

}

};

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;

}

Output :

The initial position is assumed to be a natural position for the sensor, so in that

condition whatever voltage is there that is assumed reference and after this if

some movements occurs accordingly the voltage varies which can be seen in the

next image.

Output1:

The output values as a result of external force on the object in one and another

direction.

FIR:

The FIR (Finite Impulse Response) filtering uses a convolution of input signal with predefined coefficients

to achieve filtering effect.

y[n] = ∑ 𝑏𝑗 ∗ 𝑥[𝑛 − 𝑗 + 1]

𝑁𝑏

𝑗=1

x[n] = represent the noisy filter input,

𝑏𝑗= represent the filter coefficients,

y[n] = represent the filter output

𝑁𝑏= number of filter coefficient or order of filter or number of tapings

The coefficients 𝑏𝑗 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 20th 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.2820

= 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−

220

= 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 20th 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 20th 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.