diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..402b2be --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(mpr121) diff --git a/README.md b/README.md index e41d2aa..8bba317 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,68 @@ # esp-idf-mpr121 -MPR121 Capacitive Touch Driver for esp-idf +MPR121 Capacitive Touch Driver for esp-idf. + +I ported from [here](https://github.com/BareConductive/mpr121). + +# Hardware requirements +MPR121 Capacitive Touch switch. + +![mpr121-1](https://user-images.githubusercontent.com/6020549/147515909-cd50a16a-5c60-4bd0-bc32-c288f5d8ee88.JPG) + + +# Software requirements +esp-idf v4.4 or later. +This is because this version supports ESP32-C3. + +# Installation for ESP32 + +```Shell +git clone https://github.com/nopnop2002/esp-idf-mpr121 +cd esp-idf-mpr121 +idf.py set-target esp32 +idf.py menuconfig +idf.py flash +``` + +# Installation for ESP32-S2 + +```Shell +git clone https://github.com/nopnop2002/esp-idf-mpr121 +cd esp-idf-mpr121 +idf.py set-target esp32s2 +idf.py menuconfig +idf.py flash +``` + +# Installation for ESP32-C3 + +```Shell +git clone https://github.com/nopnop2002/esp-idf-mpr121 +cd esp-idf-mpr121 +idf.py set-target esp32c3 +idf.py menuconfig +idf.py flash +``` + + +# Configuration + +![config-top](https://user-images.githubusercontent.com/6020549/147515950-b6e2cf2f-5a82-4114-a565-df7a78085c8d.jpg) + +![config-mpr121](https://user-images.githubusercontent.com/6020549/147515956-ef978fca-07ae-4dc6-b8c1-121fe17e23ef.jpg) + + +# Wirering + +|MPR121||ESP32|ESP32-S2|ESP32-C3| +|:-:|:-:|:-:|:-:|:-:| +|SCL|--|GPIO4|GPIO16|GPIO6| +|SDA|--|GPIO5|GPIO17|GPIO7| +|IRQ|--|GPIO15|GPIO18|GPIO8| +|GND|--|GND|GND|GND| +|VCC|--|3.3V|3.3V|3.3V| + +__You can change it to any pin using menuconfig.__ + + +# Screen Shot +![mpr121-2](https://user-images.githubusercontent.com/6020549/147515969-54901561-66f5-4077-b6f8-7dbd7fe49f2c.jpg) diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt new file mode 100644 index 0000000..4e8db97 --- /dev/null +++ b/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" "mpr121.c" + INCLUDE_DIRS ".") diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild new file mode 100644 index 0000000..f5ed153 --- /dev/null +++ b/main/Kconfig.projbuild @@ -0,0 +1,36 @@ +menu "MPR121 Configuration" + + config SCL_GPIO + int "SCL GPIO number" + range 0 48 + default 6 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32H2 + default 16 if IDF_TARGET_ESP32S2 + default 46 if IDF_TARGET_ESP32S3 + default 4 + help + GPIO number (IOxx) to SCL. + Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to blink. + + config SDA_GPIO + int "SDA GPIO number" + range 0 48 + default 7 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32H2 + default 17 if IDF_TARGET_ESP32S2 + default 47 if IDF_TARGET_ESP32S3 + default 5 + help + GPIO number (IOxx) to SDA. + Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to blink. + + config IRQ_GPIO + int "IRQ GPIO number" + range 0 48 + default 8 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32H2 + default 18 if IDF_TARGET_ESP32S2 + default 48 if IDF_TARGET_ESP32S3 + default 15 + help + GPIO number (IOxx) to IRQ. + Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to blink. + +endmenu diff --git a/main/component.mk b/main/component.mk new file mode 100644 index 0000000..44bd2b5 --- /dev/null +++ b/main/component.mk @@ -0,0 +1,3 @@ +# +# Main Makefile. This is basically the same as a component makefile. +# diff --git a/main/main.c b/main/main.c new file mode 100644 index 0000000..8324c1f --- /dev/null +++ b/main/main.c @@ -0,0 +1,88 @@ +/* MPR121 Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" + +#include "mpr121.h" + +#define MPR121_ADDR 0x5A + +static const char *TAG = "MAIN"; + +void app_main(void) +{ + ESP_LOGI(TAG, "CONFIG_SCL_GPIO=%d", CONFIG_SCL_GPIO); + ESP_LOGI(TAG, "CONFIG_SDA_GPIO=%d", CONFIG_SDA_GPIO); + ESP_LOGI(TAG, "CONFIG_IRQ_GPIO=%d", CONFIG_IRQ_GPIO); + MPR121_t dev; + + uint16_t touchThreshold = 40; + uint16_t releaseThreshold = 20; + //uint16_t interruptPin = 4; + + bool ret = MPR121_begin(&dev, MPR121_ADDR, touchThreshold, releaseThreshold, CONFIG_IRQ_GPIO, CONFIG_SDA_GPIO, CONFIG_SCL_GPIO); + ESP_LOGI(TAG, "MPR121_begin=%d", ret); + if (ret == false) { + switch (MPR121_getError(&dev)) { + case NO_ERROR: + ESP_LOGE(TAG, "no error"); + break; + case ADDRESS_UNKNOWN: + ESP_LOGE(TAG, "incorrect address"); + break; + case READBACK_FAIL: + ESP_LOGE(TAG, "readback failure"); + break; + case OVERCURRENT_FLAG: + ESP_LOGE(TAG, "overcurrent on REXT pin"); + break; + case OUT_OF_RANGE: + ESP_LOGE(TAG, "electrode out of range"); + break; + case NOT_INITED: + ESP_LOGE(TAG, "not initialised"); + break; + default: + ESP_LOGE(TAG, "unknown error"); + break; + } + while(1) { + vTaskDelay(1); + } + } + + +#if 0 + MPR121_setTouchThresholdAll(&dev, 40); // this is the touch threshold - setting it low makes it more like a proximity trigger, default value is 40 for touch + MPR121_setReleaseThresholdAll(&dev, 20); // this is the release threshold - must ALWAYS be smaller than the touch threshold, default value is 20 for touch +#endif + + + MPR121_setFFI(&dev, FFI_10); // AFE Configuration 1 + MPR121_setSFI(&dev, SFI_10); // AFE Configuration 2 + MPR121_setGlobalCDT(&dev, CDT_4US); // reasonable for larger capacitances + MPR121_autoSetElectrodesDefault(&dev, true); // autoset all electrode settings + + + while(1) { + MPR121_updateAll(&dev); + for (int i = 0; i < 12; i++) { + if (MPR121_isNewTouch(&dev, i)) { + ESP_LOGI(TAG, "electrode %d was just touched", i); + } else if (MPR121_isNewRelease(&dev, i)) { + ESP_LOGI(TAG, "electrode %d was just released", i); + } + } + vTaskDelay(10); + } +} diff --git a/main/mpr121.c b/main/mpr121.c new file mode 100644 index 0000000..cd58416 --- /dev/null +++ b/main/mpr121.c @@ -0,0 +1,1152 @@ +/******************************************************************************* + + Bare Conductive MPR121 library + ------------------------------ + + MPR121.cpp - MPR121 class implementation file + + Based on code by Jim Lindblom and plenty of inspiration from the Freescale + Semiconductor datasheets and application notes. + + Bare Conductive code written by Stefan Dzisiewski-Smith, Peter Krige + and Szymon Kaliski. + + This work is licensed under a MIT license https://opensource.org/licenses/MIT + + Copyright (c) 2016, Bare Conductive + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +*******************************************************************************/ + +#include +#include +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "driver/i2c.h" +#include "driver/gpio.h" + +#include "mpr121.h" + + +#define NOT_INITED_BIT 0 +#define ADDRESS_UNKNOWN_BIT 1 +#define READBACK_FAIL_BIT 2 +#define OVERCURRENT_FLAG_BIT 3 +#define OUT_OF_RANGE_BIT 4 + +#define I2C_NUM I2C_NUM_0 +//#define I2C_NUM I2C_NUM_1 + +#define I2C_MASTER_FREQ_HZ 400000 /*!< I2C master clock frequency. no higher than 1MHz for now */ + +static const char *TAG = "MPR121"; + +void MPR121_type(MPR121_t * dev){ + dev->address = 0x5C; // default address is 0x5C, for use with Bare Conductive Touch Board + dev->ECR_backup = 0x00; + dev->running = false; + dev->error = 1<touchData = 0; + dev->lastTouchData = 0; + dev->autoTouchStatusFlag = false; +} + +void MPR121_setRegister(MPR121_t * dev, uint8_t reg, uint8_t value){ + + ESP_LOGD(TAG, "setRegister reg=0x%02x value=0x%02x", reg, value); + bool wasRunning = false;; + + if(reg==MPR121_ECR){ // if we are modding MPR121_ECR, update our internal running status + if(value&0x3F){ + dev->running = true; + } else { + dev->running = false; + } + } else if(regrunning; + if(wasRunning) MPR121_stop(dev); // we should ALWAYS be in stop mode for this + // unless modding MPR121_ECR or GPIO / LED register + } + +#if 0 + Wire.beginTransmission(address); + Wire.write(reg); + Wire.write(value); + if(Wire.endTransmission()!=0){ + dev->error |= 1<error &= ~(1<address << 1) | I2C_MASTER_WRITE, true); + i2c_master_write_byte(cmd, reg, true); + i2c_master_write_byte(cmd, value, true); + i2c_master_stop(cmd); + esp_err_t espRc = i2c_master_cmd_begin(I2C_NUM, cmd, 10/portTICK_PERIOD_MS); + if (espRc == ESP_OK) { + ESP_LOGD(TAG, "setRegister reg=0x%02x value=0x%02x successfully", reg, value); + dev->error &= ~(1<error |= 1<error &= ~(1<error |= 1<address << 1) | I2C_MASTER_WRITE, true); + i2c_master_write_byte(cmd, reg, true); + + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (dev->address << 1) | I2C_MASTER_READ, true); + i2c_master_read(cmd, buf, 1, I2C_MASTER_NACK); + + i2c_master_stop(cmd); + esp_err_t espRc = i2c_master_cmd_begin(I2C_NUM, cmd, 10/portTICK_PERIOD_MS); + if (espRc == ESP_OK) { + dev->error &= ~(1<error |= 1<error |= 1<error &= ~(1<error |= 1<error &= ~(1< 0){ + if( stuck_transaction ){ + } else { + } + } + + // now we've released (if necessary) we can get on with things + Wire.begin(); +#endif + + i2c_config_t i2c_config = { + .mode = I2C_MODE_MASTER, + .sda_io_num = sda, + .scl_io_num = scl, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .master.clk_speed = I2C_MASTER_FREQ_HZ + }; + ESP_ERROR_CHECK(i2c_param_config(I2C_NUM, &i2c_config)); + ESP_ERROR_CHECK(i2c_driver_install(I2C_NUM, I2C_MODE_MASTER, 0, 0, 0)); + + // addresses only valid 0x5A to 0x5D - if we don't change the address it stays at default + if(address>=0x5A && address<=0x5D) + { + dev->address = address; // need to be specific here + } + + dev->error &= ~(1<defaultSettings ); + MPR121_settingsType(&(dev->defaultSettings)); + MPR121_applySettings(dev); + + // only apply thresholds if they differ from existing defaults + if( touchThreshold != dev->defaultSettings._TTHRESH ){ + MPR121_setTouchThresholdAll(dev, touchThreshold ); + } + + if( releaseThreshold != dev->defaultSettings._RTHRESH ){ + MPR121_setReleaseThresholdAll(dev, releaseThreshold ); + } + + if( interruptPin != dev->defaultSettings._INTERRUPT ){ + MPR121_setInterruptPin(dev, interruptPin ); + } + + return true; + + } else { + return false; + } +} + +#if 0 +void MPR121_clearSavedThresholds(MPR121_t * dev) { + #ifdef ARDUINO_ARCH_AVR + uint8_t maxElectrodes = 12; + int len = E2END; + + for(uint8_t i=0; i<13; i++){ + EEPROM.write(len - (i + 1), 255); + EEPROM.write(len - (i + 1) - maxElectrodes, 255); + } + #endif +} +#endif + +#if 0 +void MPR121_restoreSavedThresholds(MPR121_t * dev) { + #ifdef ARDUINO_ARCH_AVR + uint8_t maxElectrodes = 12; + int len = E2END; + + for(uint8_t i=0; i<13; i++){ + uint8_t releaseThreshold = EEPROM.read(len - (i + 1)); + uint8_t touchThreshold = EEPROM.read(len - (i + 1) - maxElectrodes); + + if (touchThreshold < 255) { + MPR121_setTouchThreshold(dev, i, touchThreshold + 1); // EEPROM values are saved off-by-one + } + else { + MPR121_setTouchThreshold(dev, i, defaultSettings.TTHRESH); + } + + if (releaseThreshold < 255) { + MPR121_setReleaseThreshold(dev, i, releaseThreshold + 1); // EEPROM values are saved off-by-one + } + else { + MPR121_setReleaseThreshold(dev, i, defaultSettings.RTHRESH); + } + } + #endif +} +#endif + +#if 0 +void MPR121_goSlow(MPR121_t * dev){ + Wire.setClock(100000L); // set I2C clock to 100kHz +} + +void MPR121_goFast(MPR121_t * dev){ + Wire.setClock(400000L); // set I2C clock to 400kHz +} +#endif + +void MPR121_run(MPR121_t * dev){ + if(!MPR121_isInited(dev)) return; + MPR121_setRegister(dev, MPR121_ECR, dev->ECR_backup); // restore backup to return to run mode +} + +void MPR121_stop(MPR121_t * dev){ + if(!MPR121_isInited(dev)) return; + dev->ECR_backup = MPR121_getRegister(dev, MPR121_ECR); // backup MPR121_ECR to restore when we enter run + MPR121_setRegister(dev, MPR121_ECR, dev->ECR_backup & 0xC0); // turn off all electrodes to stop +} + +bool MPR121_reset(MPR121_t * dev){ + // return true if we successfully reset a device at the + // address we are expecting + + // MPR121_AFE2 is one of the few registers that defaults to a non-zero value - + // checking it is sensible as reading back an incorrect value implies + // something went wrong - we also check MPR121_TS2 bit 7 to see if we have an + // overcurrent flag set + + MPR121_setRegister(dev, MPR121_SRST, 0x63); // soft reset + + if(MPR121_getRegister(dev, MPR121_AFE2)!=0x24){ + dev->error |= 1<error &= ~(1<error |= 1<error &= ~(1<_TTHRESH=40; + defaultSettings->_RTHRESH=20; + defaultSettings->_INTERRUPT=0; // note that this is not a hardware interrupt, just the digital + // pin that the MPR121 ~INT pin is connected to + defaultSettings->_MHDR=0x01; + defaultSettings->_NHDR=0x01; + defaultSettings->_NCLR=0x10; + defaultSettings->_FDLR=0x20; + defaultSettings->_MHDF=0x01; + defaultSettings->_NHDF=0x01; + defaultSettings->_NCLF=0x10; + defaultSettings->_FDLF=0x20; + defaultSettings->_NHDT=0x01; + defaultSettings->_NCLT=0x10; + defaultSettings->_FDLT=0xFF; + defaultSettings->_MHDPROXR=0x0F; + defaultSettings->_NHDPROXR=0x0F; + defaultSettings->_NCLPROXR=0x00; + defaultSettings->_FDLPROXR=0x00; + defaultSettings->_MHDPROXF=0x01; + defaultSettings->_NHDPROXF=0x01; + defaultSettings->_NCLPROXF=0xFF; + defaultSettings->_FDLPROXF=0xFF; + defaultSettings->_NHDPROXT=0x00; + defaultSettings->_NCLPROXT=0x00; + defaultSettings->_FDLPROXT=0x00; + defaultSettings->_DTR=0x11; + defaultSettings->_AFE1=0xFF; + defaultSettings->_AFE2=0x30; + defaultSettings->_ECR=0xCC; // default to fast baseline startup and 12 electrodes enabled, no prox + defaultSettings->_ACCR0=0x00; + defaultSettings->_ACCR1=0x00; + defaultSettings->_USL=0x00; + defaultSettings->_LSL=0x00; + defaultSettings->_TL=0x00; +} + + +//void MPR121_applySettings(MPR121_t * dev, MPR121_settings_type *settings){ +void MPR121_applySettings(MPR121_t * dev){ + bool wasRunning = dev->running; + if(wasRunning) MPR121_stop(dev); // can't change most regs when running - checking + // here avoids multiple stop() / run() calls + + MPR121_setRegister(dev, MPR121_MHDR, dev->defaultSettings._MHDR); + MPR121_setRegister(dev, MPR121_NHDR, dev->defaultSettings._NHDR); + MPR121_setRegister(dev, MPR121_NCLR, dev->defaultSettings._NCLR); + MPR121_setRegister(dev, MPR121_FDLR, dev->defaultSettings._FDLR); + MPR121_setRegister(dev, MPR121_MHDF, dev->defaultSettings._MHDF); + MPR121_setRegister(dev, MPR121_NHDF, dev->defaultSettings._NHDF); + MPR121_setRegister(dev, MPR121_NCLF, dev->defaultSettings._NCLF); + MPR121_setRegister(dev, MPR121_FDLF, dev->defaultSettings._FDLF); + MPR121_setRegister(dev, MPR121_NHDT, dev->defaultSettings._NHDT); + MPR121_setRegister(dev, MPR121_NCLT, dev->defaultSettings._NCLT); + MPR121_setRegister(dev, MPR121_FDLT, dev->defaultSettings._FDLT); + MPR121_setRegister(dev, MPR121_MHDPROXR, dev->defaultSettings._MHDPROXR); + MPR121_setRegister(dev, MPR121_NHDPROXR, dev->defaultSettings._NHDPROXR); + MPR121_setRegister(dev, MPR121_NCLPROXR, dev->defaultSettings._NCLPROXR); + MPR121_setRegister(dev, MPR121_FDLPROXR, dev->defaultSettings._FDLPROXR); + MPR121_setRegister(dev, MPR121_MHDPROXF, dev->defaultSettings._MHDPROXF); + MPR121_setRegister(dev, MPR121_NHDPROXF, dev->defaultSettings._NHDPROXF); + MPR121_setRegister(dev, MPR121_NCLPROXF, dev->defaultSettings._NCLPROXF); + MPR121_setRegister(dev, MPR121_FDLPROXF, dev->defaultSettings._FDLPROXF); + MPR121_setRegister(dev, MPR121_NHDPROXT, dev->defaultSettings._NHDPROXT); + MPR121_setRegister(dev, MPR121_NCLPROXT, dev->defaultSettings._NCLPROXT); + MPR121_setRegister(dev, MPR121_FDLPROXT, dev->defaultSettings._FDLPROXT); + MPR121_setRegister(dev, MPR121_DTR, dev->defaultSettings._DTR); + MPR121_setRegister(dev, MPR121_AFE1, dev->defaultSettings._AFE1); + MPR121_setRegister(dev, MPR121_AFE2, dev->defaultSettings._AFE2); + MPR121_setRegister(dev, MPR121_ACCR0, dev->defaultSettings._ACCR0); + MPR121_setRegister(dev, MPR121_ACCR1, dev->defaultSettings._ACCR1); + MPR121_setRegister(dev, MPR121_USL, dev->defaultSettings._USL); + MPR121_setRegister(dev, MPR121_LSL, dev->defaultSettings._LSL); + MPR121_setRegister(dev, MPR121_TL, dev->defaultSettings._TL); + + MPR121_setRegister(dev, MPR121_ECR, dev->defaultSettings._ECR); + + dev->error &= ~(1<defaultSettings._TTHRESH); + MPR121_setReleaseThresholdAll(dev, dev->defaultSettings._RTHRESH); + //MPR121_setInterruptPin(dev, dev->defaultSettings._INTERRUPT); + + if(wasRunning) MPR121_run(dev); +} + +//mpr121_error_type MPR121_getError(MPR121_t * dev){ +uint8_t MPR121_getError(MPR121_t * dev){ + // important - this resets the IRQ pin - as does any I2C comms + + MPR121_getRegister(dev, MPR121_OORS1); // OOR registers - we may not have read them yet, + MPR121_getRegister(dev, MPR121_OORS2); // whereas the other errors should have been caught + + // order of error precedence is determined in this logic block + + if(!MPR121_isInited(dev)) return NOT_INITED; // this has its own checker function + + if((dev->error & (1<error & (1<error & (1<error & (1<error = 0; +} + +bool MPR121_isRunning(MPR121_t * dev){ + return dev->running; +} + +bool MPR121_isInited(MPR121_t * dev){ + return (dev->error & (1<autoTouchStatusFlag = false; + + dev->lastTouchData = dev->touchData; + dev->touchData = (unsigned int)MPR121_getRegister(dev, MPR121_TS1) + ((unsigned int)MPR121_getRegister(dev, MPR121_TS2)<<8); +} + +bool MPR121_getTouchData(MPR121_t * dev, uint8_t electrode){ + if(electrode>12 || !MPR121_isInited(dev)) return false; // avoid out of bounds behaviour + + return((dev->touchData>>electrode)&1); +} + +uint8_t MPR121_getNumTouches(MPR121_t * dev){ + if(!MPR121_isInited(dev)) return(0xFF); + + uint8_t scratch = 0; + for(uint8_t i=0; i<13; i++){ + if(MPR121_getTouchData(dev, i)) scratch++; + } + + return(scratch); +} + +bool MPR121_getLastTouchData(MPR121_t * dev, uint8_t electrode){ + if(electrode>12 || !MPR121_isInited(dev)) return false; // avoid out of bounds behaviour + + return((dev->lastTouchData>>electrode)&1); +} + +bool MPR121_updateFilteredData(MPR121_t * dev){ + if(!MPR121_isInited(dev)) return(false); + + uint8_t buf[26]; + memset (buf, 0, 26); + uint8_t LSB, MSB; + + if(MPR121_touchStatusChanged(dev)) { + dev->autoTouchStatusFlag = true; + } + + for(int i=0; i<26; i++){ // 13 filtered values + buf[i] = MPR121_getRegister(dev, MPR121_E0FDL+i); + } + + for(int i=0; i<13; i++){ // 13 filtered values + if(MPR121_touchStatusChanged(dev)) { + dev->autoTouchStatusFlag = true; + } + LSB = buf[i*2]; + if(MPR121_touchStatusChanged(dev)) { + dev->autoTouchStatusFlag = true; + } + MSB = buf[i*2+1]; + dev->filteredData[i] = ((MSB << 8) | LSB); + } + + return true; + +#if 0 + uint8_t LSB, MSB; + + Wire.beginTransmission(address); + Wire.write(MPR121_E0FDL); // set address register to read from the start of the + //filtered data + Wire.endTransmission(false); // repeated start + + if(MPR121_touchStatusChanged(dev)) { + dev->autoTouchStatusFlag = true; + } + + if(Wire.requestFrom(address,(uint8_t)26)==26){ + for(int i=0; i<13; i++){ // 13 filtered values + if(MPR121_touchStatusChanged(dev)) { + dev->autoTouchStatusFlag = true; + } + LSB = Wire.read(); + if(MPR121_touchStatusChanged(dev)) { + dev->autoTouchStatusFlag = true; + } + MSB = Wire.read(); + dev->filteredData[i] = ((MSB << 8) | LSB); + } + return(true); + } else { + // if we don't get back all 26 values we requested, don't update the FDAT values + // and return false + return(false); + } +#endif +} + +int MPR121_getFilteredData(MPR121_t * dev, uint8_t electrode){ + if(electrode>12 || !MPR121_isInited(dev)) return(0xFFFF); // avoid out of bounds behaviour + + return(dev->filteredData[electrode]); +} + +bool MPR121_updateBaselineData(MPR121_t * dev){ + if(!MPR121_isInited(dev)) return(false); + + uint8_t buf[13]; + memset (buf, 0, 13); + + if(MPR121_touchStatusChanged(dev)) { + dev->autoTouchStatusFlag = true; + } + + for(int i=0; i<13; i++){ // 13 filtered values + buf[i] = MPR121_getRegister(dev, MPR121_E0BV+i); + if(MPR121_touchStatusChanged(dev)) { + dev->autoTouchStatusFlag = true; + } + dev->baselineData[i] = buf[i]<<2; + } + + return true; + +#if 0 + Wire.beginTransmission(address); + Wire.write(MPR121_E0BV); // set address register to read from the start of the + // baseline data + Wire.endTransmission(false); // repeated start + + if(MPR121_touchStatusChanged(dev)) { + dev->autoTouchStatusFlag = true; + } + + if(Wire.requestFrom(address,(uint8_t)13)==13){ + for(int i=0; i<13; i++){ // 13 filtered values + if(MPR121_touchStatusChanged(dev)) { + dev->autoTouchStatusFlag = true; + } + dev->baselineData[i] = Wire.read()<<2; + } + return(true); + } else { + // if we don't get back all 26 values we requested, don't update the BVAL values + // and return false + return(false); + } +#endif +} + +int MPR121_getBaselineData(MPR121_t * dev, uint8_t electrode){ + if(electrode>12 || !MPR121_isInited(dev)) return(0xFFFF); // avoid out of bounds behaviour + + return(dev->baselineData[electrode]); +} + +bool MPR121_isNewTouch(MPR121_t * dev, uint8_t electrode){ + if(electrode>12 || !MPR121_isInited(dev)) return(false); // avoid out of bounds behaviour + return((MPR121_getLastTouchData(dev, electrode) == false) && (MPR121_getTouchData(dev, electrode) == true)); +} + +bool MPR121_isNewRelease(MPR121_t * dev, uint8_t electrode){ + if(electrode>12 || !MPR121_isInited(dev)) return(false); // avoid out of bounds behaviour + return((MPR121_getLastTouchData(dev, electrode) == true) && (MPR121_getTouchData(dev, electrode) == false)); +} + +void MPR121_updateAll(MPR121_t * dev){ + MPR121_updateTouchData(dev); + MPR121_updateBaselineData(dev); + MPR121_updateFilteredData(dev); +} + +void MPR121_setTouchThresholdAll(MPR121_t * dev, uint8_t val){ + if(!MPR121_isInited(dev)) return; + bool wasRunning = dev->running; + + if(wasRunning) MPR121_stop(dev); // can only change thresholds when not running + // checking here avoids multiple stop() / run() + // calls + + for(uint8_t i=0; i<13; i++){ + MPR121_setTouchThreshold(dev, i, val); + } + + if(wasRunning) MPR121_run(dev); +} + +#if 0 +void MPR121_saveTouchThreshold(MPR121_t * dev, uint8_t electrode, uint8_t val){ + #ifdef ARDUINO_ARCH_AVR + if(electrode>12 || !MPR121_isInited(dev)) return; // avoid out of bounds behaviour + + MPR121_setTouchThreshold(dev, electrode, val); + + // store to EEPROM + uint8_t maxElectrodes = 12; + int len = E2END; + int addr = len - maxElectrodes - (electrode + 1); + EEPROM.write(addr, val - 1); // val - 1 so 255 stays as never-written-to + #endif +} +#endif + +void MPR121_setTouchThreshold(MPR121_t * dev, uint8_t electrode, uint8_t val){ + if(electrode>12 || !MPR121_isInited(dev)) return; // avoid out of bounds behaviour + + // this relies on the internal register map of the MPR121 + MPR121_setRegister(dev, MPR121_E0TTH + (electrode<<1), val); +} + +void MPR121_setReleaseThresholdAll(MPR121_t * dev, uint8_t val){ + if(!MPR121_isInited(dev)) return; + bool wasRunning = dev->running; + + if(wasRunning) MPR121_stop(dev); // can only change thresholds when not running + // checking here avoids multiple stop / starts + + for(uint8_t i=0; i<13; i++){ + MPR121_setReleaseThreshold(dev, i, val); + } + + if(wasRunning) MPR121_run(dev); +} + +void MPR121_setReleaseThreshold(MPR121_t * dev, uint8_t electrode, uint8_t val){ + if(electrode>12 || !MPR121_isInited(dev)) return; // avoid out of bounds behaviour + + // this relies on the internal register map of the MPR121 + MPR121_setRegister(dev, MPR121_E0RTH + (electrode<<1), val); +} + +#if 0 +void MPR121_saveReleaseThreshold(MPR121_t * dev, uint8_t electrode, uint8_t val){ + #ifdef ARDUINO_ARCH_AVR + if(electrode>12 || !MPR121_isInited(dev)) return; // avoid out of bounds behaviour + + MPR121_setReleaseThreshold(dev, electrode, val); + + // store to EEPROM + int len = E2END; + int addr = len - (electrode + 1); + EEPROM.write(addr, val - 1); // val - 1 so 255 stays as never-written-to + #endif +} +#endif + +uint8_t MPR121_getTouchThreshold(MPR121_t * dev, uint8_t electrode){ + if(electrode>12 || !MPR121_isInited(dev)) return(0xFF); // avoid out of bounds behaviour + return(MPR121_getRegister(dev, MPR121_E0TTH+(electrode<<1))); // "255" issue is in here somewhere + //return(101); +} + +uint8_t MPR121_getReleaseThreshold(MPR121_t * dev, uint8_t electrode){ + if(electrode>12 || !MPR121_isInited(dev)) return(0xFF); // avoid out of bounds behaviour + return(MPR121_getRegister(dev, MPR121_E0RTH+(electrode<<1))); // "255" issue is in here somewhere + //return(51); +} + +void MPR121_setInterruptPin(MPR121_t * dev, uint8_t pin){ + // :: here forces the compiler to use Arduino's pinMode, not MPR121's + if(!MPR121_isInited(dev)) return; + //::pinMode(pin, INPUT_PULLUP); + ESP_LOGD(TAG, "setInterruptPin pin=%d", pin); + gpio_reset_pin(pin); + gpio_set_direction(pin, GPIO_MODE_INPUT); + dev->interruptPin = pin; +} + +bool MPR121_touchStatusChanged(MPR121_t * dev){ + // :: here forces the compiler to use Arduino's digitalRead, not MPR121's + //return(dev->autoTouchStatusFlag || (!::digitalRead(dev->interruptPin))); + return(dev->autoTouchStatusFlag || (!gpio_get_level(dev->interruptPin))); +} + +//void MPR121_setProxMode(MPR121_t * dev, mpr121_proxmode_type mode){ +void MPR121_setProxMode(MPR121_t * dev, uint8_t mode){ + + if(!MPR121_isInited(dev)) return; + + bool wasRunning = dev->running; + + if(wasRunning) MPR121_stop(dev); + + switch(mode){ + case PROX_DISABLED: + dev->ECR_backup &= ~(3<<4); // ELEPROX_EN[1:0] = 00 + break; + case PROX_0_1: + dev->ECR_backup |= (1<<4); // ELEPROX_EN[1:0] = 01 + dev->ECR_backup &= ~(1<<5); + break; + case PROX_0_3: + dev->ECR_backup &= ~(1<<4); // ELEPROX_EN[1:0] = 10 + dev->ECR_backup |= (1<<5); + break; + case PROX_0_11: + dev->ECR_backup |= (3<<4); // ELEPROX_EN[1:0] = 11 + break; + } + + if(wasRunning) MPR121_run(dev); +} + +//void MPR121_setCalibrationLock(MPR121_t * dev, mpr121_cal_lock_type lock){ +void MPR121_setCalibrationLock(MPR121_t * dev, uint8_t lock){ + + if(!MPR121_isInited(dev)) return; + + bool wasRunning = dev->running; + + if(wasRunning) MPR121_stop(dev); + + switch(lock){ + case CAL_LOCK_ENABLED: + dev->ECR_backup &= ~(3<<6); // CL[1:0] = 00 + break; + case CAL_LOCK_DISABLED: + dev->ECR_backup |= (1<<6); // CL[1:0] = 01 + dev->ECR_backup &= ~(1<<7); + break; + case CAL_LOCK_ENABLED_5_BIT_COPY: + dev->ECR_backup &= ~(1<<6); // CL[1:0] = 10 + dev->ECR_backup |= (1<<7); + break; + case CAL_LOCK_ENABLED_10_BIT_COPY: + dev->ECR_backup |= (3<<4); // CL[1:0] = 11 + break; + } + + if(wasRunning) MPR121_run(dev); +} + +void MPR121_setGlobalCDC(MPR121_t * dev, uint8_t CDC){ + if(CDC > 63) return; // current is only valid 0..63uA + + MPR121_setRegister(dev, MPR121_AFE1, (MPR121_getRegister(dev, MPR121_AFE1) & 0xC0) | CDC); +} + +void MPR121_setElectrodeCDC(MPR121_t * dev, uint8_t electrode, uint8_t CDC){ + if(CDC > 63 || electrode > 12) return; // current is only valid 0..63uA, electrode only valid 0..12 + + MPR121_setRegister(dev, MPR121_CDC0 + electrode, CDC); +} + +//void MPR121_setGlobalCDT(MPR121_t * dev, mpr121_CDT_type CDT){ +void MPR121_setGlobalCDT(MPR121_t * dev, uint8_t CDT){ + MPR121_setRegister(dev, MPR121_AFE2, (MPR121_getRegister(dev, MPR121_AFE2) & 0x1F) | (CDT << 5)); +} + +//void MPR121_setElectrodeCDT(MPR121_t * dev, uint8_t electrode, mpr121_CDT_type CDT){ +void MPR121_setElectrodeCDT(MPR121_t * dev, uint8_t electrode, uint8_t CDT){ + MPR121_setRegister(dev, MPR121_CDT01 + (electrode >> 1), (MPR121_getRegister(dev, MPR121_CDT01 + (electrode >> 1)) & (0x0F << (((electrode + 1) % 2)<<2))) | (CDT << ((electrode % 2)<<2))); +} + +bool MPR121_autoSetElectrodeCDC(MPR121_t * dev, uint8_t electrode, uint16_t VCC_mV){ + uint16_t upper_limit_FDAT = (uint16_t)((((uint32_t)VCC_mV - 700)*256)/VCC_mV) << 2; + uint16_t target_FDAT = (uint16_t)(((uint32_t)upper_limit_FDAT * 90) / 100); + uint16_t lower_limit_FDAT = (uint16_t)(((uint32_t)upper_limit_FDAT * 65) / 100); + + uint16_t this_value; + int16_t last_distance = 0; + int16_t this_distance = 0; + + const uint8_t max_num_delay_loops = 100; + uint8_t num_delay_loops; + + bool scratch = false; // default to failure + uint8_t saved_num_enabled_electrodes = MPR121_getNumEnabledElectrodes(dev); + + MPR121_setNumEnabledElectrodes(dev, electrode + 1); // reducing the number of running electrodes to a minimum speeds things up + if(!dev->running) MPR121_run(dev); + + for(uint8_t CDC = 1; CDC < 63; CDC ++){ + MPR121_setElectrodeCDC(dev, electrode, CDC); + num_delay_loops = 0; + + do{ + MPR121_updateFilteredData(dev); + } while((MPR121_getFilteredData(dev, electrode) == 0) && (num_delay_loops++ < max_num_delay_loops)); + + this_value = MPR121_getFilteredData(dev, electrode); + + this_distance = (uint16_t)(abs((int16_t)this_value - (int16_t)target_FDAT)); // TODO: tidy up signed / unsigned types here + if(CDC > 1){ // only need to see if we need to quit once we have at least two measurements to compare + if(this_distance > last_distance){ // if we got further away from our target this setting should work (slightly prefer higher values) + MPR121_setElectrodeCDC(dev, electrode, CDC); + if((this_value >= lower_limit_FDAT) && (this_value <= upper_limit_FDAT)){ + scratch = true; // success + } + break; + } else if(CDC == 63){ // or if we're at the end of the available adjustment, see if we're close enough + MPR121_setElectrodeCDC(dev, electrode, CDC); + if((this_value >= lower_limit_FDAT) && (this_value <= upper_limit_FDAT)){ + scratch = true; // success + } + break; + } + } + last_distance = this_distance; + } + + MPR121_setRegister(dev, MPR121_ECR, dev->ECR_backup); + MPR121_setNumEnabledElectrodes(dev, saved_num_enabled_electrodes); // have to do this separately as ECR_backup gets invalidated by setNumEnabledElectrodes(electrode + 1); + + return(scratch); +} + +bool MPR121_autoSetElectrodeCDCDefault(MPR121_t * dev, uint8_t electrode){ + // default to 3.3V VCC if not explicitly stated + return(MPR121_autoSetElectrodeCDC(dev, electrode, 3300)); +} + +bool MPR121_autoSetElectrodeCDCAll(MPR121_t * dev){ + bool scratch = true; + for(uint8_t i=0; irunning; + + MPR121_stop(dev); + + MPR121_setRegister(dev, MPR121_USL, USL); + MPR121_setRegister(dev, MPR121_TL, T_L); + MPR121_setRegister(dev, MPR121_LSL, LSL); + + // don't enable retry, copy other settings from elsewhere + MPR121_setRegister(dev, MPR121_ACCR0, 1 | ((dev->ECR_backup & 0xC0) >> 4) | (MPR121_getRegister(dev, MPR121_AFE1) & 0xC0)); + // fixed charge time is useful for designs with higher lead-in resistance - e.g. using Bare Electric Paint + MPR121_setRegister(dev, MPR121_ACCR1, fixedChargeTime ? 1 << 7 : 0); + + if(wasRunning){ + MPR121_run(dev); + } + + return(!(MPR121_getRegister(dev, MPR121_OORS2) & 0xC0)); +} + +bool MPR121_autoSetElectrodesDefault(MPR121_t * dev, bool fixedChargeTime){ + return(MPR121_autoSetElectrodes(dev, 3300, fixedChargeTime)); +} + +void MPR121_setNumDigPins(MPR121_t * dev, uint8_t numPins){ + if(!MPR121_isInited(dev)) return; + bool wasRunning = dev->running; + + if(numPins>8) numPins = 8; // maximum number of GPIO pins is 8 out of 12 + + if(wasRunning){ + MPR121_stop(dev); // have to stop to change MPR121_ECR + } + dev->ECR_backup = (0x0F&(12-numPins)) | (dev->ECR_backup&0xF0); + if(wasRunning){ + MPR121_run(dev); + } +} + +void MPR121_setNumEnabledElectrodes(MPR121_t * dev, uint8_t numElectrodes){ + if(!MPR121_isInited(dev)) return; + bool wasRunning = dev->running; + + if(numElectrodes>12) numElectrodes = 12; // avoid out-of-bounds behaviour + + if(wasRunning){ + MPR121_stop(dev); // have to stop to change MPR121_ECR + } + dev->ECR_backup = (0x0F&numElectrodes) | (dev->ECR_backup&0xF0); + if(wasRunning){ + MPR121_run(dev); + } +} + +uint8_t MPR121_getNumEnabledElectrodes(MPR121_t * dev){ + if(!MPR121_isInited(dev)) return(0xFF); + + return(MPR121_getRegister(dev, MPR121_ECR) & 0x0F); +} + +#if 0 +void MPR121_pinMode(MPR121_t * dev, uint8_t electrode, mpr121_pinf_type mode){ + // only valid for ELE4..ELE11 + if(electrode<4 || electrode >11 || !MPR121_isInited(dev)) return; + + // LED0..LED7 + uint8_t bitmask = 1<<(electrode-4); + + switch(mode){ + case INPUT_PULLDOWN: + // MPR121_EN = 1 + // MPR121_DIR = 0 + // MPR121_CTL0 = 1 + // MPR121_CTL1 = 0 + MPR121_setRegister(dev, MPR121_EN, MPR121_getRegister(dev, MPR121_EN) | bitmask); + MPR121_setRegister(dev, MPR121_DIR, MPR121_getRegister(dev, MPR121_DIR) & ~bitmask); + MPR121_setRegister(dev, MPR121_CTL0, MPR121_getRegister(dev, MPR121_CTL0) | bitmask); + MPR121_setRegister(dev, MPR121_CTL1, MPR121_getRegister(dev, MPR121_CTL1) & ~bitmask); + break; + + case OUTPUT_HIGHSIDE: + // MPR121_EN = 1 + // MPR121_DIR = 1 + // MPR121_CTL0 = 1 + // MPR121_CTL1 = 1 + MPR121_setRegister(dev, MPR121_EN, MPR121_getRegister(dev, MPR121_EN) | bitmask); + MPR121_setRegister(dev, MPR121_DIR, MPR121_getRegister(dev, MPR121_DIR) | bitmask); + MPR121_setRegister(dev, MPR121_CTL0, MPR121_getRegister(dev, MPR121_CTL0) | bitmask); + MPR121_setRegister(dev, MPR121_CTL1, MPR121_getRegister(dev, MPR121_CTL1) | bitmask); + break; + + case OUTPUT_LOWSIDE: + // MPR121_EN = 1 + // MPR121_DIR = 1 + // MPR121_CTL0 = 1 + // MPR121_CTL1 = 0 + MPR121_setRegister(dev, MPR121_EN, MPR121_getRegister(dev, MPR121_EN) | bitmask); + MPR121_setRegister(dev, MPR121_DIR, MPR121_getRegister(dev, MPR121_DIR) | bitmask); + MPR121_setRegister(dev, MPR121_CTL0, MPR121_getRegister(dev, MPR121_CTL0) | bitmask); + MPR121_setRegister(dev, MPR121_CTL1, MPR121_getRegister(dev, MPR121_CTL1) & ~bitmask); + break; + + default: + break; + } +} +#endif + +void MPR121_pinMode(MPR121_t * dev, uint8_t electrode, int mode){ + // this is to catch the fact that Arduino prefers its definitions of + // INPUT, OUTPUT and INPUT_PULLUP to ours... + + // only valid for ELE4..ELE11 + if(electrode<4 || electrode >11 || !MPR121_isInited(dev)) return; + + uint8_t bitmask = 1<<(electrode-4); + + switch(mode){ + case OUTPUT: + // MPR121_EN = 1 + // MPR121_DIR = 1 + // MPR121_CTL0 = 0 + // MPR121_CTL1 = 0 + MPR121_setRegister(dev, MPR121_EN, MPR121_getRegister(dev, MPR121_EN) | bitmask); + MPR121_setRegister(dev, MPR121_DIR, MPR121_getRegister(dev, MPR121_DIR) | bitmask); + MPR121_setRegister(dev, MPR121_CTL0, MPR121_getRegister(dev, MPR121_CTL0) & ~bitmask); + MPR121_setRegister(dev, MPR121_CTL1, MPR121_getRegister(dev, MPR121_CTL1) & ~bitmask); + break; + + case INPUT: + // MPR121_EN = 1 + // MPR121_DIR = 0 + // MPR121_CTL0 = 0 + // MPR121_CTL1 = 0 + MPR121_setRegister(dev, MPR121_EN, MPR121_getRegister(dev, MPR121_EN) | bitmask); + MPR121_setRegister(dev, MPR121_DIR, MPR121_getRegister(dev, MPR121_DIR) & ~bitmask); + MPR121_setRegister(dev, MPR121_CTL0, MPR121_getRegister(dev, MPR121_CTL0) & ~bitmask); + MPR121_setRegister(dev, MPR121_CTL1, MPR121_getRegister(dev, MPR121_CTL1) & ~bitmask); + break; + + case INPUT_PULLUP: + // MPR121_EN = 1 + // MPR121_DIR = 0 + // MPR121_CTL0 = 1 + // MPR121_CTL1 = 1 + MPR121_setRegister(dev, MPR121_EN, MPR121_getRegister(dev, MPR121_EN) | bitmask); + MPR121_setRegister(dev, MPR121_DIR, MPR121_getRegister(dev, MPR121_DIR) & ~bitmask); + MPR121_setRegister(dev, MPR121_CTL0, MPR121_getRegister(dev, MPR121_CTL0) | bitmask); + MPR121_setRegister(dev, MPR121_CTL1, MPR121_getRegister(dev, MPR121_CTL1) | bitmask); + break; + + default: + break; + } +} + +void MPR121_digitalWrite(MPR121_t * dev, uint8_t electrode, uint8_t val){ + + // avoid out of bounds behaviour + + if(electrode<4 || electrode>11 || !MPR121_isInited(dev)) return; + + if(val){ + MPR121_setRegister(dev, MPR121_SET, 1<<(electrode-4)); + } else { + MPR121_setRegister(dev, MPR121_CLR, 1<<(electrode-4)); + } +} + +void MPR121_digitalToggle(MPR121_t * dev, uint8_t electrode){ + + // avoid out of bounds behaviour + + if(electrode<4 || electrode>11 || !MPR121_isInited(dev)) return; + + MPR121_setRegister(dev, MPR121_TOG, 1<<(electrode-4)); +} + +bool MPR121_digitalRead(MPR121_t * dev, uint8_t electrode){ + + // avoid out of bounds behaviour + + if(electrode<4 || electrode>11 || !MPR121_isInited(dev)) return false; + + return(((MPR121_getRegister(dev, MPR121_DAT)>>(electrode-4))&1)==1); +} + +void MPR121_analogWrite(MPR121_t * dev, uint8_t electrode, uint8_t value){ + // LED output 5 (ELE9) and output 6 (ELE10) have a PWM bug + // https://community.nxp.com/thread/305474 + + // avoid out of bounds behaviour + + if(electrode<4 || electrode>11 || !MPR121_isInited(dev)) return; + + uint8_t shiftedVal = value>>4; + + if(shiftedVal > 0){ + MPR121_setRegister(dev, MPR121_SET, 1<<(electrode-4)); // normal PWM operation + } else { + // this make a 0 PWM setting turn off the output + MPR121_setRegister(dev, MPR121_CLR, 1<<(electrode-4)); + } + + switch(electrode-4){ + + case 0: + MPR121_setRegister(dev, MPR121_PWM0, (shiftedVal & 0x0F) | (MPR121_getRegister(dev, MPR121_PWM0) & 0xF0)); + break; + case 1: + MPR121_setRegister(dev, MPR121_PWM0, ((shiftedVal & 0x0F)<<4) | (MPR121_getRegister(dev, MPR121_PWM0) & 0x0F)); + break; + case 2: + MPR121_setRegister(dev, MPR121_PWM1, (shiftedVal & 0x0F) | (MPR121_getRegister(dev, MPR121_PWM1) & 0xF0)); + break; + case 3: + MPR121_setRegister(dev, MPR121_PWM1, ((shiftedVal & 0x0F)<<4) | (MPR121_getRegister(dev, MPR121_PWM1) & 0x0F)); + break; + case 4: + MPR121_setRegister(dev, MPR121_PWM2, (shiftedVal & 0x0F) | (MPR121_getRegister(dev, MPR121_PWM2) & 0xF0)); + break; + case 5: + MPR121_setRegister(dev, MPR121_PWM2, ((shiftedVal & 0x0F)<<4) | (MPR121_getRegister(dev, MPR121_PWM2) & 0x0F)); + break; + case 6: + MPR121_setRegister(dev, MPR121_PWM3, (shiftedVal & 0x0F) | (MPR121_getRegister(dev, MPR121_PWM3) & 0xF0)); + break; + case 7: + MPR121_setRegister(dev, MPR121_PWM3, ((shiftedVal & 0x0F)<<4) | (MPR121_getRegister(dev, MPR121_PWM3) & 0x0F)); + break; + } +} + +//void MPR121_setSamplePeriod(MPR121_t * dev, mpr121_sample_interval_type period){ +void MPR121_setSamplePeriod(MPR121_t * dev, uint8_t period){ + MPR121_setRegister(dev, MPR121_AFE2, (MPR121_getRegister(dev, MPR121_AFE2) & 0xF8) | (period & 0x07)); +} + +//void MPR121_setFFI(MPR121_t * dev, mpr121_FFI_type FFI){ +void MPR121_setFFI(MPR121_t * dev, uint8_t FFI){ + MPR121_setRegister(dev, MPR121_AFE1, (MPR121_getRegister(dev, MPR121_AFE1) & 0x3F) | ((FFI & 0x03) << 6)); +} + +//void MPR121_setSFI(MPR121_t * dev, mpr121_SFI_type SFI){ +void MPR121_setSFI(MPR121_t * dev, uint8_t SFI){ + MPR121_setRegister(dev, MPR121_AFE2, (MPR121_getRegister(dev, MPR121_AFE2) & 0xE7) | ((SFI & 0x03) << 3)); +} + +//MPR121_type MPR121 = MPR121_type(); + + diff --git a/main/mpr121.h b/main/mpr121.h new file mode 100644 index 0000000..eeb69c4 --- /dev/null +++ b/main/mpr121.h @@ -0,0 +1,433 @@ +/******************************************************************************* + + Bare Conductive MPR121 library + ------------------------------ + + MPR121.h - MPR121 class header file + + Based on code by Jim Lindblom and plenty of inspiration from the Freescale + Semiconductor datasheets and application notes. + + Bare Conductive code written by Stefan Dzisiewski-Smith, Peter Krige + and Szymon Kaliski. + + This work is licensed under a MIT license https://opensource.org/licenses/MIT + + Copyright (c) 2016, Bare Conductive + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +*******************************************************************************/ + +#ifndef MPR121_H +#define MPR121_H + +#include "mpr121_defs.h" + + +// idea behind this is to create a settings structure that we can use to store +// all the setup variables for a particular setup - comes pre-instantiated with +// defaults and can be easily tweaked - we pass by reference (as a pointer) to +// save RAM + +typedef struct +{ + // touch and release thresholds + uint8_t _TTHRESH; + uint8_t _RTHRESH; + + uint8_t _INTERRUPT; + + // general electrode touch sense baseline filters + // rising filter + uint8_t _MHDR; + uint8_t _NHDR; + uint8_t _NCLR; + uint8_t _FDLR; + + // falling filter + uint8_t _MHDF; + uint8_t _NHDF; + uint8_t _NCLF; + uint8_t _FDLF; + + // touched filter + uint8_t _NHDT; + uint8_t _NCLT; + uint8_t _FDLT; + + // proximity electrode touch sense baseline filters + // rising filter + uint8_t _MHDPROXR; + uint8_t _NHDPROXR; + uint8_t _NCLPROXR; + uint8_t _FDLPROXR; + + // falling filter + uint8_t _MHDPROXF; + uint8_t _NHDPROXF; + uint8_t _NCLPROXF; + uint8_t _FDLPROXF; + + // touched filter + uint8_t _NHDPROXT; + uint8_t _NCLPROXT; + uint8_t _FDLPROXT; + + // debounce settings + uint8_t _DTR; + + // configuration registers + uint8_t _AFE1; + uint8_t _AFE2; + uint8_t _ECR; + + // auto-configuration registers + uint8_t _ACCR0; + uint8_t _ACCR1; + uint8_t _USL; + uint8_t _LSL; + uint8_t _TL; +} MPR121_settings_type; + +typedef struct { + uint8_t address; + MPR121_settings_type defaultSettings; + uint8_t ECR_backup; // so we can re-enable the correct number of electrodes + // when recovering from stop mode + uint8_t error; + bool running; + uint8_t interruptPin; + + int16_t filteredData[13]; + int16_t baselineData[13]; + uint16_t touchData; + uint16_t lastTouchData; + bool autoTouchStatusFlag; // we use this to catch touch / release events that happen + // during other update calls +} MPR121_t; + + +// GPIO pin function constants +enum mpr121_pinf_type +{ + // INPUT and OUTPUT (and others) are already defined by Arduino, use its definitions if they exist +#ifndef INPUT + INPUT, // digital input +#endif +#ifndef INPUT_PULLUP + INPUT_PULLUP, // digital input with pullup +#endif +#ifndef INPUT_PULLDOWN + INPUT_PULLDOWN, // digital input with pulldown +#endif +#ifndef OUTPUT + OUTPUT, // digital output (push-pull) +#endif +#ifndef OUTPUT_HIGHSIDE + OUTPUT_HIGHSIDE, // digital output, open collector (high side) +#endif +#ifndef OUTPUT_LOWSIDE + OUTPUT_LOWSIDE // digital output, open collector (low side) +#endif +}; + +// "13th electrode" proximity modes +// N.B. this does not relate to normal proximity detection +// see http://cache.freescale.com/files/sensors/doc/app_note/AN3893.pdf +enum mpr121_proxmode_type +{ + PROX_DISABLED, // proximity mode disabled + PROX_0_1, // proximity mode for ELE0..ELE1 + PROX_0_3, // proximity mode for ELE0..ELE3 + PROX_0_11 // proximity mode for ELE0..ELE11 +}; + +// baseline calibration lock modes +enum mpr121_cal_lock_type +{ + CAL_LOCK_ENABLED, // baseline tracking enabled, no value change on run + CAL_LOCK_DISABLED, // baseline tracking disabled + CAL_LOCK_ENABLED_5_BIT_COPY, // baseline tracking enabled, load 5 MSB of filtered data on entering run mode + CAL_LOCK_ENABLED_10_BIT_COPY // baseline tracking enabled, load 10 MSB of filtered data on entering run mode +}; + +// error codes +enum mpr121_error_type +{ + NO_ERROR, // no error + RETURN_TO_SENDER, // not implemented + ADDRESS_UNKNOWN, // no MPR121 found at specified I2C address + READBACK_FAIL, // readback from MPR121 was not as expected + OVERCURRENT_FLAG, // overcurrent on REXT pin + OUT_OF_RANGE, // autoconfiguration fail, often a result of shorted pins + NOT_INITED // device has not been initialised +}; + +// sample intervals +enum mpr121_sample_interval_type +{ + SAMPLE_INTERVAL_1MS = 0x00, + SAMPLE_INTERVAL_2MS = 0x01, + SAMPLE_INTERVAL_4MS = 0x02, + SAMPLE_INTERVAL_8MS = 0x03, + SAMPLE_INTERVAL_16MS = 0x04, + SAMPLE_INTERVAL_32MS = 0x05, + SAMPLE_INTERVAL_64MS = 0x06, + SAMPLE_INTERVAL_128MS = 0x07 +}; + +// charge / discharge times (CDT) +enum mpr121_CDT_type +{ + CDT_500NS = 0x01, + CDT_1US = 0x02, + CDT_2US = 0x03, + CDT_4US = 0x04, + CDT_8US = 0x05, + CDT_16US = 0x06, + CDT_32US = 0x07 +}; + +// first filter iterations (FFI) +enum mpr121_FFI_type +{ + FFI_6 = 0x00, + FFI_10 = 0x01, + FFI_18 = 0x02, + FFI_34 = 0x03 +}; + +// second filter iterations (SFI) +enum mpr121_SFI_type +{ + SFI_4 = 0x00, + SFI_6 = 0x01, + SFI_10 = 0x02, + SFI_18 = 0x03 +}; + + +// -------------------- BASIC FUNCTIONS -------------------- + +void MPR121_type(MPR121_t * dev); + +// begin() must be called before using any other function +// address is optional, default is 0x5C +bool MPR121_begin(MPR121_t * dev, int16_t address, int16_t touchThreshold, int16_t releaseThreshold, int16_t interruptPin, int16_t sda, int16_t scl); + +// read touch and release threshold saved to EEPROM using +// saveTouchThreshold and releaseTouchThreshold +void MPR121_restoreSavedThresholds(MPR121_t * dev); + +// reset saved thresholds to 255, which will force the MPR121 +// to load default thresholds +void MPR121_clearSavedThresholds(MPR121_t * dev); + +// I2C speed control functions - goFast() sets the SCL clock +// to 400kHz - goSlow() sets the SCL clock to 100kHz. Defaults +// to 100kHz and affects all devices on the I2C bus. Included +// for speed freaks only. +void MPR121_goSlow(MPR121_t * dev); +void MPR121_goFast(MPR121_t * dev); + +// getError() returns an mpr121_error_type indicating the current +// error on the MPR121 - clearError() clears this +uint8_t MPR121_getError(MPR121_t * dev); +void MPR121_clearError(MPR121_t * dev); + +// returns status of the MPR121 INT pin as read via digitalRead() on the +// Arduino board - this tells us if there has been a change in touch status +// on any active electrode since we last read any data +bool MPR121_touchStatusChanged(MPR121_t * dev); + +// updates the data from the MPR121 into our internal buffer +// updateTouchData() does this only for touch on / off status +// updateBaseLineData() does this for background baseline +// updateFilteredData() does this for continuous proximity data +// updateAll() does all three + +// the appropriate function from these must be called before data +// from getTouchData(), getFilteredData() etc. can be considered +// valid +void MPR121_updateTouchData(MPR121_t * dev); +bool MPR121_updateBaselineData(MPR121_t * dev); +bool MPR121_updateFilteredData(MPR121_t * dev); +void MPR121_updateAll(MPR121_t * dev); + +// returns a boolean indicating the touch status of a given electrode +bool MPR121_getTouchData(MPR121_t * dev, uint8_t electrode); + +// returns the number of touches currently detected +uint8_t MPR121_getNumTouches(MPR121_t * dev); + +bool MPR121_getLastTouchData(MPR121_t * dev, uint8_t electrode); + +// returns continous proximity or baseline data for a given electrode +int MPR121_getFilteredData(MPR121_t * dev, uint8_t electrode); +int MPR121_getBaselineData(MPR121_t * dev, uint8_t electrode); + +// returns boolean indicating whether a new touch or release has been +// detected since the last time updateTouchData() was called +bool MPR121_isNewTouch(MPR121_t * dev, uint8_t electrode); +bool MPR121_isNewRelease(MPR121_t * dev, uint8_t electrode); + +// sets touch and release thresholds either for all electrodes, or +// for a specfic electrode - higher values = less sensitive and +// release threshold must ALWAYS be lower than touch threshold +void MPR121_setTouchThresholdAll(MPR121_t * dev, uint8_t val); +void MPR121_setTouchThreshold(MPR121_t * dev, uint8_t electrode, uint8_t val); +void MPR121_saveTouchThreshold(MPR121_t * dev, uint8_t electrode, uint8_t val); + +void MPR121_setReleaseThresholdAll(MPR121_t * dev, uint8_t val); +void MPR121_setReleaseThreshold(MPR121_t * dev, uint8_t electrode, uint8_t val); +void MPR121_saveReleaseThreshold(MPR121_t * dev, uint8_t electrode, uint8_t val); + +// returns the current touch or release threshold for a specified electrode +uint8_t MPR121_getTouchThreshold(MPR121_t * dev, uint8_t electrode); +uint8_t MPR121_getReleaseThreshold(MPR121_t * dev, uint8_t electrode); + +// ------------------ ADVANCED FUNCTIONS ------------------ + +void MPR121_settingsType(MPR121_settings_type *defaultSettings); + +// applies a complete array of settings from an +// MPR121_settings_type variable passed as a pointer +// useful if you want to do a bulk setup of the device +//void MPR121_applySettings(MPR121_t * dev, MPR121_settings_type *settings); +void MPR121_applySettings(MPR121_t * dev); + +// setRegister() and getRegister() manipulate registers on +// the MPR121 directly, whilst correctly stopping and +// restarting the MPR121 if necessary +void MPR121_setRegister(MPR121_t * dev, uint8_t reg, uint8_t value); +uint8_t MPR121_getRegister(MPR121_t * dev, uint8_t reg); + +// stop() and run() take the MPR121 in and out of stop mode +// which reduces current consumption to 3uA +void MPR121_run(MPR121_t * dev); +void MPR121_stop(MPR121_t * dev); + +// resets the MPR121 +bool MPR121_reset(MPR121_t * dev); + +// tells us if we are in run mode, and if we have inited the +// MPR121 +bool MPR121_isRunning(MPR121_t * dev); +bool MPR121_isInited(MPR121_t * dev); + +// sets the pin that the MPR121 INT output is connected to on the +// Arduino board - does not have to be a hardware interrupt pin +// if it is, however, an interrupt service routine will automatically +// set an internal flag when a touch event occurs - thus minimising +// lost events if you are also reading other data types (filtered data, +// baseline data) +void MPR121_setInterruptPin(MPR121_t * dev, uint8_t pin); + +// set number of electrodes to use to generate virtual "13th" +// proximity electrode +// see http://cache.freescale.com/files/sensors/doc/app_note/AN3893.pdf +// +// N.B. - this is not related to general proximity detection or +// reading back continuous proximity data +void MPR121_setProxMode(MPR121_t * dev, uint8_t mode); + +// set calibration lock mode for baseline tracking +// this can be useful to disable baseline tracking, set it to +// current values (with 5 or 10 most significant bits copied across from +// current filtered values to baseline the next time run mode is entered) +// or leave it enabled with its current values in place (and no copy-across +// when run mode is re-entered) +void MPR121_setCalibrationLock(MPR121_t * dev, uint8_t lock); + +// set global or per-electrode charge / discharge current in microamps +// current_uA is valid 0..63 (for global value, 0 means use electrode-specific setting) +// electrode is valid 0..12 (includes virtual proximity electrode) +void MPR121_setGlobalCDC(MPR121_t * dev, uint8_t CDC); +void MPR121_setElectrodeCDC(MPR121_t * dev, uint8_t electrode, uint8_t CDC); + +// runs hardware routine for automatic electrode calibration for all electrodes +// this is implemented in the MPR121 hardware itself +// fixedChargeTime flag keeps CDT constant (useful for carbon-based inks with high lead-in resistance) +bool MPR121_autoSetElectrodes(MPR121_t * dev, uint16_t VCC_mV, bool fixedChargeTime); +bool MPR121_autoSetElectrodesDefault(MPR121_t * dev, bool fixedChargeTime); + +// software routine to keep CDT constant and adjust CDC to fit +bool MPR121_autoSetElectrodeCDC(MPR121_t * dev, uint8_t electrode, uint16_t VCC_mV); +bool MPR121_autoSetElectrodeCDCDefault(MPR121_t * dev, uint8_t electrode); +bool MPR121_autoSetElectrodeCDCAll(MPR121_t * dev); // runs autocal for all electrodes + +// set global or per-electrode charge / discharge time +// CDT follows a 0.5(2^(n-1))uS rule, so an enum type is provided for clarity +void MPR121_setGlobalCDT(MPR121_t * dev, uint8_t CDT); +void MPR121_setElectrodeCDT(MPR121_t * dev, uint8_t electrode, uint8_t CDT); + +// Set / get the number of enabled electrodes, from 0 (which implicitly enters +// stop mode) up to 12. This allows for a reduction in power consumption +// when using fewer electrodes and faster update rates. Implementation is +// similar to setNumDigPins below, butwith a different intent. +void MPR121_setNumEnabledElectrodes(MPR121_t * dev, uint8_t numElectrodes); +uint8_t MPR121_getNumEnabledElectrodes(MPR121_t * dev); + +// Enables GPIO mode for up to 8 of the MPR121 electrodes +// starts with electrode 11 - i.e. setNumDigPins(1) sets just +// electrode 11 as GPIO, setNumDigPins(2) sets electrodes 11 +// & 10 as GPIO, and so on. Electrodes 0 to 3 cannot be used +// as GPIO +// +// N.B. electrodes are 3.3V and WILL be damaged if driven by +// a greater voltage +void MPR121_setNumDigPins(MPR121_t * dev, uint8_t numPins); + +// Sets pin mode for an electrode already set as GPIO by +// setNumDigPins() - see section "GPIO pin function constants" +// for details +#if 0 +void MPR121_pinMode(MPR121_t * dev, uint8_t electrode, mpr121_pinf_type mode); +#endif +void MPR121_pinMode(MPR121_t * dev, uint8_t electrode, int mode); + +// Similar to digitalWrite in Arduino for GPIO electrode +void MPR121_digitalWrite(MPR121_t * dev, uint8_t electrode, uint8_t val); + +// Toggles electrode set as GPIO output +void MPR121_digitalToggle(MPR121_t * dev, uint8_t electrode); + +// Reads electrode set as GPIO input +bool MPR121_digitalRead(MPR121_t * dev, uint8_t electrode); + +// Writes PWM value to electrode set as GPIO output - very limited +// (4 bit, although input to function is 0..255 to match Arduino, +// internally reduced to 4 bit) and broken on ELE9 and ELE10 +// see https://community.freescale.com/thread/305474 +void MPR121_analogWrite(MPR121_t * dev, uint8_t electrode, uint8_t val); + +// Sets the sample period of the MPR121 - the time between capacitive +// readings. Higher values consume less power, but are less responsive. +void MPR121_setSamplePeriod(MPR121_t * dev, uint8_t period); + +void MPR121_setFFI(MPR121_t * dev, uint8_t FFI); + +void MPR121_setSFI(MPR121_t * dev, uint8_t SFI); + +//extern MPR121_type MPR121; + + +#endif // MPR121_H + diff --git a/main/mpr121_defs.h b/main/mpr121_defs.h new file mode 100644 index 0000000..906550d --- /dev/null +++ b/main/mpr121_defs.h @@ -0,0 +1,214 @@ +/******************************************************************************* + + Bare Conductive MPR121 library + ------------------------------ + + MPR121_defs.h - MPR121 register definitions + + Based on code by Jim Lindblom and plenty of inspiration from the Freescale + Semiconductor datasheets and application notes. + + Bare Conductive code written by Stefan Dzisiewski-Smith and Peter Krige. + + This work is licensed under a MIT license https://opensource.org/licenses/MIT + + Copyright (c) 2016, Bare Conductive + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +*******************************************************************************/ + +#ifndef MPR121_DEFS_H +#define MPR121_DEFS_H + +// MPR121 Register Defines + +// touch and OOR statuses +static uint8_t const MPR121_TS1 = 0x00; +static uint8_t const MPR121_TS2 = 0x01; +static uint8_t const MPR121_OORS1 = 0x02; +static uint8_t const MPR121_OORS2 = 0x03; + +// filtered data +static uint8_t const MPR121_E0FDL = 0x04; +static uint8_t const MPR121_E0FDH = 0x05; +static uint8_t const MPR121_E1FDL = 0x06; +static uint8_t const MPR121_E1FDH = 0x07; +static uint8_t const MPR121_E2FDL = 0x08; +static uint8_t const MPR121_E2FDH = 0x09; +static uint8_t const MPR121_E3FDL = 0x0A; +static uint8_t const MPR121_E3FDH = 0x0B; +static uint8_t const MPR121_E4FDL = 0x0C; +static uint8_t const MPR121_E4FDH = 0x0D; +static uint8_t const MPR121_E5FDL = 0x0E; +static uint8_t const MPR121_E5FDH = 0x0F; +static uint8_t const MPR121_E6FDL = 0x10; +static uint8_t const MPR121_E6FDH = 0x11; +static uint8_t const MPR121_E7FDL = 0x12; +static uint8_t const MPR121_E7FDH = 0x13; +static uint8_t const MPR121_E8FDL = 0x14; +static uint8_t const MPR121_E8FDH = 0x15; +static uint8_t const MPR121_E9FDL = 0x16; +static uint8_t const MPR121_E9FDH = 0x17; +static uint8_t const MPR121_E10FDL = 0x18; +static uint8_t const MPR121_E10FDH = 0x19; +static uint8_t const MPR121_E11FDL = 0x1A; +static uint8_t const MPR121_E11FDH = 0x1B; +static uint8_t const MPR121_E12FDL = 0x1C; +static uint8_t const MPR121_E12FDH = 0x1D; + +// baseline values +static uint8_t const MPR121_E0BV = 0x1E; +static uint8_t const MPR121_E1BV = 0x1F; +static uint8_t const MPR121_E2BV = 0x20; +static uint8_t const MPR121_E3BV = 0x21; +static uint8_t const MPR121_E4BV = 0x22; +static uint8_t const MPR121_E5BV = 0x23; +static uint8_t const MPR121_E6BV = 0x24; +static uint8_t const MPR121_E7BV = 0x25; +static uint8_t const MPR121_E8BV = 0x26; +static uint8_t const MPR121_E9BV = 0x27; +static uint8_t const MPR121_E10BV = 0x28; +static uint8_t const MPR121_E11BV = 0x29; +static uint8_t const MPR121_E12BV = 0x2A; + +// general electrode touch sense baseline filters +// rising filter +static uint8_t const MPR121_MHDR = 0x2B; +static uint8_t const MPR121_NHDR = 0x2C; +static uint8_t const MPR121_NCLR = 0x2D; +static uint8_t const MPR121_FDLR = 0x2E; + +// falling filter +static uint8_t const MPR121_MHDF = 0x2F; +static uint8_t const MPR121_NHDF = 0x30; +static uint8_t const MPR121_NCLF = 0x31; +static uint8_t const MPR121_FDLF = 0x32; + +// touched filter +static uint8_t const MPR121_NHDT = 0x33; +static uint8_t const MPR121_NCLT = 0x34; +static uint8_t const MPR121_FDLT = 0x35; + +// proximity electrode touch sense baseline filters +// rising filter +static uint8_t const MPR121_MHDPROXR = 0x36; +static uint8_t const MPR121_NHDPROXR = 0x37; +static uint8_t const MPR121_NCLPROXR = 0x38; +static uint8_t const MPR121_FDLPROXR = 0x39; + +// falling filter +static uint8_t const MPR121_MHDPROXF = 0x3A; +static uint8_t const MPR121_NHDPROXF = 0x3B; +static uint8_t const MPR121_NCLPROXF = 0x3C; +static uint8_t const MPR121_FDLPROXF = 0x3D; + +// touched filter +static uint8_t const MPR121_NHDPROXT = 0x3E; +static uint8_t const MPR121_NCLPROXT = 0x3F; +static uint8_t const MPR121_FDLPROXT = 0x40; + +// electrode touch and release thresholds +static uint8_t const MPR121_E0TTH = 0x41; +static uint8_t const MPR121_E0RTH = 0x42; +static uint8_t const MPR121_E1TTH = 0x43; +static uint8_t const MPR121_E1RTH = 0x44; +static uint8_t const MPR121_E2TTH = 0x45; +static uint8_t const MPR121_E2RTH = 0x46; +static uint8_t const MPR121_E3TTH = 0x47; +static uint8_t const MPR121_E3RTH = 0x48; +static uint8_t const MPR121_E4TTH = 0x49; +static uint8_t const MPR121_E4RTH = 0x4A; +static uint8_t const MPR121_E5TTH = 0x4B; +static uint8_t const MPR121_E5RTH = 0x4C; +static uint8_t const MPR121_E6TTH = 0x4D; +static uint8_t const MPR121_E6RTH = 0x4E; +static uint8_t const MPR121_E7TTH = 0x4F; +static uint8_t const MPR121_E7RTH = 0x50; +static uint8_t const MPR121_E8TTH = 0x51; +static uint8_t const MPR121_E8RTH = 0x52; +static uint8_t const MPR121_E9TTH = 0x53; +static uint8_t const MPR121_E9RTH = 0x54; +static uint8_t const MPR121_E10TTH = 0x55; +static uint8_t const MPR121_E10RTH = 0x56; +static uint8_t const MPR121_E11TTH = 0x57; +static uint8_t const MPR121_E11RTH = 0x58; +static uint8_t const MPR121_E12TTH = 0x59; +static uint8_t const MPR121_E12RTH = 0x5A; + +// debounce settings +static uint8_t const MPR121_DTR = 0x5B; + +// configuration registers +static uint8_t const MPR121_AFE1 = 0x5C; +static uint8_t const MPR121_AFE2 = 0x5D; +static uint8_t const MPR121_ECR = 0x5E; + +// electrode currents +static uint8_t const MPR121_CDC0 = 0x5F; +static uint8_t const MPR121_CDC1 = 0x60; +static uint8_t const MPR121_CDC2 = 0x61; +static uint8_t const MPR121_CDC3 = 0x62; +static uint8_t const MPR121_CDC4 = 0x63; +static uint8_t const MPR121_CDC5 = 0x64; +static uint8_t const MPR121_CDC6 = 0x65; +static uint8_t const MPR121_CDC7 = 0x66; +static uint8_t const MPR121_CDC8 = 0x67; +static uint8_t const MPR121_CDC9 = 0x68; +static uint8_t const MPR121_CDC10 = 0x69; +static uint8_t const MPR121_CDC11 = 0x6A; +static uint8_t const MPR121_CDCPROX = 0x6B; + +// electrode charge times +static uint8_t const MPR121_CDT01 = 0x6C; +static uint8_t const MPR121_CDT23 = 0x6D; +static uint8_t const MPR121_CDT45 = 0x6E; +static uint8_t const MPR121_CDT67 = 0x6F; +static uint8_t const MPR121_CDT89 = 0x70; +static uint8_t const MPR121_CDT1011 = 0x71; +static uint8_t const MPR121_CDTPROX = 0x72; + +// GPIO +static uint8_t const MPR121_CTL0 = 0x73; +static uint8_t const MPR121_CTL1 = 0x74; +static uint8_t const MPR121_DAT = 0x75; +static uint8_t const MPR121_DIR = 0x76; +static uint8_t const MPR121_EN = 0x77; +static uint8_t const MPR121_SET = 0x78; +static uint8_t const MPR121_CLR = 0x79; +static uint8_t const MPR121_TOG = 0x7A; + +// auto-config +static uint8_t const MPR121_ACCR0 = 0x7B; +static uint8_t const MPR121_ACCR1 = 0x7C; +static uint8_t const MPR121_USL = 0x7D; +static uint8_t const MPR121_LSL = 0x7E; +static uint8_t const MPR121_TL = 0x7F; + +// soft reset +static uint8_t const MPR121_SRST = 0x80; + +// PWM +static uint8_t const MPR121_PWM0 = 0x81; +static uint8_t const MPR121_PWM1 = 0x82; +static uint8_t const MPR121_PWM2 = 0x83; +static uint8_t const MPR121_PWM3 = 0x84; + +#endif // MPR121_DEFS_H +