Merge pull request #347 from pimoroni/driver/vl53l5cx

Add vl53l5cx driver, MicroPython bindings and examples
pull/355/head
Philip Howard 2022-05-11 10:52:25 +01:00 zatwierdzone przez GitHub
commit 84b6a0c8ee
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
20 zmienionych plików z 1264 dodań i 0 usunięć

4
.gitmodules vendored
Wyświetl plik

@ -17,3 +17,7 @@
[submodule "micropython/modules/qrcode"]
path = micropython/modules/qrcode
url = https://github.com/pimoroni/QR-Code-Generator
[submodule "drivers/vl53l5cx/src"]
path = drivers/vl53l5cx/src
url = https://github.com/ST-mirror/VL53L5CX_ULD_driver
branch = lite/en

Wyświetl plik

@ -29,3 +29,4 @@ add_subdirectory(hub75)
add_subdirectory(uc8151)
add_subdirectory(pwm)
add_subdirectory(servo)
add_subdirectory(vl53l5cx)

Wyświetl plik

@ -0,0 +1 @@
include(${CMAKE_CURRENT_LIST_DIR}/vl53l5cx.cmake)

Wyświetl plik

@ -0,0 +1,235 @@
/*******************************************************************************
* Copyright (c) 2020, STMicroelectronics - All Rights Reserved
*
* This file is part of the VL53L5CX Ultra Lite Driver and is dual licensed,
* either 'STMicroelectronics Proprietary license'
* or 'BSD 3-clause "New" or "Revised" License' , at your option.
*
********************************************************************************
*
* 'STMicroelectronics Proprietary license'
*
********************************************************************************
*
* License terms: STMicroelectronics Proprietary in accordance with licensing
* terms at www.st.com/sla0081
*
* STMicroelectronics confidential
* Reproduction and Communication of this document is strictly prohibited unless
* specifically authorized in writing by STMicroelectronics.
*
*
********************************************************************************
*
* Alternatively, the VL53L5CX Ultra Lite Driver may be distributed under the
* terms of 'BSD 3-clause "New" or "Revised" License', in which case the
* following provisions apply instead of the ones mentioned above :
*
********************************************************************************
*
* License terms: BSD 3-clause "New" or "Revised" License.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*******************************************************************************/
#include "platform.h"
#include "pico/stdlib.h"
uint8_t RdByte(
VL53L5CX_Platform *p_platform,
uint16_t RegisterAdress,
uint8_t *p_value)
{
const uint8_t buf[2] = {
RegisterAdress >> 8,
RegisterAdress & 0xff
};
i2c_write_blocking(p_platform->i2c, p_platform->address, buf, sizeof(buf), true);
if(i2c_read_blocking(p_platform->i2c, p_platform->address, p_value, 1, false) != PICO_ERROR_GENERIC){
return 0;
}
return 255;
}
uint8_t WrByte(
VL53L5CX_Platform *p_platform,
uint16_t RegisterAdress,
uint8_t value)
{
const uint8_t buf[3] = {
RegisterAdress >> 8,
RegisterAdress & 0xff,
value,
};
if(i2c_write_blocking(p_platform->i2c, p_platform->address, buf, sizeof(buf), false) != PICO_ERROR_GENERIC) {
return 0;
}
return 255;
}
uint8_t WrMulti(
VL53L5CX_Platform *p_platform,
uint16_t RegisterAdress,
uint8_t *p_values,
uint32_t size)
{
uint8_t buf[2];
buf[0] = RegisterAdress >> 8;
buf[1] = RegisterAdress & 0xff;
// Send the 16-bit address with no STOP condition
int result = i2c_write_blocking(p_platform->i2c, p_platform->address, buf, sizeof(buf), true);
// Handle an error early... it gets dicey from here
if(result == PICO_ERROR_GENERIC) return 255;
// The VL53L5CX does not support "Repeated Start" and the Pico's I2C API doesn't
// let us send more bytes without sending another start condition.
// The horrow below lets us send out "p_values" followed by a STOP condition,
// without having to copy everything into a temporary buffer.
uint8_t *src = p_values;
// Send the rest of the data, followed by a STOP condition
// This re-implements the relevant portion of i2c_write_blocking_internal which is NOT sent a timeout check function by i2c_write_blocking
for (int byte_ctr = 0; byte_ctr < size; ++byte_ctr) {
bool last = byte_ctr == size - 1;
p_platform->i2c->hw->data_cmd =
bool_to_bit(last) << I2C_IC_DATA_CMD_STOP_LSB | *src++;
// Wait until the transmission of the address/data from the internal
// shift register has completed. For this to function correctly, the
// TX_EMPTY_CTRL flag in IC_CON must be set. The TX_EMPTY_CTRL flag
// was set in i2c_init.
do {
tight_loop_contents();
} while (!(p_platform->i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_TX_EMPTY_BITS));
if (p_platform->i2c->hw->tx_abrt_source) {
// Note clearing the abort flag also clears the reason, and
// this instance of flag is clear-on-read! Note also the
// IC_CLR_TX_ABRT register always reads as 0.
p_platform->i2c->hw->clr_tx_abrt;
// An abort on the LAST byte means things are probably fine
if(last) {
// TODO Could there be an abort while waiting for the STOP
// condition here? If so, additional code would be needed here
// to take care of the abort.
do {
tight_loop_contents();
} while (!(p_platform->i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_STOP_DET_BITS));
} else {
// Ooof, unhandled abort. Fail?
return 255;
}
}
}
// Not sure it matters where we clear this, but by default a "nostop" style write
// will set this flag so the next transaction starts with a "Repeated Start."
p_platform->i2c->restart_on_next = false;
return 0;
}
uint8_t RdMulti(
VL53L5CX_Platform *p_platform,
uint16_t RegisterAdress,
uint8_t *p_values,
uint32_t size)
{
const uint8_t buf[2] = {
RegisterAdress >> 8,
RegisterAdress & 0xff
};
i2c_write_blocking(p_platform->i2c, p_platform->address, buf, sizeof(buf), true);
if(i2c_read_blocking(p_platform->i2c, p_platform->address, p_values, size, false) != PICO_ERROR_GENERIC){
return 0;
}
return 255;
}
uint8_t Reset_Sensor(
VL53L5CX_Platform *p_platform)
{
uint8_t status = 0;
/* (Optional) Need to be implemented by customer. This function returns 0 if OK */
/* Set pin LPN to LOW */
/* Set pin AVDD to LOW */
/* Set pin VDDIO to LOW */
WaitMs(p_platform, 100);
/* Set pin LPN of to HIGH */
/* Set pin AVDD of to HIGH */
/* Set pin VDDIO of to HIGH */
WaitMs(p_platform, 100);
return status;
}
void SwapBuffer(
uint8_t *buffer,
uint16_t size)
{
uint32_t i, tmp;
/*for(auto i = 0u; i < size / 4u; i++) {
uint32_t *dword = &((uint32_t *)buffer)[i];
*dword = __builtin_bswap32(*dword);
}*/
/* Example of possible implementation using <string.h> */
for(i = 0; i < size; i = i + 4)
{
tmp = (
buffer[i]<<24)
|(buffer[i+1]<<16)
|(buffer[i+2]<<8)
|(buffer[i+3]);
memcpy(&(buffer[i]), &tmp, 4);
}
}
uint8_t WaitMs(
VL53L5CX_Platform *p_platform,
uint32_t TimeMs)
{
sleep_ms(TimeMs);
return 0;
}

Wyświetl plik

@ -0,0 +1,219 @@
/*******************************************************************************
* Copyright (c) 2020, STMicroelectronics - All Rights Reserved
*
* This file is part of the VL53L5CX Ultra Lite Driver and is dual licensed,
* either 'STMicroelectronics Proprietary license'
* or 'BSD 3-clause "New" or "Revised" License' , at your option.
*
********************************************************************************
*
* 'STMicroelectronics Proprietary license'
*
********************************************************************************
*
* License terms: STMicroelectronics Proprietary in accordance with licensing
* terms at www.st.com/sla0081
*
* STMicroelectronics confidential
* Reproduction and Communication of this document is strictly prohibited unless
* specifically authorized in writing by STMicroelectronics.
*
*
********************************************************************************
*
* Alternatively, the VL53L5CX Ultra Lite Driver may be distributed under the
* terms of 'BSD 3-clause "New" or "Revised" License', in which case the
* following provisions apply instead of the ones mentioned above :
*
********************************************************************************
*
* License terms: BSD 3-clause "New" or "Revised" License.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*******************************************************************************/
#ifndef _PLATFORM_H_
#define _PLATFORM_H_
#pragma once
#include <stdint.h>
#include <string.h>
#include "hardware/i2c.h"
/**
* @brief Structure VL53L5CX_Platform needs to be filled by the customer,
* depending on his platform. At least, it contains the VL53L5CX I2C address.
* Some additional fields can be added, as descriptors, or platform
* dependencies. Anything added into this structure is visible into the platform
* layer.
*/
typedef struct
{
/* To be filled with customer's platform. At least an I2C address/descriptor
* needs to be added */
/* Example for most standard platform : I2C address of sensor */
uint16_t address;
i2c_inst_t *i2c;
} VL53L5CX_Platform;
/*
* @brief The macro below is used to define the number of target per zone sent
* through I2C. This value can be changed by user, in order to tune I2C
* transaction, and also the total memory size (a lower number of target per
* zone means a lower RAM). The value must be between 1 and 4.
*/
#define VL53L5CX_NB_TARGET_PER_ZONE 1U
/*
* @brief The macro below can be used to avoid data conversion into the driver.
* By default there is a conversion between firmware and user data. Using this macro
* allows to use the firmware format instead of user format. The firmware format allows
* an increased precision.
*/
// #define VL53L5CX_USE_RAW_FORMAT
/*
* @brief All macro below are used to configure the sensor output. User can
* define some macros if he wants to disable selected output, in order to reduce
* I2C access.
*/
// #define VL53L5CX_DISABLE_AMBIENT_PER_SPAD
// #define VL53L5CX_DISABLE_NB_SPADS_ENABLED
// #define VL53L5CX_DISABLE_NB_TARGET_DETECTED
// #define VL53L5CX_DISABLE_SIGNAL_PER_SPAD
// #define VL53L5CX_DISABLE_RANGE_SIGMA_MM
// #define VL53L5CX_DISABLE_DISTANCE_MM
// #define VL53L5CX_DISABLE_REFLECTANCE_PERCENT
// #define VL53L5CX_DISABLE_TARGET_STATUS
// #define VL53L5CX_DISABLE_MOTION_INDICATOR
/**
* @param (VL53L5CX_Platform*) p_platform : Pointer of VL53L5CX platform
* structure.
* @param (uint16_t) Address : I2C location of value to read.
* @param (uint8_t) *p_values : Pointer of value to read.
* @return (uint8_t) status : 0 if OK
*/
uint8_t RdByte(
VL53L5CX_Platform *p_platform,
uint16_t RegisterAdress,
uint8_t *p_value);
/**
* @brief Mandatory function used to write one single byte.
* @param (VL53L5CX_Platform*) p_platform : Pointer of VL53L5CX platform
* structure.
* @param (uint16_t) Address : I2C location of value to read.
* @param (uint8_t) value : Pointer of value to write.
* @return (uint8_t) status : 0 if OK
*/
uint8_t WrByte(
VL53L5CX_Platform *p_platform,
uint16_t RegisterAdress,
uint8_t value);
/**
* @brief Mandatory function used to read multiples bytes.
* @param (VL53L5CX_Platform*) p_platform : Pointer of VL53L5CX platform
* structure.
* @param (uint16_t) Address : I2C location of values to read.
* @param (uint8_t) *p_values : Buffer of bytes to read.
* @param (uint32_t) size : Size of *p_values buffer.
* @return (uint8_t) status : 0 if OK
*/
uint8_t RdMulti(
VL53L5CX_Platform *p_platform,
uint16_t RegisterAdress,
uint8_t *p_values,
uint32_t size);
/**
* @brief Mandatory function used to write multiples bytes.
* @param (VL53L5CX_Platform*) p_platform : Pointer of VL53L5CX platform
* structure.
* @param (uint16_t) Address : I2C location of values to write.
* @param (uint8_t) *p_values : Buffer of bytes to write.
* @param (uint32_t) size : Size of *p_values buffer.
* @return (uint8_t) status : 0 if OK
*/
uint8_t WrMulti(
VL53L5CX_Platform *p_platform,
uint16_t RegisterAdress,
uint8_t *p_values,
uint32_t size);
/**
* @brief Optional function, only used to perform an hardware reset of the
* sensor. This function is not used in the API, but it can be used by the host.
* This function is not mandatory to fill if user don't want to reset the
* sensor.
* @param (VL53L5CX_Platform*) p_platform : Pointer of VL53L5CX platform
* structure.
* @return (uint8_t) status : 0 if OK
*/
uint8_t Reset_Sensor(
VL53L5CX_Platform *p_platform);
/**
* @brief Mandatory function, used to swap a buffer. The buffer size is always a
* multiple of 4 (4, 8, 12, 16, ...).
* @param (uint8_t*) buffer : Buffer to swap, generally uint32_t
* @param (uint16_t) size : Buffer size to swap
*/
void SwapBuffer(
uint8_t *buffer,
uint16_t size);
/**
* @brief Mandatory function, used to wait during an amount of time. It must be
* filled as it's used into the API.
* @param (VL53L5CX_Platform*) p_platform : Pointer of VL53L5CX platform
* structure.
* @param (uint32_t) TimeMs : Time to wait in ms.
* @return (uint8_t) status : 0 if wait is finished.
*/
uint8_t WaitMs(
VL53L5CX_Platform *p_platform,
uint32_t TimeMs);
#endif // _PLATFORM_H_

@ -0,0 +1 @@
Subproject commit 834fa4e53119b987ae9357afc9dfacc6ef8261f8

Wyświetl plik

@ -0,0 +1,16 @@
add_library(vl53l5cx INTERFACE)
target_sources(vl53l5cx INTERFACE
${CMAKE_CURRENT_LIST_DIR}/vl53l5cx.cpp
${CMAKE_CURRENT_LIST_DIR}/platform.c
${CMAKE_CURRENT_LIST_DIR}/src/VL53L5CX_ULD_API/src/vl53l5cx_api.c
${CMAKE_CURRENT_LIST_DIR}/src/VL53L5CX_ULD_API/src/vl53l5cx_plugin_detection_thresholds.c
)
target_include_directories(vl53l5cx INTERFACE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/src/VL53L5CX_ULD_API/inc
)
# Pull in pico libraries that we need
target_link_libraries(vl53l5cx INTERFACE pico_stdlib hardware_i2c)

Wyświetl plik

@ -0,0 +1,85 @@
#include "vl53l5cx.hpp"
namespace pimoroni {
bool VL53L5CX::init() {
if(!is_alive()) {
return false;
}
uint8_t status = vl53l5cx_init(configuration);
return status == VL53L5CX_STATUS_OK;
}
bool VL53L5CX::is_alive() {
uint8_t is_alive = 0;
uint8_t status = vl53l5cx_is_alive(configuration, &is_alive);
return is_alive == 1 && status == VL53L5CX_STATUS_OK;
}
bool VL53L5CX::start_ranging() {
uint8_t status = vl53l5cx_start_ranging(configuration);
return status == VL53L5CX_STATUS_OK;
}
bool VL53L5CX::stop_ranging() {
uint8_t status = vl53l5cx_stop_ranging(configuration);
return status == VL53L5CX_STATUS_OK;
}
bool VL53L5CX::enable_motion_indicator(Resolution resolution) {
uint8_t status = vl53l5cx_motion_indicator_init(configuration, motion_configuration, resolution);
return status == VL53L5CX_STATUS_OK;
}
bool VL53L5CX::set_motion_distance(uint16_t distance_min, uint16_t distance_max) {
uint8_t status = vl53l5cx_motion_indicator_set_distance_motion(configuration, motion_configuration, distance_min, distance_max);
return status == VL53L5CX_STATUS_OK;
}
bool VL53L5CX::set_i2c_address(uint8_t i2c_address) {
/* Must be a 7-bit i2c address */
uint8_t status = vl53l5cx_set_i2c_address(configuration, i2c_address);
return status == VL53L5CX_STATUS_OK;
}
bool VL53L5CX::set_ranging_mode(RangingMode ranging_mode) {
uint8_t status = vl53l5cx_set_ranging_mode(configuration, (uint8_t)ranging_mode);
return status == VL53L5CX_STATUS_OK;
}
bool VL53L5CX::set_ranging_frequency_hz(uint8_t ranging_frequency_hz) {
uint8_t status = vl53l5cx_set_ranging_frequency_hz(configuration, ranging_frequency_hz);
return status == VL53L5CX_STATUS_OK;
}
bool VL53L5CX::set_resolution(Resolution resolution) {
/* One of VL53L5CX_RESOLUTION_4X4 or VL53L5CX_RESOLUTION_8X8 */
uint8_t status = vl53l5cx_set_resolution(configuration, (uint8_t)resolution);
if(status == VL53L5CX_STATUS_OK) {
this->resolution = resolution;
}
return status == VL53L5CX_STATUS_OK;
}
VL53L5CX::Resolution VL53L5CX::get_resolution() {
//Resolution resolution = RESOLUTION_4X4;
//vl53l5cx_get_resolution(configuration, (uint8_t *)&resolution);
return this->resolution;
}
bool VL53L5CX::set_integration_time_ms(uint32_t integration_time_ms) {
/* Integration time between 2ms and 1000ms */
uint8_t status = vl53l5cx_set_integration_time_ms(configuration, integration_time_ms);
return status == VL53L5CX_STATUS_OK;
}
bool VL53L5CX::set_sharpener_percent(uint8_t sharpener_percent) {
/* Sharpener intensity from 0 to 99 */
uint8_t status = vl53l5cx_set_sharpener_percent(configuration, sharpener_percent);
return status == VL53L5CX_STATUS_OK;
}
bool VL53L5CX::set_target_order(TargetOrder target_order) {
uint8_t status = vl53l5cx_set_target_order(configuration, (uint8_t)target_order);
return status == VL53L5CX_STATUS_OK;
}
bool VL53L5CX::set_power_mode(PowerMode power_mode) {
uint8_t status = vl53l5cx_set_power_mode(configuration, (uint8_t)power_mode);
return status == VL53L5CX_STATUS_OK;
}
bool VL53L5CX::data_ready() {
uint8_t is_ready;
uint8_t status = vl53l5cx_check_data_ready(configuration, &is_ready);
return status == VL53L5CX_STATUS_OK && is_ready;
}
bool VL53L5CX::get_data(ResultsData *results) {
uint8_t status = vl53l5cx_get_ranging_data(configuration, results);
return status == VL53L5CX_STATUS_OK;
}
}

Wyświetl plik

@ -0,0 +1,79 @@
#pragma once
extern "C" {
#include "drivers/vl53l5cx/src/VL53L5CX_ULD_API/inc/vl53l5cx_api.h"
#include "drivers/vl53l5cx/src/VL53L5CX_ULD_API/inc/vl53l5cx_plugin_motion_indicator.h"
}
#include "common/pimoroni_i2c.hpp"
#include "src/VL53L5CX_ULD_API/inc/vl53l5cx_api.h"
#include "src/VL53L5CX_ULD_API/inc/vl53l5cx_plugin_motion_indicator.h"
namespace pimoroni {
class VL53L5CX {
public:
typedef VL53L5CX_ResultsData ResultsData;
enum TargetOrder : uint8_t {
TARGET_ORDER_CLOSEST = VL53L5CX_TARGET_ORDER_CLOSEST,
TARGET_ORDER_STRONGEST = VL53L5CX_TARGET_ORDER_STRONGEST
};
enum Resolution : uint8_t {
RESOLUTION_4X4 = VL53L5CX_RESOLUTION_4X4,
RESOLUTION_8X8 = VL53L5CX_RESOLUTION_8X8
};
enum RangingMode : uint8_t {
RANGING_MODE_CONTINUOUS = VL53L5CX_RANGING_MODE_CONTINUOUS,
RANGING_MODE_AUTONOMOUS = VL53L5CX_RANGING_MODE_AUTONOMOUS
};
enum PowerMode : uint8_t {
POWER_MODE_SLEEP = VL53L5CX_POWER_MODE_SLEEP,
POWER_MODE_WAKEUP = VL53L5CX_POWER_MODE_WAKEUP
};
// 7-bit version of the default address (0x52)
static const uint8_t DEFAULT_ADDRESS = VL53L5CX_DEFAULT_I2C_ADDRESS >> 1;
VL53L5CX(I2C *i2c, uint8_t i2c_addr=DEFAULT_ADDRESS) {
configuration = new VL53L5CX_Configuration{
.platform = VL53L5CX_Platform{
.address = i2c_addr,
.i2c = i2c->get_i2c()
},
};
motion_configuration = new VL53L5CX_Motion_Configuration{};
}
~VL53L5CX() {
delete configuration;
delete motion_configuration;
}
bool init();
bool is_alive();
bool start_ranging();
bool stop_ranging();
bool enable_motion_indicator(Resolution resolution);
bool set_motion_distance(uint16_t distance_min, uint16_t distance_max);
bool set_i2c_address(uint8_t i2c_address);
bool set_ranging_mode(RangingMode ranging_mode);
bool set_ranging_frequency_hz(uint8_t ranging_frequency_hz);
bool set_resolution(Resolution resolution);
Resolution get_resolution();
bool set_integration_time_ms(uint32_t integration_time_ms);
bool set_sharpener_percent(uint8_t sharpener_percent);
bool set_target_order(TargetOrder target_order);
bool set_power_mode(PowerMode power_mode);
bool data_ready();
bool get_data(ResultsData *results);
VL53L5CX_Configuration* get_configuration() {
return configuration;
}
private:
VL53L5CX_Configuration *configuration;
VL53L5CX_Motion_Configuration *motion_configuration;
Resolution resolution = RESOLUTION_8X8;
};
}

Wyświetl plik

@ -21,6 +21,7 @@ add_subdirectory(breakout_as7262)
add_subdirectory(breakout_bh1745)
add_subdirectory(breakout_icp10125)
add_subdirectory(breakout_scd41)
add_subdirectory(breakout_vl53l5cx)
add_subdirectory(pico_display)
add_subdirectory(pico_display_2)

Wyświetl plik

@ -0,0 +1,12 @@
set(OUTPUT_NAME vl53l5cx_demo)
add_executable(
${OUTPUT_NAME}
vl53l5cx_demo.cpp
)
# Pull in pico libraries that we need
target_link_libraries(${OUTPUT_NAME} pico_stdlib hardware_i2c vl53l5cx pimoroni_i2c)
# create map/bin/hex file etc.
pico_add_extra_outputs(${OUTPUT_NAME})

Wyświetl plik

@ -0,0 +1,35 @@
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/i2c.h"
#include "drivers/vl53l5cx/vl53l5cx.hpp"
#include "common/pimoroni_i2c.hpp"
using namespace pimoroni;
I2C i2c(4, 5);
VL53L5CX vl53l5cx(&i2c);
int main() {
stdio_init_all();
bool result = vl53l5cx.init();
if(!result) {
printf("Error initializing...\n");
}
vl53l5cx.set_ranging_mode(VL53L5CX::RANGING_MODE_AUTONOMOUS);
vl53l5cx.set_resolution(VL53L5CX::RESOLUTION_4X4);
vl53l5cx.start_ranging();
while(true) {
if(vl53l5cx.data_ready()) {
VL53L5CX::ResultsData result;
if(vl53l5cx.get_data(&result)) {
printf("Distance: %dmm\n", result.distance_mm[0]);
}
}
sleep_ms(20);
}
return 0;
}

Wyświetl plik

@ -0,0 +1,32 @@
import pimoroni_i2c
import breakout_vl53l5cx
import time
PINS_BREAKOUT_GARDEN = {"sda": 4, "scl": 5}
PINS_PICO_EXPLORER = {"sda": 20, "scl": 21}
# Sensor startup time is proportional to i2c baudrate
# HOWEVER many sensors may not run at > 400KHz (400000)
i2c = pimoroni_i2c.PimoroniI2C(**PINS_BREAKOUT_GARDEN, baudrate=2_000_000)
print("Starting up sensor...")
t_sta = time.ticks_ms()
sensor = breakout_vl53l5cx.VL53L5CX(i2c)
t_end = time.ticks_ms()
print("Done in {}ms...".format(t_end - t_sta))
# Make sure to set resolution and other settings *before* you start ranging
sensor.set_resolution(breakout_vl53l5cx.RESOLUTION_4X4)
sensor.start_ranging()
while True:
if sensor.data_ready():
# "data" is a namedtuple (attrtuple technically)
# it includes average readings as "distance_avg" and "reflectance_avg"
# plus a full 4x4 or 8x8 set of readings (as a 1d tuple) for both values.
data = sensor.get_data()
print("{}mm {}% (avg: {}mm {}%)".format(
data.distance[0],
data.reflectance[0],
data.distance_avg,
data.reflectance_avg))

Wyświetl plik

@ -0,0 +1,35 @@
import pimoroni_i2c
import breakout_vl53l5cx
import time
from ulab import numpy
PINS_BREAKOUT_GARDEN = {"sda": 4, "scl": 5}
PINS_PICO_EXPLORER = {"sda": 20, "scl": 21}
# Sensor startup time is proportional to i2c baudrate
# HOWEVER many sensors may not run at > 400KHz (400000)
i2c = pimoroni_i2c.PimoroniI2C(**PINS_BREAKOUT_GARDEN, baudrate=2_000_000)
print("Starting up sensor...")
t_sta = time.ticks_ms()
sensor = breakout_vl53l5cx.VL53L5CX(i2c)
t_end = time.ticks_ms()
print("Done in {}ms...".format(t_end - t_sta))
# Make sure to set resolution and other settings *before* you start ranging
sensor.set_resolution(breakout_vl53l5cx.RESOLUTION_4X4)
sensor.enable_motion_indicator(breakout_vl53l5cx.RESOLUTION_4X4)
sensor.set_motion_distance(400, 1400)
sensor.start_ranging()
while True:
if sensor.data_ready():
# "data" is a namedtuple (attrtuple technically)
# it includes average readings as "distance_avg" and "reflectance_avg"
# plus a full 4x4 or 8x8 set of readings (as a 1d tuple) for both values.
# Motion data is available in "motion_detection.motion"
data = sensor.get_data()
motion = numpy.array(data.motion_indicator.motion[0:16], dtype=numpy.int16).reshape((4, 4))
print(motion)

Wyświetl plik

@ -0,0 +1,98 @@
import pimoroni_i2c
import breakout_vl53l5cx
import time
from ulab import numpy
# This example attempts to track a "bright" object (such as a white business card)
# It uses reflectance to identify the target and compute the X/Y coordinates
# of its "center of mass" in the sensors view.
# Motion indication only works at distances > 400mm so it's not
# really useful as a method to reject data.
# Configure your distance and brightness thresholds to suit your object
DISTANCE_THRESHOLD = 400 # Distance in mm
REFLECTANCE_THRESHOLD = 60 # Estimated reflectance in %
PINS_BREAKOUT_GARDEN = {"sda": 4, "scl": 5}
PINS_PICO_EXPLORER = {"sda": 20, "scl": 21}
# Sensor startup time is proportional to i2c baudrate
# HOWEVER many sensors may not run at > 400KHz (400000)
i2c = pimoroni_i2c.PimoroniI2C(**PINS_BREAKOUT_GARDEN, baudrate=2_000_000)
print("Starting up sensor...")
t_sta = time.ticks_ms()
sensor = breakout_vl53l5cx.VL53L5CX(i2c)
t_end = time.ticks_ms()
print("Done in {}ms...".format(t_end - t_sta))
# Make sure to set resolution and other settings *before* you start ranging
sensor.set_resolution(breakout_vl53l5cx.RESOLUTION_8X8)
sensor.set_ranging_frequency_hz(15)
sensor.start_ranging()
while True:
time.sleep(1.0 / 60)
if sensor.data_ready():
# "data" is a namedtuple (attrtuple technically)
# it includes average readings as "distance_avg" and "reflectance_avg"
# plus a full 4x4 or 8x8 set of readings (as a 1d tuple) for both values.
data = sensor.get_data()
reflectance = numpy.array(data.reflectance).reshape((8, 8))
distance = numpy.array(data.distance).reshape((8, 8))
scalar = 0
target_distance = 0
n_distances = 0
# Filter out unwanted reflectance values
for ox in range(8):
for oy in range(8):
d = distance[ox][oy]
r = reflectance[ox][oy]
if d > DISTANCE_THRESHOLD or r < REFLECTANCE_THRESHOLD:
reflectance[ox][oy] = 0
else:
scalar += r
# Get a total from all the distances within our accepted target
for ox in range(8):
for oy in range(8):
d = distance[ox][oy]
r = reflectance[ox][oy]
if r > 0:
target_distance += d
n_distances += 1
# Average the target distance
if n_distances > 0:
target_distance /= n_distances
else:
target_distance = 0
# Flip reflectance now we've applied distance
# both fields are upside-down!
reflectance = numpy.flip(reflectance, axis=0)
# Calculate the center of mass along X and Y
x = 0
y = 0
if scalar > 0:
for ox in range(8):
for oy in range(8):
y += reflectance[ox][oy] * ox
y /= scalar
y /= 3.5
y -= 1.0
for oy in range(8):
for ox in range(8):
x += reflectance[ox][oy] * oy
x /= scalar
x /= 3.5
x -= 1.0
print(round(x, 2), round(y, 2), round(target_distance, 2))

Wyświetl plik

@ -0,0 +1,29 @@
add_library(usermod_vl53l5cx INTERFACE)
target_sources(usermod_vl53l5cx INTERFACE
${CMAKE_CURRENT_LIST_DIR}/vl53l5cx.c
${CMAKE_CURRENT_LIST_DIR}/vl53l5cx.cpp
${CMAKE_CURRENT_LIST_DIR}/../../../drivers/vl53l5cx/vl53l5cx.cpp
${CMAKE_CURRENT_LIST_DIR}/../../../drivers/vl53l5cx/platform.c
${CMAKE_CURRENT_LIST_DIR}/../../../drivers/vl53l5cx/src/VL53L5CX_ULD_API/src/vl53l5cx_api.c
${CMAKE_CURRENT_LIST_DIR}/../../../drivers/vl53l5cx/src/VL53L5CX_ULD_API/src/vl53l5cx_plugin_motion_indicator.c
${CMAKE_CURRENT_LIST_DIR}/../../../drivers/vl53l5cx/src/VL53L5CX_ULD_API/src/vl53l5cx_plugin_detection_thresholds.c
)
target_include_directories(usermod_vl53l5cx INTERFACE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/../../../drivers/vl53l5cx/
${CMAKE_CURRENT_LIST_DIR}/../../../drivers/vl53l5cx/src/VL53L5CX_ULD_API/inc
)
target_compile_definitions(usermod_vl53l5cx INTERFACE
MODULE_VL53L5CX_ENABLED=1
)
target_link_libraries(usermod INTERFACE usermod_vl53l5cx)
set_source_files_properties(
${CMAKE_CURRENT_LIST_DIR}/vl53l5cx.c
PROPERTIES COMPILE_FLAGS
"-Wno-discarded-qualifiers -Wno-implicit-int"
)

Wyświetl plik

@ -0,0 +1,84 @@
#include "vl53l5cx.h"
MP_DEFINE_CONST_FUN_OBJ_1(VL53L5CX___del___obj, VL53L5CX___del__);
MP_DEFINE_CONST_FUN_OBJ_1(VL53L5CX_start_ranging_obj, VL53L5CX_start_ranging);
MP_DEFINE_CONST_FUN_OBJ_1(VL53L5CX_stop_ranging_obj, VL53L5CX_stop_ranging);
MP_DEFINE_CONST_FUN_OBJ_2(VL53L5CX_enable_motion_indicator_obj, VL53L5CX_enable_motion_indicator);
MP_DEFINE_CONST_FUN_OBJ_3(VL53L5CX_set_motion_distance_obj, VL53L5CX_set_motion_distance);
MP_DEFINE_CONST_FUN_OBJ_2(VL53L5CX_set_i2c_address_obj, VL53L5CX_set_i2c_address);
MP_DEFINE_CONST_FUN_OBJ_2(VL53L5CX_set_ranging_mode_obj, VL53L5CX_set_ranging_mode);
MP_DEFINE_CONST_FUN_OBJ_2(VL53L5CX_set_ranging_frequency_hz_obj, VL53L5CX_set_ranging_frequency_hz);
MP_DEFINE_CONST_FUN_OBJ_2(VL53L5CX_set_resolution_obj, VL53L5CX_set_resolution);
MP_DEFINE_CONST_FUN_OBJ_2(VL53L5CX_set_integration_time_ms_obj, VL53L5CX_set_integration_time_ms);
MP_DEFINE_CONST_FUN_OBJ_2(VL53L5CX_set_sharpener_percent_obj, VL53L5CX_set_sharpener_percent);
MP_DEFINE_CONST_FUN_OBJ_2(VL53L5CX_set_target_order_obj, VL53L5CX_set_target_order);
MP_DEFINE_CONST_FUN_OBJ_2(VL53L5CX_set_power_mode_obj, VL53L5CX_set_power_mode);
MP_DEFINE_CONST_FUN_OBJ_1(VL53L5CX_data_ready_obj, VL53L5CX_data_ready);
MP_DEFINE_CONST_FUN_OBJ_1(VL53L5CX_get_data_obj, VL53L5CX_get_data);
/***** Binding of Methods *****/
STATIC const mp_rom_map_elem_t VL53L5CX_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&VL53L5CX___del___obj) },
{ MP_ROM_QSTR(MP_QSTR_start_ranging), MP_ROM_PTR(&VL53L5CX_start_ranging_obj) },
{ MP_ROM_QSTR(MP_QSTR_stop_ranging), MP_ROM_PTR(&VL53L5CX_stop_ranging_obj) },
{ MP_ROM_QSTR(MP_QSTR_enable_motion_indicator), MP_ROM_PTR(&VL53L5CX_enable_motion_indicator_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_motion_distance), MP_ROM_PTR(&VL53L5CX_set_motion_distance_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_i2c_address), MP_ROM_PTR(&VL53L5CX_set_i2c_address_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_ranging_mode), MP_ROM_PTR(&VL53L5CX_set_ranging_mode_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_ranging_frequency_hz), MP_ROM_PTR(&VL53L5CX_set_ranging_frequency_hz_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_resolution), MP_ROM_PTR(&VL53L5CX_set_resolution_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_integration_time_ms), MP_ROM_PTR(&VL53L5CX_set_integration_time_ms_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_sharpener_percent), MP_ROM_PTR(&VL53L5CX_set_sharpener_percent_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_target_order), MP_ROM_PTR(&VL53L5CX_set_target_order_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_power_mode), MP_ROM_PTR(&VL53L5CX_set_power_mode_obj) },
{ MP_ROM_QSTR(MP_QSTR_data_ready), MP_ROM_PTR(&VL53L5CX_data_ready_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_data), MP_ROM_PTR(&VL53L5CX_get_data_obj) },
};
STATIC MP_DEFINE_CONST_DICT(VL53L5CX_locals_dict, VL53L5CX_locals_dict_table);
/***** Class Definition *****/
const mp_obj_type_t VL53L5CX_type = {
{ &mp_type_type },
.name = MP_QSTR_breakout_vl53l5cx,
.print = VL53L5CX_print,
.make_new = VL53L5CX_make_new,
.locals_dict = (mp_obj_dict_t*)&VL53L5CX_locals_dict,
};
/***** Module Globals *****/
STATIC const mp_map_elem_t vl53l5cx_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_breakout_vl53l5cx) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_VL53L5CX), (mp_obj_t)&VL53L5CX_type },
{ MP_ROM_QSTR(MP_QSTR_TARGET_ORDER_CLOSEST), MP_ROM_INT(VL53L5CX_TARGET_ORDER_CLOSEST) },
{ MP_ROM_QSTR(MP_QSTR_TARGET_ORDER_STRONGEST), MP_ROM_INT(VL53L5CX_TARGET_ORDER_STRONGEST) },
{ MP_ROM_QSTR(MP_QSTR_RESOLUTION_4X4), MP_ROM_INT(VL53L5CX_RESOLUTION_4X4) },
{ MP_ROM_QSTR(MP_QSTR_RESOLUTION_8X8), MP_ROM_INT(VL53L5CX_RESOLUTION_8X8) },
{ MP_ROM_QSTR(MP_QSTR_RANGING_MODE_CONTINUOUS), MP_ROM_INT(VL53L5CX_RANGING_MODE_CONTINUOUS) },
{ MP_ROM_QSTR(MP_QSTR_RANGING_MODE_AUTONOMOUS), MP_ROM_INT(VL53L5CX_RANGING_MODE_AUTONOMOUS) },
{ MP_ROM_QSTR(MP_QSTR_POWER_MODE_SLEEP), MP_ROM_INT(VL53L5CX_POWER_MODE_SLEEP) },
{ MP_ROM_QSTR(MP_QSTR_POWER_MODE_WAKEUP), MP_ROM_INT(VL53L5CX_POWER_MODE_WAKEUP) },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_vl53l5cx_globals, vl53l5cx_globals_table);
/***** Module Definition *****/
const mp_obj_module_t vl53l5cx_user_cmodule = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_vl53l5cx_globals,
};
/***** Module Registration: as "breakout_vl53l5cx" *****/
MP_REGISTER_MODULE(MP_QSTR_breakout_vl53l5cx, vl53l5cx_user_cmodule, MODULE_VL53L5CX_ENABLED);

Wyświetl plik

@ -0,0 +1,269 @@
#include <cstdio>
#include "vl53l5cx.hpp"
#include "pico/multicore.h"
#define MP_OBJ_TO_PTR2(o, t) ((t *)(uintptr_t)(o))
extern "C" {
#include "vl53l5cx.h"
#include "pimoroni_i2c.h"
typedef struct _mp_obj_float_t {
mp_obj_base_t base;
mp_float_t value;
} mp_obj_float_t;
const mp_obj_float_t const_float_1 = {{&mp_type_float}, 1.0f};
/***** I2C Struct *****/
typedef struct _PimoroniI2C_obj_t {
mp_obj_base_t base;
pimoroni::I2C *i2c;
} _PimoroniI2C_obj_t;
/***** Variables Struct *****/
typedef struct _VL53L5CX_obj_t {
mp_obj_base_t base;
_PimoroniI2C_obj_t *i2c;
pimoroni::VL53L5CX* breakout;
} _VL53L5CX_obj_t;
/***** Print *****/
void VL53L5CX_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind; // Unused input parameter
_VL53L5CX_obj_t *self = MP_OBJ_TO_PTR2(self_in, _VL53L5CX_obj_t);
mp_print_str(print, "VL53L5CX( ");
mp_print_str(print, "i2c = ");
mp_obj_print_helper(print, mp_obj_new_int((self->breakout->get_configuration()->platform.i2c == i2c0) ? 0 : 1), PRINT_REPR);
mp_print_str(print, " addr = ");
mp_obj_print_helper(print, mp_obj_new_int(self->breakout->get_configuration()->platform.address), PRINT_REPR);
mp_print_str(print, " )");
}
/***** Destructor ******/
mp_obj_t VL53L5CX___del__(mp_obj_t self_in) {
_VL53L5CX_obj_t *self = MP_OBJ_TO_PTR2(self_in, _VL53L5CX_obj_t);
//self->breakout->stop_ranging(); // i2c object might have been deleted already?
delete self->breakout;
return mp_const_none;
}
/***** Constructor *****/
mp_obj_t VL53L5CX_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
_VL53L5CX_obj_t *self = nullptr;
enum {
ARG_i2c,
ARG_addr
};
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_i2c, MP_ARG_OBJ, {.u_obj = nullptr} },
{ MP_QSTR_addr, MP_ARG_INT, {.u_int = pimoroni::VL53L5CX::DEFAULT_ADDRESS} }
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
if(!MP_OBJ_IS_TYPE(args[ARG_i2c].u_obj, &PimoroniI2C_type)) {
mp_raise_ValueError(MP_ERROR_TEXT("VL53L5CX: Bad i2C object"));
return mp_const_none;
}
_PimoroniI2C_obj_t *i2c = (_PimoroniI2C_obj_t *)MP_OBJ_TO_PTR(args[ARG_i2c].u_obj);
int addr = args[ARG_addr].u_int;
self = m_new_obj_with_finaliser(_VL53L5CX_obj_t);
self->base.type = &VL53L5CX_type;
self->i2c = i2c;
self->breakout = new pimoroni::VL53L5CX(i2c->i2c, addr);
if(!self->breakout->init()) {
mp_raise_msg(&mp_type_RuntimeError, "VL53L5CX: error initialising");
}
return MP_OBJ_FROM_PTR(self);
}
mp_obj_t VL53L5CX_start_ranging(mp_obj_t self_in) {
_VL53L5CX_obj_t *self = MP_OBJ_TO_PTR2(self_in, _VL53L5CX_obj_t);
bool status = self->breakout->start_ranging();
if(!status) {
mp_raise_msg(&mp_type_RuntimeError, "VL53L5CX: start_ranging error");
}
return mp_const_none;
}
mp_obj_t VL53L5CX_stop_ranging(mp_obj_t self_in) {
_VL53L5CX_obj_t *self = MP_OBJ_TO_PTR2(self_in, _VL53L5CX_obj_t);
bool status = self->breakout->stop_ranging();
if(!status) {
mp_raise_msg(&mp_type_RuntimeError, "VL53L5CX: stop_ranging error");
}
return mp_const_none;
}
mp_obj_t VL53L5CX_enable_motion_indicator(mp_obj_t self_in, mp_obj_t value) {
_VL53L5CX_obj_t *self = MP_OBJ_TO_PTR2(self_in, _VL53L5CX_obj_t);
bool status = self->breakout->enable_motion_indicator((pimoroni::VL53L5CX::Resolution)mp_obj_get_int(value));
if(!status) {
mp_raise_msg(&mp_type_RuntimeError, "VL53L5CX: enable_motion_indicator error");
}
return mp_const_none;
}
mp_obj_t VL53L5CX_set_motion_distance(mp_obj_t self_in, mp_obj_t distance_min, mp_obj_t distance_max) {
_VL53L5CX_obj_t *self = MP_OBJ_TO_PTR2(self_in, _VL53L5CX_obj_t);
bool status = self->breakout->set_motion_distance(mp_obj_get_int(distance_min), mp_obj_get_int(distance_max));
if(!status) {
mp_raise_msg(&mp_type_RuntimeError, "VL53L5CX: set_motion_distance error");
}
return mp_const_none;
}
mp_obj_t VL53L5CX_set_i2c_address(mp_obj_t self_in, mp_obj_t value) {
_VL53L5CX_obj_t *self = MP_OBJ_TO_PTR2(self_in, _VL53L5CX_obj_t);
bool status = self->breakout->set_i2c_address(mp_obj_get_int(value));
if(!status) {
mp_raise_msg(&mp_type_RuntimeError, "VL53L5CX: set_i2c_address error");
}
return mp_const_none;
}
mp_obj_t VL53L5CX_set_ranging_mode(mp_obj_t self_in, mp_obj_t value) {
_VL53L5CX_obj_t *self = MP_OBJ_TO_PTR2(self_in, _VL53L5CX_obj_t);
bool status = self->breakout->set_ranging_mode((pimoroni::VL53L5CX::RangingMode)mp_obj_get_int(value));
if(!status) {
mp_raise_msg(&mp_type_RuntimeError, "VL53L5CX: set_ranging_mode error");
}
return mp_const_none;
}
mp_obj_t VL53L5CX_set_ranging_frequency_hz(mp_obj_t self_in, mp_obj_t value) {
_VL53L5CX_obj_t *self = MP_OBJ_TO_PTR2(self_in, _VL53L5CX_obj_t);
bool status = self->breakout->set_ranging_frequency_hz(mp_obj_get_int(value));
if(!status) {
mp_raise_msg(&mp_type_RuntimeError, "VL53L5CX: set_ranging_frequency_hz error");
}
return mp_const_none;
}
mp_obj_t VL53L5CX_set_resolution(mp_obj_t self_in, mp_obj_t value) {
_VL53L5CX_obj_t *self = MP_OBJ_TO_PTR2(self_in, _VL53L5CX_obj_t);
bool status = self->breakout->set_resolution((pimoroni::VL53L5CX::Resolution)mp_obj_get_int(value));
if(!status) {
mp_raise_msg(&mp_type_RuntimeError, "VL53L5CX: set_resolution error");
}
return mp_const_none;
}
mp_obj_t VL53L5CX_set_integration_time_ms(mp_obj_t self_in, mp_obj_t value) {
_VL53L5CX_obj_t *self = MP_OBJ_TO_PTR2(self_in, _VL53L5CX_obj_t);
bool status = self->breakout->set_integration_time_ms(mp_obj_get_int(value));
if(!status) {
mp_raise_msg(&mp_type_RuntimeError, "VL53L5CX: set_integration_time_ms error");
}
return mp_const_none;
}
mp_obj_t VL53L5CX_set_sharpener_percent(mp_obj_t self_in, mp_obj_t value) {
_VL53L5CX_obj_t *self = MP_OBJ_TO_PTR2(self_in, _VL53L5CX_obj_t);
bool status = self->breakout->set_sharpener_percent(mp_obj_get_int(value));
if(!status) {
mp_raise_msg(&mp_type_RuntimeError, "VL53L5CX: set_sharpener_percent error");
}
return mp_const_none;
}
mp_obj_t VL53L5CX_set_target_order(mp_obj_t self_in, mp_obj_t value) {
_VL53L5CX_obj_t *self = MP_OBJ_TO_PTR2(self_in, _VL53L5CX_obj_t);
bool status = self->breakout->set_target_order((pimoroni::VL53L5CX::TargetOrder)mp_obj_get_int(value));
if(!status) {
mp_raise_msg(&mp_type_RuntimeError, "VL53L5CX: set_target_order error");
}
return mp_const_none;
}
mp_obj_t VL53L5CX_set_power_mode(mp_obj_t self_in, mp_obj_t value) {
_VL53L5CX_obj_t *self = MP_OBJ_TO_PTR2(self_in, _VL53L5CX_obj_t);
bool status = self->breakout->set_power_mode((pimoroni::VL53L5CX::PowerMode)mp_obj_get_int(value));
if(!status) {
mp_raise_msg(&mp_type_RuntimeError, "VL53L5CX: set_power_mode error");
}
return mp_const_none;
}
mp_obj_t VL53L5CX_data_ready(mp_obj_t self_in) {
_VL53L5CX_obj_t *self = MP_OBJ_TO_PTR2(self_in, _VL53L5CX_obj_t);
return self->breakout->data_ready() ? mp_const_true : mp_const_false;
}
mp_obj_t VL53L5CX_get_data(mp_obj_t self_in) {
_VL53L5CX_obj_t *self = MP_OBJ_TO_PTR2(self_in, _VL53L5CX_obj_t);
pimoroni::VL53L5CX::ResultsData results;
bool status = self->breakout->get_data(&results);
if(!status) {
mp_raise_msg(&mp_type_RuntimeError, "VL53L5CX: get_data error");
}
// Get the current resolution so we only look at valid results.
// This is so that our average distance works out and doesn't include bogus data.
int scale = (uint8_t)self->breakout->get_resolution();
int tuple_size = scale * VL53L5CX_NB_TARGET_PER_ZONE;
// TODO This doesn't really handle VL53L5CX_NB_TARGET_PER_ZONE > 1 gracefully
// the zone data should be split into separate tuples
mp_obj_t tuple_distance_mm[tuple_size];
mp_obj_t tuple_reflectance[tuple_size];
int32_t average_distance = 0;
int32_t average_reflectance = 0;
// Build a tuple of motion data
for(int i = 0u; i < tuple_size; i++) {
tuple_distance_mm[i] = mp_obj_new_int(results.distance_mm[i]);
tuple_reflectance[i] = mp_obj_new_int(results.reflectance[i]);
average_distance += results.distance_mm[i];
average_reflectance += results.reflectance[i];
}
average_distance /= tuple_size;
average_reflectance /= tuple_size;
mp_obj_t tuple_motion_data[32];
for(int i = 0u; i < 32; i++) {
tuple_motion_data[i] = mp_obj_new_int(results.motion_indicator.motion[i]);
}
STATIC const qstr tuple_motion_fields[] = {MP_QSTR_global_indicator_1, MP_QSTR_global_indicator_2, MP_QSTR_motion};
mp_obj_t tuple_motion[] = {
mp_obj_new_int(results.motion_indicator.global_indicator_1),
mp_obj_new_int(results.motion_indicator.global_indicator_2),
mp_obj_new_tuple(sizeof(tuple_motion_data) / sizeof(mp_obj_t), tuple_motion_data)
};
mp_obj_t tuple[] = {
mp_obj_new_int(average_distance), // Average distance
mp_obj_new_int(average_reflectance), // Average reflectance
mp_obj_new_attrtuple(tuple_motion_fields, sizeof(tuple_motion) / sizeof(mp_obj_t), tuple_motion), // Motion data
mp_obj_new_int(tuple_size), // Number of results
mp_obj_new_tuple(tuple_size, tuple_distance_mm), // Full distance results
mp_obj_new_tuple(tuple_size, tuple_reflectance) // Full reflectange results
};
STATIC const qstr tuple_fields[] = {MP_QSTR_distance_avg, MP_QSTR_reflectance_avg, MP_QSTR_motion_indicator, MP_QSTR_results, MP_QSTR_distance, MP_QSTR_reflectance};
return mp_obj_new_attrtuple(tuple_fields, sizeof(tuple) / sizeof(mp_obj_t), tuple);
}
}

Wyświetl plik

@ -0,0 +1,27 @@
#include "py/runtime.h"
#include "drivers/vl53l5cx/src/VL53L5CX_ULD_API/inc/vl53l5cx_api.h"
extern const mp_obj_type_t VL53L5CX_type;
extern void VL53L5CX_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);
extern mp_obj_t VL53L5CX___del__(mp_obj_t self_in);
extern mp_obj_t VL53L5CX_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args);
extern mp_obj_t VL53L5CX_start_ranging(mp_obj_t self_in);
extern mp_obj_t VL53L5CX_stop_ranging(mp_obj_t self_in);
extern mp_obj_t VL53L5CX_enable_motion_indicator(mp_obj_t self_in, mp_obj_t value);
extern mp_obj_t VL53L5CX_set_motion_distance(mp_obj_t self_in, mp_obj_t distance_min, mp_obj_t distance_max);
extern mp_obj_t VL53L5CX_set_i2c_address(mp_obj_t self_in, mp_obj_t value);
extern mp_obj_t VL53L5CX_set_ranging_mode(mp_obj_t self_in, mp_obj_t value);
extern mp_obj_t VL53L5CX_set_ranging_frequency_hz(mp_obj_t self_in, mp_obj_t value);
extern mp_obj_t VL53L5CX_set_resolution(mp_obj_t self_in, mp_obj_t value);
extern mp_obj_t VL53L5CX_set_integration_time_ms(mp_obj_t self_in, mp_obj_t value);
extern mp_obj_t VL53L5CX_set_sharpener_percent(mp_obj_t self_in, mp_obj_t value);
extern mp_obj_t VL53L5CX_set_target_order(mp_obj_t self_in, mp_obj_t value);
extern mp_obj_t VL53L5CX_set_power_mode(mp_obj_t self_in, mp_obj_t value);
extern mp_obj_t VL53L5CX_data_ready(mp_obj_t self_in);
extern mp_obj_t VL53L5CX_get_data(mp_obj_t self_in);

Wyświetl plik

@ -29,6 +29,7 @@ include(breakout_bme280/micropython)
include(breakout_bmp280/micropython)
include(breakout_icp10125/micropython)
include(breakout_scd41/micropython)
include(breakout_vl53l5cx/micropython)
include(pico_scroll/micropython)
include(pico_rgb_keypad/micropython)