Merge branch 'main' into motor-and-encoder

This commit is contained in:
ZodiusInfuser 2022-05-12 17:02:50 +01:00 committed by GitHub
commit 305462d33c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 1403 additions and 27 deletions

View File

@ -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/

4
.gitmodules vendored
View File

@ -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

View File

@ -32,3 +32,4 @@ add_subdirectory(pwm)
add_subdirectory(servo)
add_subdirectory(encoder)
add_subdirectory(motor)
add_subdirectory(vl53l5cx)

View File

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

235
drivers/vl53l5cx/platform.c Normal file
View File

@ -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;
}

219
drivers/vl53l5cx/platform.h Normal file
View File

@ -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_

1
drivers/vl53l5cx/src Submodule

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

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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;
};
}

View File

@ -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)

View File

@ -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})

View File

@ -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;
}

View File

@ -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)

View File

@ -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()

View File

@ -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))

View File

@ -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)

View File

@ -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))

View File

@ -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.

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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"
)

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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)