Added support for new i2c drivers

This commit is contained in:
nopnop2002
2025-06-14 16:50:49 +09:00
parent c4d8e72e8e
commit 4b722e35c7
8 changed files with 236 additions and 92 deletions

View File

@@ -1,3 +1,16 @@
set(component_srcs "mpr121.c")
# get IDF version for comparison
set(idf_version "${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}")
if(idf_version VERSION_GREATER_EQUAL "5.2")
if(CONFIG_LEGACY_DRIVER)
list(APPEND component_srcs "i2c_legacy.c")
else()
list(APPEND component_srcs "i2c_new.c")
endif()
else()
list(APPEND component_srcs "i2c_legacy.c")
endif()
idf_component_register(SRCS "${component_srcs}" PRIV_REQUIRES driver INCLUDE_DIRS ".")

View File

@@ -25,6 +25,12 @@ menu "MPR121 Configuration"
Use I2C_PORT_1.
endchoice
config LEGACY_DRIVER
bool "Force legacy i2c driver"
default false
help
Force legacy i2c driver.
config I2C_ADDRESS
hex "I2C address"
default 0x5A

View File

@@ -0,0 +1,74 @@
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <stdbool.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/i2c.h"
#include "mpr121.h"
void i2c_setRegister(MPR121_t * dev, uint8_t reg, uint8_t value) {
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (dev->_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(__FUNCTION__, "setRegister reg=0x%02x value=0x%02x successfully", reg, value);
dev->error &= ~(1<<ADDRESS_UNKNOWN_BIT);
} else {
ESP_LOGE(__FUNCTION__, "setRegister reg=0x%02x value=0x%02x failed. code: 0x%02x", reg, value, espRc);
dev->error |= 1<<ADDRESS_UNKNOWN_BIT; // set address unknown bit
}
i2c_cmd_link_delete(cmd);
}
uint8_t i2c_getRegister(MPR121_t * dev, uint8_t reg) {
ESP_LOGD(__FUNCTION__, "getRegister reg=0x%02x", reg);
uint8_t scratch = 0;
uint8_t buf[2];
memset (buf, 0, 2);
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (dev->_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<<ADDRESS_UNKNOWN_BIT);
scratch = buf[0];
ESP_LOGD(__FUNCTION__, "getRegister reg=0x%02x successfully scratch=0x%02x", reg, scratch);
} else {
ESP_LOGE(__FUNCTION__, "getRegister reg=0x%02x failed. code: 0x%02x", reg, espRc);
dev->error |= 1<<ADDRESS_UNKNOWN_BIT; // set address unknown bit
}
i2c_cmd_link_delete(cmd);
return scratch;
}
void i2c_register(MPR121_t * dev, int16_t sda, int16_t scl){
ESP_LOGI(__FUNCTION__, "Legacy i2c driver is used");
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));
ESP_LOGI(__FUNCTION__, "Legacy i2c driver installed");
}

View File

@@ -0,0 +1,68 @@
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <stdbool.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/i2c_master.h"
#include "mpr121.h"
void i2c_setRegister(MPR121_t * dev, uint8_t reg, uint8_t value) {
uint8_t out_buf[2];
out_buf[0] = reg;
out_buf[1] = value;
esp_err_t espRc = i2c_master_transmit(dev->_i2c_dev_handle, out_buf, 2, I2C_TICKS_TO_WAIT);
if (espRc == ESP_OK) {
ESP_LOGD(__FUNCTION__, "setRegister reg=0x%02x value=0x%02x successfully", reg, value);
dev->error &= ~(1<<ADDRESS_UNKNOWN_BIT);
} else {
ESP_LOGE(__FUNCTION__, "setRegister reg=0x%02x value=0x%02x failed. code: 0x%02x", reg, value, espRc);
dev->error |= 1<<ADDRESS_UNKNOWN_BIT; // set address unknown bit
}
}
uint8_t i2c_getRegister(MPR121_t * dev, uint8_t reg) {
uint8_t scratch = 0;
uint8_t out_buf[1];
out_buf[0] = reg;
uint8_t in_buf[1];
esp_err_t espRc = i2c_master_transmit_receive(dev->_i2c_dev_handle, out_buf, 1, in_buf, 1, -1);
if (espRc == ESP_OK) {
dev->error &= ~(1<<ADDRESS_UNKNOWN_BIT);
scratch = in_buf[0];
ESP_LOGD(__FUNCTION__, "getRegister reg=0x%02x successfully scratch=0x%02x", reg, scratch);
} else {
ESP_LOGE(__FUNCTION__, "getRegister reg=0x%02x failed. code: 0x%02x", reg, espRc);
dev->error |= 1<<ADDRESS_UNKNOWN_BIT; // set address unknown bit
}
return scratch;
}
void i2c_register(MPR121_t * dev, int16_t sda, int16_t scl){
ESP_LOGI(__FUNCTION__, "New i2c driver is used");
i2c_master_bus_config_t i2c_mst_config = {
.clk_source = I2C_CLK_SRC_DEFAULT,
.glitch_ignore_cnt = 7,
.i2c_port = I2C_NUM,
.scl_io_num = scl,
.sda_io_num = sda,
.flags.enable_internal_pullup = true,
};
i2c_master_bus_handle_t i2c_bus_handle;
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_mst_config, &i2c_bus_handle));
i2c_device_config_t dev_cfg = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = dev->_address,
.scl_speed_hz = I2C_MASTER_FREQ_HZ,
};
i2c_master_dev_handle_t i2c_dev_handle;
ESP_ERROR_CHECK(i2c_master_bus_add_device(i2c_bus_handle, &dev_cfg, &i2c_dev_handle));
dev->_i2c_bus_handle = i2c_bus_handle;
dev->_i2c_dev_handle = i2c_dev_handle;
ESP_LOGI(__FUNCTION__, "New i2c driver installed");
}

View File

@@ -48,25 +48,11 @@
#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
#if CONFIG_I2C_PORT_0
#define I2C_NUM I2C_NUM_0
#else
#define I2C_NUM I2C_NUM_1
#endif
#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->address = 0x5A; // default address is 0x5A, for use with Bare Conductive Touch Board
dev->_address = 0x5A; // default address is 0x5A, for use with Bare Conductive Touch Board
dev->ECR_backup = 0x00;
dev->running = false;
dev->error = 1<<NOT_INITED_BIT; // initially, we're not initialised
@@ -93,53 +79,18 @@ void MPR121_setRegister(MPR121_t * dev, uint8_t reg, uint8_t value){
// unless modding MPR121_ECR or GPIO / LED register
}
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (dev->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<<ADDRESS_UNKNOWN_BIT);
} else {
ESP_LOGE(TAG, "setRegister reg=0x%02x value=0x%02x failed. code: 0x%02x", reg, value, espRc);
dev->error |= 1<<ADDRESS_UNKNOWN_BIT; // set address unknown bit
}
i2c_cmd_link_delete(cmd);
// i2c write register
ESP_LOGD(TAG, "setRegister reg=0x%02x", reg);
i2c_setRegister(dev, reg, value);
if(wasRunning) MPR121_run(dev); // restore run mode if necessary
}
uint8_t MPR121_getRegister(MPR121_t * dev, uint8_t reg){
// i2c read register
ESP_LOGD(TAG, "getRegister reg=0x%02x", reg);
uint8_t scratch = 0;
uint8_t buf[2];
memset (buf, 0, 2);
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (dev->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<<ADDRESS_UNKNOWN_BIT);
scratch = buf[0];
ESP_LOGD(TAG, "getRegister reg=0x%02x successfully scratch=0x%02x", reg, scratch);
} else {
ESP_LOGE(TAG, "getRegister reg=0x%02x failed. code: 0x%02x", reg, espRc);
dev->error |= 1<<ADDRESS_UNKNOWN_BIT; // set address unknown bit
}
i2c_cmd_link_delete(cmd);
uint8_t scratch = i2c_getRegister(dev, reg);
// auto update errors for registers with error data
if(reg == MPR121_TS2 && ((scratch&0x80)!=0)){
@@ -157,25 +108,14 @@ uint8_t MPR121_getRegister(MPR121_t * dev, uint8_t reg){
bool MPR121_begin(MPR121_t * dev, int16_t address, int16_t touchThreshold, int16_t releaseThreshold, int16_t interruptPin, int16_t sda, int16_t scl){
// SDA and SCL should idle high, but MPR121 can get stuck waiting to complete a transaction
// this code detects this state and releases us from it
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->_address = address;
}
// i2c driver register
i2c_register(dev, sda, scl);
dev->error &= ~(1<<NOT_INITED_BIT); // clear NOT_INITED error flag
if( MPR121_reset(dev) ){
@@ -284,11 +224,15 @@ bool MPR121_reset(MPR121_t * dev){
dev->error &= ~(1<<READBACK_FAIL_BIT);
}
vTaskDelay(10);
ESP_LOGD(__FUNCTION__, "start getRegister MPR121_TS2");
if((MPR121_getRegister(dev, MPR121_TS2)&0x80)!=0){
dev->error |= 1<<OVERCURRENT_FLAG_BIT;
} else {
dev->error &= ~(1<<OVERCURRENT_FLAG_BIT);
}
vTaskDelay(10);
ESP_LOGD(__FUNCTION__, "done getRegister MPR121_TS2");
if(MPR121_getError(dev)==NOT_INITED || MPR121_getError(dev)==NO_ERROR){ // if our only error is that we are not inited...
return true;

View File

@@ -40,6 +40,26 @@
#include "mpr121_defs.h"
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0))
#include "driver/i2c_master.h"
#else
#include "driver/i2c.h"
#endif
#define I2C_MASTER_FREQ_HZ 400000 /*!< I2C master clock frequency. no higher than 1MHz for now */
#define I2C_TICKS_TO_WAIT 100 // Maximum ticks to wait before issuing a timeout.
#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
#if CONFIG_I2C_PORT_0
#define I2C_NUM I2C_NUM_0
#else
#define I2C_NUM I2C_NUM_1
#endif
// 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
@@ -107,10 +127,14 @@ typedef struct
} MPR121_settings_type;
typedef struct {
uint8_t address;
uint8_t _address;
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0))
i2c_master_bus_handle_t _i2c_bus_handle;
i2c_master_dev_handle_t _i2c_dev_handle;
#endif
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 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;
@@ -118,9 +142,8 @@ typedef struct {
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
uint16_t lastTouchData; // we use this to catch touch / release events that happen during other update calls
bool autoTouchStatusFlag;
} MPR121_t;
@@ -226,6 +249,10 @@ enum mpr121_SFI_type
// -------------------- BASIC FUNCTIONS --------------------
void i2c_setRegister(MPR121_t * dev, uint8_t reg, uint8_t value);
uint8_t i2c_getRegister(MPR121_t * dev, uint8_t reg);
void i2c_register(MPR121_t * dev, int16_t sda, int16_t scl);
void MPR121_type(MPR121_t * dev);
// begin() must be called before using any other function
@@ -428,6 +455,5 @@ void MPR121_setSFI(MPR121_t * dev, uint8_t SFI);
//extern MPR121_type MPR121;
#endif // MPR121_H