0:09
Hello and welcome to Controllers Tech.
0:11
In today's video, we're going to learn
0:14
how to interface the R307
0:16
fingerprint sensor module with an STM32
0:20
microcontroller. The R307
0:23
is an optical fingerprint scanner that
0:25
comes with a built-in DSP chip. What
0:28
this means is that the module not only
0:31
captures the fingerprint image but also
0:33
processes it internally. It takes care
0:36
of converting the image into a
0:38
fingerprint template that can be used
0:40
directly. So the microcontroller does
0:43
not need to handle heavy image
0:45
processing or recognition tasks. Another
0:48
key advantage of this sensor is its
0:50
storage capacity. The R307 can store up
0:54
to 1,000 fingerprint templates in its
0:56
internal memory. With just a few simple
0:59
commands, you can easily add new
1:01
fingerprints, search for existing ones,
1:04
or even delete entries when required.
1:07
The communication is also very
1:09
straightforward. The sensor uses UR or
1:13
the serial interface, which makes it
1:15
widely compatible with different
1:17
platforms. Whether you're working with
1:23
or even Raspberry Pi, the module could
1:26
be connected without difficulty. For
1:28
this demonstration, I'm going to use the
1:34
development board from WAX Studio. If
1:36
you're located in India, you can
1:38
conveniently purchase this board from
1:40
shop.controllerssteech.com.
1:42
Now, let's move to Cube IDE and begin by
1:46
creating a new project. As mentioned
1:48
earlier, I will be using the STM32F446RE
1:54
base development board. Give the project
1:56
a suitable name and then click on finish
1:58
to create it. The first step after
2:01
project creation is the clock
2:02
configuration. I will be using the
2:05
internal clock source and setting it to
2:07
run the system at the maximum frequency
2:10
of 180 MHz. Next, go to the system
2:14
settings, open the debug option, and
2:16
enable serial wire debug to make
2:19
debugging easier. Since the fingerprint
2:21
module communicates through UE, I will
2:24
configure UE4 for this purpose as it
2:28
provides a convenient connection option.
2:30
Enable the UE in asynchronous mode. The
2:33
R37 sensor uses a default baud rate of
2:39
bps. The word length should be set to 8
2:42
bits with no par and one stop bit. In
2:45
addition to this, I will enable one more
2:48
UE channel to display logs during
2:51
testing. On this board, the UR1 pins are
2:54
easier to access, so I will use them for
2:57
logging. You can set any baud rate for
2:59
the log UR, but I'm going to configure
3:05
bps. I'm also going to connect two LEDs
3:08
to the board. These LEDs will serve as
3:11
indicators. One will turn on if the
3:13
fingerprint matches and the other will
3:15
turn on if it does not match. So in
3:18
CubMx, set two pins as output mode.
3:21
These will be used to connect the LEDs.
3:25
That completes all the configuration we
3:27
need in CubMX. Now click on save to
3:30
generate the project code. Before moving
3:33
forward with the coding part, let's take
3:34
a quick look at the hardware schematic.
3:37
Here we have the R307S
3:40
fingerprint sensor module. Functionally,
3:42
it is the same as the R307.
3:46
The only difference is the size of the
3:48
PCB. The connector on this module has
3:51
pins labeled from 1 to six. Let's go
3:54
through them one by one. Pin one is the
3:56
VCC pin. This should be connected to the
3:59
5V pin on the STM32 board. The good
4:03
thing is the module automatically
4:06
converts this supply voltage to safe TTL
4:09
levels for UET communication. So it is
4:11
completely safe to connect it directly
4:13
to 5 Vs. Pin 2 is the ground pin and as
4:18
expected it should be connected to the
4:23
Pin 3 is the ueTX pin of module. This
4:27
pin must be connected to the RX pin of
4:31
Since I'm using UERT4, this pin will go
4:34
to PA1. Pin 4 is the URX
4:38
pin, which should be connected to the TX
4:43
Again, since Urt4 is being used, this
4:46
pin connects to PA0, which is the
4:51
The remaining pins of the connector are
4:53
not required for our project. So, we
4:55
will leave them unconnected. Now, let's
4:57
look at the LEDs. I have connected two
5:00
LEDs to pins PC0 and PC1. When a finger
5:05
placed on the sensor matches with the
5:07
data stored in the database, the green
5:09
LED will light up. If the fingerprint
5:12
does not match, the red LED will turn on
5:15
instead. For debugging and monitoring, I
5:18
am using Urt1 to output logs. Here the
5:22
STM 32 pin PA10 U31TX is connected to
5:27
the RX pin of a USB TURT module and this
5:30
module is then connected to the computer
5:33
using a USB cable. That's all for the
5:35
wiring diagram. Now let's move ahead and
5:38
continue with the project. Here I
5:40
already have the library files prepared
5:44
sensor and we will copy them into our
5:47
project. Place the C file inside the
5:50
source directory and a header file
5:52
inside the include directory of the
5:54
project. Let's begin by opening the
5:56
header file. In this file, you first
5:58
need to define the UR instance that
6:00
you're using to communicate with the
6:02
R307 sensor. This is important as the
6:06
library functions depend on the correct
6:08
UR configuration. If you run into any
6:11
issues during development, you can
6:13
enable debug logs by setting the debug
6:16
variable to one. With this option
6:18
enabled, the library will print detailed
6:20
logs for every step of execution, which
6:23
is very helpful for troubleshooting. The
6:26
main logs should always remain enabled
6:29
as they provide information about the
6:30
user interaction with the sensor. For
6:33
logging, I have used the standard printf
6:36
function. This makes it easier for us to
6:39
format and display the log data clearly
6:42
on the terminal. That's all the
6:44
configuration required in the header
6:46
file. Now let's move to the source file
6:48
and see the available functions along
6:50
with their usage. The R37
6:54
enroll function is used to enroll a
6:56
fingerprint. It requires a parameter
6:59
called page ID which is simply the
7:01
location number where the fingerprint
7:03
will be stored inside the sensor's
7:05
memory. The R307 sensor is capable of
7:08
storing up to 1,000 fingerprints with
7:12
IDs ranging from 1 to 1,000. Next is the
7:17
verify function. This function captures
7:20
a fingerprint image and searches through
7:22
the database to find a matching
7:24
template. It has two parameters. out
7:27
page ID which returns the ID of the
7:30
match fingerprint and score which
7:32
indicates how closely the captured
7:34
fingerprint matches the stored template.
7:36
Another useful function is verify
7:39
password. This is used to verify the
7:41
module's handshaking password. It takes
7:44
the password as a parameter and returns
7:47
how okay if the verification is
7:49
successful. If the password verification
7:52
fails, you can use the set password
7:54
function to set a new password for the
7:56
sensor. This function accepts the new
7:59
password as its parameter. There are
8:01
also functions to manage stored
8:04
fingerprints. For example, clear all
8:06
fingerprints will erase all the
8:08
fingerprints stored in the sensor's
8:10
memory. And the delete fingerprints
8:12
function can delete a specific number of
8:15
fingerprints starting from any given
8:17
page ID. To understand how these
8:19
functions work internally, let's take a
8:22
look at the R307 data sheet and scroll
8:25
down to the section describing the
8:27
command details. Here we can see the
8:29
general format of a command that needs
8:31
to be sent to the R307.
8:34
It begins with two bytes of header which
8:40
This is followed by four bytes of the
8:42
module address. By default, the module
8:45
address is set to 0x FF ff,
8:51
but it can be modified using specific
8:53
commands. Next, there is a one byte
8:56
package identifier. This bite helps the
8:59
sensor determine whether the packet
9:01
being sent is a command packet or a data
9:03
packet. After that, we have two bytes of
9:06
length which specify the total length of
9:09
the instruction code, parameter bytes,
9:11
and check sum. The instruction code
9:14
comes next. For example, 0x13
9:18
is the instruction code for the verify
9:20
password command. The instruction code
9:23
is followed by parameter bytes. In the
9:25
case of the verify password command, the
9:28
parameters would be four bytes
9:30
representing the password we want to
9:32
verify with the module. Finally, we add
9:35
two bytes of check sum which completes
9:38
the command packet. When the R307
9:41
receives a command, it responds with a
9:43
packet in a similar format. The first
9:46
six bytes which contain the header and
9:48
address remain unchanged. The package
9:52
identifier in the response is 0x07
9:56
which represents an acknowledgement
9:58
packet. Then we again have two bytes of
10:01
length followed by the confirmation code
10:03
and finally two bytes of check sum. The
10:06
confirmation code will vary depending on
10:08
the instruction. For example, in the
10:11
verify password command, the
10:13
confirmation code can be zero if the
10:15
password is correct, one if there was an
10:18
error in receiving the command or 13 if
10:21
the password is incorrect. Now let's see
10:24
how all of this is actually implemented
10:26
in the code. To keep things clear, I
10:29
will take the example of the verify
10:31
password command. The first step is to
10:33
prepare the parameters. Since the
10:35
password is 32 bits, we need to break it
10:39
down into four separate bytes. Once the
10:41
parameters are ready, we call the
10:43
function build command to construct the
10:46
final command packet. The function build
10:48
command takes a few parameters. The
10:51
first parameter is the structure where
10:53
the complete command will be stored. The
10:56
second parameter is the instruction code
10:58
itself. Next, we provide the instruction
11:01
parameters. And finally we pass the
11:04
number of parameter bytes inside the
11:06
build command function. The process
11:09
begins by inserting the header and the
11:11
device address at the start of the
11:12
buffer. After that the package
11:15
identifier is added. In this case the
11:18
identifier will be set to command. Next
11:21
the function calculates the total length
11:24
of the command package. This length
11:26
includes one bite for the instruction
11:28
code, the number of instruction
11:30
parameters and two bytes for the check
11:32
sum. Once the length is calculated, the
11:35
function copies the length, the
11:37
instruction code and the parameters into
11:40
the command buffer. Finally, it
11:42
calculates the check sum. The check sum
11:44
is obtained by adding all the data
11:47
starting from the sixth position in the
11:49
buffer. Once calculated, the checksum
11:52
bytes are also copied into the buffer.
11:55
At this point, the command buffer is
11:57
complete and it is ready to be sent to
11:59
the sensor through u. Now let's see how
12:02
these functions are used inside the main
12:05
C file. First include the R307
12:09
header file and then define a write
12:11
function for redirecting the printf
12:13
output. Here we will redirect all print
12:16
f outputs to ur1 which we already
12:19
configured earlier for logging. Inside
12:22
the main function, we start by calling
12:24
the function to verify the sensor
12:26
password. The default password is zero.
12:30
And if this matches the sensor's
12:32
password, the function will return how
12:35
okay. If the verification fails, we will
12:38
print the error logs on the terminal and
12:40
then call the error handler function. In
12:42
case the password does not match, you
12:45
can also call the function to set a new
12:47
password and then verify it again with
12:49
the sensor. Once the password step is
12:52
successful, the next task is to clear
12:54
all the fingerprints stored in the
12:56
sensor's memory. After clearing, we will
12:59
proceed to enroll a new fingerprint at
13:02
page ID 1. Here the program will print a
13:05
message asking the user to place their
13:07
finger on a sensor. When a user places
13:10
the finger, the enroll function will be
13:12
called. This function handles the
13:14
complete process. It captures the image,
13:18
converts it into character data and
13:20
finally stores at the specified memory
13:22
location inside the sensor. If the
13:24
process is successful, the function will
13:27
return how underscore okay. Next, we
13:30
move on to verifying a fingerprint. For
13:32
this, we first define two 16 bit
13:35
variables, one for the match page ID and
13:39
one for the score. The program will then
13:41
prompt the user to place a finger on the
13:43
sensor for verification. After that we
13:46
call the verify function. This function
13:49
captures the fingerprint image, searches
13:51
the database of stored fingerprints and
13:54
tries to find match. If a match is
13:56
found, the match page ID will be stored
13:59
in the variable we defined earlier and
14:01
the score will be stored in the score
14:03
variable. The score indicates how
14:05
closely the fingerprint matches with the
14:07
store template. The higher the score,
14:10
the better the match. In general, a
14:12
decent match will have a score of around
14:15
150 or more. That's all we need to get
14:18
the sensor tested for the first time. So
14:20
now let's go ahead and build the
14:22
project. The build is successful and
14:25
there are no errors. So the final step
14:27
is to flash the code to the STM32 board.
14:31
Now let's open the serial port that is
14:33
connected to UERT1 so we can view the
14:36
logs from the board. I will reset the
14:38
board once to start the process from the
14:40
beginning. As you can see in the logs,
14:43
the password verification is successful
14:46
and the sensor has been initialized
14:48
correctly. Now the program is asking us
14:50
to place a finger on the sensor. The
14:53
fingerprint will be stored at page ID1.
14:56
For this demo, I'm going to use my right
14:58
thumb. You can see in the logs that the
15:00
first image has been successfully
15:02
captured and converted. At this point,
15:04
we need to remove the finger and place
15:07
it again. After capturing the second
15:09
image, the sensor automatically merges
15:12
both images and generates a combined
15:15
template that completes the enrollment
15:17
process. And now the verify function
15:20
begins execution. Let's place the same
15:22
finger again. The logs confirm that a
15:25
match has been found at ID1 with a match
15:30
which indicates a very strong match. Now
15:33
let's reset the board once more to test
15:35
another case. This time I will register
15:38
the thumbrint again, but for
15:40
verification I will place my index
15:42
finger instead. As expected, the
15:44
fingerprint does not match the database.
15:47
So no match is found. To make the sensor
15:50
continuously check for fingerprints, I
15:52
have placed the verify function inside
15:55
the while loop. I have also added a
15:58
delay of 1 second before each new
16:00
verification. So the function will wait
16:03
before checking the next fingerprint.
16:05
Let's build the project again and flash
16:07
it to the board. We'll first complete
16:09
the enrollment process once more. Now
16:13
let me try verifying with my index
16:15
finger again. Since this fingerprint was
16:17
not stored earlier, there is no match
16:19
found. Because the verify function is
16:22
running inside the while loop, it
16:24
immediately asks for another fingerprint
16:27
again. Now let's try the thumb once
16:28
more. And as expected, this time the
16:31
match is found successfully. The verify
16:34
function continues to run in the
16:36
background, checking the sensor for new
16:38
fingerprints each time. So far,
16:41
everything is working exactly as
16:43
intended. However, there is one
16:45
important thing to note. Every time the
16:47
system reboots, the functions for
16:50
password verification, clearing
16:52
fingerprints, and enrollment will run
16:54
again. But we do not want to reenroll
16:56
fingerprints after every reboot.
16:59
Instead, these functions should only run
17:01
when we specifically need them. To
17:03
achieve this, we can use udt commands to
17:06
decide which function should run at
17:08
runtime. Although I am not implementing
17:10
full udert control here. I will simply
17:13
block these functions after the first
17:15
run. One way to do this is by storing a
17:18
value in the flash memory and checking
17:21
it during runtime. But since writing to
17:23
flash requires more effort, I will use a
17:26
simpler approach. we could take
17:28
advantage of the RDC backup register
17:30
which I also explained in detail during
17:33
the RDC tutorial. So let's go back to
17:35
cube MX and enable the RDC peripheral.
17:39
Do not enable anything else since we
17:42
only need its backup register
17:43
functionality. Now I have replaced the
17:45
earlier code with the updated logic.
17:48
First we define a variable to store how
17:51
many fingerprints we want to enroll. At
17:53
the beginning, we will verify the sensor
17:56
password as usual. Then we will check if
17:59
the RDC backup register already contains
18:02
this value. On the first run, this value
18:05
will not be present. So the code inside
18:07
the condition will execute. Here we will
18:10
first clear all the stored fingerprints.
18:13
Next, we will run the enrollment
18:15
function for as many fingerprints as
18:17
needed. Since storage in the sensor
18:20
begins from page ID 1, the loop variable
18:22
should also start at one. I have also
18:25
added retry functionality. So if
18:28
enrollment fails for a particular
18:30
finger, the program will attempt it
18:32
again. Once the required number of
18:34
fingerprints are successfully enrolled,
18:36
we will write the value into the RDC
18:39
backup register. This ensures that
18:41
enrollment will not run again the next
18:44
time the system reboots. After the
18:46
initial setup is complete, the program
18:49
moves to the main verification loop.
18:51
Here we continuously call the verify
18:54
function and based on its result, we
18:57
control the LEDs. First, we define the
19:00
LED ports and their pins. If the verify
19:04
function does not find a match, the red
19:07
LED will turn on to indicate failure.
19:10
Otherwise, if the fingerprint matches,
19:12
the green LED will turn on clearly
19:15
indicating that the match has been
19:17
found. After this indication, we will
19:19
wait for about 2 seconds and then turn
19:22
off both LEDs to reset the status. Let's
19:25
build the project now. It looks like
19:27
there is a small error in the pin
19:29
definition. Let me correct that and
19:32
rebuild the project again. Now,
19:34
everything compiles successfully. So
19:36
let's flash the code to the STM32 board.
19:39
First, I will enroll my right thumb. The
19:42
thumb has now been enrolled successfully
19:44
and stored at page ID 1. Next, I will
19:47
enroll my right index finger at page ID
19:50
2. With both fingers stored, let's go
19:53
ahead and verify them. As you can see,
19:56
when the correct finger is placed on the
19:58
sensor, the green LED lights up,
20:01
confirming the match. Now, let's try
20:03
with my left thumb. This time the
20:05
fingerprint is not found in the database
20:08
and therefore the red LED turns on. I
20:11
will try with my left index finger as
20:13
well. Again there is no match and the
20:16
red LED turns on to indicate failure.
20:19
But when I place the correct registered
20:21
finger again, the green LED turns on
20:24
once more. So everything is functioning
20:27
exactly as expected and our fingerprint
20:30
sensor is working perfectly. In addition
20:32
to what we tested here, you can also
20:34
make use of many more instructions
20:36
available in the data sheet. For
20:38
example, if you want to enroll multiple
20:41
fingerprints from different people at
20:43
different times and store them all, you
20:45
can use instruction 7, which checks
20:47
whether a template already exists at a
20:49
specific page ID. If the template is
20:52
present, the function will return okay,
20:55
and you can skip storing at that
20:56
location to avoid overwriting existing
20:59
data. Similarly, instruction 15 allows
21:02
you to change the device address if
21:04
needed. Now, let me quickly show you
21:07
some of the additional functions
21:08
available in the library. One such
21:11
function waits for a finger to be placed
21:14
on the sensor. It uses a timeout
21:16
feature. So, if the user does not place
21:19
their finger within the given time, the
21:21
function returns a timeout error. Inside
21:24
the enrollment function, I have set this
21:26
time out to 20 seconds, giving the user
21:29
enough time to place their finger on the
21:31
sensor. There's also another function
21:34
which waits for the finger to be removed
21:36
from the sensor before continuing. As I
21:39
mentioned at the beginning, you can
21:40
enable the debug logs to print detailed
21:43
debug level messages on the console.
21:46
These logs are generated from inside the
21:48
static functions and can be very helpful
21:50
in identifying and debugging any issues
21:53
with the sensor. So with this we have
21:56
successfully interfaced the R307
21:59
fingerprint sensor with an STM32
22:02
microcontroller using the URT interface.
22:05
The sensor can store up to 1,000
22:07
fingerprints which means it is suitable
22:10
for projects where you need to register
22:12
a large number of users. You can also
22:14
extend this project by controlling the
22:16
sensors operations using Urarti commands
22:19
or even building a GUI on a display to
22:22
make it more userfriendly. Let me know
22:24
in the comments if you would like me to
22:26
create a video demonstrating how to use
22:28
the sensor with a GUI interface. That is
22:31
all for this video. You can download the
22:34
complete project from the link given in
22:36
the description. If you have any
22:38
questions or doubts, feel free to leave
22:40
them in the comment section. Thank you
22:42
for watching and have a nice day ahead.