Memory Mapped I/O

Memory Mapped I/O

📦 전체 메모리 맵 구조 (0x0000_0000 ~ 0xFFFF_FFFF)

STM32는 주소 공간을 512MB 단위로 8개의 블록으로 나눕니다:

주소 범위 블록 설명
0x0000_0000 ~ 0x1FFF_FFFF Block 0 Code 영역 (Flash, Boot Memory)
0x2000_0000 ~ 0x3FFF_FFFF Block 1 SRAM 영역
0x4000_0000 ~ 0x5FFF_FFFF Block 2 Peripherals (레지스터)
0x6000_0000 ~ 0x7FFF_FFFF Block 3 FSMC bank1 & bank2 (외부 메모리 인터페이스)
0x8000_0000 ~ 0x9FFF_FFFF Block 4 FSMC bank3 & bank4
0xA000_0000 ~ 0xBFFF_FFFF Block 5 FSMC 레지스터
0xC000_0000 ~ 0xDFFF_FFFF Block 6 사용되지 않음
0xE000_0000 ~ 0xFFFF_FFFF Block 7 Cortex-M3 내부 시스템 및 디버그용 레지스터

🔸 Block 0 (Code 영역) 상세

주소 설명
0x0000_0000 Flash, System Memory, or SRAM으로 alias 됨 (BOOT 핀에 따라 달라짐)
0x0800_0000 ~ 0x080F_FFFF Flash 메모리
0x1FFF_0000 ~ 0x1FFF_7A0F System Memory, OTP, Option Bytes 등
0x1FFF_C000 ~ 0x1FFF_FFFF Option Bytes, Reserved 등

🔸 Block 1 (SRAM 영역) 상세

주소 설명
0x2000_0000 ~ 0x2001_BFFF SRAM (112KB)
0x2001_C000 ~ 0x2001_FFFF SRAM (16KB)
0x2002_0000 ~ 0x3FFF_FFFF Reserved (bit-band alias 영역 포함)

💡 Bit-Banding: 비트를 개별적으로 다루기 위해 특별히 매핑된 주소 영역입니다.


🔸 Block 2 (Peripherals 영역) 상세

주소 주변장치
0x4000_0000 ~ 0x4000_03FF TIM2, TIM3, TIM4 등
0x4001_0000 ~ 0x4001_FFFF USART1, SPI1, ADC1~3 등
총 0x4000_0000 ~ 0x5006_03FF 모든 AHB/APB 장치들이 여기에 위치

🔸 Block 3 & 4 (FSMC External Memory 영역)

이 영역은 **외부 메모리 (PSRAM, NOR, NAND 등)**를 연결하는 FSMC 컨트롤러의 bank별 주소입니다:

주소 범위 연결 장치
0x6000_0000 ~ 0x63FF_FFFF FSMC bank1 NOR/PSRAM 1
0x6400_0000 ~ 0x67FF_FFFF FSMC bank1 NOR/PSRAM 2
0x6800_0000 ~ 0x6BFF_FFFF FSMC bank1 NOR/PSRAM 3
0x6C00_0000 ~ 0x6FFF_FFFF FSMC bank1 NOR/PSRAM 4
0x7000_0000 ~ 0x7FFF_FFFF FSMC bank2 NAND
0x8000_0000 ~ 0x8FFF_FFFF FSMC bank3 NAND

🔸 Block 7 (Cortex-M3 내부 영역)

주소 범위 설명
0xE000_0000 ~ 0xE00F_FFFF NVIC, SCB, SysTick 등
0xE004_2000 등 디버깅, ITM, DWT 등 디버그 모듈

이 메모리 맵은 레지스터 접근, DMA 설정, Flash 접근, SRAM 제어, 부트 동작 등 STM32를 정확히 다루기 위한 핵심 정보입니다.


필요하면 각 블록별로 추가 설명이나 예제 코드도 제공 가능합니다.

특정 영역에서 자세히 알고 싶은 부분이 있나요?

나의 말:

memory mapped i/o 잖아

ChatGPT의 말:

맞습니다, 이 STM32 메모리 구조는 Memory-Mapped I/O (MMIO) 구조를 따릅니다. 아래에서 개념부터 STM32에서의 적용까지 핵심을 정리해 드리겠습니다:


✅ Memory-Mapped I/O란?

Memory-Mapped I/O는 주변 장치 (GPIO, USART, TIM 등)의 레지스터를 메모리 주소 공간에 직접 매핑해서 일반 메모리처럼 접근하는 방식입니다.

즉,

c
복사편집
#define GPIOA_MODER  (*(volatile uint32_t*)0x40020000)
GPIOA_MODER = 0x00000001;

처럼 메모리에 값을 쓰는 것처럼 레지스터를 제어하는 방식입니다.


✅ STM32에서의 MMIO 예시

STM32에서는 Block 2 (0x4000_0000 ~ 0x5FFF_FFFF)가 바로 이 MMIO를 위한 주변장치 레지스터 영역입니다.

장치 시작 주소 예시 설명
GPIOA 0x4002_0000 포트 A 제어
USART2 0x4000_4400 시리얼 통신 제어
TIM2 0x4000_0000 타이머 제어
RCC 0x4002_3800 클럭 설정

✅ 왜 MMIO를 사용할까?

방식 특징
MMIO CPU가 메모리처럼 장치 레지스터에 접근함. Load/Store 명령 사용.
Port-Mapped I/O (x86에서 사용) 특별한 I/O 명령 사용 (inout)

STM32는 MMIO 방식만 지원합니다. 장점은:

  • CPU 입장에서 I/O도 메모리처럼 읽고 씀
  • 주소 공간 통합 관리
  • 고속 처리 (버스에 직접 연결됨)

✅ STM32 MMIO 작동 방식 그림

STM32 내부 구조는 다음과 같은 흐름입니다:

복사편집
[ CPU ]
   ↓
[ BUS (AHB/APB) ]
   ↓
[ 주소 디코더 ] → 0x4002_0000 = GPIOA
   ↓
[ 장치 레지스터 ]


✅ 예제: GPIOA 핀 출력 제어 (MMIO 직접 접근)

c
복사편집
#define RCC_AHB1ENR   (*(volatile uint32_t*)0x40023830)
#define GPIOA_MODER   (*(volatile uint32_t*)0x40020000)
#define GPIOA_ODR     (*(volatile uint32_t*)0x40020014)

void gpio_init(void) {
    RCC_AHB1ENR |= (1 << 0);        // GPIOA 클럭 활성화
    GPIOA_MODER |= (1 << 10);       // PA5를 출력 모드로
}

void gpio_write_high(void) {
    GPIOA_ODR |= (1 << 5);          // PA5 출력 High
}


✅ 요약

항목 설명
MMIO란? 주변장치 레지스터를 메모리 주소처럼 직접 접근
STM32 적용 주소 0x4000_0000 ~ 0x5FFF_FFFF (Block 2)
접근 방법 C 포인터를 이용해 직접 레지스터 주소에 접근
장점 빠르고 일관된 접근 방식, 간결한 하드웨어 제어

필요하면 주변장치별 MMIO 주소 정리표나, 직접 접근 대신 CMSIS를 사용하는 구조도 정리해 드릴 수 있습니다. 특정 장치를 예로 들어볼까요?

나의 말:

block2 만 memory mapped i/o야?

ChatGPT의 말:

아주 좋은 질문입니다. 결론부터 말하면:

🟨 Block 2(0x4000_0000 ~ 0x5FFF_FFFF) 영역이 대표적인 Memory-Mapped I/O 영역이지만,

**🟥 Block 7(0xE000_0000 ~ 0xFFFF_FFFF)**도 Memory-Mapped I/O 방식으로 동작합니다.


✅ Memory-Mapped I/O가 적용된 영역

블록 주소 범위 설명 MMIO 여부
Block 2 0x4000_0000 ~ 0x5FFF_FFFF APB/AHB 버스를 통한 외부 주변장치 (GPIO, USART 등) ✅ O
Block 7 0xE000_0000 ~ 0xE00F_FFFF System Control Block (SCB)NVICSysTickDebug 등 ✅ O
기타 일부 Flash 컨트롤러, Option Bytes Flash interface (write/erase 제어용 레지스터) ✅ O (간접적으로)

❌ MMIO가 아닌 영역 예시

블록 주소 범위 설명 MMIO 여부
Block 0 0x0000_0000 ~ 0x1FFF_FFFF Flash, Boot ROM, alias 영역 ❌ (일반 메모리)
Block 1 0x2000_0000 ~ 0x3FFF_FFFF SRAM ❌ (일반 메모리)
Block 3~5 FSMC 영역 (0x6000_0000 이상) 외부 메모리 인터페이스 (SRAM, NAND 등) ❌ (외부 memory-mapped, 장치제어는 아님)

✅ 왜 Block 7도 MMIO인가?

0xE000_0000 ~ 주소는 Cortex-M3 코어 내부 시스템 장치가 위치하는 영역입니다. 예를 들어:

장치 주소 설명
SCB (System Control Block) 0xE000_ED00 인터럽트 우선순위, Sleep 제어
NVIC (Interrupt Controller) 0xE000_E100 인터럽트 활성화/비활성화
SysTick Timer 0xE000_E010 시스템 타이머

이들은 레지스터 방식으로 메모리처럼 접근하므로 Memory-Mapped I/O입니다.


🔎 정리

  • Block 2, Block 7은 모두 MMIO 영역
  • ❌ SRAM, Flash는 메모리일 뿐 I/O가 아님
  • ❌ FSMC는 외부 장치와 연결되지만 레지스터 제어용 I/O는 아님 (데이터 영역)

필요하다면 STM32 MMIO 전체 주소 정리표도 제공해 드릴 수 있어요. 특정 영역이나 레지스터가 궁금하신가요?

나의 말:

ChatGPT의 말:

좋습니다! STM32에서 사용되는 주요 Memory-Mapped I/O (MMIO) 주소 정리표를 아래에 핵심만 요약해드립니다. 이 표는 실무에서 레지스터 직접 접근하거나 디버깅할 때 매우 유용합니다.


✅ [1] Cortex-M3 시스템 MMIO (Block 7: 0xE000_0000 ~)

장치 주소 범위 설명
NVIC 0xE000_E100 ~ 인터럽트 활성화/비활성화
SCB 0xE000_ED00 ~ 우선순위, 벡터 테이블, SYSRESET 등
SysTick 0xE000_E010 ~ 시스템 타이머
ITM/DWT/TPIU 0xE000_0000 ~ 디버그 추적 모듈

✅ [2] 일반 주변장치 MMIO (Block 2: 0x4000_0000 ~)

⏱ 타이머

장치 주소
TIM2 ~ TIM5 0x4000_0000 ~ 0x4000_3FFF
TIM6 ~ TIM14 0x4000_1000 ~ 0x4000_4FFF

📡 USART / UART

장치 주소
USART1 0x4001_3800
USART2 0x4000_4400
USART3 0x4000_4800
UART4 0x4000_4C00
UART5 0x4000_5000

🌀 SPI / I2C

장치 주소
SPI1 0x4001_3000
SPI2 0x4000_3800
I2C1 0x4000_5400
I2C2 0x4000_5800

🧠 RCC / PWR

장치 주소
RCC 0x4002_3800
PWR 0x4000_7000

💡 GPIO

장치 주소
GPIOA 0x4002_0000
GPIOB 0x4002_0400
GPIOC 0x4002_0800
GPIOD 0x4002_0C00

✅ [3] Flash, Option Bytes, System Memory (Block 0)

장치 주소
Flash memory 0x0800_0000 ~
System memory (bootloader) 0x1FFF_0000 ~ 0x1FFF_7A0F
Option Bytes 0x1FFF_C000 ~

🛠 예시 코드: GPIOA의 PA5 출력

c
복사편집
#define RCC_AHB1ENR  (*(volatile uint32_t*)0x40023830)
#define GPIOA_MODER  (*(volatile uint32_t*)0x40020000)
#define GPIOA_ODR    (*(volatile uint32_t*)0x40020014)

void init_gpioa_pa5() {
    RCC_AHB1ENR |= (1 << 0);       // GPIOA 클럭 인가
    GPIOA_MODER |= (1 << 10);      // PA5 = Output
    GPIOA_ODR |= (1 << 5);         // PA5 High
}


원하시면 전체 MMIO 주소 맵을 PDF 혹은 엑셀로도 정리해드릴 수 있어요.

어떤 장치를 위주로 더 보고 싶으신가요? (예: DMA, ADC, SPI 등)

나의 말:

PDF 로 줘

ChatGPT의 말:

완료되었습니다. 아래 링크에서 STM32의 MMIO 주소 맵 PDF를 다운로드할 수 있습니다:

👉 stm32_mmio_map.pdf 다운로드

필요하시면 ADC, DMA, CAN 등 추가 주변장치도 포함해서 확장할 수 있습니다. 추가로 포함할까요?

나의 말:

i2c도 memory mapped io잖아 그러면 i2c를 함수말고 register 설정만으로 통신가능하도록

ChatGPT의 말:

맞습니다. STM32의 I2C1 (0x40005400), I2C2 (0x40005800) 는 모두 Memory-Mapped I/O 방식으로 접근 가능한 레지스터 기반 주변장치입니다.

따라서 HAL 라이브러리를 사용하지 않고도 레지스터만 직접 제어하여 I2C 통신을 구현할 수 있습니다.


✅ 목표: HAL 없이 I2C를 레지스터로 직접 제어

여기서는 마스터 송신 (Master Transmit) 기준으로 I2C1을 사용한 예제를 설명합니다.


✅ 1. 관련 레지스터 (I2C1 기준, 0x40005400)

오프셋 이름 설명
0x00 I2C_CR1 Control register 1
0x04 I2C_CR2 Control register 2
0x08 I2C_OAR1 Own address register 1
0x10 I2C_DR Data register
0x14 I2C_SR1 Status register 1
0x18 I2C_SR2 Status register 2
0x1C I2C_CCR Clock control register
0x20 I2C_TRISE Maximum rise time

✅ 2. 예제: I2C1로 0x50 주소의 EEPROM에 1바이트 쓰기

💡 기본 설정 (Clock & GPIO는 RCC/GPIO 레지스터로 별도 설정해야 함)

c
복사편집
#define I2C1_BASE      0x40005400
#define RCC_APB1ENR    (*(volatile uint32_t*)0x40023840)
#define RCC_AHB1ENR    (*(volatile uint32_t*)0x40023830)

#define I2C1_CR1       (*(volatile uint32_t*)(I2C1_BASE + 0x00))
#define I2C1_CR2       (*(volatile uint32_t*)(I2C1_BASE + 0x04))
#define I2C1_OAR1      (*(volatile uint32_t*)(I2C1_BASE + 0x08))
#define I2C1_DR        (*(volatile uint32_t*)(I2C1_BASE + 0x10))
#define I2C1_SR1       (*(volatile uint32_t*)(I2C1_BASE + 0x14))
#define I2C1_SR2       (*(volatile uint32_t*)(I2C1_BASE + 0x18))
#define I2C1_CCR       (*(volatile uint32_t*)(I2C1_BASE + 0x1C))
#define I2C1_TRISE     (*(volatile uint32_t*)(I2C1_BASE + 0x20))


✅ 3. 초기화 및 송신 함수 (직접 구현)

c
복사편집
void i2c1_init() {
    RCC_APB1ENR |= (1 << 21);    // I2C1 클럭 활성화
    RCC_AHB1ENR |= (1 << 0);     // GPIOA 클럭 활성화 등 (SCL/SDA 핀 설정 필요)

    I2C1_CR2 = 16;               // APB1 클럭 16MHz
    I2C1_CCR = 80;               // Standard mode 100kHz
    I2C1_TRISE = 17;             // 최대 상승 시간

    I2C1_CR1 |= (1 << 0);        // Peripheral Enable
}

void i2c1_start() {
    I2C1_CR1 |= (1 << 8);                    // START bit
    while (!(I2C1_SR1 & (1 << 0)));          // SB 설정될 때까지 대기
}

void i2c1_send_addr(uint8_t addr) {
    I2C1_DR = addr;
    while (!(I2C1_SR1 & (1 << 1)));          // ADDR 확인
    (void)I2C1_SR2;                          // SR2 읽기로 클리어
}

void i2c1_send_data(uint8_t data) {
    while (!(I2C1_SR1 & (1 << 7)));          // TXE
    I2C1_DR = data;
    while (!(I2C1_SR1 & (1 << 2)));          // BTF
}

void i2c1_stop() {
    I2C1_CR1 |= (1 << 9);                    // STOP
}

void i2c1_write_byte(uint8_t dev_addr, uint8_t reg, uint8_t data) {
    i2c1_start();
    i2c1_send_addr(dev_addr << 1);          // Write mode
    i2c1_send_data(reg);                    // Register address
    i2c1_send_data(data);                   // Data
    i2c1_stop();
}


✅ 4. 주의사항

  • GPIOB 핀(PB6: SCL, PB7: SDA 등)도 Alternate Function 설정 필요
  • AF4로 설정 (STM32F4 기준)
  • APB1 클럭 주파수에 따라 CCR, TRISE 값 변경 필요

✅ 요약

항목 내용
구조 I2C는 MMIO 레지스터를 통해 직접 제어 가능
주소 I2C1 = 0x40005400, I2C2 = 0x40005800
장점 HAL 미사용 → 코드 경량화, 빠른 제어
위험 오류 처리, 타이밍, ACK 체크 등 수동 처리 필요

필요하면 “I2C 수신”이나 “EEPROM 읽기”, “ACK 검사” 등도 추가로 작성해드릴 수 있습니다. 어떤 작업도 해보시겠어요?

나의 말:

코드에 주석을 달아야지

ChatGPT의 말:

물론입니다. 아래는 HAL 없이 레지스터만으로 I2C1 마스터 송신을 구현한 예제 코드에 자세한 주석을 추가한 버전입니다. 이 코드는 STM32에서 I2C를 직접 제어하여 0x50 주소의 슬레이브에 데이터를 쓰는 동작입니다.


✅ 레지스터 정의 및 초기화 함수

c
복사편집
// RCC 관련 레지스터: 클럭 설정용
#define RCC_APB1ENR    (*(volatile uint32_t*)0x40023840)  // APB1 버스 (I2C 클럭)
#define RCC_AHB1ENR    (*(volatile uint32_t*)0x40023830)  // AHB1 버스 (GPIO 클럭)

// I2C1 베이스 주소 및 레지스터 정의
#define I2C1_BASE      0x40005400
#define I2C1_CR1       (*(volatile uint32_t*)(I2C1_BASE + 0x00))  // 제어 1
#define I2C1_CR2       (*(volatile uint32_t*)(I2C1_BASE + 0x04))  // 제어 2 (클럭 설정)
#define I2C1_OAR1      (*(volatile uint32_t*)(I2C1_BASE + 0x08))  // Own Address 1
#define I2C1_DR        (*(volatile uint32_t*)(I2C1_BASE + 0x10))  // 데이터 레지스터
#define I2C1_SR1       (*(volatile uint32_t*)(I2C1_BASE + 0x14))  // 상태 1
#define I2C1_SR2       (*(volatile uint32_t*)(I2C1_BASE + 0x18))  // 상태 2
#define I2C1_CCR       (*(volatile uint32_t*)(I2C1_BASE + 0x1C))  // 클럭 제어
#define I2C1_TRISE     (*(volatile uint32_t*)(I2C1_BASE + 0x20))  // 최대 상승 시간


✅ I2C1 초기화

c
복사편집
void i2c1_init() {
    RCC_APB1ENR |= (1 << 21);    // I2C1 클럭 활성화
    RCC_AHB1ENR |= (1 << 1);     // GPIOB 클럭 활성화 (PB6=SCL, PB7=SDA)

    I2C1_CR2 = 16;               // APB1 클럭 주파수 설정 (16MHz)
    I2C1_CCR = 80;               // 100kHz 설정 (Standard Mode = 16MHz / (2*CCR))
    I2C1_TRISE = 17;             // 최대 상승 시간 = 1000ns 기준 → TRISE = Freq(MHz) + 1

    I2C1_CR1 |= (1 << 0);        // I2C1 Peripheral Enable
}


✅ I2C1 동작 함수들 (START → 주소 전송 → 데이터 전송 → STOP)

c
복사편집
void i2c1_start() {
    I2C1_CR1 |= (1 << 8);                    // START 비트 설정
    while (!(I2C1_SR1 & (1 << 0)));          // SB (Start Bit 설정됨) 플래그 대기
}

void i2c1_send_addr(uint8_t addr) {
    I2C1_DR = addr;                          // 슬레이브 주소 (LSB = 0 for Write)
    while (!(I2C1_SR1 & (1 << 1)));          // ADDR 플래그 대기 (주소 전송 완료)
    (void)I2C1_SR2;                          // SR2 읽기로 ADDR 클리어
}

void i2c1_send_data(uint8_t data) {
    while (!(I2C1_SR1 & (1 << 7)));          // TXE (전송 버퍼 Empty) 대기
    I2C1_DR = data;                          // 데이터 전송
    while (!(I2C1_SR1 & (1 << 2)));          // BTF (Byte Transfer Finished) 대기
}

void i2c1_stop() {
    I2C1_CR1 |= (1 << 9);                    // STOP 비트 설정 → 통신 종료
}


✅ I2C1 마스터 송신 (1 바이트)

c
복사편집
void i2c1_write_byte(uint8_t dev_addr, uint8_t reg, uint8_t data) {
    i2c1_start();                            // START 신호 발생
    i2c1_send_addr(dev_addr << 1);          // 슬레이브 주소 전송 (Write 모드)
    i2c1_send_data(reg);                    // 레지스터 주소 전송 (보통 EEPROM은 주소 지정 필요)
    i2c1_send_data(data);                   // 실제 전송할 데이터 바이트
    i2c1_stop();                             // STOP으로 종료
}


✅ 사용 예시

c
복사편집
i2c1_init();                                 // I2C1 초기화
i2c1_write_byte(0x50, 0x10, 0xAB);           // EEPROM 0x50, 주소 0x10에 0xAB 쓰기


⚠️ 주의사항

  • 반드시 GPIO (PB6, PB7 등)를 Alternate Function으로 설정해야 동작합니다.
  • 오류 핸들링(ACK 실패 등)은 위 코드에 포함되어 있지 않으며, 실전에서는 타임아웃 처리, 에러 플래그 확인이 추가되어야 합니다.
  • 빠르게 쓰고 반복적으로 송신할 경우, BTF 확인 없이 Stop을 내리면 문제가 생길 수 있습니다.

필요하다면 읽기(Receive) 처리, EEPROM 연속 쓰기, ACK 오류 처리, DMA 연동 버전도 도와드릴 수 있습니다. 어떤 작업을 더 해볼까요?

나의 말:

i2c 프로토콜 자세히 설명

ChatGPT의 말:

좋습니다. 아래는 I2C(Inter-Integrated Circuit) 프로토콜에 대한 핵심 개념, 동작 순서, 신호 구조, 상태 플래그 등을 포함한 완전한 설명입니다.


📌 I2C란?

I2C (Inter-Integrated Circuit)NXP(舊 Philips) 가 만든 양방향 2선식 직렬 통신 프로토콜입니다.

  • 🧷 선 2개만 사용:
    • SCL: Serial Clock Line
    • SDA: Serial Data Line
  • 🧭 마스터/슬레이브 구조

    하나의 마스터가 시계를 제어하고, 슬레이브가 응답합니다.

  • 💬 주소 기반 통신:

    슬레이브는 7비트 또는 10비트 주소를 가짐 (일반적으로 7비트)


🧩 I2C 기본 통신 구성요소

sql
복사편집
START → 주소(7bit) + R/W → ACK → 데이터 전송 → ACK → STOP

  • START (S): SDA가 High → Low로 떨어질 때, SCL은 High
  • STOP (P): SDA가 Low → High로 올라갈 때, SCL은 High
  • ACK/NACK: 수신자가 데이터를 정상 수신했음을 알리는 신호 (ACK: 0, NACK: 1)

🧾 데이터 전송 프레임 구조

구분 비트수 설명
Start 1 시작 조건
Address 7 슬레이브 주소
R/W 1 0: Write, 1: Read
ACK 1 수신자의 응답
Data 8 보낼 데이터
ACK 1 수신자의 응답
반복 가능
Stop 1 종료 조건

🔄 I2C 쓰기(Write) 시퀀스 (마스터 기준)

css
복사편집
[S] → [ADDR + 0] → [ACK] → [DATA1] → [ACK] → [DATA2] → [ACK] → [P]

예: EEPROM에 0x50 주소로 0xAB 전송

  1. START 조건 발생
  1. 슬레이브 주소 전송 (0x50 << 1 | 0 = 0xA0)
  1. 슬레이브가 ACK 보냄
  1. 데이터 바이트 전송 (0xAB)
  1. 슬레이브가 ACK 보냄
  1. STOP 발생

🔁 I2C 읽기(Read) 시퀀스

css
복사편집
[S] → [ADDR + 0] → [ACK] → [MEM_ADDR] → [ACK] → [S repeated] → [ADDR + 1] → [ACK] → [DATA] → [NACK] → [P]

  • 2개의 START 조건 사용 (Repeated START)
  • 마지막 바이트는 NACK으로 마무리

✅ I2C 상태 플래그 예시 (STM32 기준)

플래그 설명 위치
SB (Start Bit) START 신호 발생됨 SR1[0]
ADDR 주소 전송 완료 SR1[1]
BTF 바이트 전송 완료 SR1[2]
TXE 데이터 레지스터 비어 있음 SR1[7]
RXNE 수신 데이터 준비 완료 SR1[6]
STOPF 슬레이브가 STOP 감지 SR1[4]

🧠 특징 요약

항목 설명
🧷 전선 2개 (SDA, SCL)
🎛 구조 마스터-슬레이브
⏱ 속도 표준(100kHz), 패스트(400kHz), 패스트플러스(1MHz), 하이스피드(3.4MHz)
🧪 에러 처리 슬레이브가 응답하지 않으면 ACK 없음, 타임아웃 필요
🔧 장점 회로 단순, 주소 기반, 멀티슬레이브 지원
🔩 단점 SPI보다 느림, 프로토콜 복잡도 ↑

📍 실제 통신 파형 예시

text
복사편집
SCL:  __|‾|__|‾|__|‾|__|‾|__|‾|__|‾|__|‾|__|‾|__
SDA:  --\___0_1_0_1_0_0_0/---ACK---data_byte---/
        START    7bit ADDR + W