mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-16 01:53:51 +01:00
drivers: added support for the PA5100JE and PMW3901 optical flow sensor
This commit is contained in:
parent
a8f0171bc1
commit
fb4e1838d7
@ -45,6 +45,7 @@ rsource "mag3110/Kconfig"
|
|||||||
rsource "matrix_keypad/Kconfig"
|
rsource "matrix_keypad/Kconfig"
|
||||||
rsource "mma8x5x/Kconfig"
|
rsource "mma8x5x/Kconfig"
|
||||||
rsource "opt3001/Kconfig"
|
rsource "opt3001/Kconfig"
|
||||||
|
rsource "paa5100je/Kconfig"
|
||||||
rsource "seesaw_soil/Kconfig"
|
rsource "seesaw_soil/Kconfig"
|
||||||
rsource "sht2x/Kconfig"
|
rsource "sht2x/Kconfig"
|
||||||
rsource "sm_pwm_01c/Kconfig"
|
rsource "sm_pwm_01c/Kconfig"
|
||||||
|
|||||||
134
drivers/include/paa5100je.h
Normal file
134
drivers/include/paa5100je.h
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 TU Dresden
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup drivers_paa5100je PAA5100JE/PMW3901 Driver
|
||||||
|
* @ingroup drivers_sensors
|
||||||
|
* @brief Driver for the PAA5100JE/PMW3901 Optical Flow Sensor
|
||||||
|
*
|
||||||
|
* ## Description
|
||||||
|
*
|
||||||
|
* The PAA5100JE and PMW3901 sensors are accessed in the same way over SPI
|
||||||
|
* but require slightly different initialization code.
|
||||||
|
* Since the datasheets are not very detailed, I created this driver based on a reference
|
||||||
|
* implementation by Pimoroni, who designed a breakout board for the PMW3901.
|
||||||
|
*
|
||||||
|
* The motion data read represents the relative motion since the last readout.
|
||||||
|
* It depends on the surface, lighting conditions, and the sensor’s distance from the ground.
|
||||||
|
*
|
||||||
|
* The readings are scaled according to the configuration parameter `PAA5100JE_SCALE_DENOMINATOR`.
|
||||||
|
* The readings are multiplied by 100 and divided by the denominator.
|
||||||
|
*
|
||||||
|
* The scaling factor, the quality threshold, and the timeout can be configured via Kconfig.
|
||||||
|
*
|
||||||
|
* This driver provides @ref drivers_saul capabilities.
|
||||||
|
*
|
||||||
|
* Datasheets:
|
||||||
|
* * [PAA5100JE](https://cdn.shopify.com/s/files/1/0174/1800/files/PAA5100JE-Q-GDS-R1.00_25072018.pdf)
|
||||||
|
* * [PMW3901](https://wiki.bitcraze.io/_media/projects:crazyflie2:expansionboards:pot0189-pmw3901mb-txqt-ds-r1.00-200317_20170331160807_public.pdf)
|
||||||
|
*
|
||||||
|
* Reference Implementation:
|
||||||
|
* * [Pomoroni](https://github.com/pimoroni/pmw3901-python)
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
*
|
||||||
|
* @author Leonard Herbst <leonard.herbst@tu-dresden.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <periph/gpio.h>
|
||||||
|
#include <periph/spi.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Variant of the sensor
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
PAA5100JE = 0,
|
||||||
|
PMW3901 = 1,
|
||||||
|
} paa5100je_variant_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief PAA5100JE LED brightness levels
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
PAA5100JE_LED_OFF = 0,
|
||||||
|
PAA5100JE_LED_MEDIUM = 1,
|
||||||
|
PAA5100JE_LED_MAX = 2,
|
||||||
|
} paa5100je_led_brightness_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Device initialization parameters
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
spi_t spi; /**< SPI bus used */
|
||||||
|
spi_clk_t clk; /**< clock speed used on the selected SPI bus */
|
||||||
|
gpio_t cs; /**< pin connected to the chip select line */
|
||||||
|
paa5100je_variant_t var; /**< variant of the sensor used */
|
||||||
|
} paa5100je_params_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Device descriptor for the driver
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
const paa5100je_params_t *params; /**< Device initialization parameters */
|
||||||
|
} paa5100je_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the given device
|
||||||
|
*
|
||||||
|
* @param[in,out] dev Device descriptor of the driver
|
||||||
|
* @param[in] params Initialization parameters
|
||||||
|
*
|
||||||
|
* @retval 0 on success
|
||||||
|
* @retval -ENXIO invalid SPI device
|
||||||
|
* @retval -ENODEV invalid SPI CS pin/line or wrong device id or revision
|
||||||
|
*/
|
||||||
|
int paa5100je_init(paa5100je_t *dev, const paa5100je_params_t *params);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reads the relative motition vector from the device using burst read.
|
||||||
|
*
|
||||||
|
* Reads twelve bytes from the burst register.
|
||||||
|
* Repeats the read when the data is not ready, the quality is too low
|
||||||
|
* or the shutter values is too high.
|
||||||
|
* The data being read from the sensor represents the relative motion since the last readout.
|
||||||
|
* It depends on the surface, lighting conditions, and the sensor’s distance from the ground.
|
||||||
|
* The quality threshold, the timeout, and a scaling factor can be configured via Kconfig.
|
||||||
|
*
|
||||||
|
* @param[in] dev device descriptor
|
||||||
|
* @param[out] x x component in millimeters
|
||||||
|
* @param[out] y y component in millimeters
|
||||||
|
*
|
||||||
|
* @retval 0 on success
|
||||||
|
* @retval -ETIME data was not ready in time, the quality was not good enough,
|
||||||
|
* or the shutter to high
|
||||||
|
*/
|
||||||
|
int paa5100je_get_motion_burst(const paa5100je_t *dev, int16_t *x, int16_t *y);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the LED brightness level.
|
||||||
|
*
|
||||||
|
* @param[in] dev device descriptor
|
||||||
|
* @param[in] level brightness level
|
||||||
|
*
|
||||||
|
* @retval 0 on success
|
||||||
|
* @retval -EINVAL invalid brightness level
|
||||||
|
*/
|
||||||
|
int paa5100je_set_led_brightness(const paa5100je_t *dev, const paa5100je_led_brightness_t level);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @} */
|
||||||
37
drivers/paa5100je/Kconfig
Normal file
37
drivers/paa5100je/Kconfig
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2025 TU Dresden
|
||||||
|
# SPDX-License-Identifier: LGPL-2.1-only
|
||||||
|
|
||||||
|
config MODULE_PAA5100JE
|
||||||
|
bool "PAA5100JE"
|
||||||
|
depends on TEST_KCONFIG
|
||||||
|
depends on HAS_PERIPH_SPI
|
||||||
|
select MODULE_PERIPH_SPI
|
||||||
|
|
||||||
|
menu "PAA5100JE driver"
|
||||||
|
depends on USEMODULE_PAA5100JE
|
||||||
|
|
||||||
|
config PAA5100JE_QUALITY_THRESHOLD
|
||||||
|
hex "Quality Threshold"
|
||||||
|
range 0x00 0xff
|
||||||
|
default 0x19
|
||||||
|
help
|
||||||
|
Defines a minimum quality threshold when reading from the burst register.
|
||||||
|
If the reported quality is below this threshold,
|
||||||
|
the driver retries until the threshold is met or the function times out.
|
||||||
|
|
||||||
|
config PAA5100JE_TIMEOUT_MS
|
||||||
|
int "Timeout in Milliseconds"
|
||||||
|
default 1000
|
||||||
|
help
|
||||||
|
Maximum time (in milliseconds)
|
||||||
|
the driver will attempt to read valid motion data before aborting.
|
||||||
|
|
||||||
|
config PAA5100JE_SCALE_DENOMINATOR
|
||||||
|
int "Scale Denominator"
|
||||||
|
default 100
|
||||||
|
help
|
||||||
|
Denominator used for scaling motion data.
|
||||||
|
The raw motion data read from the sensor is multiplied by 100 and
|
||||||
|
divided by this value to convert it into meaningful units.
|
||||||
|
|
||||||
|
endmenu # PAA5100JE driver
|
||||||
1
drivers/paa5100je/Makefile
Normal file
1
drivers/paa5100je/Makefile
Normal file
@ -0,0 +1 @@
|
|||||||
|
include $(RIOTBASE)/Makefile.base
|
||||||
4
drivers/paa5100je/Makefile.dep
Normal file
4
drivers/paa5100je/Makefile.dep
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
FEATURES_REQUIRED += periph_spi
|
||||||
|
|
||||||
|
USEMODULE += ztimer
|
||||||
|
USEMODULE += ztimer_msec
|
||||||
2
drivers/paa5100je/Makefile.include
Normal file
2
drivers/paa5100je/Makefile.include
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
USEMODULE_INCLUDES_paa5100je := $(LAST_MAKEFILEDIR)/include
|
||||||
|
USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_paa5100je)
|
||||||
63
drivers/paa5100je/include/paa5100je_constants.h
Normal file
63
drivers/paa5100je/include/paa5100je_constants.h
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 TU Dresden
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup drivers_paa5100je
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
* @file
|
||||||
|
* @brief Internal addresses, registers and constants
|
||||||
|
*
|
||||||
|
* @author Leonard Herbst <leonard.herbst@tu-dresden.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Register definitions for the PAA5100JE amd PMW3901 optical flow sensors
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/** @brief Product ID (reset value: 0x49, read-only) */
|
||||||
|
#define REG_ID (0x00)
|
||||||
|
|
||||||
|
/** @brief Product revision ID (reset value: 0x00, read-only) */
|
||||||
|
#define REG_REV (0x01)
|
||||||
|
|
||||||
|
/** @brief Motion data ready flag (bitfield, indicates new data availability, read/write) */
|
||||||
|
#define REG_DATA_READY (0x02)
|
||||||
|
|
||||||
|
/** @brief Motion burst register: block read of motion, delta X/Y, quality, shutter, read-only */
|
||||||
|
#define REG_MOTION_BURST (0x16)
|
||||||
|
|
||||||
|
/** @brief Write 0x5A to reset internal registers/state machine (soft reset), write-only */
|
||||||
|
#define REG_POWER_UP_RESET (0x3A)
|
||||||
|
|
||||||
|
/** @brief Sensor orientation/mirroring (read/write, flips axes depending on mounting) */
|
||||||
|
#define REG_ORIENTATION (0x5B)
|
||||||
|
|
||||||
|
/** @brief Inverse Product ID (reset value: 0xB6, bitwise NOT of REG_ID, read-only) */
|
||||||
|
#define REG_INV_ID (0x5F)
|
||||||
|
|
||||||
|
/** @brief Register for controlling the LED brightness (read/write) */
|
||||||
|
#define REG_LED_BRIGHTNESS (0x6F)
|
||||||
|
|
||||||
|
/** @brief Magic value to turn the led off */
|
||||||
|
#define PAA5100JE_LED_OFF_VAL (0x00)
|
||||||
|
/** @brief Magic value to set the led to medium brightness */
|
||||||
|
#define PAA5100JE_LED_MEDIUM_VAL (0x1C)
|
||||||
|
/** @brief Magic value to set the led to maximum brightness */
|
||||||
|
#define PAA5100JE_LED_MAX_VAL (0xD5)
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @} */
|
||||||
108
drivers/paa5100je/include/paa5100je_params.h
Normal file
108
drivers/paa5100je/include/paa5100je_params.h
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 TU Dresden
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup drivers_paa5100je
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
* @file
|
||||||
|
* @brief Default configuration
|
||||||
|
*
|
||||||
|
* @author Leonard Herbst <leonard.herbst@tu-dresden.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "board.h"
|
||||||
|
#include "paa5100je.h"
|
||||||
|
#include "paa5100je_constants.h"
|
||||||
|
#include "periph/spi.h"
|
||||||
|
#include "saul_reg.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default quality threshold for motion data readout.
|
||||||
|
*/
|
||||||
|
#ifndef CONFIG_PAA5100JE_QUALITY_THRESHOLD
|
||||||
|
# define CONFIG_PAA5100JE_QUALITY_THRESHOLD (0x19)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default timeout for motion data readout in milliseconds.
|
||||||
|
*/
|
||||||
|
#ifndef CONFIG_PAA5100JE_TIMEOUT_MS
|
||||||
|
# define CONFIG_PAA5100JE_TIMEOUT_MS (1000U)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default denominator for scaling the motion data.
|
||||||
|
*/
|
||||||
|
#ifndef CONFIG_PAA5100JE_SCALE_DENOMINATOR
|
||||||
|
# define CONFIG_PAA5100JE_SCALE_DENOMINATOR (100)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Default configuration parameters for the PAA5100JE/PMW3901 driver.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#ifndef PAA5100JE_PARAM_SPI
|
||||||
|
# define PAA5100JE_PARAM_SPI (SPI_DEV(0)) /**< Default SPI device */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PAA5100JE_PARAM_SPI_CLK
|
||||||
|
# define PAA5100JE_PARAM_SPI_CLK (SPI_CLK_400KHZ) /**< Default SPI speed */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PAA5100JE_PARAM_CS
|
||||||
|
# define PAA5100JE_PARAM_CS (GPIO_PIN(1, 2)) /**< Default SPI chip select pin */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PAA5100JE_PARAM_VAR
|
||||||
|
# define PAA5100JE_PARAM_VAR PAA5100JE /**< Default variant*/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default sensor parameters.
|
||||||
|
*/
|
||||||
|
#ifndef PAA5100JE_PARAMS
|
||||||
|
# define PAA5100JE_PARAMS { .spi = PAA5100JE_PARAM_SPI, \
|
||||||
|
.clk = PAA5100JE_PARAM_SPI_CLK, \
|
||||||
|
.cs = PAA5100JE_PARAM_CS, \
|
||||||
|
.var = PAA5100JE_PARAM_VAR }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default driver SAUL registry information
|
||||||
|
*/
|
||||||
|
#ifndef PAA5100JE_SAUL_INFO
|
||||||
|
# define PAA5100JE_SAUL_INFO { .name = "Flow Sensor (PAA5100JE/PMW3901)" }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**@}*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default configuration parameters
|
||||||
|
*/
|
||||||
|
static const paa5100je_params_t paa5100je_params[] =
|
||||||
|
{
|
||||||
|
PAA5100JE_PARAMS
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Additional meta information to keep in the SAUL registry
|
||||||
|
*/
|
||||||
|
static const saul_reg_info_t paa5100je_saul_info[] =
|
||||||
|
{
|
||||||
|
PAA5100JE_SAUL_INFO
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @} */
|
||||||
430
drivers/paa5100je/paa5100je.c
Normal file
430
drivers/paa5100je/paa5100je.c
Normal file
@ -0,0 +1,430 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 TU Dresden
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup drivers_paa5100je
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief Device driver implementation for the PAA5100JE/PMW3901 optical flow sensor
|
||||||
|
*
|
||||||
|
* @author Leonard Herbst <leonard.herbst@tu-dresden.de>
|
||||||
|
*
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "paa5100je.h"
|
||||||
|
#include "paa5100je_constants.h"
|
||||||
|
#include "paa5100je_params.h"
|
||||||
|
#include "ztimer.h"
|
||||||
|
#include "macros/utils.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define PAA5100JE_CMD_READ (0b00000000) /**< Mask applied to a register address when reading */
|
||||||
|
#define PAA5100JE_CMD_WRITE (0b10000000) /**< Mask applied to a register address when writing */
|
||||||
|
|
||||||
|
/* Prototypes of private functions */
|
||||||
|
static uint8_t _read_reg(const paa5100je_t *dev, uint8_t reg);
|
||||||
|
static void _read_reg_burst(const paa5100je_t *dev, uint8_t reg, size_t num, uint8_t *buf);
|
||||||
|
static void _write_reg(const paa5100je_t *dev, uint8_t reg, uint8_t value);
|
||||||
|
static void _prop_init(const paa5100je_t *dev);
|
||||||
|
static void _init_paa5100je(const paa5100je_t *dev);
|
||||||
|
static void _init_pmw3901(const paa5100je_t *dev);
|
||||||
|
|
||||||
|
/* Public API */
|
||||||
|
|
||||||
|
int paa5100je_init(paa5100je_t *dev, const paa5100je_params_t *params)
|
||||||
|
{
|
||||||
|
assert(dev && params);
|
||||||
|
dev->params = params;
|
||||||
|
|
||||||
|
int res = spi_init_cs(params->spi, params->cs);
|
||||||
|
if (res < 0) {
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
_write_reg(dev, REG_POWER_UP_RESET, 0x5A);
|
||||||
|
|
||||||
|
for (uint8_t offset = 0; offset < 5; offset++) {
|
||||||
|
(void) _read_reg(dev, REG_DATA_READY + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
_prop_init(dev);
|
||||||
|
|
||||||
|
uint8_t id = _read_reg(dev, REG_ID);
|
||||||
|
uint8_t inv_id = _read_reg(dev, REG_INV_ID);
|
||||||
|
uint8_t rev = _read_reg(dev, REG_REV);
|
||||||
|
if ((id ^ inv_id) != 0xFF || id != 0x49 || rev != 0x00) {
|
||||||
|
LOG_ERROR("[PAA5100JE] Wrong id, inverted id, or unknown revision.\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int paa5100je_get_motion_burst(const paa5100je_t *dev, int16_t *x, int16_t *y)
|
||||||
|
{
|
||||||
|
uint8_t data[12];
|
||||||
|
ztimer_now_t start = ztimer_now(ZTIMER_MSEC);
|
||||||
|
|
||||||
|
do {
|
||||||
|
_read_reg_burst(dev, REG_MOTION_BURST, 12, data);
|
||||||
|
/* PixArt who designed the sensor is pretty secretive. The default threshold for the quality
|
||||||
|
* and for the shutter are taken from a reference implementation. */
|
||||||
|
uint8_t data_ready = data[0];
|
||||||
|
uint8_t quality = data[6];
|
||||||
|
uint8_t shutter_upper = data[10];
|
||||||
|
if ((data_ready & 0b10000000)
|
||||||
|
&& quality >= CONFIG_PAA5100JE_QUALITY_THRESHOLD
|
||||||
|
&& shutter_upper != 0x1F) {
|
||||||
|
*x = (int16_t)(data[3] << 8 | data[2]);
|
||||||
|
*y = (int16_t)(data[5] << 8 | data[4]);
|
||||||
|
/* Apply scaling factor */
|
||||||
|
*x *= 100;
|
||||||
|
*x /= CONFIG_PAA5100JE_SCALE_DENOMINATOR;
|
||||||
|
*y *= 100;
|
||||||
|
*y /= CONFIG_PAA5100JE_SCALE_DENOMINATOR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ztimer_sleep(ZTIMER_MSEC, 1);
|
||||||
|
} while (CONFIG_PAA5100JE_TIMEOUT_MS
|
||||||
|
&& ztimer_now(ZTIMER_MSEC) < start + CONFIG_PAA5100JE_TIMEOUT_MS);
|
||||||
|
return -ETIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
int paa5100je_set_led_brightness(const paa5100je_t *dev, const paa5100je_led_brightness_t level)
|
||||||
|
{
|
||||||
|
assert(dev);
|
||||||
|
uint8_t reg_val;
|
||||||
|
|
||||||
|
switch (level) {
|
||||||
|
case PAA5100JE_LED_OFF:
|
||||||
|
reg_val = PAA5100JE_LED_OFF_VAL;
|
||||||
|
break;
|
||||||
|
case PAA5100JE_LED_MEDIUM:
|
||||||
|
reg_val = PAA5100JE_LED_MEDIUM_VAL;
|
||||||
|
break;
|
||||||
|
case PAA5100JE_LED_MAX:
|
||||||
|
reg_val = PAA5100JE_LED_MAX_VAL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
_write_reg(dev, 0x7F, 0x14);
|
||||||
|
_write_reg(dev, REG_LED_BRIGHTNESS, reg_val);
|
||||||
|
_write_reg(dev, 0x7F, 0x00);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Private API */
|
||||||
|
|
||||||
|
static uint8_t _read_reg(const paa5100je_t *dev, uint8_t reg)
|
||||||
|
{
|
||||||
|
assert(dev);
|
||||||
|
assert(!(reg & 0x10000000));
|
||||||
|
|
||||||
|
uint8_t value;
|
||||||
|
|
||||||
|
spi_acquire(dev->params->spi, dev->params->cs, SPI_MODE_3, dev->params->clk);
|
||||||
|
|
||||||
|
value = spi_transfer_reg(dev->params->spi, dev->params->cs, reg | PAA5100JE_CMD_READ, 0);
|
||||||
|
|
||||||
|
spi_release(dev->params->spi);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _read_reg_burst(const paa5100je_t *dev, uint8_t reg, size_t num, uint8_t *buf)
|
||||||
|
{
|
||||||
|
assert(dev);
|
||||||
|
assert(!(reg & 0x10000000));
|
||||||
|
spi_acquire(dev->params->spi, dev->params->cs, SPI_MODE_3, dev->params->clk);
|
||||||
|
spi_transfer_regs(dev->params->spi, dev->params->cs, reg | PAA5100JE_CMD_READ, NULL, buf, num);
|
||||||
|
spi_release(dev->params->spi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _write_reg(const paa5100je_t *dev, uint8_t reg, uint8_t value)
|
||||||
|
{
|
||||||
|
assert(dev);
|
||||||
|
assert(!(reg & 0x10000000));
|
||||||
|
|
||||||
|
spi_acquire(dev->params->spi, dev->params->cs, SPI_MODE_3, dev->params->clk);
|
||||||
|
|
||||||
|
(void) spi_transfer_reg(dev->params->spi, dev->params->cs, (reg | PAA5100JE_CMD_WRITE), value);
|
||||||
|
|
||||||
|
spi_release(dev->params->spi);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Writes a set of magic values to the sensors registers.
|
||||||
|
*
|
||||||
|
* The datasheet does not explain this.
|
||||||
|
* These values and registers are taken from a reference implementation.
|
||||||
|
*
|
||||||
|
* @param[in] dev device descriptor
|
||||||
|
*/
|
||||||
|
static void _prop_init(const paa5100je_t *dev)
|
||||||
|
{
|
||||||
|
_write_reg(dev, 0x7F, 0x00);
|
||||||
|
_write_reg(dev, 0x55, 0x01);
|
||||||
|
_write_reg(dev, 0x50, 0x07);
|
||||||
|
_write_reg(dev, 0x7F, 0x0E);
|
||||||
|
_write_reg(dev, 0x43, 0x10);
|
||||||
|
|
||||||
|
int tmp = _read_reg(dev, 0x67);
|
||||||
|
if (tmp & 0b10000000){
|
||||||
|
_write_reg(dev, 0x48, 0x04);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_write_reg(dev, 0x48, 0x02);
|
||||||
|
}
|
||||||
|
|
||||||
|
_write_reg(dev, 0x7F, 0x00);
|
||||||
|
_write_reg(dev, 0x51, 0x7B);
|
||||||
|
_write_reg(dev, 0x50, 0x00);
|
||||||
|
_write_reg(dev, 0x55, 0x00);
|
||||||
|
_write_reg(dev, 0x7F, 0x0E);
|
||||||
|
|
||||||
|
tmp = _read_reg(dev, 0x73);
|
||||||
|
if (tmp == 0x00){
|
||||||
|
int c1 = _read_reg(dev, 0x70);
|
||||||
|
int c2 = _read_reg(dev, 0x71);
|
||||||
|
if (c1 <= 28) {
|
||||||
|
c1 += 14;
|
||||||
|
}
|
||||||
|
if (c1 > 28) {
|
||||||
|
c1 += 11;
|
||||||
|
}
|
||||||
|
c1 = MAX(0, MIN(0x3F, c1));
|
||||||
|
c2 = (c2 * 45);
|
||||||
|
_write_reg(dev, 0x7F, 0x00);
|
||||||
|
_write_reg(dev, 0x61, 0xAD);
|
||||||
|
_write_reg(dev, 0x51, 0x70);
|
||||||
|
_write_reg(dev, 0x7F, 0x0E);
|
||||||
|
_write_reg(dev, 0x70, c1);
|
||||||
|
_write_reg(dev, 0x71, c2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev->params->var == PAA5100JE) {
|
||||||
|
_init_paa5100je(dev);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_init_pmw3901(dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Writes a set of PAA5100JE specific magic values to the sensors registers.
|
||||||
|
*
|
||||||
|
* @param[in] dev device descriptor
|
||||||
|
*/
|
||||||
|
static void _init_paa5100je(const paa5100je_t *dev)
|
||||||
|
{
|
||||||
|
_write_reg(dev, 0x7F, 0x00);
|
||||||
|
_write_reg(dev, 0x61, 0xAD);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x7F, 0x03);
|
||||||
|
_write_reg(dev, 0x40, 0x00);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x7F, 0x05);
|
||||||
|
_write_reg(dev, 0x41, 0xB3);
|
||||||
|
_write_reg(dev, 0x43, 0xF1);
|
||||||
|
_write_reg(dev, 0x45, 0x14);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x5F, 0x34);
|
||||||
|
_write_reg(dev, 0x7B, 0x08);
|
||||||
|
_write_reg(dev, 0x5E, 0x34);
|
||||||
|
_write_reg(dev, 0x5B, 0x11);
|
||||||
|
_write_reg(dev, 0x6D, 0x11);
|
||||||
|
_write_reg(dev, 0x45, 0x17);
|
||||||
|
_write_reg(dev, 0x70, 0xE5);
|
||||||
|
_write_reg(dev, 0x71, 0xE5);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x7F, 0x06);
|
||||||
|
_write_reg(dev, 0x44, 0x1B);
|
||||||
|
_write_reg(dev, 0x40, 0xBF);
|
||||||
|
_write_reg(dev, 0x4E, 0x3F);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x7F, 0x08);
|
||||||
|
_write_reg(dev, 0x66, 0x44);
|
||||||
|
_write_reg(dev, 0x65, 0x20);
|
||||||
|
_write_reg(dev, 0x6A, 0x3A);
|
||||||
|
_write_reg(dev, 0x61, 0x05);
|
||||||
|
_write_reg(dev, 0x62, 0x05);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x7F, 0x09);
|
||||||
|
_write_reg(dev, 0x4F, 0xAF);
|
||||||
|
_write_reg(dev, 0x5F, 0x40);
|
||||||
|
_write_reg(dev, 0x48, 0x80);
|
||||||
|
_write_reg(dev, 0x49, 0x80);
|
||||||
|
_write_reg(dev, 0x57, 0x77);
|
||||||
|
_write_reg(dev, 0x60, 0x78);
|
||||||
|
_write_reg(dev, 0x61, 0x78);
|
||||||
|
_write_reg(dev, 0x62, 0x08);
|
||||||
|
_write_reg(dev, 0x63, 0x50);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x7F, 0x0A);
|
||||||
|
_write_reg(dev, 0x45, 0x60);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x7F, 0x00);
|
||||||
|
_write_reg(dev, 0x4D, 0x11);
|
||||||
|
_write_reg(dev, 0x55, 0x80);
|
||||||
|
_write_reg(dev, 0x74, 0x21);
|
||||||
|
_write_reg(dev, 0x75, 0x1F);
|
||||||
|
_write_reg(dev, 0x4A, 0x78);
|
||||||
|
_write_reg(dev, 0x4B, 0x78);
|
||||||
|
_write_reg(dev, 0x44, 0x08);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x45, 0x50);
|
||||||
|
_write_reg(dev, 0x64, 0xFF);
|
||||||
|
_write_reg(dev, 0x65, 0x1F);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x7F, 0x14);
|
||||||
|
_write_reg(dev, 0x65, 0x67);
|
||||||
|
_write_reg(dev, 0x66, 0x08);
|
||||||
|
_write_reg(dev, 0x63, 0x70);
|
||||||
|
_write_reg(dev, 0x6F, 0x1C);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x7F, 0x15);
|
||||||
|
_write_reg(dev, 0x48, 0x48);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x7F, 0x07);
|
||||||
|
_write_reg(dev, 0x41, 0x0D);
|
||||||
|
_write_reg(dev, 0x43, 0x14);
|
||||||
|
_write_reg(dev, 0x4B, 0x0E);
|
||||||
|
_write_reg(dev, 0x45, 0x0F);
|
||||||
|
_write_reg(dev, 0x44, 0x42);
|
||||||
|
_write_reg(dev, 0x4C, 0x80);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x7F, 0x10);
|
||||||
|
_write_reg(dev, 0x5B, 0x02);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x7F, 0x07);
|
||||||
|
_write_reg(dev, 0x40, 0x41);
|
||||||
|
|
||||||
|
ztimer_sleep(ZTIMER_MSEC, 100);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x7F, 0x00);
|
||||||
|
_write_reg(dev, 0x32, 0x00);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x7F, 0x07);
|
||||||
|
_write_reg(dev, 0x40, 0x40);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x7F, 0x06);
|
||||||
|
_write_reg(dev, 0x68, 0xF0);
|
||||||
|
_write_reg(dev, 0x69, 0x00);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x7F, 0x0D);
|
||||||
|
_write_reg(dev, 0x48, 0xC0);
|
||||||
|
_write_reg(dev, 0x6F, 0xD5);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x7F, 0x00);
|
||||||
|
_write_reg(dev, 0x5B, 0xA0);
|
||||||
|
_write_reg(dev, 0x4E, 0xA8);
|
||||||
|
_write_reg(dev, 0x5A, 0x90);
|
||||||
|
_write_reg(dev, 0x40, 0x80);
|
||||||
|
_write_reg(dev, 0x73, 0x1F);
|
||||||
|
|
||||||
|
ztimer_sleep(ZTIMER_MSEC, 100);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x73, 0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Writes a set of PMW301 specific magic values to the sensors registers.
|
||||||
|
*
|
||||||
|
* @param[in] dev device descriptor
|
||||||
|
*/
|
||||||
|
static void _init_pmw3901(const paa5100je_t *dev)
|
||||||
|
{
|
||||||
|
_write_reg(dev, 0x7F, 0x00);
|
||||||
|
_write_reg(dev, 0x61, 0xAD);
|
||||||
|
_write_reg(dev, 0x7F, 0x03);
|
||||||
|
_write_reg(dev, 0x40, 0x00);
|
||||||
|
_write_reg(dev, 0x7F, 0x05);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x41, 0xB3);
|
||||||
|
_write_reg(dev, 0x43, 0xF1);
|
||||||
|
_write_reg(dev, 0x45, 0x14);
|
||||||
|
_write_reg(dev, 0x5B, 0x32);
|
||||||
|
_write_reg(dev, 0x5F, 0x34);
|
||||||
|
_write_reg(dev, 0x7B, 0x08);
|
||||||
|
_write_reg(dev, 0x7F, 0x06);
|
||||||
|
_write_reg(dev, 0x44, 0x1B);
|
||||||
|
_write_reg(dev, 0x40, 0xBF);
|
||||||
|
_write_reg(dev, 0x4E, 0x3F);
|
||||||
|
_write_reg(dev, 0x7F, 0x08);
|
||||||
|
_write_reg(dev, 0x65, 0x20);
|
||||||
|
_write_reg(dev, 0x6A, 0x18);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x7F, 0x09);
|
||||||
|
_write_reg(dev, 0x4F, 0xAF);
|
||||||
|
_write_reg(dev, 0x5F, 0x40);
|
||||||
|
_write_reg(dev, 0x48, 0x80);
|
||||||
|
_write_reg(dev, 0x49, 0x80);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x57, 0x77);
|
||||||
|
_write_reg(dev, 0x60, 0x78);
|
||||||
|
_write_reg(dev, 0x61, 0x78);
|
||||||
|
_write_reg(dev, 0x62, 0x08);
|
||||||
|
_write_reg(dev, 0x63, 0x50);
|
||||||
|
_write_reg(dev, 0x7F, 0x0A);
|
||||||
|
_write_reg(dev, 0x45, 0x60);
|
||||||
|
_write_reg(dev, 0x7F, 0x00);
|
||||||
|
_write_reg(dev, 0x4D, 0x11);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x55, 0x80);
|
||||||
|
_write_reg(dev, 0x74, 0x1F);
|
||||||
|
_write_reg(dev, 0x75, 0x1F);
|
||||||
|
_write_reg(dev, 0x4A, 0x78);
|
||||||
|
_write_reg(dev, 0x4B, 0x78);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x44, 0x08);
|
||||||
|
_write_reg(dev, 0x45, 0x50);
|
||||||
|
_write_reg(dev, 0x64, 0xFF);
|
||||||
|
_write_reg(dev, 0x65, 0x1F);
|
||||||
|
_write_reg(dev, 0x7F, 0x14);
|
||||||
|
_write_reg(dev, 0x65, 0x60);
|
||||||
|
_write_reg(dev, 0x66, 0x08);
|
||||||
|
_write_reg(dev, 0x63, 0x78);
|
||||||
|
_write_reg(dev, 0x7F, 0x15);
|
||||||
|
_write_reg(dev, 0x48, 0x58);
|
||||||
|
_write_reg(dev, 0x7F, 0x07);
|
||||||
|
_write_reg(dev, 0x41, 0x0D);
|
||||||
|
_write_reg(dev, 0x43, 0x14);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x4B, 0x0E);
|
||||||
|
_write_reg(dev, 0x45, 0x0F);
|
||||||
|
_write_reg(dev, 0x44, 0x42);
|
||||||
|
_write_reg(dev, 0x4C, 0x80);
|
||||||
|
_write_reg(dev, 0x7F, 0x10);
|
||||||
|
_write_reg(dev, 0x5B, 0x02);
|
||||||
|
_write_reg(dev, 0x7F, 0x07);
|
||||||
|
_write_reg(dev, 0x40, 0x41);
|
||||||
|
_write_reg(dev, 0x70, 0x00);
|
||||||
|
|
||||||
|
ztimer_sleep(ZTIMER_MSEC, 100);
|
||||||
|
_write_reg(dev, 0x32, 0x44);
|
||||||
|
_write_reg(dev, 0x7F, 0x07);
|
||||||
|
_write_reg(dev, 0x40, 0x40);
|
||||||
|
_write_reg(dev, 0x7F, 0x06);
|
||||||
|
_write_reg(dev, 0x62, 0xF0);
|
||||||
|
_write_reg(dev, 0x63, 0x00);
|
||||||
|
_write_reg(dev, 0x7F, 0x0D);
|
||||||
|
_write_reg(dev, 0x48, 0xC0);
|
||||||
|
_write_reg(dev, 0x6F, 0xD5);
|
||||||
|
_write_reg(dev, 0x7F, 0x00);
|
||||||
|
|
||||||
|
_write_reg(dev, 0x5B, 0xA0);
|
||||||
|
_write_reg(dev, 0x4E, 0xA8);
|
||||||
|
_write_reg(dev, 0x5A, 0x50);
|
||||||
|
_write_reg(dev, 0x40, 0x80);
|
||||||
|
|
||||||
|
ztimer_sleep(ZTIMER_MSEC, 100);
|
||||||
|
_write_reg(dev, 0x7F, 0x14);
|
||||||
|
_write_reg(dev, 0x6F, 0x1C);
|
||||||
|
_write_reg(dev, 0x7F, 0x00);
|
||||||
|
}
|
||||||
40
drivers/paa5100je/paa5100je_saul.c
Normal file
40
drivers/paa5100je/paa5100je_saul.c
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 TU Dresden
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup drivers_paa5100je
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief SAUL adaption for the PAA5100JE/PMW3901 optical flow sensor
|
||||||
|
*
|
||||||
|
* The data being read from the sensor represents the relative motion since the last readout.
|
||||||
|
* It depends on the surface, lighting conditions, and the sensor’s distance from the ground.
|
||||||
|
*
|
||||||
|
* @author Leonard Herbst <leonard.herbst@tu-dresden.de>
|
||||||
|
*
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "saul.h"
|
||||||
|
#include "paa5100je.h"
|
||||||
|
|
||||||
|
static int read_motion(const void *dev, phydat_t *res)
|
||||||
|
{
|
||||||
|
int err = paa5100je_get_motion_burst((paa5100je_t *) dev, &res->val[0], &res->val[1]);
|
||||||
|
if (err) {
|
||||||
|
return -ECANCELED;
|
||||||
|
}
|
||||||
|
res->unit = UNIT_M;
|
||||||
|
res->scale = -3;
|
||||||
|
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
const saul_driver_t paa5100je_saul_driver = {
|
||||||
|
.read = read_motion,
|
||||||
|
.write = saul_write_notsup,
|
||||||
|
.type = SAUL_SENSE_DISTANCE,
|
||||||
|
};
|
||||||
67
drivers/saul/init_devs/auto_init_paa5100je.c
Normal file
67
drivers/saul/init_devs/auto_init_paa5100je.c
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 TU Dresden
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup drivers_paa5100je
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief Auto initialization for PAA5100JE/PMW3901 Optical Flow Sensors
|
||||||
|
*
|
||||||
|
* @author Leonard Herbst <leonard.herbst@tu-dresden.de>
|
||||||
|
*
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "assert.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "saul_reg.h"
|
||||||
|
#include "paa5100je.h"
|
||||||
|
#include "paa5100je_params.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Define the number of configured sensors
|
||||||
|
*/
|
||||||
|
#define PAA5100JE_NUM ARRAY_SIZE(paa5100je_params)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allocate memory for the device descriptors
|
||||||
|
*/
|
||||||
|
static paa5100je_t paa5100je_devs[PAA5100JE_NUM];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allocate Memory for the SAUL registry entry
|
||||||
|
*/
|
||||||
|
static saul_reg_t saul_entries[PAA5100JE_NUM];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Define the number of saul info
|
||||||
|
*/
|
||||||
|
#define PAA5100JE_INFO_NUM ARRAY_SIZE(paa5100je_saul_info)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Import SAUL endpoint
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
extern const saul_driver_t paa5100je_saul_driver;
|
||||||
|
|
||||||
|
void auto_init_paa5100je(void)
|
||||||
|
{
|
||||||
|
assert(PAA5100JE_INFO_NUM == PAA5100JE_NUM);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < PAA5100JE_NUM; i++) {
|
||||||
|
LOG_DEBUG("[auto_init_saul] initializing paa5100je #%u\n", i);
|
||||||
|
|
||||||
|
if (paa5100je_init(&paa5100je_devs[i], &paa5100je_params[i]) != 0) {
|
||||||
|
LOG_ERROR("[auto_init_saul] error initializing paa5100je #%u\n", i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
saul_entries[i].dev = &(paa5100je_devs[i]);
|
||||||
|
saul_entries[i].name = paa5100je_saul_info[i].name;
|
||||||
|
saul_entries[i].driver = &paa5100je_saul_driver;
|
||||||
|
saul_reg_add(&saul_entries[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -255,6 +255,10 @@ void saul_init_devs(void)
|
|||||||
extern void auto_init_opt3001(void);
|
extern void auto_init_opt3001(void);
|
||||||
auto_init_opt3001();
|
auto_init_opt3001();
|
||||||
}
|
}
|
||||||
|
if (IS_USED(MODULE_PAA5100JE)) {
|
||||||
|
extern void auto_init_paa5100je(void);
|
||||||
|
auto_init_paa5100je();
|
||||||
|
}
|
||||||
if (IS_USED(MODULE_PCA9685)) {
|
if (IS_USED(MODULE_PCA9685)) {
|
||||||
extern void auto_init_pca9685(void);
|
extern void auto_init_pca9685(void);
|
||||||
auto_init_pca9685();
|
auto_init_pca9685();
|
||||||
|
|||||||
6
tests/drivers/paa5100je/Makefile
Normal file
6
tests/drivers/paa5100je/Makefile
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
include ../Makefile.drivers_common
|
||||||
|
|
||||||
|
USEMODULE += paa5100je
|
||||||
|
USEMODULE += ztimer
|
||||||
|
|
||||||
|
include $(RIOTBASE)/Makefile.include
|
||||||
3
tests/drivers/paa5100je/Makefile.ci
Normal file
3
tests/drivers/paa5100je/Makefile.ci
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
BOARD_INSUFFICIENT_MEMORY := \
|
||||||
|
atmega8 \
|
||||||
|
#
|
||||||
11
tests/drivers/paa5100je/README.md
Normal file
11
tests/drivers/paa5100je/README.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# About
|
||||||
|
This is a manual test application for the PAA5100JE/PMW3901 optical flow sensor
|
||||||
|
driver. It reads motion data from the sensor and prints it to the console.
|
||||||
|
|
||||||
|
To run the test, connect the PAA5100JE/PMW3901 sensor to your MCU.
|
||||||
|
The sensor uses SPI for communication, so make sure to connect the SPI pins
|
||||||
|
correctly. You will also need to connect the chip select (CS) pin and power
|
||||||
|
the sensor with 3.3V to 5.0V and GND.
|
||||||
|
|
||||||
|
Before running the test, you may need to adjust the pin configuration and select
|
||||||
|
the right version of the sensor (PAA5100JE or PMW3901).
|
||||||
71
tests/drivers/paa5100je/main.c
Normal file
71
tests/drivers/paa5100je/main.c
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 TU Dresden
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup tests
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief Test application for the PAA5100JE/PMW3901 optical flow sensor driver
|
||||||
|
*
|
||||||
|
* @author Leonard Herbst <leonard.herbst@tu-dresden.de>
|
||||||
|
*
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "paa5100je.h"
|
||||||
|
#include "paa5100je_params.h"
|
||||||
|
#include "ztimer.h"
|
||||||
|
|
||||||
|
static paa5100je_t dev;
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
puts("PAA5100JE/PMW3901 Optical Flow Sensor Test Application...");
|
||||||
|
int ret = paa5100je_init(&dev, &paa5100je_params[0]);
|
||||||
|
if (ret == 0) {
|
||||||
|
puts("[OK]");
|
||||||
|
}
|
||||||
|
else if (ret == -ENXIO) {
|
||||||
|
puts("Error: Invalid SPI device!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (ret == -ENODEV) {
|
||||||
|
puts("Error: Invalid SPI CS pin/line or wrong device id or revision!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("Error: Unknown error during initialization! (%d)\n", ret);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
puts("Setting LED brightness to maximum.");
|
||||||
|
if (paa5100je_set_led_brightness(&dev, PAA5100JE_LED_MAX) != 0) {
|
||||||
|
puts("Error: Could not set LED brightness!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
puts("Printing sensor state every second.");
|
||||||
|
|
||||||
|
int16_t x = 0;
|
||||||
|
int16_t y = 0;
|
||||||
|
int16_t delta_x = 0;
|
||||||
|
int16_t delta_y = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
ret = paa5100je_get_motion_burst(&dev, &delta_x, &delta_y);
|
||||||
|
if (ret == 0) {
|
||||||
|
x += delta_x;
|
||||||
|
y += delta_y;
|
||||||
|
printf("Relative Motion : x:%d, y:%d\n", delta_x, delta_y);
|
||||||
|
printf("Absolute Position: x=%d, y=%d\n", x, y);
|
||||||
|
}
|
||||||
|
ztimer_sleep(ZTIMER_MSEC, 250);
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user