3.22. Kodda SPI¶
machine.SPI, bir donanımsal SPI denetleyicisini sarmalar; CS hatları, betik tarafından yönetilen sıradan Pin çıkışlarıdır. Bir SPI örneğini veri yolu kimliği, istenen saat hızı ve (gerekirse) mod ile oluşturun:
from machine import SPI, Pin
spi = SPI(0, baudrate=1_000_000, polarity=0, phase=0)
cs = Pin("P3", Pin.OUT, value=1) # CS idle high
id, hangi donanımsal SPI bloğunun kullanılacağını seçer; kullanılabilir numaralar ve eşleştikleri SCK/MOSI/MISO pinleri karta bağlıdır (bkz. OpenMV Kartları). baudrate, hertz cinsinden SCK frekansıdır – donanımın elde ettiği gerçek hız, saat bölmesi nedeniyle biraz daha düşük olabilir; bu durum SPI nesnesinin yazdırılan değerinde gösterilir.
CS pini value=1 ile oluşturulur, böylece pasif (deasserted) durumda boşta kalır. Her işlem CS’yi etkinleştirir (düşük seviyeye sürer), baytları hareket ettirir ve CS’yi tekrar pasifleştirir (yüksek seviyeye sürer).
3.22.1. Okuma, yazma, takas etme¶
Üç metot yaygın durumları kapsar:
cs.value(0)
spi.write(b"\x10\x20\x30") # send 3 bytes, ignore what comes back
cs.value(1)
cs.value(0)
data = spi.read(4) # read 4 bytes; sends 0x00 while reading
cs.value(1)
rx = bytearray(2)
cs.value(0)
spi.write_readinto(b"\x9F\x00", rx) # send 0x9F, 0x00; receive 2 bytes
cs.value(1)
write() yalnızca yazma için hızlı yoldur; denetleyici baytları gönderir ve çevre biriminin MISO üzerinde geri gönderdiği şeyi atar. read() bunun ayna görüntüsüdür – MOSI üzerinde sabit bir kukla bayt (varsayılan olarak 0) gönderirken N SCK darbesi saatler ve MISO baytlarını saklar. write_readinto() tam çift yönlü biçimdir: baytları bir arabellekten gönderir ve eşzamanlı MISO baytlarını başka bir arabelleğe saklar. Birçok çevre birimi bu deseni kullanır – “bir komut baytı gönder, ardından bir sonraki aktarımda yanıtı oku” – bu nedenle iki işlem doğal olarak tek bir write_readinto çağrısına sığar.
Çoğu çevre birimi, CS hattının işlemin tamamı boyunca (komut baytlarından yanıt baytlarına kadar) etkin kalmasını bekler; bu nedenle cs.value(0) / cs.value(1) parantezlerini her metot çağrısının değil, tüm dizinin etrafında tutun.
3.22.2. Tipik bir sensör okuması¶
Birçok SPI sensörü durumunu bir dizi dahili yazmaç olarak düzenler ve aynı takas biçimini izler: yazmaç adresini gönder (üst bitte bir okuma/yazma bayrağıyla), ardından yazmacın baytlarını oku veya yaz. Böyle bir cihazda 0x0F yazmacının okunması:
rx = bytearray(2)
cs.value(0)
spi.write_readinto(b"\x8F\x00", rx) # 0x80 = "read" flag, then reg 0x0F
cs.value(1)
register_value = rx[1]
İlk MISO baytı çöptür (cihaz o noktada hâlâ komutu alıyordu); ikinci MISO baytı yazmaç içeriğini tutar. Tam komut baytı biçimi – hangi bitin okuma/yazma bayrağı olduğu, çok baytlı okumalarda adresin otomatik artıp artmadığı – cihazın veri sayfasındadır.
3.22.3. Bit-banging¶
Yukarıdaki SPI örneği bir donanımsal SPI bloğu kullanır: MCU içinde, SCK / MOSI / MISO dalga biçimlerini donanımda üreten, kendi kaydırmalı yazmacı ve saat üreteci olan özel bir çevre birimi. Yazılım yalnızca ona bir bayt verir; bitler ek bir CPU yardımı olmadan tel üzerinde hareket eder ve CPU’yu paralel olarak başka işler yapmakta serbest bırakır.
Alternatif bit-banging’dir: yazılım her bit üzerinde döngü yapar ve aynı dalga biçimini üretmek için GPIO pinlerini doğrudan değiştirir. İşin içinde donanımsal bir çevre birimi yoktur – CPU her baytın her biti için SCK’yı düşük seviyeye sürer, MOSI’yi ayarlar, SCK’yı yüksek seviyeye sürer, MISO’yu örnekler ve bu böyle devam eder. Bu, CPU’yu işlemin tamamı boyunca meşgul eder ve donanım bloğunun çalışabileceğinden daha yavaş çalışır, ancak herhangi bir pinde çalışır ve bir donanım bloğunun boş olmasını gerektirmez.
machine.SoftSPI, aynı SPI API’sinin bit-bang uygulamasıdır:
from machine import SoftSPI, Pin
spi = SoftSPI(baudrate=500_000, polarity=0, phase=0,
sck=Pin("P2"), mosi=Pin("P0"), miso=Pin("P1"))
Cihazın bir donanımsal SPI bloğuna bağlı olmayan pinlerde olması gerektiğinde veya donanım bloklarının tümü kullanımda olduğunda bunu kullanın. 500 kHz çoğu kamerada rahat bir üst sınırdır; CPU işlemin tamamı boyunca meşgul kalır.