Introduction and implementation of the I2C bus
Hits: 3893892
2020-04-17
Click the blue word to follow
Official account of the Electronic Science Association of Southeast University
Last week, students from the association of science and technology brought you the first issue of science popularization series - WIFI connection based on esp32. Detailed description and clear picture guidance will surely let you learn a lot! Those who haven't seen it should go to see it earlier! If you don't say much, today I will bring you the introduction and implementation of I2C bus, the second bullet of science popularization series.
Introduction of I2C bus
purpose
I2C (IIC) is the abbreviation of inter integrated circuit. It is mainly used for communication between SOC and peripheral devices (EEPROM, various sensors). For example, I2C configures HDMI interface chip adv7611, I2C reads data of gyroscope mpu6050, I2C accesses memory 24C02, etc.
Connect
I2C bus only uses two signal lines with open drain in two directions, and uses resistance to pull up.
SCL (serial clock): serial clock line, which transmits CLK signals, generally provided by the master equipment to the slave equipment;
SDA (serial data): serial data line to transmit communication data.
Generally, I2C devices have unique (or configurable) device addresses, and internal registers (or storage spaces) of devices also have corresponding addresses.
In short, I2C communication process is as follows:
* write data: send the start signal, send the device address signal, detect the response, send the write command, send the address of the data to be written; send the data, send the stop signal.
* read data: send the start signal, send the device address signal, detect the response, send the write command, send the address to read the data; send the start signal, send the read command.
Taking single write (write only one byte of data at a time) and random read (can read data at any address) as examples, the timing of IIC is introduced:
Write data:
Send start signal; (send device address (7bits) + write command bit (1bit)); detect response; send target address; detect response; send data; detect response; send stop signal
* read data:
Send start signal; (send device address (7bit) + write command bit (1bit)); detect response; send target address; detect response; send start signal; (send device address (7bit) + read command bit (1bit)); detect response; after that, start to connect the main line and send data from the machine; after receiving, the host gives a non response and sends a stop signal.
sequential
I2C timing:
The notes of the overall sequence diagram are as follows:
① In idle state, SDA and SCL are kept high;
② I2C protocol start bit: when the SCL is in high level, SDA appears a falling edge, and a start bit is generated;
③ I2C end bit: when SCL is at high level, SDA will rise and generate a stop bit;
④ The relationship between SCL and SDA during I2C data transmission:
When the I2C master (hereinafter referred to as the master) writes data to the I2C slave (hereinafter referred to as the slave), each bit of data on the SDA changes during the low level of the SCL and is written into the slave during the high level.
Every time a byte of data or command transmission is completed, the data receiver will respond to the sender with a response bit. If the data receiver is receiving the data correctly, the data receiver will pull down the SDA bus to show the correct response.
Using STM32 to realize I2C bus
When GPIO is used to simulate I2C timing, the driver of MCU is quite simple. For the complete project, please click the link: https://github.com/sxw228/stm32f4 iuic
01
Initialization: initialization, which is essentially to configure GPIO. Here, PB8 is used as SCL and PB9 as SDA, configured as push-pull output pull-up mode. Port selection can be changed according to hardware.
void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(
RCC_AHB1Periph_GPIOB, ENABLE
); / / enable gpiob clock
//Gpiob8, B9 initialization settings
GPIO_InitStructure.GPIO_Pin =
GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode =
GPIO_Mode_OUT;
//Normal output mode
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
//Push pull output
GPIO_InitStructure.GPIO_Speed =
GPIO_Speed_100MHz; //100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
/ / pull up
GPIO ﹣ init (gpiob, & GPIO ﹣ initstructure); / / initialization
IIC_SCL = 1;
IIC_SDA = 1;
}
02
voidIIC_Start(void)
{
SDA? Out(); / / SDA line output
IIC_SDA = 1;
IIC_SCL = 1;
Delay_us (4);
IIC_SDA = 0; //START:when CLK is high,DATA change form high to low
Delay_us (4);
Iic_scl = 0; / / clamp I2C bus and prepare to send or receive data
}
voidIIC_Stop(void)
{
SDA? Out(); / / SDA line output
IIC_SCL = 0;
IIC_SDA = 0; //STOP:when CLK is high DATA change form low to high
Delay_us (4);
IIC_SCL = 1;
Iic_sda = 1; / / send I2C bus end signal
Delay_us (4);
}
03
Answer: the host waits for the answer, and the slave selects ACK or NACK
//Return value: 1, failed to receive response
//0, receive response succeeded
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime = 0;
SDA in(); / / SDA set as input
IIC_SDA=1; delay_us(1);
IIC_SCL=1; delay_us(1);
while (READ_SDA)
{
UcErrTime++;
if (ucErrTime > 250)
{
IIC_Stop ();
Return 1;
}
}
Iic_scl = 0; / / clock output 0
Return 0;
}
//Generate ack response
void IIC_Ack(void)
{
IIC_SCL = 0;
SDA_OUT ();
IIC_SDA = 0;
Delay_us (2);
IIC_SCL = 1;
Delay_us (2);
IIC_SCL = 0;
}
//No ack response
void IIC_NAck(void)
{
IIC_SCL = 0;
SDA_OUT ();
IIC_SDA = 1;
Delay_us (2);
IIC_SCL = 1;
Delay_us (2);
IIC_SCL = 0;
}
04
Byte read and write: read and write by byte, from high to low.
void IIC_Send_Byte(u8 txd)
{
U8 T;
SDA_OUT ();
Iic_scl = 0; / / pull down the clock to start data transmission
for (t = 0; t < 8; t++)
{
IIC_SDA = (txd & 0x80) >> 7;
txd <<= 1;
Delay_us (2);
IIC_SCL = 1;
Delay_us (2);
IIC_SCL = 0;
Delay_us (2);
}
}
//Read 1 byte, when ack = 1, send ACK, ACK = 0, send NACK
u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i, receive = 0;
SDA in(); / / SDA set as input
for (i=0; i < 8; i++)
{
IIC_SCL = 0;
Delay_us (2);
IIC_SCL = 1;
receive <<= 1;
if (READ_SDA) receive++;
Delay_us (1);
}
If (ACK)
Iic_nack(); / / send NACK
Else
Iic_ack(); / / send ACK
return receive;
}
Implementation of I2C bus with FPGA
The upper module will give the start signal and the read-write request and the corresponding address. After receiving these signals, the module will complete the access to the slave device through the I2C clock and data bus SCL and SDA.
After one reading and writing, the end of writing and end of reading signals Rd ﹣ done and WR ﹣ done will be given. In case of a reading request, the read data will be output after the end of this reading. If there is an error in the transmission process, the error signal err flag will be enabled to indicate the transmission error.
Interface list of modules:
Port name
I/O
Bit width
Remarks
CLK
I
One
Working clock of user port, 50m
RST
I
One
System reset
Rd_req
I
One
Read request
Wr_req
I
One
Write request
Start
I
One
Read or start writing signals
Wr_data
I
Eight
Data to write
Dev_addr
I
Eight
Device address
Mem_addr
I
Eight
Register address
Rd_data
O
Eight
Data read from device
Rd_done
O
One
Read end flag
Wr_done
O
One
Write end flag
Err_flag
O
One
False signal
SCL
O
One
I2C clock line
SDA
TRI
One
I2C three state data line
Status jump chart of the module:
Working process:
In idle state idle, if start signal is received, it will enter write start state. WR start generates the start bit needed for this transmission (when the SCL is high, the SDA shows a falling edge), and then enters the state of confirming the device address, WR dev, to send the device address to the data bus. If the device exists, enter the state of confirming the register address, wr reg, otherwise enter the state of error.
The operation mode in WR MEM state is similar to that in WR dev state. If the register address exists, it will be read according to the current
The request or write request enters the write data state WR? Data and read start state Rd? Start. In the write data state, write the 8 bit data entered by the user to the register address. If it is written correctly, it enters the stop state, otherwise it enters the error state.
In the read start state, the start bit of the read data is generated and enters the send read control word state rd_dev. if the response is received correctly in this state, it will enter the read data state rd_data. Otherwise, it will enter the error state. In the data reading state, the data will be read out from the device, and the data will enter the end state after reading.
But because the code is too long, it will not be displayed here. Sorry.
Attach link:
https://github.com/sxw228/hdmi_interface/blob/master/i2c_driver.v
This is the introduction
See you next time!
Picture song Changjun
Characters: Song Changjun, Dou Gang
Typesetting | zhangjiaxiang, Liu Runzhou