← Tüm makaleler

I2C mi, SPI mi? İkisi de Ne Zaman Kullanılır?

Fiziksel katman, hız, adresleme ve STM32 kod örnekleriyle kapsamlı protokol karşılaştırması

I2C mi, SPI mi? İkisi de Ne Zaman Kullanılır?

Sensörün veri sayfasını açtınız. Hem I2C hem SPI destekliyor. Hangisini seçeceksiniz?

Bu soruya "ikisi de olur" diye cevap vermek teknik olarak doğrudur — ama mühendislik açısından yanlıştır. İkisi farklı sorunları çözer, farklı durumlarda bozulur ve yanlış seçildiğinde sizi projenin ortasında çıkmaz sokağa sokar. Bir TFT ekranı I2C üzerinden sürmek istediğinizde, ya da aynı I2C hattına aynı adresten iki sensör bağlamaya çalıştığınızda farkı acı biçimde öğrenirsiniz.

Gömülü sistemlerde bir sensör, bir ekran veya bir bellek çipiyle konuşmanız gerektiğinde genellikle iki protokol karşınıza çıkar: I2C ve SPI.


1. Fiziksel Katman: Kaç Tel?

En belirgin fark tel sayısıdır.

I2C — 2 Tel

I2C (Inter-Integrated Circuit), 1982'de Philips tarafından geliştirildi. Yalnızca 2 sinyal hattı kullanır:

Her iki hat da açık-kollektör (open-drain) çıkışlıdır: bir cihaz hattı 0'a çekebilir ama aktif olarak 1'e çekemez. Bunun yerine pull-up dirençleri (genellikle 4,7 kΩ) hattı yüksek tutmakla sorumludur.

MCU                 Sensör A        Sensör B
 │                     │               │
SDA ─────────────────┤──────────────┤
SCL ─────────────────┤──────────────┤
     [4.7kΩ pull-up]

2 tel, birden fazla cihazı aynı hat üzerinde bağlamanıza olanak tanır. Her cihazın 7-bit benzersiz bir adresi vardır; MCU önce hangi cihazla konuşacağını belirtir, sonra veri gönderir.

SPI — 4 Tel (+ cihaz başına 1 CS)

SPI (Serial Peripheral Interface), Motorola'nın 1980'lerde ortaya koyduğu bir standarttır. 4 sinyal hattı kullanır:

Birden fazla cihaz bağlarken MOSI, MISO ve SCK hattı paylaşılır; ama her cihaz için ayrı bir CS pini gerekir:

MCU         Flash       ADC         DAC
 │             │           │           │
MOSI ────────┤───────────┤───────────┤
MISO ────────┤───────────┤───────────┤
SCK  ────────┤───────────┤───────────┤
CS1  ────────┤
CS2  ────────────────────┤
CS3  ────────────────────────────────┤

3 cihaz için 3 ayrı CS pini — 5 cihaz için 5 ayrı CS pini. Pin sayısı hızla artabilir.


2. Hız

Bu, pratikte en belirleyici farktır.

Protokol Standart mod Hızlı mod Yüksek hız
I2C 100 kHz 400 kHz 3,4 MHz (HS)
SPI — 10–50 MHz (MCU'ya bağlı) 50 MHz+

I2C, her byte için bir ACK (acknowledgement) biti bekler ve başlangıç/bitiş koşulları ekstra zaman harcatır. Bu ek yük, protokolü doğası gereği yavaşlatır.

SPI'da böyle bir yük yoktur: MCU clock pinini titretir, bit bit veri akar. Eşzamanlı tam-çift yönlü (full-duplex) iletişim yapılabilir — MCU bir byte gönderirken aynı anda bir byte alabilir.

Ne zaman önemlidir?

Bir sıcaklık sensöründen saniyede birkaç okuma yapıyorsanız I2C'nin 400 kHz'i fazlasıyla yeterlidir. Ama 240×320 piksellik bir TFT ekranı güncelleyecekseniz veya yüksek örnekleme hızında bir ADC ile çalışacaksanız, SPI'nın hızı kritik öneme sahip olur.


3. Adres ve Seçim

I2C: Yazılım adresleme

I2C'de her iletişim, MCU'nun hedef cihazın adresini yayınlamasıyla başlar. 7-bit adresleme şeması 128 farklı cihaz adresine izin verir (bazı adresler rezerve edilmiştir, pratikte ~112 kullanılabilir).

START | ADRES (7-bit) | R/W | ACK | VERİ | ACK | ... | STOP

Aynı türden iki sensörünüz varsa (örneğin iki BME280 nem/basınç sensörü), problem çıkar: aynı I2C adresine sahip olduklarından aynı hat üzerinde yan yana çalışamazlar. Çözüm için ya sensörün adres konfigürasyon pinini kullanmanız (varsa) ya da farklı I2C veri yolları oluşturmanız gerekir.

SPI: Donanım seçimi

SPI'da cihaz seçimi yazılımsal değil, donanımsaldır: MCU, CS pinini LOW'a çekerek o cihazla iletişimi başlatır, HIGH'a döndürerek bitirir. İki aynı cihaz her zaman yan yana kullanılabilir — sadece iki ayrı CS pinine ihtiyacınız vardır.


4. STM32 Üzerinde I2C: Temel Kurulum

STM32 HAL ile bir I2C cihazından veri okumak şöyle görünür:

#include "stm32f0xx_hal.h"

I2C_HandleTypeDef hi2c1;

void i2c1_init(void) {
    hi2c1.Instance             = I2C1;
    hi2c1.Init.Timing          = 0x2000090E;  /* 400 kHz @ 48 MHz */
    hi2c1.Init.OwnAddress1     = 0;
    hi2c1.Init.AddressingMode  = I2C_ADDRESSINGMODE_7BIT;
    hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    hi2c1.Init.NoStretchMode   = I2C_NOSTRETCH_DISABLE;
    HAL_I2C_Init(&hi2c1);
}

/* 7-bit adresi 0x48 olan sensörden 2 byte oku */
void read_sensor(uint8_t *buf) {
    uint8_t reg = 0x00;                         /* Okumak istediğimiz register adresi */
    HAL_I2C_Master_Transmit(&hi2c1, 0x48 << 1, &reg, 1, HAL_MAX_DELAY);
    HAL_I2C_Master_Receive (&hi2c1, 0x48 << 1, buf, 2, HAL_MAX_DELAY);
}

Not: HAL'de I2C adresi 8-bit olarak iletilir — 7-bit adresi 1 sola kaydırın (0x48 << 1 = 0x90). R/W biti HAL tarafından eklenir.


5. STM32 Üzerinde SPI: Temel Kurulum

STM32 HAL ile SPI haberleşmesi:

#include "stm32f0xx_hal.h"

SPI_HandleTypeDef hspi1;

void spi1_init(void) {
    hspi1.Instance               = SPI1;
    hspi1.Init.Mode              = SPI_MODE_MASTER;
    hspi1.Init.Direction         = SPI_DIRECTION_2LINES;    /* Tam çift yönlü */
    hspi1.Init.DataSize          = SPI_DATASIZE_8BIT;
    hspi1.Init.CLKPolarity       = SPI_POLARITY_LOW;        /* CPOL = 0 */
    hspi1.Init.CLKPhase          = SPI_PHASE_1EDGE;         /* CPHA = 0 → SPI Mode 0 */
    hspi1.Init.NSS               = SPI_NSS_SOFT;            /* CS yazılımsal */
    hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; /* 48 MHz / 8 = 6 MHz */
    hspi1.Init.FirstBit          = SPI_FIRSTBIT_MSB;
    HAL_SPI_Init(&hspi1);
}

/* CS pini PA4 */
#define CS_LOW()  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET)
#define CS_HIGH() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET)

/* Bir register oku (çoğu SPI cihazının protokolü: komut gönder, cevabı al) */
uint8_t spi_read_register(uint8_t reg_addr) {
    uint8_t tx = reg_addr | 0x80;   /* MSB = 1 → okuma komutu (cihaza göre değişir) */
    uint8_t rx = 0;
    CS_LOW();
    HAL_SPI_Transmit(&hspi1, &tx, 1, HAL_MAX_DELAY);
    HAL_SPI_Receive (&hspi1, &rx, 1, HAL_MAX_DELAY);
    CS_HIGH();
    return rx;
}

CPOL ve CPHA: SPI'ın 4 farklı çalışma modu (Mode 0–3) vardır. Veri sayfasındaki (datasheet) "SPI Mode" veya "CPOL/CPHA" tablosuna bakarak hangi modun kullanılacağını belirleyin. Yanlış mod seçilirse veri okunabilir görünür ama tutarsız olur.


6. Hangi Durumda Hangisini Seçmelisiniz?

I2C seçin, eğer:

Yaygın I2C cihazları: OLED ekranlar (SSD1306), ortam sensörleri (BME280, SHT31), gerçek zamanlı saat modülleri (DS3231), jiroskop/ivmeölçer (MPU-6050)

SPI seçin, eğer:

Yaygın SPI cihazları: SPI Flash bellek (W25Q serisi), yüksek çözünürlüklü ADC/DAC'lar, TFT ve e-ink ekranlar, SD kart arabirimleri, RF modüller (NRF24L01)


7. Karar Ağacı

Bant genişliği > 1 MHz gerekiyor mu?
    ├── Evet → SPI
    └── Hayır
            ├── Pin sayısı çok kısıtlı mı?  → I2C (2 tel yeterli)
            ├── Birden fazla aynı cihaz mı?
            │       ├── Evet, farklı adres var mı? → I2C
            │       └── Hayır (aynı adres)         → SPI
            └── Genel kullanım               → I2C (daha basit kablolama)

Özet

Kriter I2C SPI
Tel sayısı 2 (+ güç) 4 (+ cihaz başına 1 CS)
Maksimum hız ~3,4 MHz (pratik: 400 kHz) 10–50 MHz+
Çift yönlü Yarım çift yönlü Tam çift yönlü
Birden fazla cihaz Adresle, 2 tel yeterli CS pini artırarak
Adres çakışması riski Var Yok
Protokol yükü Orta (ACK, start/stop) Düşük
Tipik kullanım Sensörler, yapılandırma, ekranlar Flash, yüksek hızlı ADC, TFT

Bu platform üzerindeki STM32 derslerinde her iki protokol de register seviyesinde ele alınmaktadır — USART ve SPI birimleri gerçek donanım üzerinde adım adım yapılandırılmaktadır.

Kitap serisini incele →