05-STM32F1 – Serial communication 2-I2C (1), I2C configuration

05-STM32F1 – Serial communication 2-I2C (1), I2C configuration

Physical layer

  • It is a bus that supports devices. A “bus” refers to a signal line shared by multiple devices. In one I2C communication bus, multiple I2C communication devices can be connected to support multiple communication masters and multiple communication slaves.
  • An I2C bus uses only two bus lines, a bidirectional serial data line (SDA) and a serial clock line (SCL). The data line is used to represent data, and the clock line is used to synchronize data transmission and reception.
  • Each device connected to the bus has an independent address, and the host can use this address to access between different devices.
  • The bus is connected to the power supply through a pull-up resistor. When the I2C device is idle, it will output a high-impedance state, and when all devices are idle, they will output a high-impedance state, and the pull-up resistor will pull the bus to a high level.
  • When multiple hosts use the bus at the same time, in order to prevent data conflicts, arbitration will be used to determine which device occupies the bus.
  • There are three transmission modes: the standard mode transmission rate is 100kbit/s, the fast mode is 400kbit/s, and the high-speed mode can reach 3.4Mbit/s, but most I2C devices do not support the high-speed mode yet.
  • The number of ICs connected to the same bus is limited by the bus’s maximum capacitance of 400pF.

Protocol layer (one master and multiple slaves)

  • start signal and stop signal

    Start signal: When the SCL line is high level, the SDA line switches from high level to low level, which indicates the start of communication.

    Stop signal: When SCL is high level, the SDA line switches from low level to high level, indicating the stop of communication.

  • data validity

    During transmission, when SCL is high level, the data represented by SDA is valid, that is, when SDA is high level, it means data “1”, and when it is low level, it means data “0”. When SCL is low level, the data of SDA is invalid. Generally, at this time, SDA performs level switching to prepare for the next data representation.

STM32-I2C

Basic frame

  • Communication pin
  • clock control logic
  • data control logic
  • overall control logic

STM32F1-I2C communication process

I2C slave

I2C Slave Transmitter Transmission Sequence Diagram

I2C Slave Receiver Transfer Sequence Diagram

I2C master

I2C Master Transmitter Transfer Sequence Diagram

I2C master receiver transfer sequence diagram

I2C initialization structure

typedef struct
{
  uint32_t I2C_ClockSpeed; /*!< Specifies the clock frequency.
                                         This parameter must be set to a value lower than 400kHz */

  uint16_t I2C_Mode; /*!< Specifies the I2C mode.
                                         This parameter can be a value of @ref I2C_mode */

  uint16_t I2C_DutyCycle; /*!< Specifies the I2C fast mode duty cycle.
                                         This parameter can be a value of @ref I2C_duty_cycle_in_fast_mode */

  uint16_t I2C_OwnAddress1; /*!< Specifies the first device own address.
                                         This parameter can be a 7-bit or 10-bit address. */

  uint16_t I2C_Ack; /*!< Enables or disables the acknowledgment.
                                         This parameter can be a value of @ref I2C_acknowledgement */

  uint16_t I2C_AcknowledgedAddress; /*!< Specifies if 7-bit or 10-bit address is acknowledged.
                                         This parameter can be a value of @ref I2C_acknowledged_address */
}I2C_InitTypeDef;

Programming Essentials

I2C host communication

I2C hardware related macro definition, bsp_i2c.h

#ifndef __BSP_I2C_H
#define __BSP_I2C_H


#include "stm32f10x.h"

#define BSP_I2Cx_GPIO_Clk BSP_I2Cx_GPIO_SCL_Clk|BSP_I2Cx_GPIO_SDA_Clk
#define BSP_I2Cx_GPIO_Clk_Cmd RCC_APB2PeriphClockCmd

#define BSP_I2Cx_GPIO_SCL_Clk RCC_APB2Periph_GPIOB
#define BSP_I2Cx_GPIO_SCL_Port GPIOB
#define BSP_I2Cx_GPIO_SCL_Pin GPIO_Pin_6

#define BSP_I2Cx_GPIO_SDA_Clk RCC_APB2Periph_GPIOB
#define BSP_I2Cx_GPIO_SDA_Port GPIOB
#define BSP_I2Cx_GPIO_SDA_Pin GPIO_Pin_7

#define BSP_I2Cx_Clk RCC_APB1Periph_I2C1
#define BSP_I2Cx_Clk_Cmd RCC_APB1PeriphClockCmd

#define BSP_I2Cx I2C1
#define BSP_I2Cx_Speed 400000

#define BSP_I2Cx_Owner_Address7 0xA0

#define BSP_I2Cx_FLAG_TIMEOUT ((uint32_t)0x1000)
#define BSP_I2Cx_LONG_TIMEOUT ((uint32_t)(10 * BSP_I2Cx_FLAG_TIMEOUT))
#define BSP_I2Cx_MAX_TRIALS_NUM 150

#define __DEBUG_INFO

#ifdef __DEBUG_INFO
    #define DEBUG_INFO(fmt,arg...) printf("<<-DEBUG-INFO->> "fmt"\r\\
",##arg)
#else
    #define DEBUG_INFO(fmt,arg...)
#endif



#endif /* __BSP_I2C_H */

I2C module configuration, bsp_i2c.c

static void BSP_I2C_GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    BSP_I2Cx_GPIO_Clk_Cmd(BSP_I2Cx_GPIO_Clk, ENABLE);
    
    GPIO_InitStructure.GPIO_Pin = BSP_I2Cx_GPIO_SCL_Pin;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(BSP_I2Cx_GPIO_SCL_Port, & GPIO_InitStructure);
    
    GPIO_InitStructure.GPIO_Pin = BSP_I2Cx_GPIO_SDA_Pin;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(BSP_I2Cx_GPIO_SDA_Port, & GPIO_InitStructure);
}

static void BSP_I2C_Config(void)
{
    I2C_InitTypeDef I2C_InitStructure;
    BSP_I2Cx_Clk_Cmd(BSP_I2Cx_Clk, ENABLE);
    
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStructure.I2C_OwnAddress1 = BSP_I2Cx_Owner_Address7;
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStructure.I2C_ClockSpeed = BSP_I2Cx_Speed;
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_Init(BSP_I2Cx, &I2C_InitStructure);
    I2C_Cmd(BSP_I2Cx, ENABLE);
}

void BSP_I2C_Init(void){
    BSP_I2C_GPIO_Config();
    BSP_I2C_Config();
}

My ability is limited, if you have a good idea, please feel free to enlighten me!