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