[Fingerprint Identification] Simulation Implementation of Fingerprint Identification Algorithm Based on MATLAB/FPGA

1. Software version

MATLAB2013b,vivado2019.2

2. Theoretical knowledge of this algorithm

       Fingerprint identification technology refers to the use of imaging equipment to read the fingerprint image, extract the characteristic data in the fingerprint image through identification software, and then identify the identity of the fingerprint owner according to the result obtained by the matching algorithm. The fingerprint recognition system mainly involves three steps: fingerprint image preprocessing, feature extraction, and feature matching. The system flow diagram is shown in Figure 1-1. A brief introduction to these three parts is given below.

 

  1. Basic Features of Fingerprints

Fingerprints are actually more complicated. Unlike manual processing, many biometric technology companies do not directly store images of fingerprints. Over the years, many digital algorithms have been produced in various companies and their research institutions (the relevant laws in the United States believe that fingerprint images belong to personal privacy, so fingerprint images cannot be directly stored). But the fingerprint recognition algorithm ultimately boils down to finding and comparing the features of the fingerprint on the fingerprint image.

In fingerprint recognition systems, structural features at two levels, global and local, are usually used. Two fingerprints may have the same global features, but the local features may not be exactly the same.

  1. global features

Global features refer to those features that can be directly observed by the human eye, including: basic pattern loop (loop), arch (arch), and spiral (whorl) as shown in Figure 2-1. Other fingerprint patterns are based on these three basic patterns. It is not enough to distinguish fingerprints by pattern type alone. This is only a rough classification, but classification makes it more convenient to search fingerprints in large databases.

 

The pattern area refers to the area on the fingerprint that includes the general features, that is, the type of the fingerprint can be identified from the pattern area. Some fingerprint recognition algorithms only use the data in the pattern area. The fingerprint identification algorithm of Secure Touch uses the obtained complete fingerprint instead of just the pattern area for analysis and identification, as shown in Figure 2.

 Figure 2 Mode area

The core point is located at the progressive center of the fingerprint pattern, which serves as a reference point when reading and comparing fingerprints. Many algorithms are based on core points, which can only process and recognize fingerprints with core points. Core points are important to Secure Touch's fingerprint recognition algorithm, but it can still handle fingerprints without core points, as shown in Figure 3.

 Figure 3 core point

The triangular point is located at the first bifurcation or breakpoint from the core point, or at the convergence of the two stripes, the isolated point, the turning point, or points to these singularities. The triangular dots provide the start of counting tracking of fingerprint lines, as shown in Figure 4.

 Refers to the number of fingerprint lines in the pattern area. When calculating the number of lines in a fingerprint, generally connect the core point and the triangle point first, and the number of intersections between this line and the fingerprint lines can be considered as the number of lines in the fingerprint, as shown in Figure 2-5.

 

There are two methods of detail feature extraction: one is to extract features from grayscale images, and the other is to extract features from refined binary images. The algorithm for extracting features directly from a grayscale image is generally to track the grayscale fingerprint ridges, and find the location of the feature and determine the type of the feature according to the tracking result. This method saves the complex fingerprint image preprocessing process, but the feature extraction algorithm is very complicated, and due to the influence of noise and other factors, the feature information (position, direction, etc.) is not accurate enough. At present, most systems use the second method to extract features from the thinned binary image. This method is relatively simple. After obtaining a reliable thinned binary image, only a 3×3 template can be used to extract the endpoints and points. The fork point is extracted.

The quality of feature point extraction will directly affect the matching result. In reality, when fingerprints are input, due to the influence of sweat, dryness, different pressing force, etc., the obtained fingerprint images mostly contain quality problems such as broken lines, wrinkles, blurring, uneven grayscale, etc. Although the image quality will be improved after preprocessing. , but the adaptability and effectiveness of the preprocessing algorithm to each fingerprint will be different, and new noise will be introduced, so the obtained refined binary image often contains a large number of pseudo feature points. Pseudo feature points will not only affect the speed of matching, but also seriously affect the accuracy of the entire recognition. Therefore, after extracting feature points, pseudo-removal processing should be performed to filter out pseudo-feature points as much as possible and retain true feature points. In practice, it is found that the number of pseudo feature points generally accounts for more than half of the total number of features, so pseudo-removal is an essential process. The de-false process can be carried out in two stages: one is to smooth the thinned binary image, remove burrs, connect broken lines and other operations before feature extraction, and then extract features as true features; the other is to extract features after feature extraction. According to the relationship between the features, the pseudo feature points are identified as accurately as possible and they are filtered out. The former directly repairs the image, the operation is more complicated, and it is easy to introduce new pseudo-features; the latter judges the data after feature extraction, and the identification is more troublesome, but the speed is faster. This paper adopts the second method, that is, from the extracted features Filter out false features and keep true features.

3. Part of the core code

`timescale 1ns / 1ps
//
// Company: 
// Engineer:       ThinkSpark(CJY)
// 
// Create Date:    10:46:32 08/21/2009 
// Design Name: 
// Module Name:    spisensor 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//

`define effectvalue   1


module spisensor(//Output
                 cmd2tx_din_w,
				 rd_data_cmd_w,
				 send_rd_spidata_cmd_n_w,
                 clk180,        //spi transfer enable
				 SCK_CPOL_0,               //clk for slave
				 send_n_w,               
                 tx_rd_en_w,
                 tx_wr_en_w,
                 rx_wr_en_w,
                 locked_out0,
                 clk_24MHz,
				 div10_cnt_w,
				 sck_cnt8_w,
				 //Input
				 rx_full_n,
				 rx_first_n,
				 rx_empty_n,
				 
				 clk,                //system clock
				 rst
				              
				);
	 
output [7:0]     cmd2tx_din_w;
output [7:0]     rd_data_cmd_w;
output           SCK_CPOL_0;
output           clk180;
output           send_n_w;
output           tx_wr_en_w;
output           tx_rd_en_w;
output           rx_wr_en_w;
output           locked_out0;
output           clk_24MHz;
output [3:0]     div10_cnt_w;
output [2:0]     sck_cnt8_w;
output           send_rd_spidata_cmd_n_w;

input            clk;
input            rst;

input            rx_full_n;
input            rx_empty_n;
input            rx_first_n;



reg   [7:0]      cmdpad[31:0];    //filled with commands to be sent to slave after initialization
reg   [7:0]      rd_data_cmd_pad[1:0];
reg   [7:0]      cmd2tx_din;
reg   [7:0]      rd_data_cmd;
reg   [3:0]      div10_cnt;      //the time while div10_cnt=0 and div10_cnt=0- equals to an SCK period 
reg   [2:0]      sck_cnt8;       //sck_cnt8=7 indicates that 8bits have been transferred

reg   [3:0]      dcm_rst_delaycnt;
reg   [1:0]      rd_spidata_cmd_cnt;
reg              rd_spidata_cmd_cnt_en;
reg              send_rd_spidata_cmd_n;
reg              rd_data_cmd_rd_en;

reg   [15:0]     bytecnt;
reg   [5:0]      incr;
reg              tx_wr_en;
reg              tx_rd_en;
reg              rx_wr_en;
reg              transmision_done;
reg              addr;

reg              delaycnt_ctrl_n;
reg              transfer_n;    //data transfer enable bit,active low
reg              send_n;        //data send enable bit,active low
reg              recv_n;        //data receive enable bit,active low

reg    [7:0]     pre_state;
reg    [7:0]     nx_state;

wire             clk0_out0;
wire             locked_out0;
wire             clk0_out1;
wire             locked_out1;

wire             clk_24MHz;
wire             clk180;
wire             SCK_CPOL_0;
wire             SCK_CPOL_1;
wire             send_n_w;
//wire             transfer_n_w;
wire             tx_rd_en_w;
wire             tx_wr_en_w;
wire             rx_wr_en_w;
wire  [7:0]      cmd2tx_din_w; 
wire  [3:0]      div10_cnt_w;
wire  [2:0]      sck_cnt8_w; 
wire             send_rd_spidata_cmd_n_w;       

parameter        idle                     = 8'b00000000,
                 cmd2fifo                 = 8'b00000001,
                 sensor_initial           = 8'b00000010,
				 rd_sensor                = 8'b00000100,
				 rd_spistat               = 8'b00001000,
				 rd_spidata               = 8'b00010000,
				 send_data2uart           = 8'b00100000,
				 last_data2uart           = 8'b01000000,
				 spi_stop                 = 8'b10000000;
				 
				 

	 
dcm0 mydcm0 (
    .CLKIN_IN(clk), 
    .RST_IN(transfer_n), 
    .CLKFX_OUT(SCK_CPOL_1), 
    .CLKFX180_OUT(SCK_CPOL_0),    
    .CLK0_OUT(), 
    .LOCKED_OUT(locked_out0)
    );	 
 

dcm1 mydcm1 (
    .CLKIN_IN(clk), 
    .CLKFX_OUT(clk_24MHz),    
    .CLK0_OUT(), 
    .CLK180_OUT(clk180), 
    .LOCKED_OUT(locked_out1)
    );
//assign transfer_n_w =transfer_n; 

assign tx_wr_en_w=tx_wr_en;
assign tx_rd_en_w=tx_rd_en;
assign rx_wr_en_w=rx_wr_en;
assign send_n_w  =send_n;
assign cmd2tx_din_w=cmd2tx_din;
assign rd_data_cmd_w = rd_data_cmd;

assign div10_cnt_w = div10_cnt;
assign sck_cnt8_w  = sck_cnt8;
assign send_rd_spidata_cmd_n_w = send_rd_spidata_cmd_n;

//initialize cmdpad and transfer data in pad to Tx_fifo
always @(posedge clk)
begin
   if(rst == `effectvalue)
   begin
   cmdpad[0] <= 8'h75;
   cmdpad[1] <= 8'h7F;
   cmdpad[2] <= 8'h76;
   cmdpad[3] <= 8'h02;
   cmdpad[4] <= 8'h77;
   cmdpad[5] <= 8'h01;
   cmdpad[6] <= 8'h11;
   cmdpad[7] <= 8'h00;
   cmdpad[8] <= 8'h21;
   cmdpad[9] <= 8'h00;
   cmdpad[10] <= 8'h20;
   cmdpad[11] <= 8'h00;
   cmdpad[12] <= 8'h50;   
   cmdpad[13] <= 8'h00;
   cmdpad[14] <= 8'h00;
   cmdpad[15] <= 8'h00;
   end
   
end 	

always @(posedge clk)
begin
   if(rst == `effectvalue)
      begin
	     rd_data_cmd_pad[0] <= 8'h20;
		 rd_data_cmd_pad[1] <= 8'h00;
	  end
end


always @(posedge clk)
begin
   if(rst == `effectvalue)
      cmd2tx_din <= 8'b0;
   else 	   
	  cmd2tx_din <= cmdpad[incr];
end


//address point to data be wrote to Tx_fifo 
always @(posedge clk)
begin
   if(rst == `effectvalue)
      incr <= 6'b0;   
   else if(incr == 31)  
      incr <= 31 ;
   else	  
      incr <= incr + 1;   
end




//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

//transfer_n-\________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
//clk        |--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|
//div10_cnt   [  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ]    
//SCK       XXXXXXX________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/
//sck_cnt8         [00000000000000000000000000000000000000000000000000000][1111111111111111111111111111111111111111111111111111111111][2222222222222222222222222222222222222222222222222222222222][3333333333333333333333333333333333333333333333333333333333][4444444444444444444444444444444444444444444444444444444444][5555555555555555555555555555555555555555555555555555555555][6666666666666666666666666666666666666666666666666666666666][7777777777777777777777777777777777777777777777777777777777][0000000000000000000000000000000000000000000000000000000000][11111111111111111111111111111111111111]
//tx_rd_en      ------|_____|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\_____/----------------------------------------------------------------------------------
//tx_shifterOOOOOOOOOOOOOOOOOOO[            d7 d6 d5 d4 d3 d2 d1 d0      ][         d6 d5 d4 d3 d2 d1 d0 0                           ][                  d5 d4 d3 d2 d1 d0 0 0                   ][                  d4 d3 d2 d1 d0 0 0 0                    ][                    d3 d2 d1 d0 0 0 0 0                   ][                        d2 d1 d0 0 0 0 0 0                ][                  d1  d0  0  0  0  0  0  0                ][                      d0  0  0  0  0  0  0  0                               ][     d7 d6 d5 d4 d3 d2 d1 d0            ][           d6 d5 d4 d3 d2 d1 d0 0 ] 
//MOSI     OOOOOOOOOOOOOO000000000000000000[----------------------------d7----------------------------][----------------------------d6----------------------------][----------------------------d5----------------------------][----------------------------d4----------------------------][----------------------------d3----------------------------][----------------------------d2----------------------------][----------------------------d1----------------------------][----------------------------d0----------------------------][----------------------------d7----------------------------][--d6--]
//MISO  XXXXX[----------------------------D7-----------------------------][----------------------------D6----------------------------][----------------------------D5----------------------------][----------------------------D4----------------------------][----------------------------D3----------------------------][----------------------------D2----------------------------][----------------------------D1----------------------------][----------------------------D0----------------------------][----------------------------D7----------------------------][----------------------------D7--------
//rx_shifter0000000000000000000000000000000[                        0 0 0 0 0 0 0 D7                  ][                        0 0 0 0 0 0 D7 D6                 ][                       0 0 0 0 0 D7 D6 D5                 ][                        0 0 0 0 D7 D6 D5 D4               ][                      0 0 0 D7 D6 D5 D4 D3                ][                    0 0 D7 D6 D5 D4 D3 D2                 ][                       0 D7 D6 D5 D4 D3 D2 D1             ][                     D7 D6 D5 D4 D3 D2 D1 D0              ][                        0 0 0 0 0 0 0 D7                  ] 
//rx_wr_en------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\_____/-----------------------------------------------------------------
//----------------------------------------------------------------------------------------

//----------------------------------------------------------------------------------------
//the time while div10_cnt=0 and div10_cnt=0- equals to an SCK period 	
always @(posedge clk)
begin
   if( (rst == `effectvalue) || (transfer_n == 1'b1) )
      div10_cnt <= 4'b0;
   else if(div10_cnt == 9)
      div10_cnt <= 4'b0;
   else if(locked_out0 == 1'b1)
      div10_cnt <= div10_cnt + 1;
end
	
//----------------------------------------------------------------------------------------	
//3bits counter for SCK cycles, one counting cycle indicates one Byte transmission done	
always @ (posedge clk)
begin
   if( (rst == `effectvalue) || (transfer_n == 1'b1) )
      sck_cnt8 <= 3'b0;
   else if( (div10_cnt == 9) && (locked_out0 == 1'b1) )          //?????????????????????
      sck_cnt8 <= sck_cnt8 + 1;
   
end

//--------------------------------------------------------------------------------------------------
//------------control reading from tx_fifo and writing to rx_fifo----------------------------------
//---------------------------------begin-----------------------------------------------------------
always @(posedge clk180)                      //---- @posedge clk180 will work more precisely-----
begin
   if( (rst == `effectvalue) || (send_n == 1'b1) )        //not to read data from tx_fifo when send_n=1
      tx_rd_en <= 1'b1;
   else if( (locked_out0 == 1'b1) && (sck_cnt8 == 0) &&
            (div10_cnt == 0) )
      tx_rd_en <= 1'b0;
   else
      tx_rd_en <= 1'b1;   
end


always @(posedge clk180)
begin
   if( (rst == `effectvalue) || (send_rd_spidata_cmd_n == 1'b1) )
     rd_data_cmd_rd_en <= 1'b1;
   else if( (locked_out0 == 1'b1) && (sck_cnt8 == 0) &&
            (div10_cnt == 0) )
	 rd_data_cmd_rd_en <= 1'b0;
   else
     rd_data_cmd_rd_en <= 1'b1;
end

always @(posedge clk)
begin
   if(rst == `effectvalue)
      rd_data_cmd <= 8'b0;
   else if(rd_data_cmd_rd_en == 1'b0)
      rd_data_cmd <= rd_data_cmd_pad[addr];
end

always @(posedge clk)
begin
   if(rst == `effectvalue)
      addr <= 1'b0;
   else if (rd_data_cmd_rd_en == 1'b0) 
      addr <= ~addr;
end

always @(posedge clk)
begin
   if( (rst == `effectvalue) || (rx_full_n == 1'b0) )
      rd_spidata_cmd_cnt <= 2'b0;
   else if(rd_spidata_cmd_cnt == 2)
      rd_spidata_cmd_cnt <= 2;
   else if( (rd_spidata_cmd_cnt_en == 1'b0) && ( sck_cnt8 == 7 ) &&
             (div10_cnt == 9) )
      rd_spidata_cmd_cnt <= rd_spidata_cmd_cnt + 1;
end
///

always @(posedge clk180)                                 //---- @posedge clk180 will work more precisely-----
begin
   if( (rst == `effectvalue) || (recv_n == 1'b1) )       //not to write to rx_fifo when recv_n=1
      rx_wr_en <= 1'b1;
   else if( (locked_out0 == 1'b1) && (sck_cnt8 == 7) &&
            (div10_cnt == 6)  )                          //rx_wr_en be active while div10_cnt=6 and sck_cnt8=7 can 
	  rx_wr_en <= 1'b0;                                  //leave some time space for bytecnt
   else
      rx_wr_en <= 1'b1;
end

//------------control reading from tx_fifo and writing to rx_fifo----------------------------------
//---------------------------------end-----------------------------------------------------------

always @(posedge clk)
begin
   if( (rst == `effectvalue) || 
       ( (transfer_n == 1'b1) && (transmision_done == 1'b1) ) )
     bytecnt <= 16'b0;   
   else if( (sck_cnt8 == 7) && ( div10_cnt == 7 ) )            // one more byte has been sent and received the moment
     bytecnt <= bytecnt + 1;                                   //sck_cnt8=7 and div10_cnt=7(as the wave showed following)
   else 
     bytecnt <= bytecnt;
end	


always @(posedge clk)
begin
   if( rst == `effectvalue )
      transmision_done <= 1'b0;
   else if( (transmision_done == 1'b1) && (div10_cnt == 0) )
      transmision_done <= 1'b0;
   else if( (pre_state == sensor_initial) && (bytecnt == 6) )
      transmision_done <= 1'b1;
   else if( (pre_state == rd_sensor) && (bytecnt == 370) )
      transmision_done <= 1'b1;
   else if( (pre_state == rd_spistat) && (bytecnt == 3) )
      transmision_done <= 1'b1;
   //else if( (pre_state == rd_regs) && (bytecnt == 18) )
      //transmision_done <= 1'b1;
   else if( (pre_state == rd_spidata) && (bytecnt == 31352) )
      transmision_done <= 1'b1;
   
end

always @( posedge clk )
begin
   if( (rst == `effectvalue) || (transmision_done == 1'b1) || (rx_full_n == 1'b0) )
      dcm_rst_delaycnt <= 4'b0;
   else if( dcm_rst_delaycnt == 9 )
      dcm_rst_delaycnt <= 9;
   else if( delaycnt_ctrl_n == 1'b0 )
      dcm_rst_delaycnt <= dcm_rst_delaycnt + 1;
end

//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

//transfer_n-\________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
//clk        |--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|
//div10_cnt   [  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ]    
//SCK       XXXXXXX________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/
//sck_cnt8         [00000000000000000000000000000000000000000000000000000][1111111111111111111111111111111111111111111111111111111111][2222222222222222222222222222222222222222222222222222222222][3333333333333333333333333333333333333333333333333333333333][4444444444444444444444444444444444444444444444444444444444][5555555555555555555555555555555555555555555555555555555555][6666666666666666666666666666666666666666666666666666666666][7777777777777777777777777777777777777777777777777777777777][0000000000000000000000000000000000000000000000000000000000][11111111111111111111111111111111111111]
//tx_rd_en      ------\_____/-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\_____/----------------------------------------------------------------------------------
//tx_shifterOOOOOOOOOOOOOOOOOOO[            d7 d6 d5 d4 d3 d2 d1 d0      ][         d6 d5 d4 d3 d2 d1 d0 0                           ][                  d5 d4 d3 d2 d1 d0 0 0                   ][                  d4 d3 d2 d1 d0 0 0 0                    ][                    d3 d2 d1 d0 0 0 0 0                   ][                        d2 d1 d0 0 0 0 0 0                ][                  d1  d0  0  0  0  0  0  0                ][                      d0  0  0  0  0  0  0  0                               ][     d7 d6 d5 d4 d3 d2 d1 d0            ][           d6 d5 d4 d3 d2 d1 d0 0 ] 
//MOSI     OOOOOOOOOOOOOO000000000000000000[----------------------------d7----------------------------][----------------------------d6----------------------------][----------------------------d5----------------------------][----------------------------d4----------------------------][----------------------------d3----------------------------][----------------------------d2----------------------------][----------------------------d1----------------------------][----------------------------d0----------------------------][----------------------------d7----------------------------][--d6--]
//MISO  XXXXX[----------------------------D7-----------------------------][----------------------------D6----------------------------][----------------------------D5----------------------------][----------------------------D4----------------------------][----------------------------D3----------------------------][----------------------------D2----------------------------][----------------------------D1----------------------------][----------------------------D0----------------------------][----------------------------D7----------------------------][----------------------------D7--------
//rx_shifter0000000000000000000000000000000[                        0 0 0 0 0 0 0 D7                  ][                        0 0 0 0 0 0 D7 D6                 ][                       0 0 0 0 0 D7 D6 D5                 ][                        0 0 0 0 D7 D6 D5 D4               ][                      0 0 0 D7 D6 D5 D4 D3                ][                    0 0 D7 D6 D5 D4 D3 D2                 ][                       0 D7 D6 D5 D4 D3 D2 D1             ][                     D7 D6 D5 D4 D3 D2 D1 D0              ][                        0 0 0 0 0 0 0 D7                  ] 
//rx_wr_en------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\_____/-------------------------------------------------------------
//----------------------------------------------------------------------------------------


//-------------------------------------------------------------------------------
//-------------------------------FSM---------------------------------------------
always @(posedge clk)
begin
   if(rst == `effectvalue)
      pre_state <= idle;
   else
      pre_state <= nx_state;
end

//-----------------------------------------------------------------------
//FSM state transform---------------------------------------------------
always @(pre_state or div10_cnt or incr or transmision_done or 
         rx_empty_n or rx_full_n)
begin
   case(pre_state)
   
      idle          : nx_state = cmd2fifo;
	  
	  cmd2fifo      : begin
	                  if( incr == 31)                      //all 16 commands in cmdpad were wrote to Tx_fifo when incr=15
					     nx_state = sensor_initial;
					  else
					     nx_state = cmd2fifo;					     
					  end
      
      sensor_initial: begin
	                  if( (transmision_done == 1'b1) && (div10_cnt == 0))
					     nx_state = rd_sensor;
					  else
					     nx_state = sensor_initial;					     
					  end
      
      rd_sensor      :begin
                      if( (transmision_done == 1'b1) && (div10_cnt == 0))
					     nx_state = rd_spistat;
					  else
					     nx_state = rd_sensor;
					  end
	  
	  rd_spistat     :begin
	                  if( (transmision_done == 1'b1) && (div10_cnt == 0))
					     nx_state = rd_spidata;
					  else
					     nx_state = rd_spistat;
					  end
	  
	  rd_spidata     :begin
	                  if( (transmision_done == 1'b1) && (div10_cnt == 0))
					     nx_state = last_data2uart;
					  else if(rx_full_n == 1'b0)                             //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!               
					     nx_state = send_data2uart;
					  else
					     nx_state = rd_spidata;
					  end
	  send_data2uart:begin
	                 if(rx_empty_n == 1'b0)
					    nx_state = rd_spidata;
					 else
					    nx_state = send_data2uart;
					 end
					 
	 last_data2uart:begin
	                if(rx_empty_n == 1'b0)
					  nx_state = spi_stop;
					else
					  nx_state = last_data2uart;
					end
						
      spi_stop       :   nx_state = spi_stop; 
	  default        :   nx_state = idle;
					  
   endcase
end
//---------FSM state transform-----------------------------------------------
//-----------------------------------------------------------------------------


//-------------------------------------------
//FSM control signals output
always @(pre_state  or rx_full_n or div10_cnt or
          incr  or bytecnt or dcm_rst_delaycnt or
		  rd_spidata_cmd_cnt or rx_empty_n or rx_first_n )
begin
   case(pre_state)
   
      idle            :begin
	                   tx_wr_en    = 1'b1;
					   transfer_n  = 1'b1;
					   send_n      = 1'b1;
					   recv_n      = 1'b1;
					   delaycnt_ctrl_n = 1'b1;
					   send_rd_spidata_cmd_n = 1'b1;
					   rd_spidata_cmd_cnt_en = 1'b1;
					   end
	  
	  cmd2fifo        :begin
	                   if( (incr == 0) && (incr == 31) )
					      begin
						     tx_wr_en    = 1'b1;
							 transfer_n  = 1'b1;
							 send_n      = 1'b1;
							 recv_n      = 1'b1;
							 delaycnt_ctrl_n = 1'b1;
							 send_rd_spidata_cmd_n = 1'b1;
							 rd_spidata_cmd_cnt_en = 1'b1;
						  end
					   else
					      begin       
							 tx_wr_en    = 1'b0;
							 transfer_n  = 1'b1;
							 send_n      = 1'b1;
							 recv_n      = 1'b1;
							 delaycnt_ctrl_n = 1'b1;
							 send_rd_spidata_cmd_n = 1'b1;
							 rd_spidata_cmd_cnt_en = 1'b1;
                          end							 
					   end
	  sensor_initial  :begin
	                   if( (bytecnt == 6) && ( div10_cnt == 9) )
					      begin
						     tx_wr_en    = 1'b1;
							 transfer_n  = 1'b1;            // this will reset bytecnt when div10_cnt=9 
							 send_n      = 1'b1;
							 recv_n      = 1'b1;
							 delaycnt_ctrl_n = 1'b1;
							 send_rd_spidata_cmd_n = 1'b1;
							 rd_spidata_cmd_cnt_en = 1'b1;							 
						     
						  end
					   else if( dcm_rst_delaycnt <= 8)
					      begin
                       		 tx_wr_en    = 1'b1;
							 transfer_n  = 1'b1;                   
							 send_n      = 1'b1;
							 recv_n      = 1'b1;
                             delaycnt_ctrl_n = 1'b0;
                             send_rd_spidata_cmd_n = 1'b1;
                             rd_spidata_cmd_cnt_en = 1'b1;							 
					      end
					   else if(dcm_rst_delaycnt == 9)
					      begin
						     tx_wr_en    = 1'b1;
							 transfer_n  = 1'b0;                   
							 send_n      = 1'b0;
							 recv_n      = 1'b1;
                             delaycnt_ctrl_n = 1'b1;
							 send_rd_spidata_cmd_n = 1'b1;
							 rd_spidata_cmd_cnt_en = 1'b1;
						  end
					   else 
					      begin
						     tx_wr_en    = 1'b1;
							 transfer_n  = 1'b1;            // this will reset bytecnt when div10_cnt=9 
							 send_n      = 1'b1;
							 recv_n      = 1'b1;
							 delaycnt_ctrl_n = 1'b1;
							 send_rd_spidata_cmd_n = 1'b1;
							 rd_spidata_cmd_cnt_en = 1'b1;
						     
						  end
					   
					   end
	  rd_sensor       :begin
	                   if( dcm_rst_delaycnt <= 8)
					      begin
						     tx_wr_en    = 1'b1;
							 transfer_n  = 1'b1;                   
							 send_n      = 1'b1;
							 recv_n      = 1'b1;
                             delaycnt_ctrl_n = 1'b0;
							 send_rd_spidata_cmd_n = 1'b1;
							 rd_spidata_cmd_cnt_en = 1'b1;
						  end
					   else if( (bytecnt < 2 ) && (dcm_rst_delaycnt == 9) )
					      begin 
  						     tx_wr_en    = 1'b1;
						     transfer_n  = 1'b0;                   
						     send_n      = 1'b0;
						     recv_n      = 1'b1;
							 delaycnt_ctrl_n = 1'b1;
							 send_rd_spidata_cmd_n = 1'b1;
							 rd_spidata_cmd_cnt_en = 1'b1;
					      end
					   else if( (bytecnt >=2) && (bytecnt <=370) && (dcm_rst_delaycnt == 9))
					      begin
						     tx_wr_en    = 1'b1;
						     transfer_n  = 1'b0;                   
						     send_n      = 1'b1;
						     recv_n      = 1'b1;
							 delaycnt_ctrl_n = 1'b1;
							 send_rd_spidata_cmd_n = 1'b1;
							 rd_spidata_cmd_cnt_en = 1'b1;
						  end
					   else
					      begin
						     tx_wr_en    = 1'b1;
						     transfer_n  = 1'b1;                   
						     send_n      = 1'b1;
						     recv_n      = 1'b1;
							 delaycnt_ctrl_n = 1'b1;
							 send_rd_spidata_cmd_n = 1'b1;
							 rd_spidata_cmd_cnt_en = 1'b1;
						  end
					   end
      rd_spistat      :begin
	                   if( dcm_rst_delaycnt <= 8)
					      begin
						     tx_wr_en    = 1'b1;
							 transfer_n  = 1'b1;                   
							 send_n      = 1'b1;
							 recv_n      = 1'b1;
                             delaycnt_ctrl_n = 1'b0;
							 send_rd_spidata_cmd_n = 1'b1;
							 rd_spidata_cmd_cnt_en = 1'b1;
						  end
	                   else if( (bytecnt < 2) && (dcm_rst_delaycnt == 9) )
					      begin 
  						     tx_wr_en    = 1'b1;
						     transfer_n  = 1'b0;                   
						     send_n      = 1'b0;
						     recv_n      = 1'b1;
							 delaycnt_ctrl_n = 1'b1;
							 send_rd_spidata_cmd_n = 1'b1;
							 rd_spidata_cmd_cnt_en = 1'b1;
						  end
					   else if( (bytecnt >= 2) && (dcm_rst_delaycnt == 9) )
					      begin						      
  						     tx_wr_en    = 1'b1;
						     transfer_n  = 1'b0;                   
						     send_n      = 1'b1;
						     recv_n      = 1'b0;
							 delaycnt_ctrl_n = 1'b1;
							 send_rd_spidata_cmd_n = 1'b1;
							 rd_spidata_cmd_cnt_en = 1'b1;
						  end
					   else
					      begin						      
  						     tx_wr_en    = 1'b1;
						     transfer_n  = 1'b1;                   
						     send_n      = 1'b1;
						     recv_n      = 1'b1;
							 delaycnt_ctrl_n = 1'b1;
							 send_rd_spidata_cmd_n = 1'b1;
							 rd_spidata_cmd_cnt_en = 1'b1;
						  end
					   end
      rd_spidata      :begin
	                   if( dcm_rst_delaycnt <= 8)
					      begin
						     tx_wr_en    = 1'b1;
							 transfer_n  = 1'b1;                   
							 send_n      = 1'b1;
							 recv_n      = 1'b1;
                             delaycnt_ctrl_n = 1'b0;
							 send_rd_spidata_cmd_n = 1'b1;
							 rd_spidata_cmd_cnt_en = 1'b1;
						  end
	                   
					   else if( (bytecnt > 10) && (rx_first_n == 1'b1) &&
					            (rx_empty_n == 1'b0) && ( rd_spidata_cmd_cnt < 2 ) )
						  begin   
							 tx_wr_en    = 1'b1;
						     transfer_n  = 1'b0;                   
						     send_n      = 1'b1;
						     recv_n      = 1'b1;
							 delaycnt_ctrl_n = 1'b1;
							 send_rd_spidata_cmd_n = 1'b0;
							 rd_spidata_cmd_cnt_en = 1'b0;
					      end
					   else if( (bytecnt > 10) && (rd_spidata_cmd_cnt == 2) )
					      begin
						     tx_wr_en    = 1'b1;
						     transfer_n  = 1'b0;                   
						     send_n      = 1'b1;
						     recv_n      = 1'b0;
							 delaycnt_ctrl_n = 1'b1;
							 send_rd_spidata_cmd_n = 1'b1;
							 rd_spidata_cmd_cnt_en = 1'b1;
						  
						  end
					   else if( (bytecnt < 2) && (dcm_rst_delaycnt == 9)  )  
						  begin 
  						     tx_wr_en    = 1'b1;
						     transfer_n  = 1'b0;                   
						     send_n      = 1'b0;
						     recv_n      = 1'b1;
							 delaycnt_ctrl_n = 1'b1;
							 send_rd_spidata_cmd_n = 1'b1;
							 rd_spidata_cmd_cnt_en = 1'b1;
						  end
					   else if( (bytecnt >= 2) && (rx_full_n == 1'b1) )
					      begin						      
  						     tx_wr_en    = 1'b1;
						     transfer_n  = 1'b0;                   
						     send_n      = 1'b1;
						     recv_n      = 1'b0;
							 delaycnt_ctrl_n = 1'b1;
							 send_rd_spidata_cmd_n = 1'b1;
							 rd_spidata_cmd_cnt_en = 1'b1;
						  end
					   else
					      begin						      
  						     tx_wr_en    = 1'b1;
						     transfer_n  = 1'b1;                   
						     send_n      = 1'b1;
						     recv_n      = 1'b1;
							 delaycnt_ctrl_n = 1'b1;
							 send_rd_spidata_cmd_n = 1'b1;
							 rd_spidata_cmd_cnt_en = 1'b1;
						  end
					   end
					   
	  send_data2uart,
	  last_data2uart, 
      spi_stop        :begin
	                      tx_wr_en    = 1'b1;
						  transfer_n  = 1'b1;                   
						  send_n      = 1'b1;
						  recv_n      = 1'b1;
						  delaycnt_ctrl_n = 1'b1;
						  send_rd_spidata_cmd_n = 1'b1;
						  rd_spidata_cmd_cnt_en = 1'b1;
					   end
     default         : begin
	                      tx_wr_en    = 1'b1;
						  transfer_n  = 1'b1;                   
						  send_n      = 1'b1;
						  recv_n      = 1'b1;
						  delaycnt_ctrl_n = 1'b1;
						  send_rd_spidata_cmd_n = 1'b1;
						  rd_spidata_cmd_cnt_en = 1'b1;
					   end
	 
  endcase
end
//FSM control signals output
//--------------------------------------------


endmodule
%ProcessOfFingerPrint.m
clc;
clear;
clear all;
%--------------加载指纹文本文件-----------------------
fid=fopen('1x1.txt','r');
dd=fscanf(fid,'%x');
fclose(fid);
array=dd';
for i=0:199
    OriginFingerPrint(i+1,1:152)=array(i*152+1:i*152+152);
end
figure('name','OriginFingerPrint');
imshow(uint8(OriginFingerPrint));
%---------------灰度图像取反--------------------------
ReverseFingerPrint=255-OriginFingerPrint;
figure('name','ReverseFingerPrint');
imshow(uint8(ReverseFingerPrint));
%---------------进行二维适应性去噪过滤处理------------
FrontFilt=wiener2(ReverseFingerPrint,[3 3]);
figure('name','FrontFilt');
imshow(uint8(FrontFilt));
%---------------扩大图像的像素至400x304---------------
EnhanceFingerPrint=enhance_finger(FrontFilt);
%---------------取图像的中心点------------------------
[XofCenter,YofCenter] = centralizing(EnhanceFingerPrint);
figure('name','EnhanceFingerPrint');
imshow(uint8(EnhanceFingerPrint));
hold on;
plot(XofCenter,YofCenter,'or');
hold off;
%---------------二值化图像-----------------------------
[BinarizationFingerPrint,theta]=orientation(EnhanceFingerPrint);
figure('name','BinarizationFingerPrint');
imshow(uint8(BinarizationFingerPrint));
%----------------进行中值滤波处理----------------------
AfterFilt=median_filter(BinarizationFingerPrint);
figure('name','AfterFilt');
imshow(uint8(AfterFilt));
%----------------二值化图像细化处理--------------------
ThinFingerPrint=thinning(AfterFilt);
figure('name','ThinFingerPrint');
imshow(uint8(ThinFingerPrint));
%----------------找寻细化图像的特征点------------------
[Dpx,Dpy,Dpcount,Fpx,Fpy,Fpcount]=characterpoint(ThinFingerPrint);
hold on;
plot(Dpy,Dpx,'o');%特征端点用'o'标注
plot(Fpy,Fpx,'+');%特征分叉点用'+'标注
plot(XofCenter,YofCenter,'*r');%中心点用红色'*'标注
hold off;
%-----------------生成各特征点相对中心点的距离向量---------------
Dpcount=size(Dpx,2);
Fpcount=size(Fpx,2);
for i=1:Dpcount
    Dpdistant(i)=sqrt((Dpx(i)-YofCenter)^2+(Dpy(i)-XofCenter)^2);
end
for j=1:Fpcount
    Fpdistant(j)=sqrt((Fpx(j)-YofCenter)^2+(Fpy(j)-XofCenter)^2);
end   
%------------------特征模板建立----------------------------------------------
for i=1:Dpcount
    PointOfModel(i,1)=1;%特征端点分类为1
    PointOfModel(i,2)=Dpdistant(i);%特征端点相对中心点的距离向量
    PointOfModel(i,3)=theta(Dpx(i),Dpy(i))-theta(YofCenter,XofCenter);%特征端点相对中心点的方向向量
end
for i=Dpcount+1:Dpcount+Fpcount
    PointOfModel(i,1)=2;%特征分叉点分类为2
    PointOfModel(i,2)=Fpdistant(i-Dpcount);%特征分叉点相对中心点的距离向量
    PointOfModel(i,3)=theta(Fpx(i-Dpcount),Fpy(i-Dpcount))-theta(YofCenter,XofCenter);%特征分叉点相对中心点的方向向量
end    
%--------------------------------------------------------

4. Operation steps and simulation conclusion

 

  1. FSM module: Its main function is to initialize the Tx FIFO (transmit FIFO) after the system is reset, that is, write the command to be sent to the SPI sensor into the Tx FIFO, and then under the premise of meeting the SPI sensor timing, the FSM module controls the The Tx_rd_en signal reads out the command in the Tx FIFO and transmits it to the SPI module; when the Rx FIFO receives the fingerprint data, when the full flag Rx_full_n is valid, it means that the data in the receiving FIFO is full, then the FSM will control it through the relevant signal The SPI stops receiving data. When it detects that Rx_empty_n is valid (the receiving FIFO is empty), the FSM will send a corresponding signal to start the SPI to continue to receive data until all the fingerprint data is received.
  2. Tx FIFO module: The main function is to load the command to be sent during initialization, and then send the command under the control of the Tx_rd_en signal. Because the total number of commands does not exceed the depth of the FIFO, there is no need to empty the full flag.
  3. SPI module: Its main function is to provide the sensor with the clock signal SCK and the chip select signal SS when communicating with the external sensor, where the SCK and SS signals are initially generated and controlled by the FSM; when it is necessary to send commands to the sensor, The FSM will start the SCK and SS signals, and the SPI accepts the command read from the Tx FIFO and temporarily stores it in an 8-bit shift register tx_shifter[7:0]. After each SCK cycle, one bit is sent to MOSI, and 1 Byte is sent. After the tx_shifter will reload the new command and continue to send until the command is sent; when the SPI receives data from the sensor, the FSM will start the SCK and SS signals, and the shift register rx_shifter[7:0] in the SPI will collect the input port on the rising edge of SCK The data of MISO is shifted by one bit, and the data in the rx_shifter will be written into the Rx FIFO under the control of the FSM every 8 SCK clock cycles until the data is received.
  4. Rx FIFO module: The main function of this module is to cache the received fingerprint data to avoid the loss of fingerprint data, because the operating frequency of the SPI serial port in this system is 5MHz, while the operating frequency of the UART serial port is 38400Hz. The speed of fetching data from the FIFO is much lower than the speed of writing data to the Rx FIFO by the SPI. Rx FIFO can provide empty and full flag bits rx_empty_n, and rx_full_n to UART and FSM, so SPI and UART can work together.
  5. UART module: The main function of these modules is to communicate with the computer and display the received fingerprint data through the terminal of the computer. When the UART detects that rx_full_n is valid, it will send a read signal Rx_rd_en to read the data in the FIFO and send it to the computer, and stop when it detects that rx_empty_n is valid.

5. References 

[1] Zhao Jinming, Qian Lei, Wu Dong. Design and implementation of a fingerprint recognition acceleration structure based on FPGA [J]. Cyberspace Security, 2016, 7(005):59-64.

D234

6. How to obtain the complete source code

Method 1: Contact the blogger via WeChat or QQ

Method 2: Subscribe to the MATLAB/FPGA tutorial, get the tutorial case and any 2 complete source code for free

Guess you like

Origin blog.csdn.net/ccsss22/article/details/124207560
Recommended