The VL53L1X Time-of-Flight (ToF) module is a long-distance laser-ranging sensor that is ideal for applications like gesture recognition, user/obstacle detection, camera autofocus, etc. While its predecessor (the VL53L0X) boasted an absolute range of up to 2 meters, the pin-to-pin compatible VL53L1X surpasses it with an absolute range of 4 meters and the ability to reduce its field-of-view (FoV). Prototyping with this sensor has been made simple with the Arduino compatible X-NUCLEO-53L1A1 evaluation board. This shield is populated with one VL53L1X sensor, which may be used with the included glass cover window and spacers to simulate the sensor’s behavior in a practical application. Also included are two VL53L1X breakout boards which may be connected directly to the shield or used independently with flying leads. ST has not published any documentation describing the internal registers of the VL53L1X, meaning the VL53L1X driver (also referred to as the VL53L1X API) must be used for the MCU to interface with the sensor. This includes everything from initializing/configuring the sensor to performing ranging measurements.
At the time of writing, ST’s product page for the X-NUCLEO-53L1A1 states that this expansion board is "for the NUCLEO-F401RE and NUCLEO-L476RG development boards". This is a bit misleading. What they mean is that the example projects that have been provided for the X-NUCLEO-53L1A1 shield will only work with the NUCLEO-F401RE and NUCLEO-L476RG boards. For those wishing to get started as quickly as possible with the VL53L1X module, it is recommended that they use either of these Nucleo boards and modify ST’s example application. They might even consider purchasing the P-NUCLEO-53L1A1 evaluation kit which includes the X-NUCLEO-53L1A1 shield as well as a NUCLEO-F401RE board.
The firmware, hardware, and software used in this tutorial are as follows.
- This package contains the platform independent VL53L1X driver files (written in C). It can be found here.
- This is a software expansion package for the X-NUCLEO-53L1A1 expansion board, including a Board Support Package (BSP) that utilizes the VL53L1X driver. An example program that may be run on either the NUCLEO-F401RE and NUCLEO-L476RG development boards is provided. It can be found here.
- A Nucleo board
- An expansion board for evaluating the VL53L1X module. It can be purchased here.
- STM32CubeMX (Version 4.25.1)
- With this tool, an STM32Cube project can easily be created along with any desired C initialization code. It may be downloaded here.
- Atollic TrueSTUDIO for STM32 (Version 9.0.0)
- Feel free to use another IDE if you prefer, e.g. Keil, IAR, etc. However, since ST has recently acquired Atollic, it is likely that they will be placing more and more emphasis on TrueSTUDIO as a development tool as time goes on. It can be found here.
Creating an STM32Cube Project
For those who don’t already have an existing STM32Cube project, this section will quickly walk through setting one up using STM32CubeMX. For those looking for more detailed information and examples on using this tool, its user manual is a great resource.
Open STM32CubeMX and select New Project. Using either the MCU selector tab or the Board selector tab, choose the MCU/board being used for the project. The Board selector tab (Figure 1) is the preferred option when using an ST evaluation board because not only are there fewer options to wade through, but the Pinout view will be initialized with the pin assignments for the LEDs, buttons, communication interfaces, etc. Use the filters to narrow down your choices, make a selection, and click Start Project. When it asks you if you would like to initialize all peripherals with their default mode, click No.
The MCU selector can be used during the initial design phase of a project to choose an MCU or development board based on your desired criteria.
Creating a new STM32Cube project for the NUCLEO-F103RB board.Figure 1:
- The X-NUCLEO-53L1A1 expansion board communicates with the MCU via the I2C1 peripheral on pins PB8 (
I2C1_SCL) and PB9 (
I2C1_SDA). In the Pinout view, click on each of these pins and select their I2C alternate functions. When this is done, the pins should be highlighted orange because the I2C1 peripheral has not yet been enabled. To enable it, expand I2C1 in the peripheral tree and select I2C from the dropdown list. Pins PB8 and PB9 should change from orange to green (see Figure 2).
To print ranging data from the VL53L1X sensor to a serial terminal, pins PA2 and PA3 need to be configured as
USART2_RXrespectively. If the Board selector tab was used to create the project, the alternate functions for these pins should already be configured. If not, configure them in the same way the I2C1 pins were configured in the previous step. Then, enable the USART2 peripheral by expanding USART2 in the peripheral tree and selecting Asynchronous mode from the dropdown list, as shown in Figure 2. Again, the pins will change from orange to green.
Don’t worry about peripherals in the list with red crosses or yellow exclamation marks next to them. These are not errors, just FYI’s. For more information, move your mouse over the name of the peripheral with a symbol next to it and a tooltip will appear explaining the reason for the symbol.
Figure 2: Configuring the MCU pins and enabling the corresponding peripherals
Open the settings window (Figure 3) by choosing Project > Settings from the main menu bar. Give your project a name and choose where to save it. Also, select your desired Toolchain/IDE from the dropdown list. Everything else should be fine at its default value. Click OK.
Figure 3: Modifying the project settings
- Generate the code for your project by selecting Project > Generate Code from the main menu bar. If all goes well, a message will be displayed confirming successful code generation. Click Close.
- Open Atollic TrueSTUDIO and navigate to File > Open Projects from File System. If you are using an older version and this option is not available, navigate instead to File > Import, choose Projects from Folder or Archive and click Next. Clicking the Directory button will open a browser from which you can select the directory which contains your project. Make sure that the box next to your project name is checked, as shown in Figure 4, and click Finish.
Figure 4: Importing the project into TrueSTUDIO
The project should now be available in the Project Explorer. If you expand the project directory and then expand the Src directory, you should find the
main.c file. Looking through this file, you will see that along with the peripheral configuration functions, there are comments that designate user sections. Any code placed in these sections will be preserved the next time code is generated in STM32CubeMX.
Adding the VL53L1X Driver
Adding the VL53L1X driver to an STM32Cube project is quite simple once you understand the differences between the STSW-IMG007 package and the X-CUBE-53L1A1 package. The STSW-IMG007 package contains the VL53L1X driver along with a few "platform" files that must be modified by the programmer to port the driver to a specific MCU platform. The X-CUBE-53L1A1, on the other hand, is a complete STM32Cube expansion package that bundles the VL53L1X driver with a board support package (BSP) for the X-NUCLEO-53L1A1 expansion kit. In this package, one of the platform files has been modified to allow the driver to run on top of the STM32Cube HAL (hardware abstraction layer), thereby porting it to the entire STM32 MCU line. This modified platform file will be added along with the STSW-IMG007 files to our STM32Cube project. This way, we don’t have to modify the platform files ourselves to get the driver working on the STM32 platform.
In the steps below, files from both the STSW-IMG007 and X-CUBE-53L1A1 packages will be copied into the STM32Cube project we created in the previous section. This can easily be done in Atollic by dragging and dropping files into the desired folder in the Project Explorer.
Unzip the STSW-IMG007 package and add the core and platform directories to your project. For simplicities sake, I added them both to the Drivers directory after creating a subdirectory called VL53L1X, as shown in Figure 5. However, you can add them anywhere that makes the most sense to you. Exploring the X-CUBE-53L1A1 package will give you an idea of how ST chooses to organize these files in their projects.
Figure 5: The STM32Cube project's directory structure after adding the VL53L1X driver files
To port the VL53L1X driver to the STM32Cube project, unzip the X-CUBE-53L1A1 package and locate the file
en.X-CUBE-53L1A1/SMT32CubeExpansion_53L1A1_V1.0.0/Projects/Multi/Examples/VL53L1X/SimpleRangingExamples/Src/. Copy this file into the platform directory of the project, replacing the version that is already there.
The driver files we just added contain many header files that will not be found by the compiler unless we add the directories that contain them to the list of include directories. This can easily be done in Atollic by right-clicking on the directory in the Project Explorer and selecting Add/remove include path…, as shown in Figure 6a. This will result in the window shown in Figure 6b. Make sure both boxes are checked and click OK. For this example, this needs to be done for both the core directory and the platform directory.
a) Right-click on the folder and select Add/remove include path...
b) If the box is checked, the path will be added. If the box is unchecked, the path will be removed.
Figure 6: Adding a directory to the list of include directories
Alternatively, one could navigate to Project > Properties in the menu bar and from the resulting window, navigate to C/C++ General > Paths and Symbols. There, the desired directories can be added manually as shown in Figure 7.
The core and platform directories added to the list of included directoriesFigure 7:
main.cfile in the editor. In the user section for includes, include the file
vl53l1_api.h, as shown in Figure 8.
Figure 8: Including the VL53L1X API in
Open the file
vl53l1_platform_user_data.h(Figure 9a). Find the line where
#include "stm32xxx_hal.h"is commented out. Replace this line with an include statement for the
xx_hal.hfile for your MCU. In my case, I added
#include "stm32f1xx_hal.h". A few lines below this line, there should be a dummy structure called
I2C_HandleTypeDef. Either comment this structure out or delete it. These changes are shown in Figure 9b.
Figure 9: Modifying the
- Similarly, open the file
#include "stm32xxx_hal.h"with the appropriate
The project should now build successfully.
Using the VL53L1X Driver
Once the driver has been added to the project, you may wish to consult the VL53L1X API user manual to understand the different initialization, calibration, and ranging functions. However, while this manual provides plenty of excellent information about the driver and capabilities of the module, it lacks any example code. Luckily, as previously mentioned, the X-CUBE-53L1A1 package contains an example project that runs on two of the Nucleo boards. The
main.c file found in
en.X-CUBE-53L1A1/SMT32CubeExpansion_53L1A1_V1.0.0/Projects/Multi/Examples/VL53L1X/SimpleRangingExamples/Src/ contains a function called
AutonomousLowPowerRangingTest() that demonstrates how the module can be configured and used in either interrupt or polling mode.
For those not using either the NUCLEO-F401RE or the NUCLEO-L476RG, it requires a bit of extra work getting the aforementioned example project to a run on a different board. This is because the BSP for the X-NUCLEO-53L1A1 shield used in the example has not been ported to any of the other Nucleo boards. Rather than port it to my board, however, I chose to re-write the example without the BSP. The only annoyance in doing this is interfacing with the GPIO expanders on the X-NUCLEO-53L1A1 shield. These expanders (ST's STMPE1600 expanders) are essentially leftover from the previous iteration of this shield which utilized the VL53L0X module and included a 4-digit display. The final result is the
main.c file provided below.
To run this example on your board, start by follow the steps outlined in the sections above. Once you have an STM32Cube project with the VL53L1X driver added, copy and paste the user code sections from the
main.c file above to the
main.c file in your project. These sections will be designated by comments of the form
/* USER CODE BEGIN <section> */ and
/* USER CODE END <section> */. You cannot copy the entire
main.c unless you are also using the NUCLEO-F103RB board.
By default, my STM32Cube project was using the newlib-nano library, which decreases the functionality of the printf function. In order to print all of the ranging data to the serial terminal, I had to switch to the newlib standard library. In TrueSTUDIO, this can be done by choosing Project > Properties from the main menu bar, navigating to C/C++ Build > Settings, and selecting the Tool Settings tab. In the General settings, you can select your desired runtime library from the dropdown list.
Contact the Author
There are a few different ways one could go about adding the VL53L1X driver to their project, but I tried to select the simplest. Using both the STSW-IMG007 and X-CUBE-53L1A1 packages seems to require the least amount of file manipulation and reorganization. Hopefully you find the tutorial and example code helpful. If you have any questions or would like to provide feedback, feel free to send an email to firstname.lastname@example.org or visit Digi-Key's TechForum.