First I2C transaction is at wrong speed
Posted: Sun Jul 21, 2019 5:04 pm
IDF V 3.2
When running I2C even when rate set to 100KHz first transaction is at >1MHz.
If you do a fake 1st transacton it sorts itself out and rate is fine after
Using code below
_________
//
//
//
When running I2C even when rate set to 100KHz first transaction is at >1MHz.
If you do a fake 1st transacton it sorts itself out and rate is fine after
Using code below
Code: Select all
// I2C.h
#pragma once
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "freertos/queue.h"
#include "driver/i2c.h"
#include <functional>
#define I2C_MASTER_FREQ_HZ 100000
#define I2CScanCallBack std::function<bool(uint8_t)>
class I2C {
public:
I2C(uint32_t vSpeed = I2C_MASTER_FREQ_HZ,gpio_num_t vSDA = GPIO_NUM_21, gpio_num_t vSCL = GPIO_NUM_22, i2c_port_t vPort= I2C_NUM_1);
~I2C();
bool WriteBytes(uint8_t vAddress, uint8_t* vData, uint16_t vCount);
bool ReadRegisterBytes(uint8_t vAddress, uint8_t VRegister, uint8_t* vData, uint16_t vCount);
uint8_t ScanDevices(I2CScanCallBack vCallback=NULL);
private:
static SemaphoreHandle_t sLock; //Shared Semaphore used to ensure exclusive I2C access
static i2c_port_t sPort;
};
_________
//
//
//
Code: Select all
#include "I2C.h"
#include "esp_log.h"
#define ACK_VAL 0x0 /*!< I2C ack value */
#define NACK_VAL 0x1 /*!< I2C nack value */
#define I2C_TAG "I2C"
SemaphoreHandle_t I2C::sLock = NULL; //Used to ensure exclusive I2C access, shared by all
i2c_port_t I2C::sPort; //Static port number
I2C::I2C(uint32_t vSpeed,gpio_num_t vSDA, gpio_num_t vSCL, i2c_port_t vPort) {
if (sLock == NULL) { //Only create I2C class once
if ((sLock = xSemaphoreCreateMutex()) == NULL) {
ESP_LOGE(I2C_TAG, "I2C No Murex Error");
return;
}
i2c_config_t tConf;
sPort = vPort;
tConf.mode = I2C_MODE_MASTER;
tConf.sda_io_num = vSDA;
tConf.sda_pullup_en = GPIO_PULLUP_DISABLE;
tConf.scl_io_num = vSCL;
tConf.scl_pullup_en = GPIO_PULLUP_DISABLE;
tConf.master.clk_speed = vSpeed;
i2c_param_config(sPort, &tConf);
if (i2c_driver_install(sPort, tConf.mode, 0, 0, 0) != ESP_OK) {
ESP_LOGE(I2C_TAG, "I2C Init Error");
return;
}
}
}
I2C::~I2C() {
i2c_driver_delete(sPort); //Clear up I2C
vSemaphoreDelete(sLock);
sLock = NULL;
}
bool I2C::WriteBytes(uint8_t vAddress, uint8_t * vData, uint16_t vCount) {
if (xSemaphoreTake(sLock, 100 / portTICK_RATE_MS) == pdTRUE) {
i2c_cmd_handle_t tCMD = i2c_cmd_link_create();
i2c_master_start(tCMD);
i2c_master_write_byte(tCMD, vAddress << 1, true);
while (vCount--) {
i2c_master_write_byte(tCMD, *vData++, true);
}
i2c_master_stop(tCMD);
esp_err_t ret = i2c_master_cmd_begin(sPort, tCMD, 100 / portTICK_RATE_MS);
i2c_cmd_link_delete(tCMD);
xSemaphoreGive(sLock);
return (ret == ESP_OK);
}
return false;
}
bool I2C::ReadRegisterBytes(uint8_t vAddress, uint8_t vRegister, uint8_t * vData, uint16_t vCount) {
esp_err_t ret;
if (xSemaphoreTake(sLock, 100 / portTICK_RATE_MS) == pdTRUE) {
i2c_cmd_handle_t tCMD = i2c_cmd_link_create();
ret =i2c_master_start(tCMD);
ret =i2c_master_write_byte(tCMD, vAddress << 1, true); //Address
ret =i2c_master_write_byte(tCMD, vRegister, true); //Register
ret =i2c_master_start(tCMD); //Restart
ret =i2c_master_write_byte(tCMD, (vAddress << 1) | 1, true); //Read from address
if (vCount > 1) {
ret = i2c_master_read(tCMD, vData, vCount - 1, I2C_MASTER_ACK);
vData += vCount - 1;
}
ret = i2c_master_read_byte(tCMD, vData, I2C_MASTER_NACK);
ret = i2c_master_stop(tCMD);
ret = i2c_master_cmd_begin(sPort, tCMD, 100 / portTICK_RATE_MS);
i2c_cmd_link_delete(tCMD);
xSemaphoreGive(sLock);
return (ret == ESP_OK);
}
return false;
}
uint8_t I2C::ScanDevices(I2CScanCallBack vCallback) {
uint8_t tCount = 0;
for (uint8_t tAddress = 8; tAddress <= 0x77; tAddress++) {
if (xSemaphoreTake(sLock, 100 / portTICK_RATE_MS) == pdTRUE) {
i2c_cmd_handle_t tCMD = i2c_cmd_link_create();
i2c_master_start(tCMD);
i2c_master_write_byte(tCMD, tAddress << 1, true);
i2c_master_stop(tCMD);
esp_err_t ret = i2c_master_cmd_begin(sPort, tCMD, 100 / portTICK_RATE_MS);
i2c_cmd_link_delete(tCMD);
xSemaphoreGive(sLock);
if (ret == ESP_OK) {
tCount++;
if (vCallback) {
if (!(vCallback)(tAddress)) break;
}
}
}
}
return tCount;
}