STM32CubeMX series | I2C bus

I2C bus

1 Introduction

1.1 Introduction to I2C bus

The I2C (Inter-Integrated Circuit) bus is a two-wire serial bus developed by PHILIPS, which is used to connect microcontrollers and their peripheral devices. It is a serial bus composed of data line SDA and clock line SCL, which can send and receive data. Two-way transmission is performed between the CPU and the controlled IC, and between the IC and the IC, and the high-speed I2C bus can generally reach more than 400kbps. Let's learn about I2C from the physical layer and the protocol layer.

  • I2C physical layer: can connect multiple I2C communication devices, support multiple communication hosts and slaves; each device connected to the bus has an independent address, and the host uses this address to access different devices; the bus passes the upper The pull-up resistor is connected to the power supply, and when the I2C device is idle, it will output a high-impedance state; when multiple hosts use the bus at the same time, the arbitration method is used to determine which device occupies the bus; there are three transmission modes, standard mode (100kbit/s), fast mode ( 400kbit/s), high-speed mode (3.4Mbit/s is not supported by most I2C devices); the number of I2C connected to the same bus is limited by the maximum capacitance of 400pF

  • I2C protocol layer: I2C bus has three types of signals in the process of transmitting data. Among these signals, the start signal is necessary, and the end and response signals are not necessary; I2C bus addressing can be divided into 7 bits and 7 bits according to the slave address. 10 bits (addressing byte) address two kinds, D7~D1 bits form the address of the slave machine, D0 bit is the data transfer direction (0 means the host writes data to the slave machine / 1 means the host reads data from the slave machine)
  • Start signal: When SCL is high level, SDA jumps from high level to low level and starts to transmit data
  • End signal: When SCL is high level, SDA jumps from low level to high level, ending the transmission of data
  • Response signal: After receiving the 8-bit data, the IC that receives the data sends a specific low-level pulse to the IC that sends the data, indicating that the data has been received. After the CPU sends a signal to the controlled unit, it waits for the controlled unit to send a response signal. After receiving the response signal, the CPU makes a judgment on whether to continue to transmit the signal according to the actual situation. If the response is received, it is judged that the controlled unit is faulty

1.2 Introduction of AT24C02 chip

AT24C02 is a 2K-bit serial CMOS with 256 bytes inside. This chip has an I2C communication interface. The data stored in the chip will not be lost in case of power failure (EEPROM), and it is often used to store more important data. This experiment uses AT24C02 chip in SOP-8 package, and its pin description is shown in the figure below

The device address of the AT24C02 chip is 7 bits, the upper 4 bits are fixed at 1010, the lower 3 bits are determined by the level of the A0/A1/A2 pins in the above table, and there is one bit (the lowest bit R/W) to select the read write directions. In this experiment, the A0/A1/A2 pins are connected to GND, so the device address is 1010000; after adding the lowest read and write direction bits, the write device address is 10100000 (0xA0), and the read device address is 10100001 (0xA1)

The following figure shows the bus timing diagram and time parameters of AT24C02

At present, most MCU s have an I2C bus interface, but here we do not use the hardware I2C of STM32F1 to read and write AT24C02, but through software simulation. In order to avoid the patent problem of Philips I2C, ST designed the hardware I2C of STM32 is more complicated, and the stability is not good, it is not recommended to use

2. Hardware Design

The D1 indicator light is used to indicate the system running status, the K_UP button is used to control the data writing of the 24C02, the K_DOWN button is used to control the data reading of the 24C02, and the data writing and reading information is printed out through the serial port 1

  • D1 indicator
  • K_UP and K_DOWN buttons
  • USART1
  • AT24C02

3. Software Design

3.1 STM32CubeMX settings
  • RCC sets the external HSE, the clock is set to 72M
  • PC0 is set to GPIO push-pull output mode, pull-up, high-speed, and the default output level is high level
  • USART1 is selected as the asynchronous communication mode, the baud rate is set to 115200Bits/s, the transmission data length is 8Bit, no parity check, 1 stop bit
  • PA0 is set to GPIO input mode, pull-down mode; PE3 is set to GPIO input mode, pull-up mode
  • Activate I2C2, select standard transfer mode, select 7-bit addressing address, and the rest are default settings

  • Enter the project name, select the project path (do not have Chinese), select MDK-ARM V5; check Generated periphera initialization as a pair of ‘.c/.h’ files per IP; click GENERATE CODE to generate the project code
3.2 MDK-ARM programming
  • You can see the I2C initialization function under the i2c.c file
void MX_I2C2_Init(void){
  hi2c2.Instance = I2C2;
  hi2c2.Init.ClockSpeed = 100000;
  hi2c2.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c2.Init.OwnAddress1 = 0;
  hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c2.Init.OwnAddress2 = 0;
  hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c2) != HAL_OK){

void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle){
  GPIO_InitTypeDef GPIO_InitStruct = {0};
    /**I2C2 GPIO Configuration    
    PB10     ------> I2C2_SCL
    PB11     ------> I2C2_SDA*/
    GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    /* I2C2 clock enable */
    __HAL_RCC_I2C2_CLK_ENABLE();	//I saw a lot of information on the Internet that the I2C clock initialization function here should be placed before the GPIO initialization, but there is no adjustment here, and the EEPROM can be read and written normally.

The 2Kbit of AT24C02 is divided into 32 pages, each page is 8 bytes. The EEPROM can also be written by page. In this example, the way of writing by page is used, and it is written in 32 times. Note that each write requires a delay of 5ms, which is the requirement of the AT24C02 chip; there is no page limit for reading data, and 256 bytes can be read at one time

#define ADDR_24CXX_WRITE 0XA0
#define ADDR_24CXX_READ  0XA1
uint8_t WriteBuf[256];
uint8_t ReadBuf[256];
uint16_t i,j;
void SystemClock_Config(void);
int main(void){
  uint8_t key;
  printf("\r\n*********STM32CubeMX I2C AT24C02 Example*********\r\n");
  for(i = 0;i < 256; i++){	 //Initialize write data buffer
	WriteBuf[i] = i;
  /* USER CODE END 2 */
  while (1){
	key = KEY_Scan(0);
	if(key == KEY_UP_PRES){
		for(j = 0;j < 32;j++){	//Write to EEPROM by page, divided into 32 times
			if(HAL_I2C_Mem_Write(&hi2c2,ADDR_24CXX_WRITE,8*j,I2C_MEMADD_SIZE_8BIT,WriteBuf+8*j,8,0xFF) == HAL_OK){
				printf("\r\nEEPROM 24C02 Write Test OK!\r\n");
				printf("\r\nEEPROM 24C02 Write Test False!\r\n");
	if(key == KEY_DOWN_PRES){	//EEPROM read has no page limit and can read 256 bytes at a time
			printf("0x%02X ",ReadBuf[i]);
		if(memcmp(WriteBuf,ReadBuf,256) == 0){	//Through memory comparison, determine whether the data read and written are the same
			printf("\r\nEEPROM 24C02 Read Test OK!\r\n");
			printf("\r\nEEPROM 24C02 Read Test False!\r\n");

4. Download verification

After compiling and downloading to the development board without error, you can see that the D1 indicator keeps flashing. When the K_UP button is pressed, the data is written into the 24C02 chip. When the K_DOWN button is pressed, the value of the 24C02 chip is read, and the serial port prints out the corresponding information.

Tags: C Embedded system Single-Chip Microcomputer stm32

Posted by lanbor on Sat, 14 May 2022 12:49:37 +0300