EBU5476 Microprocessor System Design Knowledge Points Summary_8 I2C

2C

Transmission scheme for connecting multiple modules: I2C, using two buses.

image-20230622000302459

The two buses are the clock bus SCL and the data bus SDA.

communication process

Now let's go through the process of sending a message from one module (master) to another module (slave) on I2C.

1687363434463

  1. The MCU uses a certain method to identify itself to start transmission.
  2. The MCU sends the address of the LCD slave + a read-write bit, and other modules receive it and find that the address is not their own, so they do not process it.
  3. After LCD receives it, it knows that the target is itself, so it returns ack.
  4. MCU sends a frame of data after receiving ACK.
  5. After sending, the MCU waits for the ACK, and continues to send the next frame of data after receiving the ACK.
  6. Send until the end of sending stop bit stop.

image-20230622000920336

The data length can be set, such as 789.

Devices on the bus communicate half-duplex with open-drain outputs.

image-20230713135505107

The default bus is pulled high by the pull-up resistor.

When the device output out is low, the bus is turned on to ground and the bus is pulled low (the entire bus is pulled low). The example given by Mr. Jiangxie Science and Technology is very good. It is like a crossbar on a bus. Someone pulls the crossbar and pulls it down. The whole crossbar is pulled down. low, someone is using the bus".

Then there is the way the bus transmits data. Under what circumstances do the two buses of SCL and SDA indicate start stop 0 1 bit?

image-20230713140225426

First of all, the value of SDA is only meaningful when SCL is high level.

SDA is from high to low, indicating the start bit. From low to high, indicates the stop bit.

After start bit, SDA high level means 1, low level means 0.

After sending 1byte data, the bus keeps pulling high. If the receiver pulls the bus down and the sender finds that the bus is 1 → 0 (not pulled by the sender himself, the receiver pulled it down for him, but the sender can detect it), it means that the receiver has successfully received and pulled Pull the bus to show "received". If SDA is still at a high level, it means that the receiver has not successfully received or successfully sent ACK.

image-20230713140822834

problem solving

I2C is a very simple master-slave communication protocol, but it has many limitations. For example, the 7-bit address line only allows 2^7 devices; at most two devices communicate master-slave at a time; the speed of a device will affect The communication of the whole bus, etc.

Question 1: What should I do if the processing speed of the slave device is too slow to receive new data frames in the next clock cycle?

Method: clock stretching, pulling down SCL for a period of time to pretend that the next clock cycle has not yet arrived.

image-20230713141906054

Question 2: What should I do if multiple devices send data conflicts at the same time?

Method: Bus Aribitation, we know that the bus is pulled down by a device, and all devices can receive the signal that the bus is pulled down. Therefore, if two devices start sending information at the same time, it doesn’t matter if the previous data is consistent. When the data is inconsistent for the first time, one device sends data 0 and the other sends data 1. At this time, the SDA bus is pulled down by 0 of DATA2.

image-20230713142029471

The device sending DATA1 data will understand: someone is sending data with me at the same time, so the bus is not 1 as I expected, but it is pulled down to 0 by him. Then I quit, you send it. Then there is only the data sent by DATA2.

Question 3: The data sent above is 1byte 8bits every time, which is just right. What if the address to be sent is not 8bits?

Method: less than 8bits are filled with some fixed extra start bits, addresses more than 8bits are filled with two bytes, and those that are not enough are also filled with extra start bits.

image-20230713143052018

Question 3: If my master finishes sending data and wants to receive data immediately and become a slave, is it feasible?

Method: Resend the start bit through an sr signal, that is, repeat start, to identify itself as read instead of write, and restart communication.

image-20230713143601570

addressing format

There are some fixed formats for slave address addressing.

image-20230713143744619

0000 000 0: Broadcast, talk to all slave nodes. If the slave ignores (NACK), it will not participate in the broadcast. Participated if ACK is returned. However, if multiple slaves return ACK, the master does not know who responded.

The second byte sends some behavior related, such as: start, clear, reset software

programming application

slave mode:

  • I2C devices work in slave mode by default.
  • Peripheral clocks are programmed in the I2C_CR2 register. The frequency is between 2kHz~100kHz.
  • The hardware automatically waits for the start and addr information sent.
  • If the addr information is the same as the address stored in OAR1, it means the target is itself. If the ACK bit is 1, send an ack pulse.
  • Set the ADDR bit, 1 means match.
  • If ITEVFEN is the interrupt event flag is 1, an interrupt is generated.
  • The TRA bit indicates whether the slave is in R or T mode (receive or transmit).
  • The BTF bit mark has been confiscated.

1689255491311

image-20230713214410998

It's still a bit confusing to say so. What exactly did I2C go through to send data smoothly?

First, from the concept of the main mode. The master master mode drives the clock signal and initiates the transfer; the slave slave mode responds to the transfer.

main mode

I2C transfer sequence diagram for master sending data

send:

All EV events pull SCL low until the corresponding software sequence is executed.

S: start event. For example, set the peripheral clock in the CR2 register, configure the clock register, rise the clock register, enable CR1 to enable the clock, set the start bit in CR1, wait for the bus to be pulled low to indicate ready, send the start signal, and switch to the main mode.

EV5: Start event successfully, set SB register = 1. Only after SB register = 1 can the address phase be performed, and the SB and EV5 events will be automatically cleared after the address phase is executed.

Address: address stage. Transmit 7-bit address + 1 read-write bit, and then wait for the slave's ack. Receive ack and enter EV6.

EV6: Setting the addr bit=1 means that the address phase is successfully executed, and the master has received the ack. Automatically enter EV8 after clearing EV6.

EV8: Set TxE and prepare to write the data to be sent by the host. TxE indicates that the data register is empty and can be written. Every time data is written to DR, the TxE and EV8 events will be cleared. After writing the data, the data is transmitted, and the host continues to transmit after receiving the ack. Use BTF=1 to indicate the end of data transfer.

void i2c_write(uint8_t address, uint8_t *buffer, int buff_len) {
    
    
	int i = 0;
    // Send in sequence: Start bit, Contents of buffer 0..buff_len, Stop
    while (((I2C1->SR2>>1)&1)); // wait until I2C1 is not busy anymore
    I2C_GenerateSTART(I2C1, ENABLE); // Send I2C1 START condition
    // wait for I2C1 EV5 --> Slave has acknowledged start condition
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
    // Send slave Address for write then wait for EV6
    I2C_Send7bitAddress(I2C1, address, I2C_Direction_Transmitter);
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    while (i < buff_len){
    
    
        I2C_SendData(I2C1, buffer[i]); // send data then wait for EV8_2
        while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
        i++;
    }
    I2C_GenerateSTOP(I2C1, ENABLE); // send stop bit
}

image-20230714110003657

take over:

The front is the same as the master transmit.

TxE has been changed to RxE, and =1 indicates that data has been received.

After the master sets the stop event (sends NACK), it stops receiving.

void i2c_read(uint8_t address, uint8_t *buffer, int buff_len) {
    
    
    int i = 0;
    // Start bit, Contents of buffer from 0..buff_len, sending a NACK
    // for the last item and an ACK otherwise, Stop bit
    I2C_GenerateSTART(I2C1, ENABLE);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); //EV5
    // Send slave Address for write then wait for EV6
    I2C_Send7bitAddress(I2C1, address, I2C_Direction_Receiver);
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
    I2C_AcknowledgeConfig(I2C1, ENABLE); // going to send ACK
    while (i < buff_len - 1){
    
    
        while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); //EV7
        buffer[i] = I2C_ReceiveData(I2C1); // get data byte
        i++;
    }
    I2C_AcknowledgeConfig(I2C1, DISABLE); // going to send NACK
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); //EV7
    buffer[i] = I2C_ReceiveData(I2C1); // get the last byte
    I2C_GenerateSTOP(I2C1, ENABLE); // send stop
}

slave mode

1689259086166

send:

start The start event is initiated by the master. The slave checks the address and decides whether to send an ack bit.

EV1: Setting the addr bit indicates an address match.

EV3-1: Set the TxE bit and start the incoming data. Until the host returns NACK to indicate that it does not want any more data, or AF=1 indicates that the ack fails.

1689259113895

take over:

The front to EV1 and slave transmit are the same.

  1. Data is read from the DR register.
  2. After reading a byte, if the ack bit has been set, return the ack information.
  3. The RxE bit is the status register for received data.
  4. Stop when master generates a stop condition.

abnormal situation:

Bus error, NACK, arbitration failure, clock exception timeout.

image-20230714110916968

Guess you like

Origin blog.csdn.net/jtwqwq/article/details/131719394
Recommended