6 集成电路间总线(I2C)
6.3 使用方法
6.3.1 Master读些,采用QUEUE模式
#define I2C_PORT I2C_PORT_0
#define I2C_ADDR 0X76
6.3.1.1 打开I2C时钟
( (1 << SYSCTRL_ClkGate_APB_I2C0)
SYSCTRL_ClearClkGateMulti|(1 << SYSCTRL_ClkGate_APB_PinCtrl));
6.3.1.2 配置I2C的IO口
(10, IO_SOURCE_I2C0_SCL_O);
PINCTRL_SetPadMux(11, IO_SOURCE_I2C0_SDO);
PINCTRL_SetPadMux(I2C_PORT, 10); PINCTRL_SelI2cSclIn
6.3.1.4 I2C写操作
int i2c_do_write(const i2c_port_t port, const uint32_t nrm, uint8_t addr, const uint8_t *byte_data, int16_t length)
{
uint32_t *p_data = (uint32_t *)(byte_data + 3);
uint32_t data = (addr << 1) | 0; // control: write
*BASE = I2C_BASE(port);
I2C_TypeDef int timeout = I2C_HW_TIME_OUT;
if (length > 0)
|= (byte_data[0] << 8) | (byte_data[1] << 16) | (byte_data[2] << 24);
data
(BASE, I2C_CTRL0_SFTRST | I2C_CTRL0_CLKGATE);
I2C_CTRL0_CLR
// ONLY SUPPORT PIO QUEUE MODE, SET HW_I2C_QUEUECTRL_PIO_QUEUE_MODE AT FRIST
(BASE, I2C_QUEUECTRL_PIO_QUEUE_MODE);
I2C_QUEUECTRL_SET
// frist operation, do not need clear I2C_QUEUECTRL and I2C_QUEUECMD.
->I2C_QUEUECMD.NRM = nrm + 1 + length;
BASE
(BASE, I2C_QUEUECTRL_QUEUE_RUN);
I2C_QUEUECTRL_SET
+= 1;
length while (1)
{
(I2C_QUEUESTAT_WR_QUEUE_FULL(BASE));
while_with_timeout->I2C_DATA = data;
BASE-= 4;
length if (length <= 0)
break;
= *p_data;
data ++;
p_data}
// WAIT I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ (software polling)
(GET_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ(BASE) == 0);
while_with_timeout(BASE, I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ);
I2C_CTRL1_CLR
// NOTE : MUST SET I2C_QUEUECTRL_WR_CLEAR
(BASE, I2C_QUEUECTRL_WR_CLEAR);
I2C_QUEUECTRL_SET(BASE, I2C_QUEUECTRL_WR_CLEAR);
I2C_QUEUECTRL_CLR
return 0;
}
6.3.1.5 I2C读操作
int i2c_read(const i2c_port_t port, uint8_t addr,
const uint8_t *write_data, int16_t write_len,
uint8_t *read_data, int16_t read_length)
{
*BASE = I2C_BASE(port);
I2C_TypeDef int timeout = I2C_HW_TIME_OUT;
if (write_len)
{
// STEP 1: send write command
int r = i2c_do_write(port, I2C_QUEUECMD_PRE_SEND_START | I2C_QUEUECMD_MASTER_MODE | I2C_QUEUECMD_DIRECTION,
, write_data, write_len);
addrif (r != 0) return r;
}
else
{
(BASE, I2C_CTRL0_SFTRST | I2C_CTRL0_CLKGATE);
I2C_CTRL0_CLR
// ONLY SUPPORT PIO QUEUE MODE, SET HW_I2C_QUEUECTRL_PIO_QUEUE_MODE AT FRIST
(BASE, I2C_QUEUECTRL_PIO_QUEUE_MODE);
I2C_QUEUECTRL_SET}
// STEP 2 : transmit (control byte + Read command), need hold SCL (I2C_QUEUECMD_RETAIN_CLOCK)
->I2C_QUEUECMD.NRM = (I2C_QUEUECMD_RETAIN_CLOCK | I2C_QUEUECMD_PRE_SEND_START | I2C_QUEUECMD_MASTER_MODE | I2C_QUEUECMD_DIRECTION |
BASE1);
(BASE, I2C_QUEUECTRL_QUEUE_RUN);
I2C_QUEUECTRL_SET
->I2C_DATA = 0xA5UL << 24 | 0x5A << 16 |0xAA << 8 | (addr << 1) | 1;
BASE
(GET_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ(BASE) == 0);
while_with_timeout
// CLEAR I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ
(BASE, I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ);
I2C_CTRL1_CLR
// NOTE : MUST SET I2C_QUEUECTRL_WR_CLEAR
(BASE, I2C_QUEUECTRL_WR_CLEAR);
I2C_QUEUECTRL_SET(BASE, I2C_QUEUECTRL_WR_CLEAR);
I2C_QUEUECTRL_CLR
//
// STEP 3 : read data byte + (NO ACK) + STOP
//
->I2C_QUEUECMD.NRM = (I2C_QUEUECMD_SEND_NAK_ON_LAST | I2C_QUEUECMD_POST_SEND_STOP | I2C_QUEUECMD_MASTER_MODE |
BASE/*I2C_QUEUECMD_XFER_COUNT*/
);
read_length
(BASE, I2C_QUEUECTRL_QUEUE_RUN);
I2C_QUEUECTRL_SET
// Receive DATA use I2C_QUEUEDATA;
while (read_length > 0)
{
// check whether rdFIFO is empty
(I2C_QUEUESTAT_RD_QUEUE_EMPTY(BASE));
while_with_timeout
int len = write_bytes(read_data, BASE->I2C_QUEUEDATA, read_length);
+= len;
read_data -= len;
read_length }
// WAIT I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ (software polling)
(GET_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ(BASE) == 0);
while_with_timeout
// cLEAR I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ
(BASE, I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ);
I2C_CTRL1_CLR
// NOTE : CLEAR I2C_QUEUECTRL_RD_CLEAR
(BASE, I2C_QUEUECTRL_RD_CLEAR);
I2C_QUEUECTRL_SET(BASE, I2C_QUEUECTRL_RD_CLEAR);
I2C_QUEUECTRL_CLR
return 0;
}