SPI Nedir?
SPI Nedir? Serial Peripheral Interface/ Seri Çevre Birimi Arayüzü (SPI), mikrodenetleyiciler, shift registerlar, sensörler ve SD kartlar gibi küçük çevre birimleri arasında veri göndermek için yaygın olarak kullanılan bir haberleşme veriyoludur. İletişime geçmek istediğiniz cihazı seçmek için bir seçim hattı ile birlikte ayrı saat ve veri hatları kullanır.
Seri iletişim, bir iletişim kanalı veya veri yolu üzerinden sırayla, her seferinde bir bit veri gönderme işlemidir. UART, CAN, USB, I2C ve SPI iletişimi gibi birçok seri iletişim türü vardır.
SPI Tarihçesi
SPI (Serial Peripheral Interface) bir seri iletişim protokolüdür. SPI arabirimi Motorola tarafından 1970 yılında bulunmuştur. SPI, tam çift yönlü bağlantıya sahiptir, bu da verilerin aynı anda gönderilip alınması anlamına gelir. Yani bir master, bir slave’e veri gönderebilir ve bir slave, aynı anda master’a veri gönderebilir. SPI, senkron seri iletişimdir, iletişim amacıyla saatin gerekli olduğu anlamına gelir.
Seri Bağlantı Noktalarında Sorun Nedir? (TX-RX)
TX ve RX hatlarındaki türden ortak bir seri bağlantı noktası, “asenkron” (senkron değil) olarak adlandırılır, çünkü verilerin ne zaman gönderileceği üzerinde herhangi bir kontrol veya her iki tarafın da tam olarak aynı hızda çalıştığına dair herhangi bir garanti yoktur. Bilgisayarlar normalde her şeyin tek bir “saatle” (her şeyi çalıştıran bir bilgisayara bağlı ana kristal) senkronize olmasına dayandığından, saatleri biraz farklı olan iki sistem birbiriyle iletişim kurmaya çalıştığında bu bir sorun olabilir.
Bu soruna geçici bir çözüm bulmak için, asenkron seri bağlantılar, her bayta fazladan başlatma ve durdurma bitleri ekler, alıcının gelen verileri eşitlemesine yardımcı olur. Her iki taraf da önceden iletim hızı (saniyede 9600 bit gibi) üzerinde anlaşmalıdır. Alıcı her baytın başında yeniden eşitlendiğinden, iletim hızındaki küçük farklılıklar sorun oluşturmaz.

Bu arada, yukarıdaki şemada “11001010” un 0x53’e eşit olmadığını fark ettiyseniz, bunu bir hata olduğunu düşünebilirsiniz fakat, seri protokoller genellikle en az anlamlı bitleri önce gönderir, bu nedenle en küçük bit en soldadır. Alttaki nybble aslında 0011 = 0x3’tür ve üstteki nybble 0101 = 0x5’tir.
Asenkron seri haberleşme aslında gayet iyi çalışır, ancak hem her baytla gönderilen ekstra başlatma ve durdurma bitlerinde hem de veri gönderip almak için gereken karmaşık donanımda çok fazla ek yüke sahiptir. Ve muhtemelen kendi projelerinizde fark ettiğiniz gibi, her iki taraf da aynı hıza ayarlanmazsa, alınan veriler anlamsız ve işe yaramaz olur. Bunun nedeni, alıcının bitleri belirli zamanlarda örneklemesidir (yukarıdaki şemadaki oklar). Alıcı yanlış zamanlara bakıyorsa, yanlış bitleri görecektir.
Senkron Haberleşme Çözümü
SPI yukarıdaki örneğe göre farklı bir şekilde çalışır. SPI, “senkron” bir veri yoludur; bu, veriler için ayrı hatlar ve her iki tarafı da mükemmel senkronizasyonda tutan bir “saat” kullandığı anlamına gelir. Saat, alıcıya veri hattındaki bitleri tam olarak ne zaman örnekleyeceğini söyleyen salınımlı bir sinyaldir. Bu, saat sinyalinin yükselen (düşükten yükseğe) veya düşen (yüksekten düşüğe) kenarı olabilir; Kullanılan komponentin veri sayfası(datasheet) hangisinin kullanılacağını belirleyecektir. Alıcı bu kenarı algıladığında, bir sonraki biti okumak için hemen veri hattına bakacaktır (aşağıdaki şemadaki oklara bakın). Saat verilerle birlikte gönderildiğinden, cihazların çalışabilecekleri en yüksek hıza sahip olmalarına rağmen, hızın belirtilmesi önemli değildir (uygun saat kenarını ve hızı seçmeye birazdan bakacağız).

SPI’nin bu kadar popüler olmasının bir nedeni, alıcı donanımın basit bir shift register olabilmesidir. Bu, asenkron serinin gerektirdiği eksiksiz UART’tan (Evrensel Asenkron Alıcı / Verici) çok daha basit (ve daha ucuz) bir donanım parçasıdır.
Hatırlatma
SPI pinleri için COPI/CIPO/CS/SDO/SDI etiketlerini ilk defa görüyor olabilirsiniz. Open Source Hardware Association(OSHWA) topluluğu, “Master” ve “Slave” gibi kavramları kullanmaktan uzaklaşmak için SPI etiketlerinde böyle bir değişikliğe gitti. Detayları okumak için buradaki içeriğimize göz atabilirsiniz.
SPI etiketlerinde yapılan güncelleme sonrasında pin giriş ve çıkışlarını anlamak için bu içeriğimizi okumanızı öneriyoruz.
Verinin Alınması
Kendi kendinize, bunun tek yönlü iletişim için kulağa harika geldiğini düşünüyor olabilirsiniz, ancak verileri ters yönde nasıl geri gönderirsiniz? Burada işler biraz daha karmaşık hale geliyor.
SPI’de, yalnızca bir taraf saat sinyalini üretir (genellikle Seri Saat için CLK veya SCK olarak adlandırılır). Saati oluşturan tarafa “kontrolör/controller”, diğer tarafa “periferik/peripheral/çevre birimi” denir. Her zaman yalnızca bir denetleyici vardır (neredeyse her zaman mikro denetleyicinizdir), ancak birden fazla çevre birimi olabilir.
Denetleyiciden bir çevre birimine veri gönderildiğinde, “Kontrolör Çıkışı / Çevre Birimi Girişi ya da Controller Out / Peripheral In” için COPI adlı bir veri hattına gönderilir. Çevre biriminin denetleyiciye bir yanıt göndermesi gerekiyorsa, denetleyici önceden ayarlanmış sayıda saat döngüsü oluşturmaya devam edecek ve çevre birimi verileri “Kontrolör Girişi / Çevre Birimi Çıkışı ya da Controller In / Peripheral Out” için CIPO adlı üçüncü bir veri hattına koyacaktır.

Dikkat edin, yukarıdaki açıklamada “önceden düzenlenmiş” dedik. Denetleyici her zaman saat sinyali ürettiği için, bir çevre biriminin ne zaman veri döndürmesi gerektiğini ve ne kadar veri döndürüleceğini önceden bilmesi gerekir. Bu, herhangi bir zamanda her iki yönde de rastgele miktarda verinin gönderilebildiği asenkron seriden çok farklıdır. Pratikte bu bir sorun değildir, çünkü SPI genellikle çok özel bir komut yapısına sahip sensörlerle konuşmak için kullanılır. Örneğin, bir cihaza “veri oku” komutunu gönderirseniz, cihazın size her zaman örneğin iki bayt göndereceğini bilirsiniz. (Değişken miktarda veri döndürmek isteyebileceğiniz durumlarda, verilerin uzunluğunu belirterek her zaman bir veya iki bayt döndürebilir ve ardından denetleyicinin tam miktarı almasını sağlayabilirsiniz.)
SPI’nin “tam çift yönlü” olduğunu (ayrı gönderme ve alma hatlarına sahip olduğunu) ve bu nedenle, belirli durumlarda aynı anda veri gönderip alabileceğinizi unutmayın (örneğin, verileri alıcıdan alırken yeni bir sensör okuması talep etmek). Cihazınızın veri sayfası bunun mümkün olup olmadığını size söyleyecektir.
Chip Select (CS) Eski Adıyla Slave Select(SS)
Dikkat etmeniz gereken önemli bir yer daha var, Chip Select (CS). Bu, çevre birimine uyanması ve veri alması/göndermesi gerektiğini söyler ve ayrıca konuşmak istediğiniz çevre birimini seçmek için birden fazla çevre birimi mevcut olduğunda kullanılır.

CS hattı normalde yüksek tutulur, bu da çevre birimini SPI veri yolundan ayırır. (Bu mantık türü “etkin düşük” olarak bilinir ve genellikle hatları etkinleştirmek ve sıfırlamak için kullanıldığını göreceksiniz.) Veriler çevre birimine gönderilmeden hemen önce, hat alçaltılır, bu da çevre birimini etkinleştirir. Çevre birimini kullanmayı bitirdiğinizde, hat tekrar yükselir. Bir shift register’da bu, alınan verileri çıkış hatlarına aktaran “latch/mandal” girişine karşılık gelir.
Çoklu Çevre Birimi
Birden fazla çevre birimini bir SPI veri yoluna bağlamanın iki yolu vardır:
Genel olarak, her çevre biriminin ayrı bir CS hattına ihtiyacı olacaktır. Belirli bir çevre birimiyle konuşmak için, o çevre biriminin CS hattını düşük yapacak ve geri kalanını yüksek tutacaksınız (aynı anda iki çevre biriminin etkinleştirilmesini istemezsiniz, aksi takdirde ikisi de aynı CIPO hattında konuşmaya çalışabilir, sonuç olarak bozuk veriler elde edilir). Çok sayıda çevre birimi, çok sayıda CS hattı gerektirecektir; çıkışlarınız azalıyorsa, CS çıkışlarınızı çoğaltabilen ikili kod çözücü entegreler vardır.

Öte yandan, bazı parçalar, birinin CIPO’su (çıktı) diğerinin COPI’sine (girişine) giderken, birbirine zincirleme bağlanmayı tercih eder. Bu durumda, tek bir CS hattı tüm çevre birimlerine gider. Tüm veriler gönderildiğinde, CS hattı yükseltilir ve bu da tüm enteglerin aynı anda etkinleştirilmesine neden olur. Bu genellikle zincirleme shift register ve adreslenebilir LED sürücüleri için kullanılır.

Bu düzen için, bir çevre biriminden diğerine veri taşar, bu nedenle herhangi bir çevre birimine veri göndermek için hepsine ulaşmak için yeterli veri iletmeniz gerektiğini unutmayın. Ayrıca, ilettiğiniz ilk veri parçasının son çevre biriminde sona ereceğini unutmayın.
Bu tür yerleşim, tipik olarak, herhangi bir veriyi geri almanız gerekmeyen LED sürme gibi yalnızca çıktı durumlarında kullanılır. Bu durumlarda kontrolörün CIPO hattının bağlantısı kesilmiş halde bırakabilirsiniz. Bununla birlikte, verilerin denetleyiciye döndürülmesi gerekiyorsa, bunu zincirleme döngüyü kapatarak yapabilirsiniz (yukarıdaki şemada mavi kablo). Bunu yaparsanız, çevre birimi 1’den gelen dönüş verilerinin denetleyiciye geri dönmeden önce tüm çevre birimlerinden geçmesi gerekeceğini unutmayın, bu nedenle ihtiyacınız olan verileri almak için yeterli sayıda alma komutu gönderdiğinizden emin olun.
SPI Programlama
Birçok mikrodenetleyici, veri gönderme ve almanın tüm ayrıntılarını işleyen ve bunu çok yüksek hızlarda yapabilen yerleşik SPI çevre birimlerine sahiptir. SPI protokolü aynı zamanda sizin veri aktarımı için G/Ç(I/O) hatlarını uygun sırayla manipüle etmek için kendi rutinlerinizi yazabileceğiniz kadar basittir. (İyi bir örnek Wikipedia SPI sayfasındadır.)
Arduino kullanıyorsanız, SPI cihazlarıyla iletişim kurmanın iki yolu vardır:
shiftIn() ve shiftOut() komutlarını kullanabilirsiniz. Bunlar, herhangi bir grup pin üzerinde çalışacak, ancak biraz yavaş olacak yazılım tabanlı komutlardır.
Veya mikrodenetleyicide yerleşik olarak bulunan SPI donanımından yararlanan SPI Library kullanabilirsiniz. Bu, yukarıdaki komutlardan çok daha hızlıdır, ancak yalnızca belirli pinlerde çalışır.
Arayüzünüzü ayarlarken bazı seçenekleri seçmeniz gerekecektir. Bu seçenekler, konuştuğunuz cihazınkilerle eşleşmelidir; ne gerektirdiğini görmek için cihazın veri sayfasını kontrol edin.
Arayüz, verileri önce en anlamlı bit (MSB) veya en az anlamlı bit (LSB) ile gönderebilir. Arduino SPI kitaplığında bu, setBitOrder() işlevi tarafından kontrol edilir.
Çevre birimi, verileri saat darbesinin yükselen kenarında veya düşen kenarında okuyacaktır. Ek olarak, saat yüksek veya düşük olduğunda “boşta” olarak kabul edilebilir. Arduino SPI kitaplığında bu seçeneklerin her ikisi de setDataMode() işlevi tarafından kontrol edilir.
SPI, bazı cihazlar için çok hızlı olabilen aşırı yüksek hızlarda (saniyede milyonlarca bayt) çalışabilir. Bu tür cihazları barındırmak için veri hızını ayarlayabilirsiniz. Arduino SPI kitaplığında hız, kontrolör saatini (çoğu Arduino’da 16MHz) 8MHz (/2) ve 125kHz (/128) arasında bir frekansa bölen setClockDivider() işlevi tarafından ayarlanır.
SPI kütüphanesini kullanıyorsanız, donanım bu pinlere bağlı olduğundan, sağlanan SCK, COPI ve CIPO pinlerini kullanmanız gerekir. Ayrıca kullanabileceğiniz özel bir CS pini de vardır (en azından SPI donanımının çalışması için bir çıkışa ayarlanması gerekir), ancak CS için mevcut diğer herhangi bir çıkış pinini/pinlerini kullanabileceğinizi unutmayın.
Daha eski Arduino’larda, CS pin(ler)ini kendiniz kontrol etmeniz gerekecek, bu pinlerden birini veri aktarımınızdan önce düşük ve sonrasında yüksek yapacaksınız. Due gibi daha yeni Arduino’lar, veri aktarımının bir parçası olarak her CS pinini otomatik olarak kontrol edebilir; daha fazla bilgi için Due SPI dokümantasyon sayfasına bakın.
İki Arduino Arasında SPI Haberleşme
Kısa mesafeli maksimum 1-5m aralığında uzaklıklar için düşük veri transferi hızlarında kullanılabilir.

SPI Hattı | Arduino UNO |
COPI(MOSI) | 11 ya da ICSP-4 |
CIPO(MISO) | 12 ya da ICSP-1 |
SCK | 13 ya da ICSP-3 |
CS(SS) | 10 |
Bağlantı Şeması
Şimdi iki Arduino UNO kartını birbirine bağlayacağız; biri ana kontrolcü, diğeri çevre birimi olacak.
(CS/SS) : pin 10
(COPI/MOSI): pin 11
(CIPO/MISO) : pin 12
(SCK) : pin 13
GND ortak olmalıdır.
Her iki geliştirme kartı arasındaki bağlantının şematik gösterimi aşağıdadır:

Kod ve Fonksiyon Açıklamaları
SPI.h kütüphanesi projeye dahil edilince gelen fonksiyonların açıklamalarına göz atalım:
- SPI.begin(): SCK, MOSI ve SS’yi çıkışlara ayarlayarak, SCK ve MOSI’yi düşüğe ve SS’yi yükseğe çekerek SPI veri yolunu başlatır.
- SPI.setClockDivider(bölücü): SPI saat bölücüyü sistem saatine göre ayarlamak için. AVR tabanlı kartlarda, mevcut bölücüler 2, 4, 8, 16, 32, 64 veya 128’dir. Varsayılan ayar, SPI saatini sistem saatinin frekansının dörtte birine ayarlayan SPI_CLOCK_DIV4’tür. (20MHz’de çalışan kartlarda 5MHz olur.)
- bölücü: (SPI_CLOCK_DIV2, SPI_CLOCK_DIV4, SPI_CLOCK_DIV8, SPI_CLOCK_DIV16, SPI_CLOCK_DIV32, SPI_CLOCK_DIV64, SPI_CLOCK_DIV128) olabilir.
- SPI.transfer(val): SPI aktarımı, eşzamanlı gönderme ve alma işlemine dayalıdır: alınan veriler receivedVal’de döndürülür.
- SPI.beginTransaction(SPISettings(speedMaximum, dataOrder, dataMode)): speedMaximum saattir, dataOrder(MSBFIRST veya LSBFIRST), dataMode(SPI_MODE0, SPI_MODE1, SPI_MODE2 veya SPI_MODE3) olabilir.
SPI’de aşağıdaki gibi dört çalışma modu vardır:
- Mode 0 (varsayılan): Saat normalde düşüktür (CPOL = 0) ve veriler düşükten yükseğe geçişte (ön uç) örneklenir (CPHA = 0).
- Mode 1: Saat normalde düşüktür (CPOL = 0) ve veriler yüksekten düşüğe geçişte (arka kenar) örneklenir (CPHA = 1).
- Mode 2: Saat normalde yüksektir (CPOL = 1) ve veriler yüksekten düşüğe geçişte (ön uç) örneklenir (CPHA = 0).
- Mode 3: Saat normalde yüksektir (CPOL = 1) ve veriler düşükten yükseğe geçişte (arka kenar) örneklenir (CPHA = 1).
- SPI.attachInterrupt(handler): Bir bağımlı cihaz ana cihazdan veri aldığında çağrılacak fonksiyon.
Kontrolcü Kodu(Master)
#include <SPI.h> void setup (void) { Serial.begin(115200); //usart için baud hızını 115200 olarak ayarla digitalWrite(SS, HIGH); // Slave Select'i devre dışı bırak SPI.begin (); SPI.setClockDivider(SPI_CLOCK_DIV8);//saat hızını 8'e böl } void loop (void) { char c; digitalWrite(SS, LOW); // Slave Select'i aktifleştir // string yolla for (const char * p = "devreyakan.com\r" ; c = *p; p++) { SPI.transfer (c); Serial.print(c); } digitalWrite(SS, HIGH); // Slave Select'i devre dışı bırak delay(2000); }
Çevre Birimi Kodu(Slave)
#include <SPI.h> char buff [50]; volatile byte indx; volatile boolean process; void setup (void) { Serial.begin (115200); pinMode(MISO, OUTPUT); // kontrolcüye göndermek zorunda, bu yüzden output olarak ayarlandı SPCR |= _BV(SPE); // çevre biriminde(slave) SPI'yi aç indx = 0; // boş buffer process = false; SPI.attachInterrupt(); // kesmeyi(interrupt) aç } ISR (SPI_STC_vect) // SPI kesme rutini { byte c = SPDR; // SPI Data Register'dan bayt oku if (indx < sizeof buff) { buff [indx++] = c; // dizi buff'ında bir sonraki dizine verileri kaydet if (c == '\r') //kelimenin sonunu kontrol et process = true; } } void loop (void) { if (process) { process = false; //işlemi sıfırla Serial.println (buff); //diziyi seri monitörde yazdır indx= 0; //buffer sıfırla } }
SPI İpuçları
Yüksek hızlı sinyaller nedeniyle, SPI yalnızca kısa mesafelerde (birkaç metreye kadar) veri göndermek için kullanılmalıdır. Bundan daha fazla veri göndermeniz gerekiyorsa, saat hızını düşürmek ve özel sürücü entegreleri kullanmayı düşünün.
İşler düşündüğünüz gibi çalışmıyorsa, bir mantık analizörü çok yardımcı bir araçtır. Analizörler, bir görüntüleme veya günlük kaydı için veri baytlarının kodunu bile çözebilir.
SPI Avantajları ve Dezavantajları
Avantajları
- Asenkron seri haberleşmeden daha hızlıdır
- Veri alma donanımı basit bir shift register olabilir
- Birden fazla çevre birimini(alıcı) destekler
Dezavantajları
- Diğer iletişim yöntemlerinden daha fazla sinyal hattı (kablo) gerektirir
- İletişim önceden iyi tanımlanmış olmalıdır (istediğiniz zaman rastgele miktarda veri gönderemezsiniz)
- Denetleyici tüm iletişimi kontrol etmelidir (çevre birimleri doğrudan birbirleriyle konuşamaz)
- Genellikle her bir çevre birimi için ayrı CS hatları gerektirir; bu, çok sayıda çevre birimine ihtiyaç duyulursa sorunlu olabilir.
Yorum yapma özelliği, forum tarafından gelen istek sebebiyle kapatılmıştır. Lütfen tartışmalar ve sorularınız için topluluk forumumuza katılın.