diff --git a/.github/workflows/micropython-with-blinka.yml b/.github/workflows/micropython-with-blinka.yml index 0250061e..ea3aa8d5 100644 --- a/.github/workflows/micropython-with-blinka.yml +++ b/.github/workflows/micropython-with-blinka.yml @@ -9,8 +9,8 @@ on: env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) MICROPYTHON_VERSION: v1.18 - BLINKA_VERSION: 6.20.1 - PLATFORMDETECT_VERSION: 3.19.3 + BLINKA_VERSION: 7.3.0 + PLATFORMDETECT_VERSION: 3.22.1 BUILD_TYPE: Release BOARD_TYPE: PICO @@ -64,6 +64,7 @@ jobs: cp -r pimoroni-pico-${GITHUB_SHA}/micropython/modules_py/* micropython/ports/rp2/modules/ mkdir -p micropython/ports/rp2/modules/adafruit_blinka/microcontroller/ cp -r Adafruit_Blinka/src/adafruit_blinka/microcontroller/rp2040 micropython/ports/rp2/modules/adafruit_blinka/microcontroller/ + cp -r Adafruit_Blinka/src/adafruit_blinka/microcontroller/generic_micropython micropython/ports/rp2/modules/adafruit_blinka/microcontroller/ mkdir -p micropython/ports/rp2/modules/adafruit_blinka/board/raspberrypi/ cp Adafruit_Blinka/src/adafruit_blinka/microcontroller/__init__.py micropython/ports/rp2/modules/adafruit_blinka/microcontroller/ cp Adafruit_Blinka/src/adafruit_blinka/board/__init__.py micropython/ports/rp2/modules/adafruit_blinka/board/ diff --git a/.gitmodules b/.gitmodules index 474f7d55..dc560193 100644 --- a/.gitmodules +++ b/.gitmodules @@ -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 diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index c76e13fa..3fbe4fb3 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -32,3 +32,4 @@ add_subdirectory(pwm) add_subdirectory(servo) add_subdirectory(encoder) add_subdirectory(motor) +add_subdirectory(vl53l5cx) diff --git a/drivers/vl53l5cx/CMakeLists.txt b/drivers/vl53l5cx/CMakeLists.txt new file mode 100644 index 00000000..1322c351 --- /dev/null +++ b/drivers/vl53l5cx/CMakeLists.txt @@ -0,0 +1 @@ +include(${CMAKE_CURRENT_LIST_DIR}/vl53l5cx.cmake) \ No newline at end of file diff --git a/drivers/vl53l5cx/platform.c b/drivers/vl53l5cx/platform.c new file mode 100644 index 00000000..c3582fe0 --- /dev/null +++ b/drivers/vl53l5cx/platform.c @@ -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 */ + 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; +} diff --git a/drivers/vl53l5cx/platform.h b/drivers/vl53l5cx/platform.h new file mode 100644 index 00000000..9a4548e9 --- /dev/null +++ b/drivers/vl53l5cx/platform.h @@ -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 +#include + +#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_ \ No newline at end of file diff --git a/drivers/vl53l5cx/src b/drivers/vl53l5cx/src new file mode 160000 index 00000000..834fa4e5 --- /dev/null +++ b/drivers/vl53l5cx/src @@ -0,0 +1 @@ +Subproject commit 834fa4e53119b987ae9357afc9dfacc6ef8261f8 diff --git a/drivers/vl53l5cx/vl53l5cx.cmake b/drivers/vl53l5cx/vl53l5cx.cmake new file mode 100644 index 00000000..085947ce --- /dev/null +++ b/drivers/vl53l5cx/vl53l5cx.cmake @@ -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) diff --git a/drivers/vl53l5cx/vl53l5cx.cpp b/drivers/vl53l5cx/vl53l5cx.cpp new file mode 100644 index 00000000..d962f21b --- /dev/null +++ b/drivers/vl53l5cx/vl53l5cx.cpp @@ -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; + } +} \ No newline at end of file diff --git a/drivers/vl53l5cx/vl53l5cx.hpp b/drivers/vl53l5cx/vl53l5cx.hpp new file mode 100644 index 00000000..9198c58f --- /dev/null +++ b/drivers/vl53l5cx/vl53l5cx.hpp @@ -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; + }; +} \ No newline at end of file diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 24de6b59..2fc73111 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -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) diff --git a/examples/breakout_vl53l5cx/CMakeLists.txt b/examples/breakout_vl53l5cx/CMakeLists.txt new file mode 100644 index 00000000..953461bf --- /dev/null +++ b/examples/breakout_vl53l5cx/CMakeLists.txt @@ -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}) diff --git a/examples/breakout_vl53l5cx/vl53l5cx_demo.cpp b/examples/breakout_vl53l5cx/vl53l5cx_demo.cpp new file mode 100644 index 00000000..c0eb829d --- /dev/null +++ b/examples/breakout_vl53l5cx/vl53l5cx_demo.cpp @@ -0,0 +1,35 @@ +#include +#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; +} \ No newline at end of file diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index 4992e8dc..a80857cf 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -87,4 +87,4 @@ namespace pimoroni { void line(Point p1, Point p2); }; -} \ No newline at end of file +} diff --git a/micropython/examples/badger2040/README.md b/micropython/examples/badger2040/README.md index adfa1167..22a9bcba 100644 --- a/micropython/examples/badger2040/README.md +++ b/micropython/examples/badger2040/README.md @@ -14,6 +14,7 @@ - [Image](#image) - [QR gen](#qr-gen) - [Launcher](#launcher) + - [Conway](#conway) ## Function Examples @@ -56,10 +57,12 @@ python3 convert.py --binary --resize image_file_1.png image_file_2.png image_fil A checklist application, letting you navigate through items and tick each of them off. +* `checklist.txt` - A text file containing the titles of items for the list. + ### Clock [clock.py](clock.py) -A simple clock showing the time and date, that uses the E Ink's fast speed to update every second +A simple clock showing the time and date, that uses the E Ink's fast speed to update every second. ### E-Book [ebook.py](ebook.py) @@ -83,10 +86,17 @@ python3 convert.py --binary --resize image_file_1.png image_file_2.png image_fil ### QR gen [qrgen.py](qrgen.py) -This application looks for a file on your MicroPython drive: -- `qrcode.txt` - A text file containing 9 lines. The first line should be a URL which will be converted into and displayed as a QR code. Up to 8 more lines of information can be added, which will be shown as plain text to the right of the QR code. +Displays and lets you cycle through multiple QR codes, with configuration stored in text files within the MicroPython device's `/qrcodes` directory. + +- `/qrcodes/qrcode.txt` - A text file containing 9 lines. The first line should be a URL which will be converted into and displayed as a QR code. Up to 8 more lines of information can be added, which will be shown as plain text to the right of the QR code. +- `/qrcodes/*.txt` - additional text files can be created using the same format. All text files can be cycled through. ### Launcher [launcher.py](launcher.py) -A launcher-style application, that provide a menu of other applications that can be loaded, as well as information such as battery level. +A launcher-style application, providing a menu of other applications that can be loaded, as well as information such as battery level. + +### Conway +[conway.py](conway.py) + +Conway's classic Game of Life, implemented on the Badger. Note: this application is *not* linked from the Launcher by default - it can be run directly using Thonny or your MicroPython editor of choice, or you can modify the Launcher to add it (you'll want to update `launchericons.png` as well) diff --git a/micropython/examples/breakout_roundlcd/drawing_primitives_demo.py b/micropython/examples/breakout_roundlcd/drawing_primitives_demo.py new file mode 100644 index 00000000..86bec1bc --- /dev/null +++ b/micropython/examples/breakout_roundlcd/drawing_primitives_demo.py @@ -0,0 +1,101 @@ +from breakout_roundlcd import BreakoutRoundLCD + + +width = BreakoutRoundLCD.WIDTH +height = BreakoutRoundLCD.HEIGHT + +display_buffer = bytearray(width * height * 2) # 2-bytes per pixel (RGB565) +display = BreakoutRoundLCD(display_buffer) + +display.set_backlight(1) + +while True: + display.set_pen(0, 0, 0) + display.clear() + + # circle + display.set_pen(255, 0, 0) + display.circle( + width // 5, # center point x + height // 3, # center point y + 16, # radius + ) + + # rectangle + display.set_pen(255, 255, 0) + display.rectangle( + int((width * 2 / 5) - 16), # starting point x + int(height // 3) - 8, # starting point y + 32, # width + 16, # height + ) + + # triangle + display.set_pen(0, 255, 0) + display.triangle( + int(width * 3 / 5), int(height // 3) - 16, # point 1 x, y + int(width * 3 / 5) - 16, int(height // 3) + 16, # point 2 x, y + int(width * 3 / 5) + 16, int(height // 3) + 16, # point 3 x, y + ) + + # character + display.set_pen(0, 255, 255) + display.character( + 64, # int character code + int(width * 4 / 5 - 16), # box starting point x + int(height // 3) - 16, # box starting point y + 4, # scale - not required, default is 2 + ) + + # pixel span + display.set_pen(255, 255, 255) + display.pixel_span( + int(width * 1 / 5), # starting point x + int(height * 2.5 / 5), # starting point y + 130, # length + ) + + # text + display.set_pen(0, 0, 255) + display.text( + 'test text', # text + int(width // 5), # box starting point x + int(height * 3 / 5), # box starting point y + True, # word wrap + 6, # scale - not required, default is 2 + ) + + # lines + display.set_pen(255, 0, 255) + display.line( + 0, # staring point x + int(height / 2), # staring point y + width, # end point x + height, # end point y + ) + display.line( + width, # staring point x + int(height / 2), # staring point y + 0, # end point x + height, # end point y + ) + + # set clip + display.set_clip( + int(width * 2 / 5), + int(height * 2 / 5), + int(width * 1 / 5), + int(height * 1 / 5) + ) + + # draw a clipped circle + display.circle( + int(width * 2 / 5), + int(height * 2 / 5), + 32, + ) + + # remove clip + display.remove_clip() + + display.update() diff --git a/micropython/examples/breakout_vl53l5cx/vl53l5cx_demo.py b/micropython/examples/breakout_vl53l5cx/vl53l5cx_demo.py new file mode 100644 index 00000000..ff0f1edd --- /dev/null +++ b/micropython/examples/breakout_vl53l5cx/vl53l5cx_demo.py @@ -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)) diff --git a/micropython/examples/breakout_vl53l5cx/vl53l5cx_motion.py b/micropython/examples/breakout_vl53l5cx/vl53l5cx_motion.py new file mode 100644 index 00000000..10ffec38 --- /dev/null +++ b/micropython/examples/breakout_vl53l5cx/vl53l5cx_motion.py @@ -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) diff --git a/micropython/examples/breakout_vl53l5cx/vl53l5cx_object_tracking.py b/micropython/examples/breakout_vl53l5cx/vl53l5cx_object_tracking.py new file mode 100644 index 00000000..8f05d28a --- /dev/null +++ b/micropython/examples/breakout_vl53l5cx/vl53l5cx_object_tracking.py @@ -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)) diff --git a/micropython/modules/badger2040/badger2040.cpp b/micropython/modules/badger2040/badger2040.cpp index fbd29c26..748e8c3a 100644 --- a/micropython/modules/badger2040/badger2040.cpp +++ b/micropython/modules/badger2040/badger2040.cpp @@ -179,7 +179,7 @@ MICROPY_EVENT_POLL_HOOK } absolute_time_t t_end = make_timeout_time_ms(self->badger2040->update_time()); - self->badger2040->partial_update(x, y, w, h); + self->badger2040->partial_update(x, y, w, h, false); // Ensure blocking for the minimum amount of time // in cases where "is_busy" is unreliable. diff --git a/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp b/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp index 47f9092c..03ef5175 100644 --- a/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp +++ b/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp @@ -493,10 +493,10 @@ mp_obj_t BreakoutColourLCD160x80_triangle(size_t n_args, const mp_obj_t *pos_arg int x1 = args[ARG_x1].u_int; int y1 = args[ARG_y1].u_int; - int x2 = args[ARG_x1].u_int; - int y2 = args[ARG_y1].u_int; - int x3 = args[ARG_x1].u_int; - int y3 = args[ARG_y1].u_int; + int x2 = args[ARG_x2].u_int; + int y2 = args[ARG_y2].u_int; + int x3 = args[ARG_x3].u_int; + int y3 = args[ARG_y3].u_int; Point p1(x1, y1); Point p2(x2, y2); @@ -523,8 +523,8 @@ mp_obj_t BreakoutColourLCD160x80_line(size_t n_args, const mp_obj_t *pos_args, m int x1 = args[ARG_x1].u_int; int y1 = args[ARG_y1].u_int; - int x2 = args[ARG_x1].u_int; - int y2 = args[ARG_y1].u_int; + int x2 = args[ARG_x2].u_int; + int y2 = args[ARG_y2].u_int; Point p1(x1, y1); Point p2(x2, y2); diff --git a/micropython/modules/breakout_colourlcd240x240/breakout_colourlcd240x240.cpp b/micropython/modules/breakout_colourlcd240x240/breakout_colourlcd240x240.cpp index 56650064..670029e2 100644 --- a/micropython/modules/breakout_colourlcd240x240/breakout_colourlcd240x240.cpp +++ b/micropython/modules/breakout_colourlcd240x240/breakout_colourlcd240x240.cpp @@ -493,10 +493,10 @@ mp_obj_t BreakoutColourLCD240x240_triangle(size_t n_args, const mp_obj_t *pos_ar int x1 = args[ARG_x1].u_int; int y1 = args[ARG_y1].u_int; - int x2 = args[ARG_x1].u_int; - int y2 = args[ARG_y1].u_int; - int x3 = args[ARG_x1].u_int; - int y3 = args[ARG_y1].u_int; + int x2 = args[ARG_x2].u_int; + int y2 = args[ARG_y2].u_int; + int x3 = args[ARG_x3].u_int; + int y3 = args[ARG_y3].u_int; Point p1(x1, y1); Point p2(x2, y2); @@ -523,8 +523,8 @@ mp_obj_t BreakoutColourLCD240x240_line(size_t n_args, const mp_obj_t *pos_args, int x1 = args[ARG_x1].u_int; int y1 = args[ARG_y1].u_int; - int x2 = args[ARG_x1].u_int; - int y2 = args[ARG_y1].u_int; + int x2 = args[ARG_x2].u_int; + int y2 = args[ARG_y2].u_int; Point p1(x1, y1); Point p2(x2, y2); diff --git a/micropython/modules/breakout_roundlcd/breakout_roundlcd.c b/micropython/modules/breakout_roundlcd/breakout_roundlcd.c index 4010fcca..00bc2fb2 100644 --- a/micropython/modules/breakout_roundlcd/breakout_roundlcd.c +++ b/micropython/modules/breakout_roundlcd/breakout_roundlcd.c @@ -75,4 +75,4 @@ const mp_obj_module_t breakout_roundlcd_user_cmodule = { //////////////////////////////////////////////////////////////////////////////////////////////////// MP_REGISTER_MODULE(MP_QSTR_breakout_roundlcd, breakout_roundlcd_user_cmodule, MODULE_BREAKOUT_ROUNDLCD_ENABLED); //////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file +//////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/micropython/modules/breakout_roundlcd/breakout_roundlcd.cpp b/micropython/modules/breakout_roundlcd/breakout_roundlcd.cpp index c84ce05c..6a92809f 100644 --- a/micropython/modules/breakout_roundlcd/breakout_roundlcd.cpp +++ b/micropython/modules/breakout_roundlcd/breakout_roundlcd.cpp @@ -474,10 +474,10 @@ mp_obj_t BreakoutRoundLCD_triangle(size_t n_args, const mp_obj_t *pos_args, mp_m int x1 = args[ARG_x1].u_int; int y1 = args[ARG_y1].u_int; - int x2 = args[ARG_x1].u_int; - int y2 = args[ARG_y1].u_int; - int x3 = args[ARG_x1].u_int; - int y3 = args[ARG_y1].u_int; + int x2 = args[ARG_x2].u_int; + int y2 = args[ARG_y2].u_int; + int x3 = args[ARG_x3].u_int; + int y3 = args[ARG_y3].u_int; Point p1(x1, y1); Point p2(x2, y2); @@ -504,8 +504,8 @@ mp_obj_t BreakoutRoundLCD_line(size_t n_args, const mp_obj_t *pos_args, mp_map_t int x1 = args[ARG_x1].u_int; int y1 = args[ARG_y1].u_int; - int x2 = args[ARG_x1].u_int; - int y2 = args[ARG_y1].u_int; + int x2 = args[ARG_x2].u_int; + int y2 = args[ARG_y2].u_int; Point p1(x1, y1); Point p2(x2, y2); diff --git a/micropython/modules/breakout_vl53l5cx/micropython.cmake b/micropython/modules/breakout_vl53l5cx/micropython.cmake new file mode 100644 index 00000000..71880809 --- /dev/null +++ b/micropython/modules/breakout_vl53l5cx/micropython.cmake @@ -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" +) \ No newline at end of file diff --git a/micropython/modules/breakout_vl53l5cx/vl53l5cx.c b/micropython/modules/breakout_vl53l5cx/vl53l5cx.c new file mode 100644 index 00000000..04be5574 --- /dev/null +++ b/micropython/modules/breakout_vl53l5cx/vl53l5cx.c @@ -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); diff --git a/micropython/modules/breakout_vl53l5cx/vl53l5cx.cpp b/micropython/modules/breakout_vl53l5cx/vl53l5cx.cpp new file mode 100644 index 00000000..662a982f --- /dev/null +++ b/micropython/modules/breakout_vl53l5cx/vl53l5cx.cpp @@ -0,0 +1,269 @@ +#include +#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); +} + +} \ No newline at end of file diff --git a/micropython/modules/breakout_vl53l5cx/vl53l5cx.h b/micropython/modules/breakout_vl53l5cx/vl53l5cx.h new file mode 100644 index 00000000..74c151eb --- /dev/null +++ b/micropython/modules/breakout_vl53l5cx/vl53l5cx.h @@ -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); \ No newline at end of file diff --git a/micropython/modules/micropython.cmake b/micropython/modules/micropython.cmake index 7380d885..49089b9e 100644 --- a/micropython/modules/micropython.cmake +++ b/micropython/modules/micropython.cmake @@ -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)