mirror of
https://github.com/whowechina/chu_pico.git
synced 2025-02-17 18:49:18 +01:00
Use MPR121 internal logic now
This commit is contained in:
parent
7b1c41d3ca
commit
39eb467824
Binary file not shown.
@ -9,4 +9,3 @@ set(CMAKE_C_STANDARD 11)
|
||||
pico_sdk_init()
|
||||
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(lib/pico-mpr121 mpr121)
|
||||
|
@ -1,17 +0,0 @@
|
||||
add_library(pico-mpr121 INTERFACE)
|
||||
|
||||
target_include_directories(pico-mpr121
|
||||
INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/include
|
||||
)
|
||||
|
||||
target_link_libraries(pico-mpr121
|
||||
INTERFACE
|
||||
hardware_i2c
|
||||
)
|
||||
|
||||
target_sources(pico-mpr121
|
||||
INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/mpr121.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/include/mpr121.h
|
||||
)
|
@ -1,363 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022 Antonio González
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef _MPR121_H_
|
||||
#define _MPR121_H_
|
||||
|
||||
#include "pico.h"
|
||||
#include "hardware/i2c.h"
|
||||
|
||||
/** \file mpr121.h
|
||||
* \brief Library for using an MPR121-based touch sensor with the
|
||||
* Raspberry Pi Pico
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct mpr121_sensor {
|
||||
i2c_inst_t *i2c_port;
|
||||
uint8_t i2c_addr;
|
||||
// uint8_t i2c_sda;
|
||||
// uint8_t ic2_scl;
|
||||
} mpr121_sensor_t;
|
||||
|
||||
/*! \brief MPR121 register map
|
||||
*/
|
||||
enum mpr121_register {
|
||||
MPR121_TOUCH_STATUS_REG = 0x00u,
|
||||
MPR121_OUT_OF_RANGE_STATUS_0_REG = 0x02u,
|
||||
MPR121_OUT_OF_RANGE_STATUS_1_REG = 0x03u,
|
||||
MPR121_ELECTRODE_FILTERED_DATA_REG = 0x04u,
|
||||
MPR121_BASELINE_VALUE_REG = 0x1Eu,
|
||||
// Registers 0x2B ~ 0x7F are control and configuration registers
|
||||
MPR121_MAX_HALF_DELTA_RISING_REG = 0x2Bu,
|
||||
MPR121_NOISE_HALF_DELTA_RISING_REG = 0x2Cu,
|
||||
MPR121_NOISE_COUNT_LIMIT_RISING_REG = 0x2Du,
|
||||
MPR121_FILTER_DELAY_COUNT_RISING_REG = 0x2Eu,
|
||||
MPR121_MAX_HALF_DELTA_FALLING_REG = 0x2Fu,
|
||||
MPR121_NOISE_HALF_DELTA_FALLING_REG = 0x30u,
|
||||
MPR121_NOISE_COUNT_LIMIT_FALLING_REG = 0x31u,
|
||||
MPR121_FILTER_DELAY_COUNT_FALLING_REG = 0x32u,
|
||||
MPR121_NOISE_HALF_DELTA_TOUCHED_REG = 0x33u,
|
||||
MPR121_NOISE_COUNT_LIMIT_TOUCHED_REG = 0x34u,
|
||||
MPR121_FILTER_DELAY_COUNT_TOUCHED_REG = 0x35u,
|
||||
// (ELEPROX 0x36 .. 0x40)
|
||||
MPR121_TOUCH_THRESHOLD_REG = 0x41u,
|
||||
MPR121_RELEASE_THRESHOLD_REG = 0x42u,
|
||||
// (ELEPROX 0x59 .. 0x5A)
|
||||
MPR121_DEBOUNCE_REG = 0x5Bu,
|
||||
MPR121_AFE_CONFIG_REG = 0x5Cu,
|
||||
MPR121_FILTER_CONFIG_REG = 0x5Du,
|
||||
MPR121_ELECTRODE_CONFIG_REG = 0x5Eu,
|
||||
MPR121_ELECTRODE_CURRENT_REG = 0x5Fu,
|
||||
MPR121_ELECTRODE_CHARGE_TIME_REG = 0x6Cu,
|
||||
MPR121_GPIO_CTRL_0_REG = 0x73u,
|
||||
MPR121_GPIO_CTRL_1_REG = 0x74u,
|
||||
MPR121_GPIO_DATA_REG = 0x75u,
|
||||
MPR121_GPIO_DIRECTION_REG = 0x76u,
|
||||
MPR121_GPIO_ENABLE_REG = 0x77u,
|
||||
MPR121_GPIO_DATA_SET_REG = 0x78u,
|
||||
MPR121_GPIO_DATA_CLEAR_REG = 0x79u,
|
||||
MPR121_GPIO_DATA_TOGGLE_REG = 0x7Au,
|
||||
MPR121_AUTOCONFIG_CONTROL_0_REG = 0x7Bu,
|
||||
MPR121_AUTOCONFIG_CONTROL_1_REG = 0x7Cu,
|
||||
MPR121_AUTOCONFIG_USL_REG = 0x7Du,
|
||||
MPR121_AUTOCONFIG_LSL_REG = 0x7Eu,
|
||||
MPR121_AUTOCONFIG_TARGET_REG = 0x7Fu,
|
||||
MPR121_SOFT_RESET_REG = 0x80u
|
||||
};
|
||||
|
||||
/*! \brief Initialise the MPR121 and configure registers
|
||||
*
|
||||
* The default parameters used here to configure the sensor are as in
|
||||
* the MPR121 Quick Start Guide (AN3944).
|
||||
*
|
||||
* \param i2c_port The I2C instance, either i2c0 or i2c1
|
||||
* \param i2c_addr The I2C address of the MPR121 device
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
void mpr121_init(i2c_inst_t *i2c_port, uint8_t i2c_addr,
|
||||
mpr121_sensor_t *sensor);
|
||||
|
||||
/*! \brief Write a value to the specified register
|
||||
*
|
||||
* \param reg The register address
|
||||
* \param val The value to write
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_write(enum mpr121_register reg, uint8_t val,
|
||||
mpr121_sensor_t *sensor) {
|
||||
uint8_t buf[] = {reg, val};
|
||||
i2c_write_blocking(sensor->i2c_port, sensor->i2c_addr, buf, 2,
|
||||
false);
|
||||
}
|
||||
|
||||
/*! \brief Read a byte from the specified register
|
||||
*
|
||||
* \param reg The register address
|
||||
* \param dst Pointer to buffer to receive data
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_read(enum mpr121_register reg, uint8_t *dst,
|
||||
mpr121_sensor_t *sensor) {
|
||||
i2c_write_blocking(sensor->i2c_port, sensor->i2c_addr, ®, 1,
|
||||
true);
|
||||
i2c_read_blocking(sensor->i2c_port, sensor->i2c_addr, dst, 1,
|
||||
false);
|
||||
}
|
||||
|
||||
/*! \brief Read a 2-byte value from the specified register
|
||||
*
|
||||
* \param reg The register address
|
||||
* \param dst Pointer to buffer to receive data
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_read16(enum mpr121_register reg, uint16_t *dst,
|
||||
mpr121_sensor_t *sensor) {
|
||||
uint8_t vals[2];
|
||||
i2c_write_blocking(sensor->i2c_port, sensor->i2c_addr, ®, 1,
|
||||
true);
|
||||
i2c_read_blocking(sensor->i2c_port, sensor->i2c_addr, vals, 2,
|
||||
false);
|
||||
*dst = vals[1] << 8 | vals[0];
|
||||
}
|
||||
|
||||
/*! \brief Set touch and release thresholds
|
||||
*
|
||||
* From the MPR121 datasheet (section 5.6):
|
||||
* > In a typical application, touch threshold is in the range 4--16,
|
||||
* > and it is several counts larger than the release threshold. This
|
||||
* > is to provide hysteresis and to prevent noise and jitter.
|
||||
*
|
||||
* \param touch Touch threshold in the range 0--255
|
||||
* \param release Release threshold in the range 0--255
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_set_thresholds(uint8_t touch, uint8_t release,
|
||||
mpr121_sensor_t *sensor) {
|
||||
uint8_t config;
|
||||
mpr121_read(MPR121_ELECTRODE_CONFIG_REG, &config, sensor);
|
||||
if (config != 0){
|
||||
// Stop mode
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, 0x00, sensor);
|
||||
}
|
||||
|
||||
for (uint8_t i=0; i<12; i++) {
|
||||
mpr121_write(MPR121_TOUCH_THRESHOLD_REG + i * 2, touch, sensor);
|
||||
mpr121_write(MPR121_RELEASE_THRESHOLD_REG + i * 2, release,
|
||||
sensor);
|
||||
}
|
||||
|
||||
if (config != 0){
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, config, sensor);
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief Enable only the number of electrodes specified
|
||||
*
|
||||
* \param nelec Number of electrodes to enable
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*
|
||||
* E.g. if `nelec` is 3, electrodes 0 to 2 will be enabled; if `nelec`
|
||||
* is 6, electrodes 0 to 5 will be enabled. From the datasheet:
|
||||
* "Enabling specific channels will save the scan time and sensing
|
||||
* field power spent on the unused channels."
|
||||
*/
|
||||
static void mpr121_enable_electrodes(uint8_t nelec,
|
||||
mpr121_sensor_t *sensor){
|
||||
uint8_t config;
|
||||
mpr121_read(MPR121_ELECTRODE_CONFIG_REG, &config, sensor);
|
||||
|
||||
// Clear bits 3-0, which controls the operation of the 12
|
||||
// electrodes.
|
||||
config &= ~0x0f;
|
||||
|
||||
// Set number of electrodes enabled
|
||||
config |= nelec;
|
||||
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, 0x00, sensor);
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, config, sensor);
|
||||
}
|
||||
|
||||
/*! \brief Read the touch/release status of all 13 input channels
|
||||
*
|
||||
* \param dst Pointer to buffer to receive data
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*
|
||||
* In the value read, bits 11-0 represent electrodes 11 to 0,
|
||||
* respectively, and bit 12 is the proximity detection channel. Each
|
||||
* bit represent the status of these channels: 1 if the channel is
|
||||
* touched, 0 if it is released.
|
||||
*/
|
||||
static void mpr121_touched(uint16_t *dst, mpr121_sensor_t *sensor) {
|
||||
mpr121_read16(MPR121_TOUCH_STATUS_REG, dst, sensor);
|
||||
*dst &= 0x0fff;
|
||||
}
|
||||
|
||||
/*! \brief Determine whether an electrode has been touched
|
||||
*
|
||||
* \param electrode Electrode number
|
||||
* \param dst Pointer to buffer to receive data
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_is_touched(uint8_t electrode, bool *dst,
|
||||
mpr121_sensor_t *sensor){
|
||||
uint16_t touched;
|
||||
mpr121_touched(&touched, sensor);
|
||||
*dst = (bool) ((touched >> electrode) & 1);
|
||||
}
|
||||
|
||||
/*! \brief Read an electrode's filtered data value
|
||||
*
|
||||
* \param electrode Electrode number
|
||||
* \param dst Pointer to buffer to receive data
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*
|
||||
* The data range of the filtered data is 0 to 1024.
|
||||
* \sa mpr121_baseline_value
|
||||
*/
|
||||
static void mpr121_filtered_data(uint8_t electrode, uint16_t *dst,
|
||||
mpr121_sensor_t *sensor){
|
||||
mpr121_read16(MPR121_ELECTRODE_FILTERED_DATA_REG + (electrode * 2),
|
||||
dst, sensor);
|
||||
// Filtered data is 10-bit
|
||||
*dst &= 0x3ff;
|
||||
}
|
||||
|
||||
/*! \brief Read an electrode's baseline value
|
||||
*
|
||||
* \param electrode Electrode number
|
||||
* \param dst Pointer to buffer to receive data
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*
|
||||
* From the MPR112 datasheet:
|
||||
* > Along with the 10-bit electrode filtered data output, each channel
|
||||
* > also has a 10-bit baseline value. These values are the output of
|
||||
* > the internal baseline filter operation tracking the slow-voltage
|
||||
* > variation of the background capacitance change. Touch/release
|
||||
* > detection is made based on the comparison between the 10-bit
|
||||
* > electrode filtered data and the 10-bit baseline value.
|
||||
*
|
||||
* > Although internally the baseline value is 10-bit, users can only
|
||||
* > access the 8 MSB of the 10-bit baseline value through the baseline
|
||||
* > value registers.
|
||||
*
|
||||
* \sa mpr121_filtered_data
|
||||
*/
|
||||
static void mpr121_baseline_value(uint8_t electrode, uint16_t *dst,
|
||||
mpr121_sensor_t *sensor){
|
||||
uint8_t baseline;
|
||||
mpr121_read(MPR121_BASELINE_VALUE_REG + electrode, &baseline,
|
||||
sensor);
|
||||
// From the datasheet: Although internally the baseline value is
|
||||
// 10-bit, users can only access the 8 MSB of the 10-bit baseline
|
||||
// value through the baseline value registers. The read out from the
|
||||
// baseline register must be left shift two bits before comparing it
|
||||
// with the 10-bit electrode data.
|
||||
*dst = baseline << 2;
|
||||
}
|
||||
|
||||
/*! \brief Set the Max Half Delta
|
||||
*
|
||||
* The Max Half Delta determines the largest magnitude of variation to
|
||||
* pass through the third level filter. See application note MPR121
|
||||
* Baseline System (AN3891) for details.
|
||||
*
|
||||
* \param rising Value in the range 1~63
|
||||
* \param falling Value in the range 1~63
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_set_max_half_delta(uint8_t rising, uint8_t falling,
|
||||
mpr121_sensor_t *sensor) {
|
||||
// Read current configuration then enter stop mode
|
||||
uint8_t config;
|
||||
mpr121_read(MPR121_ELECTRODE_CONFIG_REG, &config, sensor);
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, 0x00, sensor);
|
||||
// Write MHD values
|
||||
mpr121_write(MPR121_MAX_HALF_DELTA_RISING_REG, rising, sensor);
|
||||
mpr121_write(MPR121_MAX_HALF_DELTA_FALLING_REG, falling, sensor);
|
||||
// Re-enable electrodes
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, config, sensor);
|
||||
}
|
||||
|
||||
/*! \brief Set the Noise Half Delta
|
||||
*
|
||||
* The Noise Half Delta determines the incremental change when
|
||||
* non-noise drift is detected. See application note MPR121 Baseline
|
||||
* System (AN3891) for details.
|
||||
*
|
||||
* \param rising Value in the range 1~63
|
||||
* \param falling Value in the range 1~63
|
||||
* \param touched Value in the range 1~63
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_set_noise_half_delta(uint8_t rising, uint8_t falling,
|
||||
uint8_t touched, mpr121_sensor_t *sensor) {
|
||||
// Read current configuration then enter stop mode
|
||||
uint8_t config;
|
||||
mpr121_read(MPR121_ELECTRODE_CONFIG_REG, &config, sensor);
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, 0x00, sensor);
|
||||
// Write NHD values
|
||||
mpr121_write(MPR121_NOISE_HALF_DELTA_RISING_REG, rising, sensor);
|
||||
mpr121_write(MPR121_NOISE_HALF_DELTA_FALLING_REG, falling, sensor);
|
||||
mpr121_write(MPR121_NOISE_HALF_DELTA_TOUCHED_REG, touched, sensor);
|
||||
// Re-enable electrodes
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, config, sensor);
|
||||
}
|
||||
|
||||
/*! \brief Set the Noise Count Limit
|
||||
*
|
||||
* The Noise Count Limit determines the number of samples consecutively
|
||||
* greater than the Max Half Delta necessary before it can be
|
||||
* determined that it is non-noise. See application note MPR121 Baseline
|
||||
* System (AN3891) for details.
|
||||
*
|
||||
* \param rising Value in the range 0~255
|
||||
* \param falling Value in the range 0~255
|
||||
* \param touched Value in the range 0~255
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_set_noise_count_limit(uint8_t rising,
|
||||
uint8_t falling, uint8_t touched, mpr121_sensor_t *sensor) {
|
||||
// Read current configuration then enter stop mode
|
||||
uint8_t config;
|
||||
mpr121_read(MPR121_ELECTRODE_CONFIG_REG, &config, sensor);
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, 0x00, sensor);
|
||||
// Write new NCL values
|
||||
mpr121_write(MPR121_NOISE_COUNT_LIMIT_RISING_REG, rising, sensor);
|
||||
mpr121_write(MPR121_NOISE_COUNT_LIMIT_FALLING_REG, falling, sensor);
|
||||
mpr121_write(MPR121_NOISE_COUNT_LIMIT_TOUCHED_REG, touched, sensor);
|
||||
// Re-enable electrodes
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, config, sensor);
|
||||
}
|
||||
|
||||
/*! \brief Set the Filter Delay Limit
|
||||
*
|
||||
* The Filter Delay Limit determines the rate of operation of the
|
||||
* filter. A larger number makes it operate slower. See application
|
||||
* note MPR121 Baseline System (AN3891) for details.
|
||||
*
|
||||
* \param rising Value in the range 0~255
|
||||
* \param falling Value in the range 0~255
|
||||
* \param touched Value in the range 0~255
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_set_filter_delay_limit(uint8_t rising,
|
||||
uint8_t falling, uint8_t touched, mpr121_sensor_t *sensor) {
|
||||
// Read current configuration then enter stop mode
|
||||
uint8_t config;
|
||||
mpr121_read(MPR121_ELECTRODE_CONFIG_REG, &config, sensor);
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, 0x00, sensor);
|
||||
// Write new FDL values
|
||||
mpr121_write(MPR121_FILTER_DELAY_COUNT_RISING_REG, rising, sensor);
|
||||
mpr121_write(MPR121_FILTER_DELAY_COUNT_FALLING_REG, falling,
|
||||
sensor);
|
||||
mpr121_write(MPR121_FILTER_DELAY_COUNT_TOUCHED_REG, touched,
|
||||
sensor);
|
||||
// Re-enable electrodes
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, config, sensor);
|
||||
}
|
||||
|
||||
#endif
|
@ -1,170 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022 Antonio González
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "mpr121.h"
|
||||
|
||||
void mpr121_init(i2c_inst_t *i2c_port, uint8_t i2c_addr,
|
||||
mpr121_sensor_t *sensor) {
|
||||
sensor->i2c_port = i2c_port;
|
||||
sensor->i2c_addr = i2c_addr;
|
||||
|
||||
// Enter stop mode by setting ELEPROX_EN and ELE_EN bits to zero.
|
||||
// This is needed because register write operations can only take
|
||||
// place in stop mode.
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, 0x00, sensor);
|
||||
|
||||
// Writing 0x80 (SOFT_RESET) with 0x63 asserts soft reset.
|
||||
mpr121_write(MPR121_SOFT_RESET_REG, 0x63, sensor);
|
||||
|
||||
// == Capacitance sensing settings (AN2889), Filtering and =========
|
||||
// timing settings (AN3890)
|
||||
|
||||
// These settings are configured in two registers: the Filter and
|
||||
// Global CDC CDT Configuration registers (0x5C, 0x5D).
|
||||
//
|
||||
// Charge-discharge current (CDC) and charge-discharge time (CDT)
|
||||
// can be configured globally or on a per-electrode basis. Here,
|
||||
// The global CDC and CDT values are set to their defaults, and then
|
||||
// these values are overriden by independently configuring each
|
||||
// electrode (auto-configuration).
|
||||
|
||||
// Filter/global CDC configuration register (0x5C)
|
||||
//
|
||||
// First filter iterations (FFI), bits 7-6. Number of samples taken
|
||||
// as input to the first level of filtering. Default is 0b00 (sets
|
||||
// samples taken to 6)
|
||||
//
|
||||
// Charge-discharge current (CDC), bits 5-0. Sets the value of
|
||||
// charge-discharge current applied to the electrode. Max is 63 µA
|
||||
// in 1 µA steps. Default is 0b010000 (16 µA)
|
||||
//
|
||||
// AFE configuration register default, 0b00010000 = 0x10
|
||||
mpr121_write(MPR121_AFE_CONFIG_REG, 0x10, sensor);
|
||||
|
||||
// Filter/global CDC configuration register (0x5D)
|
||||
//
|
||||
// Charge discharge time (CDT), bits 7-5. Selects the global value
|
||||
// of charge time applied to electrode. The maximum is 32 μs,
|
||||
// programmable as 2^(n-2) μs. Default is 0b001 (time is set to
|
||||
// 0.5 µs)
|
||||
//
|
||||
// Second filter iterations (SFI), bits 4-3. Selects the number of
|
||||
// samples taken for the second level filter. Default is 0b00
|
||||
// (number of samples is set to 4)
|
||||
//
|
||||
// Electrode sample interval (ESI), bits 2-0. Controls the sampling
|
||||
// rate of the device. The maximum is 128 ms, programmable to 2^n
|
||||
// ms. Decrease this value for better response time, increase to
|
||||
// save power. Default is 0b100 (period set to 16 ms).
|
||||
//
|
||||
// Filter configuration register default, 0b00100100 = 0x24
|
||||
// I do not need power saving features but I want fast responses,
|
||||
// so I set this to 0x20.
|
||||
mpr121_write(MPR121_FILTER_CONFIG_REG, 0x20, sensor);
|
||||
|
||||
// Auto-configuration
|
||||
//
|
||||
// Sets automatically charge current (CDC) and time (CDT) values for
|
||||
// each electrode.
|
||||
//
|
||||
// Autoconfig USL register: the upper limit for the
|
||||
// auto-configuration. This value (and those that follow below)
|
||||
// were calculated based on Vdd = 3.3 V and following the equations
|
||||
// in NXP Application Note AN3889.
|
||||
// USL = 201 = 0xC9
|
||||
mpr121_write(MPR121_AUTOCONFIG_USL_REG, 0xC9, sensor);
|
||||
|
||||
// Autoconfig target level register: the target level for the
|
||||
// auto-configuration baseline search.
|
||||
// TL = 181 = 0xB5
|
||||
mpr121_write(MPR121_AUTOCONFIG_TARGET_REG, 0xB5, sensor);
|
||||
|
||||
// Autoconfig LSL register: the lower limit for the
|
||||
// auto-configuration.
|
||||
// LSL = 131 = 0x83
|
||||
mpr121_write(MPR121_AUTOCONFIG_LSL_REG, 0x83, sensor);
|
||||
|
||||
// Autoconfiguration control register. Default value is 0b00001011 =
|
||||
// 0x0B, where:
|
||||
//
|
||||
// First filter iterations (FFI), bits 7-6. Must be the same value
|
||||
// of FFI as in register MPR121_AFE_CONFIG_REG (0x5C) above;
|
||||
// default is 0b00.
|
||||
//
|
||||
// Retry, bits 5-4. Default is disabled, 0b00.
|
||||
//
|
||||
// Baseline value adjust (BVA), bits 3-2. This value must be the
|
||||
// same as the CL (calibration lock) value in the Electrode
|
||||
// Configuration Register, below, i.e. 0b10.
|
||||
//
|
||||
// Automatic Reconfiguration Enable (ARE), bit 1. Default is 0b1,
|
||||
// enabled.
|
||||
//
|
||||
// Automatic Reconfiguration Enable (ACE), bit 0. Default is 0b1,
|
||||
// enabled.
|
||||
mpr121_write(MPR121_AUTOCONFIG_CONTROL_0_REG, 0x0B, sensor);
|
||||
|
||||
// == Baseline system (AN3891) =====================================
|
||||
|
||||
// Maximum Half Delta (MHD): Determines the largest magnitude of
|
||||
// variation to pass through the baseline filter. The range of the
|
||||
// effective value is 1~63.
|
||||
mpr121_write(MPR121_MAX_HALF_DELTA_RISING_REG, 0x01, sensor);
|
||||
mpr121_write(MPR121_MAX_HALF_DELTA_FALLING_REG, 0x01, sensor);
|
||||
|
||||
// Noise Half Delta (NHD): Determines the incremental change when
|
||||
// non-noise drift is detected. The range of the effective value is
|
||||
// 1~63.
|
||||
mpr121_write(MPR121_NOISE_HALF_DELTA_RISING_REG, 0x01, sensor);
|
||||
mpr121_write(MPR121_NOISE_HALF_DELTA_FALLING_REG, 0x01, sensor);
|
||||
mpr121_write(MPR121_NOISE_HALF_DELTA_TOUCHED_REG, 0x01, sensor);
|
||||
|
||||
// Noise Count Limit (NCL): Determines the number of samples
|
||||
// consecutively greater than the Max Half Delta value. This is
|
||||
// necessary to determine that it is not noise. The range of the
|
||||
// effective value is 0~255.
|
||||
mpr121_write(MPR121_NOISE_COUNT_LIMIT_RISING_REG, 0x00, sensor);
|
||||
mpr121_write(MPR121_NOISE_COUNT_LIMIT_FALLING_REG, 0xFF, sensor);
|
||||
mpr121_write(MPR121_NOISE_COUNT_LIMIT_TOUCHED_REG, 0x00, sensor);
|
||||
|
||||
// Filter Delay Count Limit (FDL): Determines the operation rate of
|
||||
// the filter. A larger count limit means the filter delay is
|
||||
// operating more slowly. The range of the effective value is 0~255.
|
||||
mpr121_write(MPR121_FILTER_DELAY_COUNT_RISING_REG, 0x00, sensor);
|
||||
mpr121_write(MPR121_FILTER_DELAY_COUNT_FALLING_REG, 0x02, sensor);
|
||||
mpr121_write(MPR121_FILTER_DELAY_COUNT_TOUCHED_REG, 0x00, sensor);
|
||||
|
||||
// == Debounce and thresholds (AN3892) =============================
|
||||
|
||||
// Debounce. Value range for each is 0~7.
|
||||
// Bits 2-0, debounce touch (DT).
|
||||
// Bits 6-4, debounce release (DR).
|
||||
mpr121_write(MPR121_DEBOUNCE_REG, 0x00, sensor);
|
||||
|
||||
// Touch and release threshold values for all electrodes.
|
||||
for (uint8_t i=0; i<12; i++) {
|
||||
mpr121_write(MPR121_TOUCH_THRESHOLD_REG + i * 2, 0x0F, sensor);
|
||||
mpr121_write(MPR121_RELEASE_THRESHOLD_REG + i * 2, 0x0A, sensor);
|
||||
}
|
||||
|
||||
// Electrode Configuration Register (ECR, 0x5E). This must be the
|
||||
// last register to write to because setting ELEPROX_EN and/or
|
||||
// ELE_EN to non-zero puts the sensor in Run Mode.
|
||||
//
|
||||
// Calibration lock (CL), bits 7-6. The default on reset is 0b00
|
||||
// (CL enabled). Here I set this instead to 0b10 because this
|
||||
// enables baseline tracking with initial baseline value loaded
|
||||
// with the 5 high bits of the first electrode data value, which
|
||||
// makes the sensor stabilise sooner. Note that ths value must
|
||||
// match BVA bits in the Auto-configure Control Register above.
|
||||
//
|
||||
// Proximity enable (ELEPROX_EN), bits 5-4. Default, 0b00
|
||||
// (proximity detection disabled).
|
||||
//
|
||||
// Electrode enabled (ELE_EN), bits 3-0. Default, 0b1100 (enable
|
||||
// all 12 electrodes).
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, 0x8C, sensor);
|
||||
}
|
@ -4,7 +4,8 @@ set(LWIP_ROOT ${PICO_SDK_PATH}/lib/lwip)
|
||||
function(make_firmware board board_def)
|
||||
pico_sdk_init()
|
||||
add_executable(${board}
|
||||
main.c slider.c air.c rgb.c save.c config.c cmd.c lzfx.c vl53l0x.c usb_descriptors.c)
|
||||
main.c slider.c air.c rgb.c save.c config.c cmd.c lzfx.c
|
||||
vl53l0x.c mpr121.c usb_descriptors.c)
|
||||
target_compile_definitions(${board} PUBLIC ${board_def})
|
||||
pico_enable_stdio_usb(${board} 1)
|
||||
pico_enable_stdio_uart(${board} 0)
|
||||
@ -20,7 +21,7 @@ function(make_firmware board board_def)
|
||||
target_link_libraries(${board} PRIVATE
|
||||
pico_multicore pico_stdlib hardware_pio hardware_pwm hardware_flash
|
||||
hardware_adc hardware_i2c hardware_watchdog
|
||||
tinyusb_device tinyusb_board pico-mpr121)
|
||||
tinyusb_device tinyusb_board)
|
||||
|
||||
pico_add_extra_outputs(${board})
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
#define I2C_PORT i2c0
|
||||
#define I2C_SDA 16
|
||||
#define I2C_SCL 17
|
||||
#define I2C_FREQ 733*1000
|
||||
#define I2C_FREQ 533*1000
|
||||
|
||||
#define I2C_HUB_EN 19
|
||||
|
||||
|
@ -11,8 +11,8 @@
|
||||
#include "slider.h"
|
||||
#include "save.h"
|
||||
|
||||
#define SENSE_LIMIT_MAX 8
|
||||
#define SENSE_LIMIT_MIN -8
|
||||
#define SENSE_LIMIT_MAX 7
|
||||
#define SENSE_LIMIT_MIN -7
|
||||
|
||||
#define MAX_COMMANDS 20
|
||||
#define MAX_COMMAND_LENGTH 20
|
||||
@ -76,15 +76,15 @@ static void list_sense()
|
||||
printf("[Sense]\n");
|
||||
printf(" Global: %d, debounce (touch, release): %d, %d\n", chu_cfg->sense.global,
|
||||
chu_cfg->sense.debounce_touch, chu_cfg->sense.debounce_release);
|
||||
printf(" | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11| 12| 13| 14| 15| 16|\n");
|
||||
printf(" -----------------------------------------------------------------\n");
|
||||
printf(" | 1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|13|14|15|16|\n");
|
||||
printf(" -------------------------------------------------\n");
|
||||
printf(" A |");
|
||||
for (int i = 0; i < 16; i++) {
|
||||
printf("%3d|", chu_cfg->sense.keys[i * 2]);
|
||||
printf("%2d|", chu_cfg->sense.keys[i * 2]);
|
||||
}
|
||||
printf("\n B |");
|
||||
for (int i = 0; i < 16; i++) {
|
||||
printf("%3d|", chu_cfg->sense.keys[i * 2 + 1]);
|
||||
printf("%2d|", chu_cfg->sense.keys[i * 2 + 1]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
@ -244,12 +244,12 @@ static uint8_t *extract_key(const char *param)
|
||||
|
||||
static void handle_sense(int argc, char *argv[])
|
||||
{
|
||||
const char *usage = "Usage: sense [key] <+|->\n"
|
||||
const char *usage = "Usage: sense [key] <+|-|0>\n"
|
||||
"Example:\n"
|
||||
" >sense +\n"
|
||||
" >sense -\n"
|
||||
" >sense 1A +\n"
|
||||
" >sense 13B -\n";
|
||||
" >sense 13B 0\n";
|
||||
if ((argc < 1) || (argc > 2)) {
|
||||
printf(usage);
|
||||
return;
|
||||
@ -273,11 +273,14 @@ static void handle_sense(int argc, char *argv[])
|
||||
if (*target > SENSE_LIMIT_MIN) {
|
||||
(*target)--;
|
||||
}
|
||||
} else if (strcmp(op, "0") == 0) {
|
||||
*target = 0;
|
||||
} else {
|
||||
printf(usage);
|
||||
return;
|
||||
}
|
||||
|
||||
slider_update_config();
|
||||
config_changed();
|
||||
list_sense();
|
||||
}
|
||||
@ -285,7 +288,7 @@ static void handle_sense(int argc, char *argv[])
|
||||
static void handle_debounce(int argc, char *argv[])
|
||||
{
|
||||
const char *usage = "Usage: debounce <touch> [release]\n"
|
||||
" touch, release: 0-255\n";
|
||||
" touch, release: 0-7\n";
|
||||
if ((argc < 1) || (argc > 2)) {
|
||||
printf(usage);
|
||||
return;
|
||||
@ -300,7 +303,8 @@ static void handle_debounce(int argc, char *argv[])
|
||||
release = extract_non_neg_int(argv[1], 0);
|
||||
}
|
||||
|
||||
if ((touch < 0) || (release < 0)) {
|
||||
if ((touch < 0) || (release < 0) ||
|
||||
(touch > 7) || (release > 7)) {
|
||||
printf(usage);
|
||||
return;
|
||||
}
|
||||
@ -308,34 +312,11 @@ static void handle_debounce(int argc, char *argv[])
|
||||
chu_cfg->sense.debounce_touch = touch;
|
||||
chu_cfg->sense.debounce_release = release;
|
||||
|
||||
slider_update_config();
|
||||
config_changed();
|
||||
list_sense();
|
||||
}
|
||||
|
||||
static void handle_baseline()
|
||||
{
|
||||
printf(" | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11| 12| 13| 14| 15| 16|\n");
|
||||
printf(" -----------------------------------------------------------------\n");
|
||||
printf(" A |");
|
||||
for (int i = 0; i < 16; i++) {
|
||||
printf("%3d|", slider_baseline(i * 2));
|
||||
}
|
||||
printf("\n B |");
|
||||
for (int i = 0; i < 16; i++) {
|
||||
printf("%3d|", slider_baseline(i * 2 + 1));
|
||||
}
|
||||
printf("\n");
|
||||
printf(" dA |");
|
||||
for (int i = 0; i < 16; i++) {
|
||||
printf("%3d|", slider_delta(i * 2));
|
||||
}
|
||||
printf("\n dB |");
|
||||
for (int i = 0; i < 16; i++) {
|
||||
printf("%3d|", slider_delta(i * 2 + 1));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void handle_save()
|
||||
{
|
||||
save_request(true);
|
||||
@ -356,7 +337,6 @@ void cmd_init()
|
||||
register_command("tof", handle_tof);
|
||||
register_command("sense", handle_sense);
|
||||
register_command("debounce", handle_debounce);
|
||||
register_command("baseline", handle_baseline);
|
||||
register_command("save", handle_save);
|
||||
register_command("factory", config_factory_reset);
|
||||
}
|
||||
|
@ -30,8 +30,8 @@ static chu_cfg_t default_cfg = {
|
||||
.pitch = 18,
|
||||
},
|
||||
.sense = {
|
||||
.debounce_touch = 1,
|
||||
.debounce_release = 8,
|
||||
.debounce_touch = 0,
|
||||
.debounce_release = 1,
|
||||
},
|
||||
.hid = {
|
||||
.joy = 0x0f,
|
||||
@ -52,6 +52,22 @@ static void config_loaded()
|
||||
chu_cfg->tof = default_cfg.tof;
|
||||
config_changed();
|
||||
}
|
||||
if ((chu_cfg->sense.global > 7) || (chu_cfg->sense.global < -7)) {
|
||||
chu_cfg->sense.global = default_cfg.sense.global;
|
||||
config_changed();
|
||||
}
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if ((chu_cfg->sense.keys[i] > 7) || (chu_cfg->sense.keys[i] < -7)) {
|
||||
chu_cfg->sense.keys[i] = default_cfg.sense.keys[i];
|
||||
config_changed();
|
||||
}
|
||||
}
|
||||
if ((chu_cfg->sense.debounce_touch > 7) |
|
||||
(chu_cfg->sense.debounce_release > 7)) {
|
||||
chu_cfg->sense.debounce_touch = default_cfg.sense.debounce_touch;
|
||||
chu_cfg->sense.debounce_release = default_cfg.sense.debounce_release;
|
||||
config_changed();
|
||||
}
|
||||
}
|
||||
|
||||
void config_changed()
|
||||
|
@ -138,11 +138,9 @@ static void core1_loop()
|
||||
{
|
||||
while (1) {
|
||||
if (mutex_try_enter(&core1_io_lock, NULL)) {
|
||||
run_lights();
|
||||
rgb_update();
|
||||
mutex_exit(&core1_io_lock);
|
||||
}
|
||||
slider_update_baseline();
|
||||
fps_count(1);
|
||||
sleep_ms(1);
|
||||
}
|
||||
@ -162,6 +160,8 @@ static void core0_loop()
|
||||
gen_nkro_report();
|
||||
report_usb_hid();
|
||||
tud_task();
|
||||
|
||||
run_lights();
|
||||
}
|
||||
}
|
||||
|
||||
|
186
firmware/src/mpr121.c
Normal file
186
firmware/src/mpr121.c
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* MP121 Captive Touch Sensor
|
||||
* WHowe <github.com/whowechina>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "hardware/i2c.h"
|
||||
|
||||
#include "mpr121.h"
|
||||
#include "board_defs.h"
|
||||
|
||||
#define IO_TIMEOUT_US 1000
|
||||
|
||||
#define TOUCH_THRESHOLD_BASE 17
|
||||
#define RELEASE_THRESHOLD_BASE 10
|
||||
|
||||
#define MPR121_TOUCH_STATUS_REG 0x00
|
||||
#define MPR121_OUT_OF_RANGE_STATUS_0_REG 0x02
|
||||
#define MPR121_OUT_OF_RANGE_STATUS_1_REG 0x03
|
||||
#define MPR121_ELECTRODE_FILTERED_DATA_REG 0x04
|
||||
#define MPR121_BASELINE_VALUE_REG 0x1E
|
||||
|
||||
#define MPR121_MAX_HALF_DELTA_RISING_REG 0x2B
|
||||
#define MPR121_NOISE_HALF_DELTA_RISING_REG 0x2C
|
||||
#define MPR121_NOISE_COUNT_LIMIT_RISING_REG 0x2D
|
||||
#define MPR121_FILTER_DELAY_COUNT_RISING_REG 0x2E
|
||||
#define MPR121_MAX_HALF_DELTA_FALLING_REG 0x2F
|
||||
#define MPR121_NOISE_HALF_DELTA_FALLING_REG 0x30
|
||||
#define MPR121_NOISE_COUNT_LIMIT_FALLING_REG 0x31
|
||||
#define MPR121_FILTER_DELAY_COUNT_FALLING_REG 0x32
|
||||
#define MPR121_NOISE_HALF_DELTA_TOUCHED_REG 0x33
|
||||
#define MPR121_NOISE_COUNT_LIMIT_TOUCHED_REG 0x34
|
||||
#define MPR121_FILTER_DELAY_COUNT_TOUCHED_REG 0x35
|
||||
|
||||
#define MPR121_TOUCH_THRESHOLD_REG 0x41
|
||||
#define MPR121_RELEASE_THRESHOLD_REG 0x42
|
||||
|
||||
#define MPR121_DEBOUNCE_REG 0x5B
|
||||
#define MPR121_AFE_CONFIG_REG 0x5C
|
||||
#define MPR121_FILTER_CONFIG_REG 0x5D
|
||||
#define MPR121_ELECTRODE_CONFIG_REG 0x5E
|
||||
#define MPR121_ELECTRODE_CURRENT_REG 0x5F
|
||||
#define MPR121_ELECTRODE_CHARGE_TIME_REG 0x6C
|
||||
#define MPR121_GPIO_CTRL_0_REG 0x73
|
||||
#define MPR121_GPIO_CTRL_1_REG 0x74
|
||||
#define MPR121_GPIO_DATA_REG 0x75
|
||||
#define MPR121_GPIO_DIRECTION_REG 0x76
|
||||
#define MPR121_GPIO_ENABLE_REG 0x77
|
||||
#define MPR121_GPIO_DATA_SET_REG 0x78
|
||||
#define MPR121_GPIO_DATA_CLEAR_REG 0x79
|
||||
#define MPR121_GPIO_DATA_TOGGLE_REG 0x7A
|
||||
#define MPR121_AUTOCONFIG_CONTROL_0_REG 0x7B
|
||||
#define MPR121_AUTOCONFIG_CONTROL_1_REG 0x7C
|
||||
#define MPR121_AUTOCONFIG_USL_REG 0x7D
|
||||
#define MPR121_AUTOCONFIG_LSL_REG 0x7E
|
||||
#define MPR121_AUTOCONFIG_TARGET_REG 0x7F
|
||||
#define MPR121_SOFT_RESET_REG 0x80
|
||||
|
||||
static void write_reg(uint8_t addr, uint8_t reg, uint8_t val)
|
||||
{
|
||||
uint8_t buf[] = {reg, val};
|
||||
i2c_write_blocking_until(I2C_PORT, addr, buf, 2, false,
|
||||
time_us_64() + IO_TIMEOUT_US);
|
||||
}
|
||||
|
||||
static uint8_t read_reg(uint8_t addr, uint8_t reg)
|
||||
{
|
||||
uint8_t value;
|
||||
i2c_write_blocking_until(I2C_PORT, addr, ®, 1, true,
|
||||
time_us_64() + IO_TIMEOUT_US);
|
||||
i2c_read_blocking_until(I2C_PORT, addr, &value, 1, false,
|
||||
time_us_64() + IO_TIMEOUT_US);
|
||||
return value;
|
||||
}
|
||||
|
||||
void mpr121_init(uint8_t i2c_addr)
|
||||
{
|
||||
write_reg(i2c_addr, 0x80, 0x63); // Soft reset MPR121 if not reset correctly
|
||||
|
||||
//touch pad baseline filter
|
||||
//rising: baseline quick rising
|
||||
write_reg(i2c_addr, 0x2B, 0x01); // Max half delta Rising
|
||||
write_reg(i2c_addr, 0x2C, 0x01); // Noise half delta Rising
|
||||
write_reg(i2c_addr, 0x2D, 0x00); // Noise count limit Rising
|
||||
write_reg(i2c_addr, 0x2E, 0x00); // Delay limit Rising
|
||||
|
||||
//falling: baseline slow falling
|
||||
write_reg(i2c_addr, 0x2F, 0x01); // Max half delta Falling
|
||||
write_reg(i2c_addr, 0x30, 0x01); // Noise half delta Falling
|
||||
write_reg(i2c_addr, 0x31, 0xFF); // Noise count limit Falling
|
||||
write_reg(i2c_addr, 0x32, 0x0); // Delay limit Falling
|
||||
|
||||
//touched: baseline keep
|
||||
write_reg(i2c_addr, 0x33, 0x00); // Noise half delta Touched
|
||||
write_reg(i2c_addr, 0x34, 0x00); // Noise count Touched
|
||||
write_reg(i2c_addr, 0x35, 0x00); // Delay limit Touched
|
||||
|
||||
//Touch pad threshold
|
||||
for (uint8_t i=0; i<12; i++) {
|
||||
write_reg(i2c_addr, 0x41 + i * 2, TOUCH_THRESHOLD_BASE);
|
||||
write_reg(i2c_addr, 0x42 + i * 2, RELEASE_THRESHOLD_BASE);
|
||||
}
|
||||
|
||||
//touch and release debounce
|
||||
write_reg(i2c_addr, 0x5B, 0x00);
|
||||
|
||||
//AFE and filter configuration
|
||||
write_reg(i2c_addr, 0x5C, 0b01010000); // AFES=6 samples, same as AFES in 0x7B, Global CDC=16uA
|
||||
write_reg(i2c_addr, 0x5D, 0b00101000); // CT=0.5us, TDS=4samples, TDI=16ms
|
||||
write_reg(i2c_addr, 0x5E, 0x80); // Set baseline calibration enabled, baseline loading 5MSB
|
||||
|
||||
//Auto Configuration
|
||||
write_reg(i2c_addr, 0x7B, 0b01001001); // AFES=6 samples, same as AFES in 0x5C
|
||||
// retry=2b00, no retry,
|
||||
// BVA=2b10, load 5MSB after AC,
|
||||
// ARE/ACE=2b11, auto configuration enabled
|
||||
//write_reg(i2c_addr, 0x7C,0x80); // Skip charge time search, use setting in 0x5D,
|
||||
// OOR, AR, AC IE disabled
|
||||
// Not used. Possible Proximity CDC shall over 63uA
|
||||
// if only use 0.5uS CDT, the TGL for proximity cannot meet
|
||||
// Possible if manually set Register0x72=0x03
|
||||
// (Auto configure result) alone.
|
||||
write_reg(i2c_addr, 0x7D, 0xc8); // AC up limit /C8/BD/C0/9C
|
||||
write_reg(i2c_addr, 0x7E, 0x82); // AC low limit /82/7A/7C/65
|
||||
write_reg(i2c_addr, 0x7F, 0xb4); // AC target /B4/AA/AC/8C target for /3.0V/2.8V/1.8V
|
||||
write_reg(i2c_addr, 0x5E, 0x8C); // Run 12 touch, CL=2b10, load 5MSB to baseline
|
||||
}
|
||||
|
||||
#define ABS(x) ((x) < 0 ? -(x) : (x))
|
||||
|
||||
static void mpr121_read_many(uint8_t addr, uint8_t reg, uint8_t *buf, size_t n)
|
||||
{
|
||||
i2c_write_blocking_until(I2C_PORT, addr, ®, 1, true,
|
||||
time_us_64() + IO_TIMEOUT_US);
|
||||
i2c_read_blocking_until(I2C_PORT, addr, buf, n, false,
|
||||
time_us_64() + IO_TIMEOUT_US * n / 2);
|
||||
}
|
||||
|
||||
static void mpr121_read_many16(uint8_t addr, uint8_t reg, uint16_t *buf, size_t n)
|
||||
{
|
||||
uint8_t vals[n * 2];
|
||||
mpr121_read_many(addr, reg, vals, n * 2);
|
||||
for (int i = 0; i < n; i++) {
|
||||
buf[i] = (vals[i * 2 + 1] << 8) | vals[i * 2];
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t mpr121_touched(uint8_t addr)
|
||||
{
|
||||
uint16_t touched;
|
||||
mpr121_read_many16(addr, MPR121_TOUCH_STATUS_REG, &touched, 2);
|
||||
return touched;
|
||||
}
|
||||
|
||||
static uint8_t mpr121_stop(uint8_t addr)
|
||||
{
|
||||
uint8_t ecr = read_reg(addr, MPR121_ELECTRODE_CONFIG_REG);
|
||||
write_reg(addr, MPR121_ELECTRODE_CONFIG_REG, ecr & 0xC0);
|
||||
return ecr;
|
||||
}
|
||||
|
||||
static uint8_t mpr121_resume(uint8_t addr, uint8_t ecr)
|
||||
{
|
||||
write_reg(addr, MPR121_ELECTRODE_CONFIG_REG, ecr);
|
||||
}
|
||||
|
||||
void mpr121_debounce(uint8_t addr, uint8_t touch, uint8_t release)
|
||||
{
|
||||
uint8_t ecr = mpr121_stop(addr);
|
||||
write_reg(addr, 0x5B, (release & 0x07) << 4 | (touch & 0x07));
|
||||
mpr121_resume(addr, ecr);
|
||||
}
|
||||
|
||||
void mpr121_sense(uint8_t addr, int8_t sense, int8_t *sense_keys)
|
||||
{
|
||||
uint8_t ecr = mpr121_stop(addr);
|
||||
for (int i = 0; i < 12; i++) {
|
||||
int8_t delta = sense + sense_keys[i];
|
||||
write_reg(addr, MPR121_TOUCH_THRESHOLD_REG + i * 2,
|
||||
TOUCH_THRESHOLD_BASE - delta);
|
||||
write_reg(addr, MPR121_RELEASE_THRESHOLD_REG + i * 2,
|
||||
RELEASE_THRESHOLD_BASE - delta / 2);
|
||||
}
|
||||
mpr121_resume(addr, ecr);
|
||||
}
|
15
firmware/src/mpr121.h
Normal file
15
firmware/src/mpr121.h
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* MP121 Captive Touch Sensor
|
||||
* WHowe <github.com/whowechina>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MP121_H
|
||||
#define MP121_H
|
||||
|
||||
void mpr121_init(uint8_t addr);
|
||||
uint16_t mpr121_touched(uint8_t addr);
|
||||
void mpr121_debounce(uint8_t addr, uint8_t touch, uint8_t release);
|
||||
void mpr121_sense(uint8_t addr, int8_t sense, int8_t *sense_keys);
|
||||
|
||||
#endif
|
@ -13,14 +13,12 @@
|
||||
|
||||
#include "bsp/board.h"
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/i2c.h"
|
||||
|
||||
#include "board_defs.h"
|
||||
#include "mpr121.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define TOUCH_THRESHOLD 17
|
||||
#define RELEASE_THRESHOLD 8
|
||||
#include "mpr121.h"
|
||||
|
||||
#define MPR121_ADDR 0x5A
|
||||
|
||||
@ -30,37 +28,6 @@ static uint16_t readout[36];
|
||||
static bool touched[36];
|
||||
static uint16_t touch[3];
|
||||
|
||||
static struct mpr121_sensor mpr121[3];
|
||||
|
||||
#define ABS(x) ((x) < 0 ? -(x) : (x))
|
||||
|
||||
static void mpr121_read_many(uint8_t addr, uint8_t reg, uint8_t *buf, size_t n)
|
||||
{
|
||||
i2c_write_blocking_until(I2C_PORT, addr, ®, 1, true, time_us_64() + 2000);
|
||||
i2c_read_blocking_until(I2C_PORT, addr, buf, n, false, time_us_64() + 2000);
|
||||
}
|
||||
|
||||
static void mpr121_read_many16(uint8_t addr, uint8_t reg, uint16_t *buf, size_t n)
|
||||
{
|
||||
uint8_t vals[n * 2];
|
||||
mpr121_read_many(addr, reg, vals, n * 2);
|
||||
for (int i = 0; i < n; i++) {
|
||||
buf[i] = (vals[i * 2 + 1] << 8) | vals[i * 2];
|
||||
}
|
||||
}
|
||||
|
||||
static void init_baseline()
|
||||
{
|
||||
sleep_ms(100);
|
||||
for (int m = 0; m < 3; m++) {
|
||||
uint8_t vals[12];
|
||||
mpr121_read_many(MPR121_ADDR + m, MPR121_BASELINE_VALUE_REG, vals, 12);
|
||||
for (int i = 0; i < 12; i++) {
|
||||
baseline[m * 12 + i] = vals[i] * 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void slider_init()
|
||||
{
|
||||
i2c_init(I2C_PORT, I2C_FREQ);
|
||||
@ -70,114 +37,31 @@ void slider_init()
|
||||
gpio_pull_up(I2C_SCL);
|
||||
|
||||
for (int m = 0; m < 3; m++) {
|
||||
mpr121_init(I2C_PORT, MPR121_ADDR + m, mpr121 + m);
|
||||
mpr121_init(MPR121_ADDR + m);
|
||||
}
|
||||
|
||||
init_baseline();
|
||||
slider_update_config();
|
||||
}
|
||||
|
||||
void slider_update()
|
||||
{
|
||||
uint8_t reg = MPR121_ELECTRODE_FILTERED_DATA_REG;
|
||||
mpr121_read_many16(MPR121_ADDR, reg, readout, 12);
|
||||
mpr121_read_many16(MPR121_ADDR + 1, reg, readout + 12, 12);
|
||||
mpr121_read_many16(MPR121_ADDR + 2, reg, readout + 24, 12);
|
||||
// mpr121_touched(touch, mpr121);
|
||||
// mpr121_touched(touch + 1, mpr121 + 1);
|
||||
// mpr121_touched(touch + 2, mpr121 + 2);
|
||||
touch[0] = mpr121_touched(MPR121_ADDR);
|
||||
touch[1] = mpr121_touched(MPR121_ADDR + 1);
|
||||
touch[2] = mpr121_touched(MPR121_ADDR + 2);
|
||||
}
|
||||
|
||||
void slider_update_baseline()
|
||||
{
|
||||
static int iteration = 0;
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
int16_t delta = readout[i] - baseline[i];
|
||||
if (ABS(delta) > RELEASE_THRESHOLD) {
|
||||
continue;
|
||||
}
|
||||
error[i] += delta;
|
||||
}
|
||||
|
||||
iteration++;
|
||||
if (iteration > 50) {
|
||||
iteration = 0;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (error[i] > 50) {
|
||||
baseline[i] ++;
|
||||
} else if (error[i] < -50) {
|
||||
baseline[i] --;
|
||||
} else {
|
||||
}
|
||||
error[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int slider_value(unsigned key)
|
||||
{
|
||||
if (key >= 32) {
|
||||
return 0;
|
||||
}
|
||||
return readout[key];
|
||||
}
|
||||
|
||||
int slider_baseline(unsigned key)
|
||||
{
|
||||
if (key >= 32) {
|
||||
return 0;
|
||||
}
|
||||
return baseline[key];
|
||||
}
|
||||
|
||||
int slider_delta(unsigned key)
|
||||
{
|
||||
if (key >= 32) {
|
||||
return 0;
|
||||
}
|
||||
return readout[key] - baseline[key];
|
||||
}
|
||||
|
||||
static uint16_t touch_count[36];
|
||||
static uint16_t release_count[36];
|
||||
|
||||
bool slider_touched(unsigned key)
|
||||
{
|
||||
if (key >= 32) {
|
||||
return 0;
|
||||
}
|
||||
int delta = baseline[key] - readout[key];
|
||||
|
||||
int bias = chu_cfg->sense.global + chu_cfg->sense.keys[key];
|
||||
int touch_thre = TOUCH_THRESHOLD - bias;
|
||||
int release_thre = RELEASE_THRESHOLD - bias / 2;
|
||||
|
||||
if (touched[key]) {
|
||||
if (delta > release_thre) {
|
||||
release_count[key] = 0;
|
||||
} else {
|
||||
release_count[key]++;
|
||||
}
|
||||
if (release_count[key] > chu_cfg->sense.debounce_release) {
|
||||
touch_count[key] = 0;
|
||||
touched[key] = false;
|
||||
}
|
||||
} else if (!touched[key]) {
|
||||
if (delta < touch_thre) {
|
||||
touch_count[key] = 0;
|
||||
} else {
|
||||
touch_count[key]++;
|
||||
}
|
||||
if (touch_count[key] > chu_cfg->sense.debounce_touch) {
|
||||
release_count[key] = 0;
|
||||
touched[key] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return touched[key];
|
||||
return touch[key / 12] & (1 << (key % 12));
|
||||
}
|
||||
|
||||
uint16_t slider_hw_touch(unsigned m)
|
||||
void slider_update_config()
|
||||
{
|
||||
return touch[m];
|
||||
for (int m = 0; m < 3; m++) {
|
||||
mpr121_debounce(MPR121_ADDR + m, chu_cfg->sense.debounce_touch,
|
||||
chu_cfg->sense.debounce_release);
|
||||
mpr121_sense(MPR121_ADDR + m, chu_cfg->sense.global, chu_cfg->sense.keys + m * 12);
|
||||
}
|
||||
}
|
||||
|
@ -10,12 +10,8 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
void slider_init();
|
||||
int slider_value(unsigned key);
|
||||
int slider_baseline(unsigned key);
|
||||
int slider_delta(unsigned key);
|
||||
bool slider_touched(unsigned key);
|
||||
uint16_t slider_hw_touch(unsigned m);
|
||||
void slider_update();
|
||||
void slider_update_baseline();
|
||||
bool slider_touched(unsigned key);
|
||||
void slider_update_config();
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user