[STM32] I2C

CS·2025년 3월 7일

STM32

목록 보기
7/8

I2C 통신

이제 사용하는 통신 방식들에 대해 알아보겠다.

  • I2C

MCU와 장치를 연결하는 직렬 통신 Interface중 하나로
SDA와 SCL 두 개의 라인을 사용하여 여러 장치를 연결할 수 있는
Multi master-slave 방식의 통신이다.
이를 통해 한 개의 마스터 (ex. STM32 MCU)
여러 개의 슬레이브(ex. Sensor/Actuator)를 제어할 수 있다.

1️⃣ Master : 모든 직렬 통신 방식에서 통신에 필요한 clock을 만드는 부품

2️⃣ Slave : Master로 부터 생성된 clock을 받아 구동되는 부품

장치들은 설정에 따라 master / slave가 될 수가 있다.

주요 특징:

  1. Serial 통신 (한 번에 한 비트씩 전송)

  2. clock 동기식 통신 (마스터가 클럭 신호 제공)

  3. Multi master-slave 지원

  4. 주소 기반 데이터 송수신 (각 Slave는 고유한 주소를 가짐)

  5. 최대 전송 속도: 일반적으로 100kHz(standard mode), 400kHz(fast mode), 1MHz
    이 외 clock에서도 동작 가능

STM32에서 I2C 통신을 설정하려면 HAL 라이브러리 또는 레지스터를 활용하여 설정할 수 있으며,
소자와의 통신 시 Slave addressData Frame을 맞춰야 한다.

대표적으로, EEPROM과 연결시 I2C 통신을 사용한다.

SDA, SCL 선 모두 Pull-up 저항으로 연결되어 있고, Slave address로 소자들을 구분한다.

1️⃣ SCL(Serial CLock pin) :
I2C 통신을 위한 Clock이 다니는 line

2️⃣ SDA(Serial DAta pin) :
I2C 통신에서의 Data line. 송수신을 1개의 SDA line에서 수행하므로
어느 한 시점에 송신 혹은 수신을 하고 있다면, 송신과 수신중 1개밖에 못한다.
즉, Half-Duplex 방식을 사용한다.

UART와 다른 점은, I2C는 clock기반 동기식 송수신 방식이다.
UART는 clock없이 2개의 data line을 송수신 하는 비동기식 송수신 방식이다.

SDA의 첫 1Byte는 Slave address인데, 이를 통해 1개의 SDA 신호 선에 다른 주소의 여러 부품들을 연결할 수 있다.

SCL의 Falling-edge에 start bit를 보내고, 1Byte 크기 Slave address와 R/~W를 전송한다.
이후, Slave로부터 ACK 1bit를 기다리고 발생하면, 1Byte의 Data를 보내고 또 ACK 1bit를 기다린다.
이후 SCL의 Rising-edge에 stop bit를 보내주면
I2C 통신이 마무리된다.

즉, Address에 따라 I2C방식에선 Slave를 272^7=128개 까지 구분이 가능하다.
이를 I2C 7bit Addressing방식이라고 한다.

I2C의 All Data전송은 1Byte단위로 이루어지는데,
각각의 Byte는 ACK 1bit를 위한 SCL clock이 1개 더 필요하다.
그러므로, 각각의 1Byte 전송 시, 총 9 SCL clock이 필요하다.

stop condition은 Slave address 전송 이후 임의 Data에 대한 R/W 동작 완료시 발생한다.

I2C HAL 라이브러리

STM32 MCU는 2개 이상의 I2C Interface를 지원한다.

1️⃣ I2C_HandleTypeDef handle struct :

I2C_HandleTypeDef hi2c;

와 같이 handle 구조체를 선언한다.

2️⃣ MX_I2Cx_Init() :
CubeMX에서 생성해주는 framework file들에서 이를 호출하여
지정한 I2C low level 자원을 초기화 해준다.

3️⃣ Data 송/수신을 위한 polling/interrupt mode service 함수 :

// Polling mode I/O 연산

HAL_I2C_Master_Transmit() : 지정한 Data 양을 master mode에서 송신
HAL_I2C_Master_Receive() : 지정한 Data 양을 master mode에서 수신

// Polling mode I/O MEM 연산

외부 I2C 메모리 디바이스와 통신시 사용

일반적으로, I2C는 MCU와 EEPROM 연결에 많이 사용된다.
EEPROM은 주로 Setting값이나 자주 변경되는 내용을 담는 저속 대용량 비휘발성 메모리이다.
이와 특화된 service 함수들이 존재한다.


입력 parameters
uint16_t MemAddress : I2C에 연결된 device에 대한 주소
uint16_t MemAddSize : 그 주소의 크기 (8bits or 16bits)

즉, 8 or 16bits의 Address 크기를 가지는 device만 지원한다는 얘기이다.


HAL_I2C_Mem_Write() : 지정 memory Address로 지정 Data 크기만큼 송신

ex) Buf[0] = data; // uint8_t Buf[2] = {0,0}; Mem_AddrSize = 2
	HAL_I2C_Mem_Write(&hi2c1, Mem_DevAddr, Mem_Addr, Mem_AddrSize, Buf, 1, 1000);
    HAL_Delay(10);
    

HAL_I2C_Mem_Read() : 지정 memory Address로부터 지정 Data 크기만큼 수신

ex) uint16_t Mem_result = 0;
	HAL_I2C_Mem_Read(&hi2c1, Mem_DevAddr, Mem_Addr, Mem_AddrSize, Buf, 1, 1000);
    HAL_Delay(10);
    Mem_result = Buf[0];
    
    
    
    
// Interrupt mode I/O 연산

HAL_I2C_Master_Transmit_IT() : 지정 Data양을 master mode에서 Interrupt 방식으로 송신
HAL_I2C_Master_Receive_IT() : 지정 Data양을 master mode에서 Interrupt 방식으로 수신

HAL_I2C_Slave_Transmit_IT() : 지정 Data양을 slave mode에서 Interrupt 방식으로 송신
HAL_I2C_Slave_Receive_IT() : 지정 Data양을 slave mode에서 Interrupt 방식으로 수신

Example

  1. I2C 메모리 쓰기 (HAL_I2C_Mem_Write())

// EEPROM에 1Byte Write

uint8_t Buf[1] = {0x55};  // EEPROM에 저장할 데이터 (0x55)
uint16_t Mem_Addr = 0x0010;  // EEPROM 내 0x0010 번지에 저장

HAL_I2C_Mem_Write(&hi2c1, 0xA0, Mem_Addr, I2C_MEMADD_SIZE_16BIT, Buf, 1, 1000);
HAL_Delay(10);  // EEPROM 쓰기 대기 시간(필수)

📌 EEPROM 쓰기는 내부적으로 시간이 걸리므로, HAL_Delay(10) 같은 딜레이 필수.

  1. I2C 메모리 읽기 (HAL_I2C_Mem_Read())


// EEPROM에서 1Byte Read

uint8_t Buf[1] = {0};  // 데이터를 저장할 버퍼
uint16_t Mem_Addr = 0x0010;  // 읽을 EEPROM 주소
uint8_t Mem_result = 0;

HAL_I2C_Mem_Read(&hi2c1, 0xA0, Mem_Addr, I2C_MEMADD_SIZE_16BIT, Buf, 1, 1000);
HAL_Delay(10);  // EEPROM 읽기 대기 시간
Mem_result = Buf[0];  // 읽은 데이터를 변수에 저장
----------------------------------------------------------------------------
  1. Mem_AddrSize 설정

STM32 HAL에서는 EEPROM 주소 크기(8비트 or 16비트) 를 지정해야 함.

#define I2C_MEMADD_SIZE_8BIT   0x01  // 8비트 주소
#define I2C_MEMADD_SIZE_16BIT  0x02  // 16비트 주소

이는 EEPROM 종류에 따라 맞춰야 함.

8비트 주소 EEPROM: I2C_MEMADD_SIZE_8BIT
16비트 주소 EEPROM: I2C_MEMADD_SIZE_16BIT


📌 EEPROM 쓰기 과정
마스터(MCU) → 슬레이브(EEPROM) 로 Mem_Addr 전송
Buf(데이터) 전송
EEPROM이 데이터를 저장하는 동안 MCU는 일정 시간 대기 (HAL_Delay(10))

📌 EEPROM 읽기 과정
마스터(MCU) → 슬레이브(EEPROM) 로 Mem_Addr 전송 (읽을 주소 설정)
EEPROM이 해당 주소의 데이터를 보냄
MCU가 데이터를 Buf에 저장하고 사용


  1. SCL :
    positive/negative edge clock에서 각각 EEPROM device 안에 Data를 Write
    하거나 EEPROM device로부터 Read

  2. SDA :
    I/O Data 전송을 위한 신호선, 어느 한 순간에 Read or Write 한 동작만 가능

SCL, SDA 신호 선들은 모두 Open-Drain으로 구동됨.

profile
학습

0개의 댓글