Page 1 of 1

First I2C transaction is at wrong speed

Posted: Sun Jul 21, 2019 5:04 pm
by richardl
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

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;
}


Re: First I2C transaction is at wrong speed

Posted: Mon Jul 22, 2019 1:33 pm
by richardl
Please ignore this, turns out SPI GPIO was conflicting with I2C