SPI Protokolü

IoT projelerinde, ekranlar (TFT, OLED), SD kart modülleri, RFID okuyucular veya yüksek hassasiyetli harici ADC/DAC entegreleri ile çalışırken I2C protokolünün hızı (400kHz – 1MHz) genellikle yetersiz kalır. Bu senaryolarda devreye, multi megahertz (MHz) mertebelerinde hızlara çıkabilen senkron ve tam çift yönlü (Full-Duplex) çalışan SPI (Serial Peripheral Interface) protokolü girer.

Bu yazıda, SPI protokolünün çalışma mantığını, ESP32 mikrodenetleyicisinin içindeki donanımsal SPI birimlerini ve sahada hayat kurtaran esnek pin atama (Matrix IO) özelliklerini inceliyoruz.

1. SPI Haberleşme Protokolü Nasıl Çalışır?

SPI, bir Master (Ana Cihaz) ve bir veya birden fazla Slave (Bağımlı Cihaz) arasında veri aktarımı sağlayan 4 telli bir veri yoludur. Senkron bir protokol olduğu için verinin ne zaman okunacağını belirleyen ortak bir saat sinyali (Clock) hattı bulunur.

SPI Veri Hattı Sinyalleri:

  • MOSI (Master Out Slave In): Master cihazdan Slave cihaza veri gönderim hattı.
  • MISO (Master In Slave Out): Slave cihazdan Master cihaza veri geliş hattı.
  • SCLK (Serial Clock): Master tarafından üretilen ve veri iletim hızını belirleyen saat sinyali.
  • CS / SS (Chip Select / Slave Select): Master cihazın, hattaki hangi Slave cihazla konuşacağını seçtiği aktif-düşük (Active-Low) hat.

2. ESP32 Donanımsal SPI Mimarisi (VSPI ve HSPI)

ESP32 içinde aslında 4 adet SPI denetleyicisi barındırır (SPI0, SPI1, HSPI ve VSPI). Ancak bunlardan SPI0 ve SPI1, ESP32’nin kendi dahili Flash belleği ve PSRAM’i ile haberleşmesi için ayrılmıştır; geliştirici olarak biz bunlara dokunmayız.

Bizim projelerimizde özgürce kullanabileceğimiz iki adet bağımsız donanımsal SPI birimi vardır: HSPI ve VSPI. İsimlerindeki “H” ve “V” harflerinin donanımsal olarak bir üstünlüğü yoktur (Hardware/Virtual gibi bir ayrım değildir), sadece iki farklı birimi ayırt etmek için verilmiştir. İkisi de aynı hız ve yeteneklere sahiptir.

Varsayılan Donanım Pinleri (Default Pins)

ESP32’de özel bir kütüphane yapılandırması yapmadan doğrudan SPI.begin() çağırdığınızda, sistem varsayılan olarak VSPI birimini aktif eder.

Sinyal AdıVSPI Varsayılan Pin (Default)HSPI Varsayılan Pin (Default)
MOSIGPIO 23GPIO 13
MISOGPIO 19GPIO 12
SCLKGPIO 18GPIO 14
CS / SSGPIO 5GPIO 15

3. ESP32 GPIO Matrix: İstediğin Pini SPI Yapmak

ESP32’nin en büyük avantajlarından biri GPIO Matrix mimarisidir. Eğer yukarıda belirtilen varsayılan pinler başka bir sensör veya donanım tarafından işgal edildiyse, SPI hatlarını (MOSI, MISO, SCLK, CS) ESP32’nin hemen hemen istediğiniz herhangi bir GPIO pinine yönlendirebilirsiniz.

Ancak burada dikkat edilmesi gereken kritik bir mühendislik detayı vardır:

💡 IOMUX vs GPIO Matrix: SPI sinyallerini kendi orijinal (yukarıdaki tabloda yer alan) pinlerinde çalıştırırsanız, sinyaller IOMUX üzerinden doğrudan geçer ve $80\text{ MHz}$ gibi çok yüksek frekanslara çıkabilir. Sinyalleri farklı pinlere haritalandırırsanız (GPIO Matrix kullanılır), aradaki anahtarlama katmanı nedeniyle güvenli maksimum hız sınırı $26.6\text{ MHz}$ civarına düşer. Ekran sürerken bu hız farkı önemlidir.

4. ESP32 Arduino IDE Örnek Kod Yapıları

Senaryo A: Varsayılan SPI (VSPI) Kullanımı

Standart bir SPI cihazını bağlarken ekstra pin belirtmenize gerek yoktur.

C++

#include <SPI.h>

void setup() {
  Serial.begin(115200);
  
  // Varsayılan VSPI pinlerini (18, 19, 23, 5) başlatır
  SPI.begin(); 
}

void loop() {
  // SPI cihazı ile haberleşme başlatma ayarları
  // 10 MHz hızında, MSBFIRST (Önce en yüksek bit) ve SPI_MODE0 frekansında
  SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));
  
  digitalWrite(SS, LOW); // Slave cihazı seç
  byte gelenVeri = SPI.transfer(0x42); // 0x42 verisini gönder, gelen veriyi oku
  digitalWrite(SS, HIGH); // Slave cihazı serbest bırak
  
  SPI.endTransaction();
  delay(1000);
}

Senaryo B: Özel Pinler (Custom Pins) ile SPI Başlatma

Eğer pinleri değiştirmek istiyorsanız, begin fonksiyonuna parametre geçmeniz yeterlidir.

C++

#include <SPI.h>

#define CUSTOM_MOSI 25
#define CUSTOM_MISO 26
#define CUSTOM_SCLK 27
#define CUSTOM_CS   14

void setup() {
  // Özel pin konfigürasyonu ile SPI hattını ayağa kaldırıyoruz
  SPI.begin(CUSTOM_SCLK, CUSTOM_MISO, CUSTOM_MOSI, CUSTOM_CS);
}

void loop() {
  // Haberleşme döngüsü burada işletilir
}

Görseldeki şema, endüstriyel ve gömülü sistemlerde sıklıkla kullandığımız I2C (Inter-Integrated Circuit) protokolünün Veri Paketi (Message Frame) yapısını gösteriyor.

İçeriği sitene ekleyebileceğin formatta hem Türkçe görsel tasarımı için metinsel haritasıyla hem de mühendislik mantığına uygun detaylı teknik açıklamasıyla hazırladım.

I2C Haberleşme Protokolü: Paket Yapısı ve Bit Seviyesinde Analiz

I2C (Inter-Integrated Circuit), özellikle mikrodenetleyiciler ile kısa mesafedeki sensörler, EEPROM’lar, RTC (Gerçek Zamanlı Saat) modülleri veya donanımsal sürücüler arasında haberleşmeyi sağlayan, sadece 2 tel (SDA: Seri Veri, SCL: Seri Saat) kullanan senkron bir protokoldür.

SPI’dan farklı olarak, hat üzerindeki cihazları seçmek için fiziksel bağımsız hatlar (CS/SS) kullanmak yerine, veri paketinin içerisine gömülmüş Yazılımsal Adresleme mantığını kullanır. Aşağıda, hat üzerinde akan tek bir I2C mesaj paketinin bit seviyesindeki anatomisi yer almaktadır.

1. I2C Paket Şeması (Türkçe Haritası)

Mevcut şemayı Türkçe içeriklerine entegre etmek veya yeniden çizmek (Lucidchart, Canva, Draw.io vb. araçlarla) istersen terim eşleşmeleri ve yerleşim yapısı şu şekildedir:

Plaintext

2. Bit Seviyesinde Paket Bileşenlerinin Analizi

A. Başlangıç Koşulu (Start Condition)

I2C hattı boştayken (Idle) hem SDA hem de SCL hatları pull-up dirençleri nedeniyle mantıksal 1 (High) seviyesindedir. Haberleşmeyi başlatmak isteyen Master cihaz, SCL hattı hala High seviyesindeyken SDA hattını Low seviyesine çeker. Bu durum hattaki tüm Slave cihazlara “Dinlemeye geçin, yeni bir paket başlıyor” uyarısıdır.

B. Adres Çerçevesi (Address Frame)

Başlangıç durumundan hemen sonra gelen ilk 7 bit (bazı gelişmiş entegrelerde 10 bit), Master’ın hedeflediği Slave cihazın benzersiz donanımsal adresidir. Hat üzerindeki tüm cihazlar bu adresi okur, ancak sadece kendi adresiyle eşleşen Slave cihaz hatta cevap vermek üzere tetiklenir.

C. Okuma / Yazma Biti (Read/Write Bit)

Adres bitlerinin hemen ardından gelen 8. bit, operasyonun yönünü belirler:

  • 0 (Low): Yazma (Write) modudur. Master, Slave cihaza veri göndereceğini bildirir.
  • 1 (High): Okuma (Read) modudur. Master, Slave cihazın veri göndermesini bekler.

D. Onay Biti (ACK / NACK – Acknowledge)

I2C protokolünde her 8 bitlik veri transferinin ardından bir dokuzuncu bitlik “onay” penceresi açılır.

  • ACK (0 / Low): Verinin başarıyla alındığını ve hatanın olmadığını belirtir.
  • NACK (1 / High): Alıcının meşgul olduğunu, veriyi anlamadığını veya hattın koptuğunu belirtir.(Şemada ilk ACK/NACK adresin ulaştığını doğrulamak için Slave tarafından üretilir. Sonraki ACK bitleri ise verinin ulaştığını teyit etmek için veri akış yönüne göre Master veya Slave tarafından üretilir).

E. Veri Çerçeveleri (Data Frame 1 & 2)

Adres doğrulandıktan sonra asıl taşınmak istenen veri (sensör datası, register adresleri vb.) 8 bitlik (1 Bayt) paketler halinde hatta basılır. Her baytın iletiminden sonra alıcı taraf bir ACK biti döndürmek zorundadır. Paket uzunluğu teorik olarak sınırsızdır; Stop biti gelene kadar ardışık veri çerçeveleri gönderilmeye devam edebilir.

F. Bitiş Koşulu (Stop Condition)

Haberleşmeyi sonlandırmak isteyen Master cihaz, SCL hattı High seviyesindeyken SDA hattını Low’dan High seviyesine çeker. Bu geçiş, hattın tekrar boşa (Idle) çıktığını ve diğer cihazların veya yeni bir paketin hattı kullanabileceğini ilan eder.

Leave a Reply

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir