STM32 entry development: introduce IIC bus, read and write AT24C02 (EEPROM) (using analog timing)

1. Environmental introduction

Programming software: keil5

Operating system: win10

MCU model: STM32F103ZET6

STM32 programming method: register development (convenient for program porting to other microcontrollers)

IIC bus:  STM32 itself supports IIC hardware timing. This article uses analog timing. The next article will introduce the IIC hardware timing of configuring STM32 to read and write AT24C02 and AT24C08.

The simulation sequence is more convenient to transplant to other single-chip microcomputers, with higher versatility, regardless of MCU; hardware sequence efficiency is higher, each MCU configuration method is different, and it depends on the hardware itself.

Current device: using AT24C02 EEPROM memory chip

The complete project source code download address, download it to compile and run the test (including simulated IIC timing, STM32 hardware IIC timing to drive AT24C02 and AT24C08 respectively): https://download.csdn.net/download/xiaolong1126626497/19399945

Two, AT24C02 memory chip introduction

2.1 Introduction to chip features

AT24C02 is a serial CMOS type EEPROM memory chip. The AT24C0x series includes specific chip models such as AT24C01, AT24C02, AT24C04, AT24C08, and AT24C16 .

Their capacities are: 1K (128 x 8), 2K (256 x 8), 4K (512 x 8), 8K (1024 x 8), 16K (2048 x 8), where 8 means 8 bits (bit)

Their pin functions and packaging features are as follows:

Chip function description:

The AT24C02 series supports I2C, the bus data transfer protocol I2C. The bus protocol stipulates that any device that transmits data to the bus is used as a transmitter. Any device that receives data from the bus is a receiver; data transmission is controlled by the master device that generates the serial clock and all start and stop signals. Both the master device and the slave device can be used as transmitters or receivers, but the master device controls the mode of transmitting data (sending or receiving). Because A0, A1 and A2 can form eight situations from 000 to 111, that is, through the device address input terminal A0, A1, and A2 can connect up to 8 AT24C02 devices to the bus, and select devices through different configurations.

Introduction of chip characteristics:

1. Low voltage and standard voltage operation
          -2.7 (VCC=2.7V to 5.5V)
          -1.8 (VCC=1.8V to 5.5V)

2. Two-wire serial interface (SDA, SCL)

3. There is a write protection pin for hardware data protection

4. Self-timed write cycle (5 milliseconds to 10 milliseconds), because there is a page buffer inside, after writing data to AT24C0x, you also need to wait for AT24C0x to write the buffer data to the internal EEPROM area.

5. Data can be stored for up to 100 years

6. 1 million erase and write cycles

7. The high data transfer rate is 400KHz, the low speed 100KHZ is compatible with IIC bus. 100 kHz (1.8V) and 400 kHz (2.7V, 5V)

8. 8-byte page write buffer
       The size of this buffer is related to the specific chip model: 8-byte pages (1K, 2K), 16-byte pages (4K, 8K, 16K)

2.2 Introduction of chip device address

The standard address bit of the IIC device is 7 bits. In the above figure, 1010 of AT24C02 is a fixed value inside the chip. A2, A1, and A0 are hardware pins, and the level is determined by the hardware; the last bit is the read/write bit (1 is read, 0 is write), read and write bits Not counted in the address bits, but according to the timing sequence of the IIC, before operating the device, you need to send a 7-bit address and then a 1-bit read/write bit to start the operation of the chip. We are writing the simulation timing for the convenience of unification Write the for loop and send it in bytes, so it is usually combined with 7 address bits and 1 read and write bits to form 1 byte, which is convenient for byte-by-byte transmission of data.

The schematic diagram of the AT24C02 on the development board I am using now looks like this:

Then the standard device address of this AT24C02 is: 0x50 (hexadecimal), and the corresponding binary is: 1010000

If the read and write bits are combined, the address of the device with read permission: 0xA1 (10100001) and the address of the device with write permission: 0xA0 (10100000)

2.3 The instruction flow (timing) of writing data by byte to AT24C02

explain in detail:

1. Send the start signal first

2. Sending device address (write permission)

3. Wait for AT24C02 response, low level is active

4. Send the storage address. There is a total of 256 bytes in AT24C02. The addressing starts from 0 and the range is (0~255). Sending this memory address tells AT24C02 where to store the next data.

5. Waiting for AT24C02 response, low level is active

6. Send one byte of data, this data is the data you want to store in AT24C02.

7. Wait for AT24C02 response, low level is active

8. Send stop signal

2.3 The instruction flow of writing data by page to AT24C02 (timing)

explain in detail:

1. Send the start signal first

2. Sending device address (write permission)

3. Wait for AT24C02 response, low level is active

4. Send the storage address. There is a total of 256 bytes in AT24C02. The addressing starts from 0 and the range is (0~255). Sending this memory address tells AT24C02 where to store the next data.

5. Waiting for AT24C02 response, low level is active

6. 8 bytes of data can be sent cyclically. These data are the data that you want to store in AT24C02.

The page buffer of AT24C02 is 8 bytes, and all the loops here can only send 8 bytes at most, and the more bytes sent will overwrite the previous ones.

Points to note: The addressing of this page buffer also starts from 0, for example: 0~7 counts as the 1st page, 8~15 counts as the 2nd page...and so on. If the starting address of writing data is 3, then only 5 bytes can be written on this page; it does not mean that 8 bytes can be written in a loop from anywhere.

Detailed process: The for loop is generally used in this program to achieve

(1). Send byte 1

(2). Wait for AT24C02 response, low level is active

(3). Send byte 2

(4). Waiting for AT24C02 response, low level is active

.........

Up to 8 times.

7. Wait for AT24C02 response, low level is active

8. Send stop signal

2.4 Read any byte data from any address of AT24C02 (timing)

AT24C02 supports current address reading, arbitrary address reading, the most commonly used is arbitrary address reading, because the address for reading data can be specified, which is more flexible. The above specified timing diagram is arbitrary address reading.

explain in detail:

1. Send the start signal first

2. Sending device address (write permission)

3. Wait for AT24C02 response, low level is active

4. Send the memory address. There are a total of 256 bytes in AT24C02. The addressing starts from 0 and the range is (0~255). Sending this memory address tells AT24C02 that the data at that address should be returned to the MCU next.

5. Waiting for AT24C02 response, low level is active

6. Resend the start signal (switch read and write mode)

7. Sending device address (read permission)

8. Waiting for AT24C02 response, low level is active

9. Cyclic read data: Receive data returned by AT24C02.

There is no byte limit for reading data, the first byte or the entire chip can be read continuously.

10. Send non-response (active high)

11. Send stop signal

Three, IIC bus introduction

2.1 Introduction to IIC bus

The I2C (Inter-Integrated Circuit) bus is a two-wire serial bus developed by PHILIPS, which is used to connect microcontrollers and their peripherals. It is a bus standard widely used in the field of microelectronics communication control. It has the advantages of fewer interface lines, simple control mode, small device package form, and higher communication speed.

The I2C protocol uses master/slave two-way communication. The device sending data to the bus is defined as a transmitter, and the device receiving data is defined as a receiver. Both the master device and the slave device can work in receiving and sending states.

The I2C bus transfers information between the devices connected to the bus through the serial data (SDA) line and the serial clock (SCL) line. Each device has a unique address identification, and can be used as a transmitter or receiver (determined by the function of the device).

I2C has four working modes:
       1. Host send
       2. Host receive
       3. Slave send
       4. Slave receive

The I2C bus uses only two wires: serial data SDA (Serial Data) and serial clock SCL (Serial Clock).

The bus must be controlled by a host (usually a microcontroller). The host generates a serial clock (SCL) to control the transmission direction of the bus and generate start and stop conditions.

The data state on the SDA line can only be changed when SCL is low.

2.2 Device connection diagram on IIC bus

The I2C bus is very simple in physical connection, consisting of SDA (serial data line) and SCL (serial clock line) and pull-up resistors. The communication principle is to generate the signals required by the I2C bus protocol for data transmission by controlling the high and low timing of the SCL and SDA lines. When the bus is in the idle state, these two lines are generally pulled high by the pull-up resistor connected above, and maintain a high level.

The pull-up resistance range is 4.7K~100K.

2.3 I2C bus characteristics

Each device on the I2C bus can be used as a master device or a slave device, and each slave device corresponds to a unique address (which can be learned from the data manual of the I2C device). The master and slave devices use this address to determine which device to communicate with. In normal applications, we use the CPU module with I2C bus interface as the master device, and all other devices connected to the bus as slave devices.

1. The number of devices
      that can be attached to the bus The number of devices that can be attached to the I2C bus is limited by the bus's maximum capacitance of 400pF. If the device is of the same model, it is also limited by the device address.
    Generally, the I2C device address is a 7-bit address (there are also 10 bits), and the address is divided into two parts: the chip curing address (which is grounded when the chip is produced, and which is connected to the power supply, which has been fixed), and the programmable address (leads out the IO port, which is determined by the hardware device) .
     For example: A certain device has a 7-bit address. The upper 4 bits of 10101 xxx are fixed at the factory, and the lower 3 bits can be determined by the designer.
At least 8 devices of this type can only be connected to an I2C bus.
If all 7-bit addresses can be programmed, then in theory 128 devices can be reached, but in practice, so many devices will not be mounted.

2. Bus speed transmission speed:
I2C bus data transmission rate can reach 100kbit/s in standard mode, 400kbit/s in fast mode, and 3.4Mbit/s in high-speed mode. The adjustment of the transmission rate is generally realized through the programmable clock of the I2C bus interface.

3. Bus data length
Two-way data transmission is carried out in bytes (8 bits) between the master device and the slave device on the I2C bus.

2.4 I2C bus protocol basic timing signal

Idle state: Both SCL and SDA remain high.

Start condition: When the bus is in the idle state, both SCL and SDA remain high. When SCL is high, the transition of SDA from high to low indicates that a starting condition is generated. After the initial condition is generated, the bus is in a busy state and is exclusively occupied by the master and slave devices of this data transfer, and other I2C devices cannot access the bus.

Stop condition: When SCL is high and SDA transitions from low to high, it means that a stop condition is generated.

Acknowledgment signal : the next clock signal after the completion of each byte transmission. During the high level of SCL, when SDA is low, it means an acknowledge signal.

Non-accepted signal: the next clock signal after the completion of each byte transmission. During the high level of SCL, when SDA is high, it means an acknowledge signal. The acknowledge signal or non-acknowledge signal is sent by the receiver, and the transmitter detects this signal (the transmitter, the receiver can be a slave device or a master device).

Note: The start and end signals are always generated by the master device.

2.5 Start signal and stop signal

The start signal is: when the clock line SCL is at a high level, the data line SDA changes from a high level to a low level. SCL=1; SDA=1; SDA=0;

The stop signal is: when the clock line SCL is at a low level, the data line SDA changes from a low level to a high level. SCL=1; SDA=0; SDA=1;

2.6 Response signal

The ninth bit of the data bit is an immediate response bit. The process of reading the response bit is the same as that of reading the data bit. Example: SCL=0;SCL=1; ACK =SDA; This ACK is the read response status.

2.7 Data bit transmission timing

Through the timing diagram, the data is stable when SCL is at a high level, and data is unstable when SCL is at a low level.

Then for writing a bit of data (STM32--->AT24C02):  SCL=0; SDA=data; SCL=1;

Then for reading one bit of data (STM32<-----AT24C02):  SCL=0;SCL=1;data=SDA;

2.8 Bus timing

Four, IIC bus timing code, AT24C02 read and write code

When debugging the IIC simulation timing, you can buy a 24M USB logic analyzer on Taobao. If there is a problem with the timing, you can quickly find the problem by analyzing the logic analyzer.

4.1 iic.c This is the complete code for IIC simulation timing

#include "iic.h" /*函数功能:IIC接口初始化硬件连接:SDA:PB7SCL:PB6*/void IIC_Init(void){	RCC->APB2ENR|=1<<3;//PB	GPIOB->CRL&=0x00FFFFFF;	GPIOB->CRL|=0x33000000;	GPIOB->ODR|=0x3<<6;} /*函数功能:IIC总线起始信号*/void IIC_Start(void){	IIC_SDA_OUTMODE(); //初始化SDA为输出模式	IIC_SDA_OUT=1; 		 //数据线拉高	IIC_SCL=1;     		 //时钟线拉高	DelayUs(4);        //电平保持时间	IIC_SDA_OUT=0; 		 //数据线拉低	DelayUs(4);        //电平保持时间	IIC_SCL=0;     		 //时钟线拉低}  /*函数功能:IIC总线停止信号*/void IIC_Stop(void){	IIC_SDA_OUTMODE();    //初始化SDA为输出模式	IIC_SDA_OUT=0; 		 //数据线拉低	IIC_SCL=0;     		 //时钟线拉低	DelayUs(4);           //电平保持时间	IIC_SCL=1;     		 //时钟线拉高	DelayUs(4);           //电平保持时间	IIC_SDA_OUT=1; 		 //数据线拉高} /*函数功能:获取应答信号返 回 值:1表示失败,0表示成功*/u8 IIC_GetACK(void){	u8 cnt=0;	IIC_SDA_INPUTMODE();//初始化SDA为输入模式	IIC_SDA_OUT=1; 		  //数据线上拉	DelayUs(2);         //电平保持时间	IIC_SCL=0;     		  //时钟线拉低,告诉从机,主机需要数据	DelayUs(2);         //电平保持时间,等待从机发送数据	IIC_SCL=1;     		  //时钟线拉高,告诉从机,主机现在开始读取数据	while(IIC_SDA_IN)   //等待从机应答信号	{		cnt++;		if(cnt>250)return 1;	}	IIC_SCL=0;     		  //时钟线拉低,告诉从机,主机需要数据	return 0;}  /*函数功能:主机向从机发送应答信号函数形参:0表示应答,1表示非应答*/void IIC_SendACK(u8 stat){	IIC_SDA_OUTMODE(); //初始化SDA为输出模式	IIC_SCL=0;     		 //时钟线拉低,告诉从机,主机需要发送数据	if(stat)IIC_SDA_OUT=1; //数据线拉高,发送非应答信号	else IIC_SDA_OUT=0; 	 //数据线拉低,发送应答信号	DelayUs(2);            //电平保持时间,等待时钟线稳定	IIC_SCL=1;     		     //时钟线拉高,告诉从机,主机数据发送完毕	DelayUs(2);            //电平保持时间,等待从机接收数据	IIC_SCL=0;     		  	 //时钟线拉低,告诉从机,主机需要数据}  /*函数功能:IIC发送1个字节数据函数形参:将要发送的数据*/void IIC_WriteOneByteData(u8 data){	u8 i;	IIC_SDA_OUTMODE(); //初始化SDA为输出模式	IIC_SCL=0;     		 //时钟线拉低,告诉从机,主机需要发送数据	for(i=0;i<8;i++)	{		if(data&0x80)IIC_SDA_OUT=1; //数据线拉高,发送1		else IIC_SDA_OUT=0; 	 //数据线拉低,发送0		IIC_SCL=1;     		     //时钟线拉高,告诉从机,主机数据发送完毕		DelayUs(2);            //电平保持时间,等待从机接收数据		IIC_SCL=0;     		 		 //时钟线拉低,告诉从机,主机需要发送数据		DelayUs(2);            //电平保持时间,等待时钟线稳定		data<<=1;              //先发高位	}}  /*函数功能:IIC接收1个字节数据返 回 值:收到的数据*/u8 IIC_ReadOneByteData(void){	u8 i,data;	IIC_SDA_INPUTMODE();//初始化SDA为输入模式	for(i=0;i<8;i++)	{		IIC_SCL=0;     		  //时钟线拉低,告诉从机,主机需要数据		DelayUs(2);         //电平保持时间,等待从机发送数据		IIC_SCL=1;     		  //时钟线拉高,告诉从机,主机现在正在读取数据		data<<=1;           		if(IIC_SDA_IN)data|=0x01;		DelayUs(2);         //电平保持时间,等待时钟线稳定	}	IIC_SCL=0;     		  		//时钟线拉低,告诉从机,主机需要数据 (必须拉低,否则将会识别为停止信号)	return data;}  

4.2 AT24C02.c This is the complete read and write code of AT24C02

#include "at24c02.h"/*函数功能:检查AT24C02是否存在返 回 值:1表示失败,0表示成功*/u8 At24c02Check(void){	u8 data;	At24c02WriteOneByteData(255,0xAA);	data=At24c02ReadOneByteData(255);	if(data==0xAA)return 0;	else return 1;}  /*函数功能:AT24C02随机读数据函数形参:读取的地址(0~255)返 回 值:读出一个数据*/u8 At24c02ReadOneByteData(u32 addr){	u8 data;	IIC_Start(); //发送起始信号		IIC_WriteOneByteData(AT24C02_WRITE_ADDR); //设置写模式	IIC_GetACK();//获取应答	IIC_WriteOneByteData(addr); //设置读取数据的位置	IIC_GetACK();//获取应答 	IIC_Start(); //发送起始信号		IIC_WriteOneByteData(AT24C02_READ_ADDR); //设置读模式	IIC_GetACK();//获取应答	data=IIC_ReadOneByteData(); //接收数据	IIC_SendACK(1); //发送非应答信号	IIC_Stop(); //停止信号	return data;}  /*函数功能:AT24C02写一个字节的数据函数形参:		addr:写入的地址(0~255)		data:写入的数据*/void At24c02WriteOneByteData(u32 addr,u8 data){	IIC_Start(); //发送起始信号	IIC_WriteOneByteData(AT24C02_WRITE_ADDR); //设置写模式	IIC_GetACK();//获取应答	IIC_WriteOneByteData(addr); //设置写入数据的位置	IIC_GetACK();//获取应答	IIC_WriteOneByteData(data); //设置写入的数据	IIC_GetACK();//获取应答	IIC_Stop();  //停止信号	DelayMs(10); //等待写入完毕}  /*函数 功 能:AT24C02当前位置读一个字节数据函数返回值:读出的数据*/u8 At24c02CurrentAddrReadOneByteData(void){	u8 data;	IIC_Start(); //发送起始信号	IIC_WriteOneByteData(AT24C02_READ_ADDR); //设置读模式	IIC_GetACK();//获取应答	data=IIC_ReadOneByteData(); //接收数据	IIC_SendACK(1); //发送非应答信号	IIC_Stop(); //停止信号	return data;}   /*函数功能:AT24C02连续读数据函数形参:u8 addr   //读取的地址(0~255)u8 len    //读取的长度u8 *buff  //读出的数据存放缓冲区*/void At24c02ReadByteData(u32 addr,u8 len,u8 *buff){	u8 i;	IIC_Start(); //发送起始信号		IIC_WriteOneByteData(AT24C02_WRITE_ADDR); //设置写模式	IIC_GetACK();//获取应答	IIC_WriteOneByteData(addr); //设置读取数据的位置	IIC_GetACK();//获取应答		IIC_Start(); //发送起始信号		IIC_WriteOneByteData(AT24C02_READ_ADDR); //设置读模式	IIC_GetACK();//获取应答 	for(i=0;i<len;i++)	{		 buff[i]=IIC_ReadOneByteData(); //接收数据		 IIC_SendACK(0); //发送应答信号	}	IIC_SendACK(1); //发送非应答信号	IIC_Stop(); //停止信号}  /*函数功能:AT24C02页写函数形参:		addr:写入的地址(0~255)		*data:写入的数据缓冲区		len :写入的长度1. 页写的缓冲区大小是8个字节,一次最多写8个字节进去。2. 页写的地址是固定的。0~7 是第一页8~15是第二页			*/void At24c02PageWrite(u32 addr,u8 *data,u8 len){	u8 i;	IIC_Start(); //发送起始信号	IIC_WriteOneByteData(AT24C02_WRITE_ADDR); //设置写模式	IIC_GetACK();//获取应答	IIC_WriteOneByteData(addr); //设置写入数据的位置	IIC_GetACK();//获取应答 	for(i=0;i<len;i++)	{		IIC_WriteOneByteData(data[i]); //设置写入的数据		IIC_GetACK();//获取应答	}	IIC_Stop();  //停止信号	DelayMs(10); //等待写入完毕}  void AT24C02_WriteData(u32 addr,u8 *data,u8 len){    u32 page_remain=8-addr%8; //一页剩余的字节数量    if(page_remain>=len)    {        page_remain=len;    }    while(1)    {        At24c02PageWrite(addr,data,page_remain);        if(page_remain==len)        {            break;        }        addr+=page_remain;        data+=page_remain;        len-=page_remain;        if(len>=8)page_remain=8;        else page_remain=len;    }}