Key Reader Using STM32 DCMI and FMC

by JonMackey in Circuits > Arduino

129 Views, 2 Favorites, 0 Comments

Key Reader Using STM32 DCMI and FMC

Key Reader Demo

Last year I published my Key Code Cutter instructable. To use the Key Code Cutter you would enter the key’s code in order to cut a key.

This instructable is an accessory that uses a camera to determine the key code and sends it to the Key Code Cutter to be cut.

Even if you have zero interest in making keys, this instructable demonstrates the basics of how to use the STM32 DCMI and FMC features within an Arduino project. This project also demonstrates how to customize the compiler flags and package defaults without modifying the STM32 package.

Supplies

Camera OV5640.png

The main board and parts list is available on PCBWay here.

The camera board and parts list is available on PCBWay here.

(1) OV5640 500W camera source

(1) 1mm pitch, 15cm, 20P, AA (not reversed) FFC cable source

(2) M3x8 Flathead stainless steel screws source

(3) M3x20 Flathead stainless steel screws source

(6) M2x12 Flathead stainless steel screws source

(2) M2x5 Button head stainless steel screws source

(10) M2x3 brass inserts source

(2) M3x4 brass inserts source

(3) M3 20 series sliding T nuts source

(1) Adafruit 1626 12x40mm backlight source

(1) 100 Ohm 1/4 watt axial lead resistor for 12x40mm backlight. source

Wire and XH2.5-3P connector shells + pins, to connect the serial port on the main board to the CNC board. source

Wire and PH2.0-2P connector shell + pins, to connect the 12x40mm backlight to main board. source


As noted above, both of these (bare) boards are available on PCBWay.com. I’ve been using PCBWay since the first board I designed. High quality boards at a reasonable price, with excellent customer service. With the tariffs going into effect and the removal of import de minimis from China, I thought I would have to find a different source for my PCBs. It turns out that I’m now paying about the same as what I was paying before January 2025 to order boards shipped to the US. PCBWay offers the shipping method, Global Direct Shipping, that includes the US import fees for around $7 USD provided the total cost of the order is under $60. For my last order of 2 designs, 5 boards each, I paid a total of $17.22, including shipping and import fees. Note that PCBWay offered to sponsor this project but I declined. I feel reviews carry more weight when the reviewer isn’t being compensated.

The Boards

Bare Boards Front.jpeg

I designed two boards for this project, the main board, and the camera board.


Main Board

The main board uses a STM32F429 mcu to interface with the camera to stream video to a 16 bit parallel 3.5” 480 x 320 display. This board uses the DCMI and FMC features of the STM32F429. Note that this board doesn’t have any SRAM other than the 256KB available in the STM32F429 itself. This means that this board would not be useful for creating high resolution photos. When high res is used the line data is processed immediately and only a small amount of memory is needed.


Soldering the main board

- add the STM32F429 and the 40 pin FFC connector to the board first before any other parts. The pins on these two parts have a 0.5mm pitch making them difficult to mount. It’s easier to accurately check continuity on these two parts before the board is fully populated.

- mount the rest of the surface mount parts.

- cut any through hole pins flush with the display side of the board before soldering to minimize the pin height. The display back is bare metal, so to avoid any shorts when the display is mounted, these pins must be as close to flush as possible.


Mounting the display

Display

The 3.5” display should be mounted to the back of the main board using three double layer strips of double sided tape suitable for displays. I recommend using 8mm wide 3M brand 9080 double sided tape. Use six strips total to double the thickness to avoid the bare metal back of the display coming in contact with the pins of the connectors and power switch. My AliExpress source no longer offers this tape. Two years ago I paid under $5 USD including shipping for a 50 meter roll. The best price I could locate today was on eBay


Alignment Accuracy

Alignment Done

The camera board is an amalgamation of what I could glean from the OV5640 documentation and available camera module schematics. The main reason I designed my own was I wanted to use flat cables (FFC) rather than bulky 2.54 pitch headers and connectors.

The camera board has two 20 pin FFC connectors, one on each end to allow the camera to be oriented in either direction relative to the main board’s 20 pin connector.

The 3D Parts

3D Parts.png

Print the 3D parts using black PLA.

Assembly

Assembly.jpeg

Assembly:

Using a brass insert iron with a tip sized for the insert: source

- insert 8 M2 brass inserts into the Main Board Cover and Camera Middle prints.

- insert 2 M2 brass inserts into the Camera Middle w Open Side print.

- insert 2 M3 brass inserts into the U Base print (main board support arms.)


Backlight

Preparing the 12x40mm backlight:

Cut a length of 2 conductor 26 to 22 gauge wire, approximately 18cm long. The backlight requires a current limiting resistor. The resistor specified in the supplies step is a 100ohm 1/4 watt axial lead resistor. From one end, carefully cut just the red wire at 4cm. Remove wire the length of the resistor from the cut red wire. Strip the ends of the cut red wire and apply solder. Snip the resistor leads to size and solder in the resistor. Slide a piece of heat shrink tubing over the resistor, the soldered connection, and the black wire. Apply heat to shrink the tubing.


Using a DVM, determine the positive LED lead of the backlight. Cut both backlight leads to about 8mm and apply solder. From the end of the wire closest to the resistor, strip about 2mm from each conductor and apply solder. Slide a 2cm piece of heat shrink over both conductors. Slide an additional length of heat shrink tubing over just the red conductor. Solder the red conductor to the positive backlight lead and the black conductor to the other lead. Slide forward and apply heat to shrink the tubing on the red conductor. Slide forward and apply heat to shrink the tubing covering both wires as shown in the picture below.


On the other end of the wire, attach a PH2.0-2P connector as shown in the picture below showing the correct polarity.


Backlight Assy PHP2.0 Zoomed

Using a strip of the same tape used to adhere the display to the main board, install the 12x40mm backlight on the Main Board Base print.


Connect one end of the15cm, 20P, FFC cable to the main board as shown below with the blue tab facing up, away from the board.

Main Board

Place the main board into the Main Board Cover print. Place the Main Board Base print over the cover. Use 4 M2x12 flathead screws to secure it to the cover.

Main Board Cover

Main Assy Back

The Software

Arduino Tools Menu.png


The software for this project can be downloaded from GitHub here.

If you don't already have the STM32 boards package loaded, you can load it via Arduino IDE->Tools->Board->Boards Manager... Then load the "STM32 boards groups". I'm using version 2.5.0.

The main board's mcu is a STM32F429VGT6. The software only uses about 10% of the 1MB flash memory.

The 5V power for the main board can be supplied from either the 2 pin XH2.5 connector, or the USB-C connector. The USB-C connector has 5.1K resistors that requests at least 1.5A of power. The board uses much less than 1.5A, generally around 250mA at most when both the camera and display are active.

Apply power and verify that you can measure 3.3V on the main board at the large pad of the AMS1117 voltage regulator and ground. Ground can be found on any bare metal parts, such as the power switch, Micro SD, or USB connector.

Configure the board in the Arduino IDE's Tool menu based on the screenshot above.

Open the Arduino IDE Settings and point the Sketchbook Location to the Key Reader folder, the folder that contains the libraries folder.

Open the sketch KeyReader.ino and verify that it builds.

If there are no errors, attach your ST-Link to the ST-Link header on the main board and upload the sketch. Note that you should only connect 3 wires: GND, SWCLK and SWIO. You don't want to power the main board via the ST-Link cable.


If there are no errors, proceed to the next step or continue below for more detail about the software.


History: A few years ago I wrote a set of classes that I use to interface several common displays. The base display controller class handles common drawing functions such as lines, circles and rectangles. The display controller is used by another set of classes that draws text in any font. On top of these classes are a set of classes that draw the user interface elements and interpret clicks from the touch screen.


Classes:

There are two classes that have only been tested to work with a STM32F4 series mcu, TFT_ILI9488P and DCMI_OV5640.


The TFT_ILI9488P class is a subclass of DisplayController. This class controls the ILI9488 display and the STM32 Flexible Memory Controller (FMC.)

The DCMI_OV5640 class controls the OV5640 camera and the Digital Camera Interface (DCMI.)


In order to enable the FMC and DCMI modules, two defines were added to “Key Reader/KeyReader/hal_conf_extra.h”. Using hal_conf_extra.h allows you to change the hal configuration specific to a single Arduino project, without having to modify the code in the STM32 package.


Any non-standard pin assignments were changed by adding new entries in “Key Reader/KeyReader/build_opt.h”


Class DCMI_OV5640:

Although the DCMI_OV5640 class name appears to be a general class, it turned out to be specific to the function of reading a key, so the name is a bit misleading.


The DCMI_OV5640 performs two functions:

- it initializes the camera to stream video to the display.

- it initializes the camera to stream high resolution video data that is processed as it’s received when doing a scan.


Determining the camera initialization settings wasn’t easy and still isn’t perfect. After looking at a lot of publicly available code, all are based on a single document provided by the camera’s manufacturer. Looking at threads on the the camera initialization by various authors you see a lot of comments like, “it’s working, don’t change anything.” I spent a lot of time trying to determine the differences between various initialization settings.


My changes to the initialization code:

- change the window dimensions to eliminate areas that are not needed.

- hard code the exposure. It’s an enclosed box, the exposure is always the same.

- control of the camera strobe overhead LEDs.

- enable the use of the external 1.5V regulator.


This last one, the use of the external regulator, is odd because none of the code by other authors I looked at use the external regulator yet their boards contain the external 1.5V regulator AND the conditions for when it should be used as defined by the manufacturer.


Modified versions of a few STM32 hal routines are part of the DCMI_OV5640 class. Rather than use HAL_DCMI_Start_DMA(), I use my own version named StartDMA. HAL_DCMI_Start_DMA makes the assumption that an entire frame will be buffered where my version only buffers two lines of data. When streaming to the display as color or B&W, RGB565 data is copied as is, or YUV422 data is lightly processed to make it B&W. When streaming high res data, each YUV422 data line is reduced to a single 16 bit value representing the run of black pixels following a run of white pixels. Because the key is vertical in the frame, this 16 bit value represents the thickness of the key at that line. Processing the high res data as it arrives reduces nearly 4MB of data to less than 4KB, avoiding the need to have external frame memory.


Class TFT_ILI9488P

For the camera to stream video you need a display faster than the data stream coming from the camera. All of the displays I’ve used before this project were serial, either I2C or SPI, too slow for video. For this project I wrote a display controller subclass that controls a 16 bit parallel TFT ILI9488 display utilizing the STM32 FMC interface. This parallel interface is quite fast.

TFT_ILI9488P isn’t specific to this project. It will work on any STM32F4 FMC capable mcu where you need a ILI9488 parallel display. As noted above a parallel display is many times faster than a serial display. Commands are written to the base address. Data is written to the base address + the address line mask. There is no begin transaction, end transaction overhead that you have with serial, you just write to an address and the rest is handled by the mcu.


Class XKeyView

XKeyView is a subclass of XView. XKeyView manages a window that displays the preview stream from the camera. XKeyView also analyzes and displays the high res data to determine a key’s key code. If any of the cut depths are outside of a set tolerance, the cut is considered custom. When the cut information is sent to the key code cutter control board, either just the key code is sent, or the key code plus any custom cut depths are sent.


Class KeyReaderSTM32

KeyReaderSTM32 manages the UI and ties all of the classes together.

Setup

Setup.jpeg

Before the touch panel can be used it must be aligned. There are two buttons on the main board labeled Enter and Cancel. Pressing the Enter button or sending the letter ‘A’ via the serial port, will display the alignment screen as shown below.

Aligning the display


Follow the displayed instructions. Keep selecting the white dot within the circle till the magenta dot covers or nearly covers the white dot.

Alignment Accuracy

Alignment Done


As noted in the instructions in the screenshot above, you keep selecting the white dot within the white circle as they appear in each corner after each click till the accuracy is acceptable. Acceptable is defined as the magenta dots completely or mostly covering the associated white dots. You then press the Enter button on the main board or send the letter ‘S’ via the serial port, to save the alignment parameters to the EEPROM. Pressing Cancel on the main board or sending the letter ‘C’ via the serial port, exits display alignment without saving the settings to EEPROM.


The lens needs to be refocused to an object closer than the focus set at the factory. The OV5640 camera lens has a small dab of hard glue that locks the threads on the camera lens. Using a sharp blade, scratch off the hard glue so that the focus can be changed. Verify that you can turn the lens. Mount the camera board on the “Camera Middle w Open Side” print using two M2x5 screws. Attach the 15cm flat cable with the blue tab facing up. The flat cable should already be attached to the main board. Apply power to the main board and move the power switch to the on position, the position closest to the center of the board. On the main board display, select Color as the Preview type, then press the Preview button. With a key inserted in the key slot under the camera, an out of focus key should appear. Adjust the lens on the camera till an in focus, sharp image appears.


Mount the camera board on the “Camera Middle” print using two M2x5 button head screws. Mount the camera board cover using two M2x12 flathead screws.


Currently only Schlage and Kwikset house keys have specifications defined. These are hard coded at the start of KeyReaderSTM32.cpp. If anyone actually builds this project and needs to add more key types, send me a message and I’ll describe the steps. It’s not difficult.


Select the Keyway for the test key you will be using below to adjust the alignment.


With the preview mode set to B&W, press the Preview button. A preview image should appear on the main window. Adjust the key verifying that it is in the key slot firmly against the stop and straight. You can tell it’s straight when you don’t see a jagged edge on the bottom flat edge of the key blade.


Press the Scan button. After a few seconds a magnified image of the key cuts should appear. Note that the few second delay is due to the fact that the first 3 high res frames are always skipped because they are unusable. Once the camera stabilizes, around the 4th frame, the data is checked for errors. In some cases a few more frames are skipped.

Scan SC wo adjustments


Once a magnified image of the key cuts appears, there should be a vertical red line in the center of each cut. The left most red line should always be in the center of the first cut, and the remainder of the red lines may be a bit off center.


Utilities Dialog


From the main menu, open the Utilities dialog. Select ‘Show adjustment controls’, then close the dialog. In the main window you should now see additional controls to set the pin tolerance, centers and depths. The pin tolerance is the allowable deviation from the key specification for any pin in pixels. The scale from pixels to unit of measurement is controlled by the centers and depths values. The centers value is the horizontal scale along the key blade, and the depths value is the vertical scale across the blade. I expected these scales to be the same but they’re slightly different, and most likely different for each camera based on focus. Note that a scale value of 6200 is 0.00062 of an inch per pixel. Therefore 6200 and 6300 are quite close. The allowed range for scale values is 6000 to 7000.


Scan SC w adjustments


The first adjustment to be made is to the centers scale. Changing the value of the Centers scale will move all of the center lines to the right of the first cut. The Centers value can be changed from the main window using the up and down stepper control or by sending a new value via the serial port. Using the serial port is the fastest way of changing a value. The serial format is the letter c followed by 4 digits and a newline. For example, ‘c 6300’ will change the centers value in the main window to 6300 and will redraw the red center lines to reflect the new centers scale. Make changes to the centers value till the red center lines are, on average, in the center of each cut.


Now adjust the depths scale. Like the centers scale, the depths scale can be changed using the stepper control or via the serial port. The serial format is the letter d followed by 4 digits and a newline character. For example, ‘d 6375’ will change the depths value in the main window to 6375 and will redraw the cut pin indexes above each red center line to reflect the new depths scale. When the adjustment controls are showing, the cut pin index above each red center line will also include its deviation from the specification. Play with the depths value till the average deviation is low, something within the tolerance. When it’s outside of the tolerance the letter ‘C’ will replace the expected cut pin index which means it’s custom. In most cases you don’t want a custom cut. For most house locks, the key cuts should be standard indexes. When you’re out of tolerance it generally means that the depths scale is off.


Once you get scale values that appear to be accurate, try scanning other keys to verify the accuracy.


If the accuracy looks good, press the Save button to save your changes to EEPROM.


Go back to the utilities dialog and uncheck the ‘Show adjustment controls’ checkbox to hide the adjustment controls in the main window.


At this point key reader is ready to use. Connect the serial line to the key machine control board. Verify that the serial ground pins are connected between boards and that the transmit and receive lines are swapped.


Serial command summary:

All serial commands should be terminated with a newline character.

>HHHHHHHH Set Unix Time where HHHHHHHH is the unix time in hex.

A Show the display alignment screen.

S Save the display alignment to EEPROM

C Cancel display alignment, if cancellable.

D Toggle sending debug strings to the serial port (by default OFF)

c #### Set the center scale in the UI.

d #### Set the depths scale in the UI.

t ## Set the pin tolerance in the UI.

s Save UI adjustments to EEPROM.

i Dump the current scan summary, if any, to the serial port.

Normal Operation

Scan.jpeg

To cut a key

- mount a key blank in the key machine's key holder.

- insert a key in the key slot under the camera.

- preview the key by pressing Preview.

- verify that the key is up against the stop and is straight.

- scan the key by pressing Scan.

- once the scan finishes press the Cut button.


That’s it. The cut information will be sent to the key machine control board and cutting will begin.