STM32-IIC Configuration Explanation (Original) STM32 - I2C Introduction: The I2C bus interface connects the microcontroller and the serial I2C bus. It provides multi-host functionality and controls all I2C bus-specific timing, protocols, arbitration and timing. It supports both standard and fast modes. In addition, the I2C of STM32 can be operated using DMA. This article mainly uses an example to introduce the configuration method of STM32-I2C and which library functions are called in the project to realize the communication of I2C devices . Example: Write data to the device AT24C02 and read the stored data. Let's first talk about the basic configuration of the port of the STM32 I2C module. The STM32 Chinese reference manual can be used to find out which mode the corresponding pin should be configured to when using I2C. Both the SCL and SDA pins are configured as open-drain multiplexed outputs.
I use STM32F103VET6, which has 2 I2C interfaces. The I/O port is defined as PB6-I2C_SCL,
PCB 7-I2C1_SDA; PB10-I2C_SCL, PB11-I2C_SDA. The corresponding port can be found in the manual.
The picture and text are as follows:
Call the library function to configure the I2C port (this article uses PB6 and PB7 ports):
The program code is as follows:
void I2C_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //GPIO structure definition
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //Enable I2C IO port
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; //Open drain output
GPIO_Init(GPIOB, &GPIO_InitStructure); //Initialize structure configuration
}
void I2C_Mode_config(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE); I2C_InitTypeDef
I2C_InitStructure;
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
C_OwnAddress1 =0x0A;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 400000; I2C_Init(I2C1, &I2C_InitStructure); } Well, the working mode of the I2C module inside STM32 is set up like this. Next, we need to complete the communication with the external device AT24C02 (EEPROM). The code analysis will be divided into two parts. The first part is: write , and the second part is: read operation to AT24C02. Part 1 (Write): Note: I2C_PageSize is a macro definition #define I2C_PageSize 8 ; void I2C_EE_BufferWrite(u8* pBuffer, u8 WriteAddr, u16 NumByteToWrite) { u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0; Addr = WriteAddr % I2C_PageSize; // Check if the input address is an integer multiple of 8 count = I2C_PageSize - Addr; // Indicates the distance from the first address of the next page (number of steps) NumOfPage = NumByteToWrite / I2C_PageSize; // Calculate how many pages there are in total NumOfSingle = NumByteToWrite % I2C_PageSize; // Calculate the remainder of the data that is not enough for one page if(Addr == 0) // If the input address is the first page address { if(NumOfPage == 0) //If there is less than one page of data { I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);//Call the write function, the remainder of NumOfSingle is less than one page as the actual parameterI2C_EE_WaitEepromStandbyState();//Wait for the EEPROM device to complete internal operations } else //If there is more than one page of data { while(NumOfPage--)//Use a while loop to execute the page write loop operation, write as many times as there are pages { I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize); //Call the write function, and use the I2C_PageSize variable as the actual parameter to execute page writeI2C_EE_WaitEepromStandbyState ();//Wait for the EEPROM device to complete internal operations
WriteAddr += I2C_PageSize;//Each time a page write is completed, the corresponding address also needs to be shifted by 8 bits
pBuffer += I2C_PageSize;//The data pointer is shifted by 8 bits
}
if(NumOfSingle!=0)//If there is less than one page of data remainder, execute
{
I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);//Call the write function,
the remainder of NumOfSingle that is less than one page is used as the actual parameter
I2C_EE_WaitEepromStandbyState();//Wait for the EEPROM device to complete internal operations
}
}
}
else //The input address is not the home page address
{
if(NumOfPage== 0) //If less than one page
{
I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);//Call the write function, NumOfSingle
The remainder that is less than
I2C_EE_WaitEepromStandbyState(); //Wait for the EEPROM device to complete internal operations
}
else //If there is one page or more than one page
{
NumByteToWrite -= count; //Fill the default position after the address with data. The amount of data is the value of count . The value of the NumByteToWrite variable is the number of unsent
data after filling in the data NumOfPage = NumByteToWrite / I2C_PageSize; //Number of remaining pages NumOfSingle = NumByteToWrite % I2C_PageSize; //Number of data less than one page if (count != 0) //Fill the default position after the address with data { I2C_EE_PageWrite(pBuffer, WriteAddr, count); //Call the write function with count as the actual parameter to fill the default part of the address with data I2C_EE_WaitEepromStandbyState(); //Wait for EEPROM The device completes the internal operation WriteAddr += count; //After adding count, the address is shifted to the first address of the next page pBuffer += count; //The data pointer moves count bits } while(NumOfPage--) //Write the remaining pages of data to the EEPROM { I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize); //Call the write function and use the I2C_PageSize variable as the actual parameter to perform page write I2C_EE_WaitEepromStandbyState(); //Wait for the EEPROM device to complete the internal operation WriteAddr += I2C_PageSize; //Shift the address by 8 bits pBuffer += I2C_PageSize; //Shift the data pointer by 8 bits } if(NumOfSingle != 0) //Write less than one page of data to the EEPROM { I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle); //Call the write function, The remainder of NumOfSingle that is not enough for one page is taken as the actual parameter I2C_EE_WaitEepromStandbyState(); //Wait for the EEPROM device to complete internal operations } } } } In the above write operations, we take the frequently called I2C_EE_PageWrite function and the I2C_EE_WaitEepromStandbyState function and combine them with the STM32 Chinese reference manual pictures and text for comparative analysis . When reading the I2C_EE_PageWrite function, please read it in conjunction with the above timing diagram and the following code! Note: EEPROM_ADDRESS is the device address. You can write it according to your specific device address. For example: #define EEPROM_ADDRESS 0xA0 void I2C_EE_PageWrite(u8* pBuffer, u8 WriteAddr, u8 NumByteToWrite) { I2C_GenerateSTART(I2C1, ENABLE);//Generate start bitwhile (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); //Clear EV5 I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direc ti on_Transmitter);//Send device addresswhile (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); //ADDR=1, clear EV6 I2C_SendData(I2C1, WriteAddr); //EEPROM The specific storage address location while(! I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); //The shift register is not empty, the data register is empty, EV8 is generated, and sending data to DR can clear the event
while(NumByteToWrite--) //Use while loop to send data
{
I2C_SendData(I2C1, *pBuffer); //Send data
pBuffer++; //Data pointer shiftwhile
(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//Clear
EV8
}
I2C_GenerateSTOP(I2C1, ENABLE);//Generate stop signal
}
I2C_EE_WaitEepromStandbyState This function is called after each call to the write operation function.
This function is used to detect whether the EEPROM device has completed the internal write operation, and determine whether the device has completed the operation before proceeding
to the next step! The code is as follows:
void I2C_EE_WaitEepromStandbyState(void)
{
vu16 SR1_Tmp = 0;
do
{
I2C_GenerateSTART(I2C1, ENABLE);//Generate start signal
SR1_Tmp = I2C_ReadRegister(I2C1, I2C_Register_SR1);//Read SR1 register
I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);//Send device
address clear
event
}while(!(I2C_ReadRegister(I2C1, I2C_Register_SR1) & 0x0002));//If no
response it means that the EEPROM device is still working until the operation is completed and the loop body is jumped out!
I2C_ClearFlag(I2C1, I2C_FLAG_AF);//Clear AF flag bit
I2C_GenerateSTOP(I2C1, ENABLE); //Generate stop signal
}
Part 2 (Read):
From the above AT24C02 read timing diagram, we can know that the read part needs to generate two start signals
. In addition, the master device sends a NACK after receiving the last byte from the slave device. After receiving the NACK, the slave device
releases control of the SCL and SDA lines; the master device can send a stop/restart condition.
● In order to generate a NACK pulse after receiving the last byte, the ACK bit must be cleared after reading the second-to-last data byte (after
the second-to-last RxNE event).
● In order to generate a stop/restart condition, the software must set the STOP/START bit after reading the second-to-last data byte (after the second-to
-last RxNE event).
● When receiving only one byte, the generation bit of the response and stop
conditions .
Please read the code and the figure together!
void I2C_EE_BufferRead(u8* pBuffer, u8 ReadAddr, u16 NumByteToRead)//Two
start
{
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); //Call library function to detect whether the I2C device
is in BUSY stateI2C_GenerateSTART
(I2C1, ENABLE);//Turn on signalwhile
(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));//Clear EV5
I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);//Write
device addresswhile
(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//
Clear EV6
I2C_SendData(I2C1, ReadAddr); //Send the read addresswhile
(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//Clear EV8
I2C_GenerateSTART(I2C1, ENABLE);//Turn on the signalwhile
(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));//Clear EV5
I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Receiver);//Transmit the device address
, the master is readingwhile
(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));//Clear
EV6
while(NumByteToRead)
{
if(NumByteToRead == 1)//Enter the if statement when only the last data is left
{
I2C_AcknowledgeConfig(I2C1, DISABLE); //Disable the response bit when there is a data at the end
I2C_GenerateSTOP(I2C1, ENABLE); //Enable the stop bit when there is a data at the end
}
if(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)) //Read data
{
*pBuffer = I2C_ReceiveData(I2C1);//Call library function to fetch data into pBuffer
pBuffer++; //Pointer shift
NumByteToRead--;//Number of bytes minus 1
}
}
I2C_AcknowledgeConfig(I2C1, ENABLE);//Enable the acknowledge bit and wait for next communication
}
The STM32-IIC configuration explanation ends here!
If there is anything wrong, please give me more advice and I will correct it in time;
welcome everyone to communicate and learn with me, thank you.
Previous article:Issues that should be noted when using hardware simulation serial port interrupt processing function in STM32
Next article:STM32 external interrupt usage precautions
Recommended ReadingLatest update time:2024-11-16 13:47
- Popular Resources
- Popular amplifiers
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- 【AT32F421 Review】+ CoreMark score
- Unboxing Review
- Supplementary information on the two disassembled isolators and detailed disassembly pictures
- MCU reset problem
- Please advise on PMOS high-side driver under wide voltage range!
- LIS2MDL array magnet displacement data acquisition for magnetic nail navigation AGV
- Domestic Bluetooth BLE chip
- EEWORLD University Hall----Digital Image Processing (MATLAB) Shandong University (Jiang Mingyan)
- [RT-Thread reading notes] First acquaintance
- Support jesd204b protocol high-speed DAC chip AD9144-FMC-EBZ configuration notes