9. ünite / 11 · yaklaşık 5 saat
I²C ve SPI: zamanlama diyagramları
I²C'de START/STOP, adres, ACK/NACK, çekme dirençleri; SPI'da CPOL/CPHA kipleri ve CS; mantık analizörüyle hata bulma.
Bu ünitenin sonunda
- Bir I²C işlemini START'tan STOP'a çizmek ve ACK/NACK'ı yorumlamak
- I²C çekme direnci için alt ve üst sınırı hesaplamak
- SPI'ın dört kipini ayırt etmek ve kip uyuşmazlığının belirtisini tanımak
- HAL ile bir sensör yazmacını okumak ve hata durumunu ele almak
Ders notları
Raspberry Pi dersinde I²C ve SPI'ı "cihaz bağla, kütüphane çağır" düzeyinde kullandık. Burada tellerde ne olduğuna bakıyoruz; çünkü bir sensör yanıt vermediğinde sorunu ancak dalga biçimi söyler.
I²C
İki açık-drain hat: SDA (veri) ve SCL (saat), ikisi de çekme dirençleriyle 3,3 V'a bağlı. Kural: SDA yalnız SCL düşükken değişir. SCL yüksekken SDA'nın düşmesi START, yükselmesi STOP'tur. START'tan sonra 7 bit adres + 1 bit R/W gönderilir; dokuzuncu saatte köle SDA'yı 0'a çekerse ACK, çekmezse NACK (cihaz yok, adres yanlış ya da meşgul). Okumada efendi, son baytta NACK vererek "yeter" der.
Çekme direnci çok büyükse kenarlar yavaş yükselir (yol kapasitesi × R); çok küçükse çıkış 3 mA'dan fazla çekmek zorunda kalır. 100 kHz ve 200 pF için yaklaşık 1–6 kΩ arası uygundur; 4,7 kΩ yaygın seçimdir.
SPI
Dört hat: SCK, MOSI, MISO, CS. Her saat darbesinde iki yönde birer bit gider. CPOL boştaki saat seviyesini, CPHA verinin hangi kenarda örneklendiğini belirler; dört kip (0–3) vardır. Efendi ile köle aynı kipte değilse okunan bayt bir bit kayar ya da tamamen bozulur: tipik belirti "değerler ikiye katlanmış ya da yarıya inmiş" gibidir. Sensörün veri sayfası kipi söyler.
Mantık analizörü
Ucuz bir mantık analizörü ve PulseView gibi bir yazılım, I²C ve SPI'ı çözümleyip baytları ekrana yazar. "Kod doğru ama sensör çalışmıyor" durumunda ilk araç budur.
Simülasyon
I²C ve SPI zamanlama diyagramları
I²C'de adres, R/W, veri baytları ve cihaz yokken NACK; SDA'nın yalnız SCL düşükken değiştiğini izle. SPI'da dört kipi (CPOL/CPHA) karşılaştır ve kip uyuşmazlığının okunan baytı nasıl bozduğunu gör.
Kendin dene
I²C sekmesinde 0x76 adresine 0xD0 yazmacını okuyan işlemi çiz; sonra "cihaz yok" seçip NACK'ı gör. SDA'nın SCL yüksekken yalnız START ve STOP'ta değiştiğini doğrula. SPI sekmesinde dört kipi tek tek seç ve örnekleme kenarlarını karşılaştır; köleyi kip 0, efendiyi kip 1 yapıp okunan baytı yaz.
Kod
uint8_t bme280_id(void) {
uint8_t id = 0;
/* HAL 8 bit adres ister: 7 bit adres << 1 */
if (HAL_I2C_Mem_Read(&hi2c1, 0x76 << 1, 0xD0, I2C_MEMADD_SIZE_8BIT, &id, 1, 10) != HAL_OK)
return 0; /* NACK: cihaz yok ya da adres yanlış */
return id; /* 0x60 beklenir */
}
uint8_t spi_xfer(uint8_t tx) {
uint8_t rxb = 0;
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET); /* CS düşük: köle seçildi */
HAL_SPI_TransmitReceive(&hspi1, &tx, &rxb, 1, 10); /* tam çift yönlü */
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET);
return rxb;
}Sık yapılan hatalar
- HAL'e 7 bitlik adresi kaydırmadan vermek: HAL 8 bitlik (adres << 1) ister, cihaz NACK verir.
- I²C çekme dirençlerini unutmak ya da her modülün kendi direncini paralel bırakmak (eşdeğer direnç çok küçülür).
- SPI CS hattını işlem boyunca düşük tutmamak.
- Zaman aşımını HAL_MAX_DELAY yapmak: takılan bir I²C yolu tüm programı kilitler.
Yazılım mühendisliği bağlantısı
Sürücüyü iki katmana ayır: yol (i2c_read(addr, reg, buf, n)) ve cihaz (bme280_read_temp()).
- Cihaz katmanı sahte bir yol ile bilgisayarda test edilir: kayıtlı yazmaç değerlerinden doğru sıcaklık çıkıyor mu?
- Her yol çağrısının hata kodu kontrol edilir ve günlüğe yazılır; sessizce 0 döndürmek yok.
Kendini sına
I²C'de SCL yüksekken SDA düşerse bu nedir?
Adres baytından sonra dokuzuncu saatte SDA yüksek kaldıysa?
SPI kip 3 hangi CPOL/CPHA'dır?
HAL_I2C_Mem_Read'e BME280 (0x76) için hangi adres verilir?