248 lines
7.8 KiB
C
248 lines
7.8 KiB
C
|
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||
|
//
|
||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
// you may not use this file except in compliance with the License.
|
||
|
// You may obtain a copy of the License at
|
||
|
|
||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||
|
//
|
||
|
// Unless required by applicable law or agreed to in writing, software
|
||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
// See the License for the specific language governing permissions and
|
||
|
// limitations under the License.
|
||
|
|
||
|
#include "esp32-hal-i2c.h"
|
||
|
#include "freertos/FreeRTOS.h"
|
||
|
#include "freertos/task.h"
|
||
|
#include "rom/ets_sys.h"
|
||
|
#include "soc/i2c_reg.h"
|
||
|
#include "soc/dport_reg.h"
|
||
|
|
||
|
#define I2C_DEV(i) (volatile i2c_dev_t *)((i)?DR_REG_I2C1_EXT_BASE:DR_REG_I2C_EXT_BASE)
|
||
|
//#define I2C_DEV(i) ((i2c_dev_t *)(REG_I2C_BASE(i)))
|
||
|
#define I2C_SCL_IDX(p) ((p==0)?I2CEXT0_SCL_OUT_IDX:((p==1)?I2CEXT1_SCL_OUT_IDX:0))
|
||
|
#define I2C_SDA_IDX(p) ((p==0)?I2CEXT0_SDA_OUT_IDX:((p==1)?I2CEXT1_SDA_OUT_IDX:0))
|
||
|
|
||
|
void i2cAttachSCL(i2c_t * i2c, int8_t scl)
|
||
|
{
|
||
|
pinMode(scl, INPUT);
|
||
|
pinMatrixOutAttach(scl, I2C_SCL_IDX(i2c->num), false, false);
|
||
|
pinMatrixInAttach(scl, I2C_SCL_IDX(i2c->num), false);
|
||
|
}
|
||
|
|
||
|
void i2cDetachSCL(i2c_t * i2c, int8_t scl)
|
||
|
{
|
||
|
pinMatrixOutDetach(scl, false, false);
|
||
|
pinMatrixInDetach(I2C_SCL_IDX(i2c->num), false, false);
|
||
|
pinMode(scl, INPUT);
|
||
|
}
|
||
|
|
||
|
void i2cAttachSDA(i2c_t * i2c, int8_t sda)
|
||
|
{
|
||
|
pinMode(sda, INPUT);
|
||
|
pinMatrixOutAttach(sda, I2C_SDA_IDX(i2c->num), false, false);
|
||
|
pinMatrixInAttach(sda, I2C_SDA_IDX(i2c->num), false);
|
||
|
}
|
||
|
|
||
|
void i2cDetachSDA(i2c_t * i2c, int8_t sda)
|
||
|
{
|
||
|
pinMatrixOutDetach(sda, false, false);
|
||
|
pinMatrixInDetach(I2C_SDA_IDX(i2c->num), false, false);
|
||
|
pinMode(sda, INPUT);
|
||
|
}
|
||
|
|
||
|
enum {
|
||
|
I2C_CMD_RSTART,
|
||
|
I2C_CMD_WRITE,
|
||
|
I2C_CMD_READ,
|
||
|
I2C_CMD_STOP,
|
||
|
I2C_CMD_END
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
* index - command index (0 to 15)
|
||
|
* op_code - is the command
|
||
|
* ack_val - Each data byte is terminated by an ACK bit used to set the bit level.
|
||
|
* ack_exp - This bit is to set an expected ACK value for the transmitter.
|
||
|
* ack_check - This bit is to decide whether the transmitter checks ACK bit. 1 means yes and 0 means no.
|
||
|
* byte_num - This register is to store the amounts of data that is read and written. byte_num in RSTART, STOP, END is null.
|
||
|
* */
|
||
|
void i2cSetCmd(i2c_t * i2c, uint8_t index, uint8_t op_code, uint8_t byte_num, bool ack_val, bool ack_exp, bool ack_check)
|
||
|
{
|
||
|
i2c->dev->command[index].val = 0;
|
||
|
i2c->dev->command[index].ack_en = ack_check;
|
||
|
i2c->dev->command[index].ack_exp = ack_exp;
|
||
|
i2c->dev->command[index].ack_val = ack_val;
|
||
|
i2c->dev->command[index].byte_num = byte_num;
|
||
|
i2c->dev->command[index].op_code = op_code;
|
||
|
}
|
||
|
|
||
|
int i2cWrite(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * data, uint8_t len, bool sendStop)
|
||
|
{
|
||
|
uint8_t index = 0;
|
||
|
uint8_t dataLen = len + (addr_10bit?2:1);
|
||
|
address = (address << 1);
|
||
|
|
||
|
while(dataLen) {
|
||
|
uint8_t willSend = (dataLen > 32)?32:dataLen;
|
||
|
uint8_t dataSend = willSend;
|
||
|
i2cSetCmd(i2c, 0, I2C_CMD_RSTART, 0, false, false, false);//START
|
||
|
i2cSetCmd(i2c, 1, I2C_CMD_WRITE, willSend, false, false, true);
|
||
|
if(!index) {
|
||
|
i2c->dev->fifo_data.data = address & 0xFF;
|
||
|
dataSend--;
|
||
|
if(addr_10bit) {
|
||
|
i2c->dev->fifo_data.data = (address >> 8) & 0xFF;
|
||
|
dataSend--;
|
||
|
}
|
||
|
}
|
||
|
int i = 0;
|
||
|
while(i<dataSend) {
|
||
|
i++;
|
||
|
i2c->dev->fifo_data.data = data[index++];
|
||
|
}
|
||
|
dataLen -= willSend;
|
||
|
if(dataLen) {
|
||
|
i2cSetCmd(i2c, 2, I2C_CMD_END, 0, false, false, false);
|
||
|
} else if(sendStop) {
|
||
|
i2cSetCmd(i2c, 2, I2C_CMD_STOP, 0, false, false, true);
|
||
|
}
|
||
|
i2c->dev->ctr.trans_start = 1;
|
||
|
while(i2c->dev->ctr.trans_start || i2c->dev->status_reg.bus_busy || (!i2c->dev->int_raw.ack_err && !i2c->dev->command[2].done));
|
||
|
if(!i2c->dev->command[2].done) {
|
||
|
log_e("Ack Error");
|
||
|
return -1;
|
||
|
}
|
||
|
if(i2c->dev->status_reg.arb_lost || i2c->dev->status_reg.time_out) {
|
||
|
log_e("Bus Fail");
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int i2cRead(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * data, uint8_t len, bool sendStop)
|
||
|
{
|
||
|
address = (address << 1) | 1;
|
||
|
uint8_t addrLen = (addr_10bit?2:1);
|
||
|
uint8_t index = 0;
|
||
|
uint8_t cmdIdx;
|
||
|
uint8_t willRead;
|
||
|
|
||
|
i2cSetCmd(i2c, 0, I2C_CMD_RSTART, 0, false, false, false);//START
|
||
|
i2cSetCmd(i2c, 1, I2C_CMD_WRITE, addrLen, false, false, true);
|
||
|
i2c->dev->fifo_data.data = address & 0xFF;
|
||
|
if(addr_10bit) {
|
||
|
i2c->dev->fifo_data.data = (address >> 8) & 0xFF;
|
||
|
}
|
||
|
while(len) {
|
||
|
cmdIdx = (index)?0:2;
|
||
|
willRead = (len > 32)?32:(len-1);
|
||
|
i2cSetCmd(i2c, cmdIdx++, I2C_CMD_READ, willRead, false, false, false);
|
||
|
if((len - willRead) > 1) {
|
||
|
i2cSetCmd(i2c, cmdIdx++, I2C_CMD_END, 0, false, false, false);
|
||
|
} else {
|
||
|
willRead++;
|
||
|
i2cSetCmd(i2c, cmdIdx++, I2C_CMD_READ, 1, true, false, false);
|
||
|
if(sendStop) {
|
||
|
i2cSetCmd(i2c, cmdIdx++, I2C_CMD_STOP, 0, false, false, false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
i2c->dev->ctr.trans_start = 1;
|
||
|
while(i2c->dev->ctr.trans_start || i2c->dev->status_reg.bus_busy || (!i2c->dev->int_raw.ack_err && !i2c->dev->command[cmdIdx-1].done));
|
||
|
if(!i2c->dev->command[cmdIdx-1].done) {
|
||
|
log_e("Ack Error");
|
||
|
return -1;
|
||
|
}
|
||
|
if(i2c->dev->status_reg.arb_lost || i2c->dev->status_reg.time_out) {
|
||
|
log_e("Bus Fail");
|
||
|
return -1;
|
||
|
}
|
||
|
int i = 0;
|
||
|
while(i<willRead) {
|
||
|
i++;
|
||
|
data[index++] = i2c->dev->fifo_data.data;
|
||
|
}
|
||
|
len -= willRead;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void i2cResetFiFo(i2c_t * i2c)
|
||
|
{
|
||
|
//TX FIFO
|
||
|
i2c->dev->fifo_conf.tx_fifo_rst = 1;
|
||
|
i2c->dev->fifo_conf.tx_fifo_rst = 0;
|
||
|
//RX FIFO
|
||
|
i2c->dev->fifo_conf.rx_fifo_rst = 1;
|
||
|
i2c->dev->fifo_conf.rx_fifo_rst = 0;
|
||
|
}
|
||
|
|
||
|
void i2cSetFrequency(i2c_t * i2c, uint32_t clk_speed)
|
||
|
{
|
||
|
uint32_t period = (APB_CLK_FREQ/clk_speed) / 2;
|
||
|
i2c->dev->scl_low_period.scl_low_period = period;
|
||
|
i2c->dev->scl_high_period.period = period;
|
||
|
|
||
|
i2c->dev->scl_start_hold.time = 50;
|
||
|
i2c->dev->scl_rstart_setup.time = 50;
|
||
|
|
||
|
i2c->dev->scl_stop_hold.time = 50;
|
||
|
i2c->dev->scl_stop_setup.time = 50;
|
||
|
|
||
|
i2c->dev->sda_hold.time = 40;
|
||
|
i2c->dev->sda_sample.time = 40;
|
||
|
}
|
||
|
|
||
|
uint32_t i2cGetFrequency(i2c_t * i2c)
|
||
|
{
|
||
|
return APB_CLK_FREQ/(i2c->dev->scl_low_period.scl_low_period+i2c->dev->scl_high_period.period);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* mode - 0 = Slave, 1 = Master
|
||
|
* slave_addr - I2C Address
|
||
|
* addr_10bit_en - enable slave 10bit address mode.
|
||
|
* clk_speed - SCL Frequency
|
||
|
* */
|
||
|
|
||
|
i2c_t * i2cInit(uint8_t i2c_num, uint16_t slave_addr, bool addr_10bit_en)
|
||
|
{
|
||
|
i2c_t* i2c = (i2c_t*) malloc(sizeof(i2c_t));
|
||
|
if(i2c == 0) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
i2c->num = i2c_num;
|
||
|
i2c->dev = I2C_DEV(i2c_num);
|
||
|
|
||
|
if(i2c->num == 0) {
|
||
|
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG,DPORT_I2C_EXT0_CLK_EN);
|
||
|
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,DPORT_I2C_EXT0_RST);
|
||
|
} else if(i2c->num == 1) {
|
||
|
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG,DPORT_I2C_EXT1_CLK_EN);
|
||
|
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,DPORT_I2C_EXT1_RST);
|
||
|
}
|
||
|
|
||
|
i2c->dev->ctr.rx_lsb_first = 0 ;
|
||
|
i2c->dev->ctr.tx_lsb_first = 0 ;
|
||
|
i2c->dev->ctr.ms_mode = (slave_addr == 0);
|
||
|
i2c->dev->ctr.sda_force_out = 1 ;
|
||
|
i2c->dev->ctr.scl_force_out = 1 ;
|
||
|
i2c->dev->ctr.sample_scl_level = 0 ;
|
||
|
|
||
|
i2c->dev->timeout.tout = 2000;
|
||
|
i2c->dev->fifo_conf.nonfifo_en = 0;
|
||
|
|
||
|
if (slave_addr) {
|
||
|
i2c->dev->slave_addr.addr = slave_addr;
|
||
|
i2c->dev->slave_addr.en_10bit = addr_10bit_en;
|
||
|
}
|
||
|
|
||
|
return i2c;
|
||
|
}
|
||
|
|
||
|
|