STM32 I2C bus self-summary learning

Publisher:美好未来Latest update time:2017-11-28 Source: eefocusKeywords:STM32 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

A few days ago, I was learning STM32's 485 communication. I basically understood the principle and successfully operated it. I will learn more in the future to communicate with the frequency converter to control the 380V motor!


Now I plan to thoroughly understand the I2C bus communication of STM32 - first of all, the reading and writing of AT24C02 - I have the IO expansion chip of PCF8574, which is also I2C protocol, and hope to achieve multiple controls!

        STM32's I2C has its own hardware driver, and can also be simulated using GPIO-----First summarize the problems under the hardware driver.

----------------------------------Hardware-----Take AT24C02 and PCF8574 as an example---------------


------The first part is a simple macro definition-------       

#define I2C_Speed ​​300000 //Transmission rate--When there are many original components mounted, the rate needs to be reduced. I have encountered such problems during debugging.
#define I2C1_OWN_ADDRESS7 0x0A //Host custom address--Each device on the bus needs an address---including the host STM32
#define I2C_PageSize 8 // AT24C02 has 8 bytes per page 

#define EEP_Firstpage 0x00 //Write start address

#define EEPROM_ADDRESS 0xA0 //AT24C02 slave address--assign value later
#define PCF8574_ADDRESS 0x70 //PCF8574 slave address--assign value later


uint8_t I2c_Buf_Write[256]; //Write cache
uint8_t I2c_Buf_Read[256]; //Read cache

------ The second part is IO---Clock---I2C hardware configuration-------    


static void I2C_Configuration(void)
{
        GPIO_InitTypeDef GPIO_InitStructure; 
        I2C_InitTypeDef I2C_InitStructure;

  //----Clock-----

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);  
    
  // -----GPIO settings-----PB6-I2C1_SCL-----PB7-I2C1_SDA---- 


        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);
  
  //-- I2C configuration-------------------------- 

        I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;//Select I2C mode
        I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;//High and low level duty cycle is 2:1
        I2C_InitStructure.I2C_OwnAddress1 =I2C1_OWN_ADDRESS7;//Local address
        I2C_InitStructure.I2C_Ack = I2C_Ack_Enable ;//Response allowed
        I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//Addressing mode is 7 bits---(there is also a 10-bit option)
        I2C_InitStructure.I2C_ClockSpeed ​​= I2C_Speed;//Transmission rate 30000--When mounting many components, it is required to reduce the rate. I have encountered such problems during debugging
  
        I2C_Cmd(I2C1, ENABLE); // Enable I2C1
        I2C_Init(I2C1, &I2C_InitStructure); //I2C1 initialization
}

------The third part is----I2C writes a byte to AT24C02----I will not study the while loop in detail, but mainly judge whether each step is completed  

void I2C_EE_ByteWrite(u8* pBuffer, u8 WriteAddr)
{
        u8 i=0;
        I2C_GenerateSTART(I2C1, ENABLE); //----(1.)----Generate communication start signalwhile
        (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
        {
                i++;
                if(i>100)//Prevent device damage from causing an infinite loop
                     break;    
        }  

        I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS,I2C_Direction_Transmitter); //---(2.)---Send address to find a match-- I2C_Direction_Transmitter--Indicates that the data transmission direction is STM32 sending-- I2C_Direction_Receiver--Indicates that the data transmission direction is STM32 receiving

        while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
        {
                i++;
                if(i>100)//Prevent device damage from causing an infinite loop
                     break;    
        }   
        I2C_SendData(I2C1, WriteAddr); //---(3.)---Write the start addresswhile 
        (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
        {
                i++;
                if(i>100)//Prevent device damage from causing an infinite loop
                     break;    
        }
        I2C_SendData(I2C1, *pBuffer); //---(4.)---Write datawhile
        (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
        {
                i++;
                if(i>100)//Prevent device damage from causing an infinite loop
                     break;    
        }
        I2C_GenerateSTOP(I2C1, ENABLE); //---(5.)---Generate an end signal
}

-----Part 4---I2C writes multiple bytes to AT24C02, but not more than 8 bytes in one page of AT24C02----I will not study the while loop in detail, but mainly judge whether each step is completed 


void I2C_EE_PageWrite(u8* pBuffer, u8 WriteAddr, u8 NumByteToWrite)
{
        u8 i=0;
        while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY))//---(1.)---Detect bus status
        {
                i++;
                if(i>100)
                     break;    
        }
        I2C_GenerateSTART(I2C1, ENABLE);//---(2.)---Start signalwhile
        (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
        {
                i++;
                if(i>100)
                     break;    
        } 
        I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter); //---(3.)---Send address addressing matchwhile
        (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
        {
                i++;
                if(i>100)
                     break;    
        }      
        I2C_SendData(I2C1, WriteAddr); //---(4.)---Write start addresswhile 
        (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
        {
                i++;
                if(i>100)
                     break;    
        }
        while(NumByteToWrite--) //Write in sequence according to the number of writes
        {
                I2C_SendData(I2C1, *pBuffer); //---(5.)---Write data
                pBuffer++; 
                while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
               {
                       i++;
                       if(i>100)
                            break;    
                }
        }
        I2C_GenerateSTOP(I2C1, ENABLE);//---(6.)---Generate end signal
}

-----Part 5---I2C reads multiple bytes from AT24C02----We will not study the while loop in detail, but mainly judge whether each step is completedvoid

I2C_EE_BufferRead(u8* pBuffer, u8 ReadAddr, u16 NumByteToRead)
{  
        u8 i=0;
        while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY))//---(1.)---Busy signal
        {
                i++;
                if(i>100)
                     break;    
        }  
        I2C_GenerateSTART(I2C1, ENABLE);//---(2.)---Start signalwhile
        (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
        {
                i++;
                if(i>100)
                     break;    
        }
        I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);//---(3.)---Address matchingwhile
        (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
        {
                i++;
                if(i>100)
                     break;    
        }
        I2C_Cmd(I2C1, ENABLE);
        I2C_SendData(I2C1, ReadAddr); //---(4.)---Read the starting address of the datawhile
        (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
        {
                i++;
                if(i>100)
                     break;    
        }
        I2C_GenerateSTART(I2C1, ENABLE);//---(5.)---Specialty of reading data---Resend the start signalwhile
        (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
        {
                i++;
                if(i>100)
                     break;    
        }
        I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Receiver);//---(6.)---Address matchingwhile
        (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
        {
                i++;
                if(i>100)
                     break;    
        } 
        while(NumByteToRead)  
        {
                if(NumByteToRead == 1)
                {
                        I2C_AcknowledgeConfig(I2C1, DISABLE);//Turn off responseI2C_GenerateSTOP
                        (I2C1, ENABLE);//Stop signal
                }
                if(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))  
                {      
                        *pBuffer = I2C_ReceiveData(I2C1); //---(7.)---Read data in
                        sequencepBuffer++; 
                        NumByteToRead--;        
                }   
        }
        I2C_AcknowledgeConfig(I2C1, ENABLE);
}

-----Part 6---I2C writes a byte of data to PCF8574----I will not study the while loop in detail, but mainly judge whether each step is completed

void I2C_PCF8574_ByteWrite(u8 PCF_ADD, u8 WriteData)
{
        u8 i=0;
        I2C_GenerateSTART(I2C1, ENABLE); //----(1.)----Generate communication start signalwhile
        (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
        {
                i++;
                if(i>100)
                     break;    
        }
        i=0;  
        I2C_Send7bitAddress(I2C1, PCF_ADD, I2C_Direction_Transmitter); //----(2.)----Send address to find a matchwhile
        (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
        {
                i++;
                if(i>100)
                     break;    
        }  
        i=0;
        I2C_SendData(I2C1, WriteData); //----(3.)----Write data
        while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
        {
                i++;
                if(i>100)
                     break;    
        } 
        I2C_GenerateSTOP(I2C1, ENABLE); //----(4.)----Generate stop signal
}

-----Part 7----

int main(void)
{
        u8 i,led=0x01;

        USART1_Config();
        GPIO_Config();
        I2C_All_Init();

        while (1)
        {
                led++;
                if(led>98)
                      led=0x01;
                I2C_PCF8574_ByteWrite(0x70,led);
                Delay(0xffffe);  
        

                printf("\r\nRead data\r\n");

                I2C_EE_BufferRead(I2c_Buf_Read, 0, 100); //Keep the EEPROM read data in order in I2c_Buf_Read 

                printf("0x%02X \r\n", I2c_Buf_Read[led]);    
                printf("0x%02X \r\n ", I2c_Buf_Read[led+1]);  

  
                printf("\r\nI2C(AT24C02) read and write test successful\r\n");
                Delay(0xffffe);  
        }
}

---------------------To summarize from the above---------------------

        For writing to the I2C bus, pay attention to the following steps

-------(1.)----Detect busy signal----

-------(2.)----Send start signal

-------(3.)----Send address matching signal

-------(4.)----Send or receive data----Sometimes you need to look at the chip manual----For example, AT24C02 interprets the first data sent at this time as the starting address for reading and writing-----but PCF8574 does not, it directly interprets it as data for reading!

-------(5.)----Send bus end signal

        For reading the I2C bus, pay attention to the following steps - here we take AT24C02 as an example - simple differences for other chips

-------(1.)----Detect busy signal----

-------(2.)----Send start signal

-------(3.)----Send address matching signal

-------(4.)----Send the starting address of the read

-------(5.)----Resend the start signal

-------(6.)----Resend address matching signal

-------(7.)----Read data in sequence

-------(8.)----Send bus end signal


----------------------------------GPIO software simulation-----Take AT24C02 and PCF8574 as an example------------

----1.----I2C bus GPIO configuration----

static void i2c_CfgGpio(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;

        RCC_APB2PeriphClockCmd(RCC_I2C_PORT, ENABLE);

        GPIO_InitStructure.GPIO_Pin = I2C_SCL_PIN | I2C_SDA_PIN;
        GPIO_InitStructure.GPIO_Speed ​​= GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //Open drain output
        GPIO_Init(GPIO_PORT_I2C, &GPIO_InitStructure);

        i2c_Stop(); //Send a stop signal to reset all devices on the bus
}

----2.----I2C bus start signal----

void i2c_Start(void) //When SCL is high, a falling edge appears on SDA, indicating the start signal of the I2C bus
{
        I2C_SDA_1();
        I2C_SCL_1();
        i2c_Delay();
        I2C_SDA_0();
        i2c_Delay();
        I2C_SCL_0();
        i2c_Delay();
}

----3.----I2C bus stop signal----

void i2c_Stop(void) //When SCL is high, a rising edge appears on SDA, indicating the I2C bus stop signal
{
        I2C_SDA_0();
        I2C_SCL_1();
        i2c_Delay();
        I2C_SDA_1();
}

----4.----Send 8Bit data to I2C bus----

void i2c_SendByte(uint8_t _ucByte) 
{
        uint8_t i;

        for (i = 0; i < 8; i++) //Send the high bit first
        {
                if (_ucByte & 0x80)
                        I2C_SDA_1();
                else
                        I2C_SDA_0();
                i2c_Delay();
                I2C_SCL_1() ;
                i2c_Delay();  
                I2C_SCL_0();
                if (i == 7)
                        I2C_SDA_1();
                _ucByte <<= 1;
                i2c_Delay();
        }
}

----5.----Read 8Bit data from I2C bus----

uint8_t i2c_ReadByte(void)
{
        uint8_t i;
        uint8_t value;

        value = 0;
        for (i = 0; i < 8; i++) //Read the high bit first
        {
                value <<= 1;
                I2C_SCL_1();
                i2c_Delay();
                if (I2C_SDA_READ())
                        value++;
                I2C_SCL_0();
                i2c_Delay();
        }
        return value;
}

----6.----Generate an ACK signal to I2C----

void i2c_Ack(void)
{
        I2C_SDA_0();
        i2c_Delay();
        I2C_SCL_1();
        i2c_Delay();
        I2C_SCL_0();
        i2c_Delay();
        I2C_SDA_1();
}

----7.----Generate a NACK signal to I2C----

void i2c_NAck(void)
{
        I2C_SDA_1();
        i2c_Delay();
        I2C_SCL_1();
        i2c_Delay();
        I2C_SCL_0();
        i2c_Delay();
}

----8.----Detect I2C bus devices, send device addresses, read device responses to determine if a device at this address exists----

uint8_t i2c_CheckDevice(uint8_t _Address)
{
        uint8_t ucAck;

        i2c_CfgGpio();//Configure GPIO
        i2c_Start();//Start signal
        i2c_SendByte(_Address | I2C_WR);//Send device address and read/write control--the last bit indicates read/write selection
        ucAck = i2c_WaitAck();//Detect response
        i2c_Stop();//Send stop signal

        return ucAck;
}

----9.---- Here we will not use AT24C02 as an example, because the code is a little more, here we use PCF8574 as an example------

uint8_t I2C_PCF8574_ByteWrite(, uint16_tPCF_ADD,uint8_t *_pWriteBuf)
{
        uint16_t i,m;

        i2c_Stop();
        for (m = 0; m < 100; m++) //Multiple detections---Exit when time exceeds
       {
                i2c_Start();
                i2c_SendByte(PCF_ADD); //Here is the write address instructionif
                (i2c_WaitAck() == 0)
                        break;
        }
        if (m == 100)
                goto cmd_fail;//I2C device fails, no response, jump

        i2c_SendByte((uint8_t)_pWriteBuf);
        if (i2c_WaitAck() != 0)
                goto cmd_fail;//I2C device fails, no response, jump to

        i2c_Stop(); //Command execution is successful, send I2C bus stop signalreturn
        1;

cmd_fail: //After the command execution fails, remember to send a stop signal to avoid affecting other devices on the I2C busi2c_Stop 
        (); //Send I2C bus stop signalreturn
        0;
}

----10.----Simple call of main function----Control PCF8574 to switch LED light---

int main(void)
{
        u8 led=0x00;
        USART1_Config();

        while(1)

        {
                led++;
                if(led>255)
                        led=0x00;
                I2C_PCF8574_ByteWrite(led,0x70); //Light up different LED lights according to different values ​​of led
        }
}



---------------------Summarized as follows----------

        The steps are the same, the main thing is to pay attention to stopping the bus signal ---- and detecting the ACK response at all times ---


---------------------------Some pictures---------------------

--------------------------0---------------------------- ----------


--------------------------1----------------------- -----------------------



---------------------------------------------2---- -------------------



--------------------------------3-------------------------------- -------------


Keywords:STM32 Reference address:STM32 I2C bus self-summary learning

Previous article:STM32 MDK project creation diagram steps self-study summary
Next article:STM32 485 communication self-study summary

Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号