1. I2C Hakkında
I2C (Inter-Integrated Circuit) 1984 yılında Philips tarafından tasarlanmış bir seri haberleşme protokolüdür. Eski olmasına karşın hala birçok cihazda kullanılmaktadır. Genellikle aynı kart (PCB) üzerinde bulunan entegreler arası gibi kısa mesafelerde kullanılır. Haberleşme SDA (Serial Data) ve SCL (Serial Clock) olmak üzere iki tel üzerinden gerçekleşir. İletişim tek yönlüdür (Half-Duplex). Protokoldeki 7 bitlik (1992 versiyonunda 10 bit seçeneğide eklenmiştir) adres alanı ile 1 Master ile 128 Slave arasında iletişim gerçekleştirilebilir. I2C standardında bazı adresler özel olarak ayrılmıştır (Reserved Addresses). Bunlardan biri 0x00 adresidir ve “General Call” olarak adlandırılır. İletişim hızı ilk versiyonda (1984) 100Khz olarak belirlenmiştir (SCL frekansı). 1992 yılında Fm (Fast-mode) olarak adlandırılan 400Khz hızına sahip versiyonu çıkmıştır. Daha sonraki versiyonlarda bu hız daha da arttırılmıştır.
1.2 I2C Protokolü
Aşağıdaki resimler NXP’nin yayınladığı UM10204 User Manuelinden alınmıştır. İlk resimde Master'dan Slave'e veri aktarımı göstermiştir.
İletişim SDA nın ‘1’ den ‘0’ a çekilmesi ile başlar, bu bit “Start bit” olarak adlandırılır. Start bitini ardından 7 bitlik adres alanı gelir. Bu adres alanına sahip olmayan slave cihazlar bu noktadan sonra iletişimden çekilir ve doğru adres alanına sahip cihaz ile bağlantı kurulur. Adres alanından sonra slave cihazdan okuma yada yazma yapılacağını belirten “R/~W” biti gelir. Master'dan Slave'e veri aktarımı yapacağımızdan bu bitin değeri ‘0’ dır. Bu bitten sonra Slave'den Master'a “ACK” (Acknowledge) biti yolanır. Eğer belirtilen adres alanına sahip cihaz yok ise bu bitin değeri ‘1’ olacaktır ve Master cihaz bu adrese sahip cihazın olmadığına karar verecektir. “ACK” bitinden sonra sırayla veriler gönderilmeye başlar. Gönderilen her byte'tan sonra Slave cihaz Master'a “ACK” gönderir. Slave cihaz daha fazla veri alamayacak ise "ACK" yerine "NACK" (Not Acknowledge) gönderir. İletişim Master cihazın “Stop bit”i ile sonlanır.
Yukarıdaki resimde ise Master cihazın Slave cihazdan nasıl veri okuyacağı gösteriliyor. Start biti ve adres alanı yazma ile tamamen aynı. “R/~W” biti okuma için ‘1’ değerinde. Doğru adres alanına sahip Slave cihaz Master cihazın “ACK” bitinden sonra verileri göndermeye başlar. Master cihaz “NACK” ve “Stop bit”ini gönderdikten sonra iletişim sonlanır.
Yukarıda ise Master cihazın Slave cihazdan veri gönderme ve almasının tek bir “Stop” biti ile nasıl gerçekleştirileceğini gösteriyor. Yazma ve okumalar arasına 1 “Start bit”i konularak iletişimin sürekliliği sağlanmış olur. İletişim “Stop bit”i ile sonlanır. Register içeren Slave cihazlar ile bu yöntemle registerlere erişim sağlanır. İlk olarak Master cihaz “R/~W” biti ‘0’ olarak erişilmek istenen registerin adresini gönderir. Daha sonra tekrar “Start bit”i gönderilerek iletişim sonlandırılmadan devam ettirilir. İkinci kısımda “R/~W” biti ile registere yazma yada okuma işlemlerinden hangisinin yapılacağı seçilir.
2. Uygulama
Bu yazıda biri master diğeri slave olmak üzere 2 Stm32f4 kiti arasında I2C ile iletişim kuracağım. Slave cihaz 2 registere sahip olacak ve 2 register de dışarıdan 2 buton ile kontrol edilecek. Master cihaz sırayla slave cihaz üzerindeki 2 registeri okuyup bu registerlere göre kit üzerindeki ledleri yakıp söndürecek. Algoritmaların akış diyagramı aşaıdaki gibidir.
Master için:
Slave için:
2.1. Master Cihaz için Donanımın Hazırlanması
Master için Stm32f429zi mikrodenetleyicisine sahip kiti kullandım. Mikrodenetleyici 8Mhz harici kristal ve PLL yardımı ile 168Mhz de çalışacak. İşlemcinin 168 Mhz'de çalışmasından dolayı flash donanımı her cycle sonrası 5WS (Wait-State) kadar bekleyecetir. Ledler G portunun 13. 14. bacaklarına bağlı. I2C iletişimi I2C3 donanımı ve PA8 , PC9 pinleri ile gerçekleştirilecektir.
Master cihazın donanımının hazırlanması için yapılması sırasıyla yapılması gerekenler:
- Clock ve Flash Konfigürasyonları
- GPIO Konfigürasyonları
- I2C Konfigürasyonları
2.1.1. Clock ve Flash Konfigürasyonları
Stm32f4 ailesinin clock donanımı aşağıda görülmektedir.
Mikrodenetleyiciyi dışarıdan bir kristal yardımı ile sürülebilmek için HSE modülünün aktif edilmesi gerekir. İşlemcinin 168Mhz de çalışabilmesi için PLL nin doğru katsayılar ile ayarlanması ve PLL çıkışının ana clock hattı olarak seçilmesi gerekmektedir. GPIO ve I2C donanımlarının doğru çalışabilmesi için APB1 ve APB2 clock hattının doğru frekanslarda ayarlanması gerekmektedir.
Clock ve Flash Konfigürasyonu için sırayla yapılması gerekenler:
- PLL için Doğru Katsayıların Hesaplanması
- HSE'nin ve PLL nin Aktifleştirilmesi
- APB1 ve APB2 Hattları için Frekans Bölücü Katsayılarının Hesaplanması
- Flash donanımının 5WS de çalışacak şekilde ayarlanması
- Ana Clock Kaynağı olarak PLL'in seçilmesi
- GPIOA, GPIOC, GPIOG ve I2C3 Donanımlarının Clock Hatlarının Aktifleştirilmesi
2.1.1.1. PLL için Doğru Katsayıların Hesaplanması
RCC_PLLCFGR registerindeki PLLN, PLLM, PLLP değerini değiştirerek istenilen frekans üretilebilir.
PLL nin giriş frekansı 8Mhz (HSE) olduğuna göre PLL çıkışının 168MHz olması için PLLM = 8, PLLN = 336, PLLP = 2 ve PLLQ (RNG , USB ve SDIO için 48Mhz) = 7 olarak ayarlanması gerekir.
2.1.1.2. HSE'nin ve PLL'nin Aktifleştirilmesi
PLL_CR registerinin 16. ve 24. bitleri '1' yapılarak PLL ve HSE aktifleştirilir.
2.1.1.3. APB1 ve APB2 Hattları için Frekans Bölücü Katsayılarının Hesaplanması
APB1 ve APB2 clock hatlarının maksimum çalışabileceği bir frekans olduğundan, APB1 ve APB2 hatlarına giden clock'u frekans bölücüler ile düşürmemiz gerekmektedir. APB1 için bu sınır 45Mhz, APB2 içinde de 90Mhz'dir. PLL çıkış freknsımız 168Mhz olduğuna göre APB1 frekans bölücüsünü 4, APB2 frekans bölücüsünü ise 2 ile bölersek, APB1 = 42Mhz, APB2 = 84Mhz olacaktır. RCC_CFGR registerinin 15:10 bitleri ayarlanak frekans bölücüler hazırlanmış olur.
2.1.1.4 Flash donanımının 5WS de çalışacak şekilde ayarlanması
FLASH_ACR registerinin 2:0 bitlerini '101' yaparak flash donanımını 5WS gecikme ile çalışacak hale getiririz.
2.1.1.5 Ana Clock Kaynağı olarak PLL'in seçilmesi
RCC_CFGR registerinin 1:0 bilerinin '10' yaparak Ana clock kaynağı PLL seçilmiş olur.
2.1.1.6 GPIOA, GPIOC, GPIOG ve I2C3 Donanımlarının Clock Hatlarının Aktifleştirilmesi
RCC_AHB1ENR registerinin 6., 2. ve 0. bitlerinin '1' yapılması ile isteninlen GPIO hatlarının clockları aktifleştirilir.
2.1.2 GPIO Konfigürasyonları
I2C nin çalışabilmesi için PA8 ve PC9 bacaklarının, Open-Drain, Pull_Up, Alternate function ve I2C3 donanımına bağlı olması gerekir. Ledlere bağlı olan PG13 ve PG14 bacaklarının ise Push-Pull ve Output şeklinde ayarlanması gerekiyor. GPIO için yapılması gerekenler :
- PA8 ve PC9 bacakalarının alternate function, PG13 ve PG14 bacaklarının Output olarak ayarlanması
- PA8 ve PC9 bacaklarının Open-Dran olarak ayarlanaması
- PA8 ve PC9 bacaklarının Pull-Up olarak ayarlanması
- PA8 ve PC9 bacaklarının I2C3 donanımına bağlanması
2.1.2.1 PA8 ve PC9 bacakalarının alternate function, PG13 ve PG14 bacaklarının Output olarak ayarlanması
GPIOA_MODER registerlerinin 17:16 bitlerini '10', GPIOC_MODER registerinin 19:18 biterini '10' ve GPIOG_MODER registerinin 29:26 bitlerini '0101' ayarlayarak bacaklarının türünü seçmiş oluruz.
2.1.2.2 PA8 ve PC9 bacaklarının Open-Dran olarak ayarlanaması
GPIOA_OTYPER registerinin 7. bitini '1' ve GPIOC_OTYPER registerinin 8. bitini '1' yaparak bu bacakları Open-Drain olarak ayarlarız. Bu register reset durumunda '0x0000', yani bütün bacakların Push-Pull olarak tanımladığından PG13, PG14 bacakları için GPIOG_OTYPER registerinde herhangi bir değişiklik yapmamız gerekmemektedir.
2.1.2.3 PA8 ve PC9 bacaklarının Pull-Up olarak ayarlanması
GPIOA_PUPDR registerinin 17:16 bitlerini '01' ve GPIOC_PUPDR registerinin 19:18 bitlerini '01' yaparak bu pinleri Pull-Up olarak ayarlamış oluruz.
2.1.2.4 PA8 ve PC9 bacaklarının I2C3 donanımına bağlanması
GPIOA_AFRH registerinin 3:0 bitlerini '0100' (AF4), GPIOC_AFRH registerinin 7:4 bitlerini '0100' yaparak bu bacakarı I2C3 donanımına bağlamış oluruz.
2.1.3 I2C Konfigürasyonları
Bu uygulamada iletişim hızı 100Khz (Sm) ve slave adres uzunlu 7bit olacaktır. İletişim hızının 100Khz e ayarlanabilmesi için I2C3 registerlerinden iletişim hızını 100Khz ve APB1 hatının frekansının 42Mhz olduğunu belirmetmemiz gerekmektedir. I2C konfigürasyonları için sırayla yapılması gerekenler:
- APB2 Hatının 42Mhz Olduğunun Belirtilmesi
- 7 Bit Adresleme Kullanılacağının Belirtilmesi
- Clock Ayarlarının Yapılması
- Donanımın Aktif Edilmesi
2.1.3.1 APB2 Hatının 42Mhz Olduğunun Belirtilmesi
I2C3_CR registerinin 5:0 bitlerinin '0d42' yapılması ile APB1 hattının 42Mhz de çalıştığı belirtilir.
2.1.3.2 7 Bit Adresleme Kullanılacağının Belirtilmesi
I2C3_OAR1 registerinin 15. bitinin '0' yapılması ile 7 bit adreslemenin kullanılacağı belirtilmiş olur. Slave cihaz adresi, bu registerin 7:1 bitleri ile belirtilir. Master cihaz için bu bitlerin bir önemi yoktur.
2.1.3.3 Clock Ayarlarının Yapılması
I2C3_CCR registerinin 15.bitinin '0' yapılması ile Sm (100Khz) modu seçilmiş olur. Yine aynı registerin 11:0 bitlerini '0d210' yaparak SCL için clock ayarını yapmış oluruz. SCL un clock ayarı sadece master cihaz için gereklidir.
I2C3_TRISE registerinin 5:0 bitlerinin '0d43' ayarlanması maksimum rise süresi belirlenmiş olur. SCL sadece master tarafından üretildiğinden, bu ayarın sadece master için yapılması yeterlidir.
2.1.3.4 Donanımın Aktif Edilmesi
I2C3_CR1 registerinin 0. bitinin '1' yapılması ile I2C3 donanımı çalıştırılmış olur.
2.2 I2C Master Algoritması
Bu uygulamada master cihaz, slave cihaz üzerindeki 2 registeri okuyup bu register değerlerine göre ilgili ledleri yakıp söndürecektir. Master cihaz slave cihaz üzerinden hem yazma (ilgili register adresi) hem de okuma (slave cihazın gönderdiği register değeri) yapacaktır. Master cihazın I2C bölümünün algoritması aşağıdaki akış diyagramından görülebilir.
Start bitinin beklenmesi, gelen bir verinin olup olmaması gibi durumları öğrenmek için I2C3_SR1 ve I2C3_SR2 registerlerinden yararlanılır. Start, stop ve ACK/NACK bitleri I2C3_CR1 registeri ile gönderilir. Aşağıda I2C3_SR1, I2C3_SR2 ve I2C3_CR1 registerlerinin açıklaması bulunmaktasır.
2.2.1 Start Bitinin Gönderilmesi
I2C3_CR1 registerinin 8. bitinin '1' yapılması ile start biti gönderilir.
2.2.2 Start Bitinin Beklenmesi
I2C3_SR1 registerinin 1. bitinin '1', I2C3_SR2 registerinin 1:0 bitlerinin '11' olması ile start bitinin üretildiği anlaşılır.
2.2.3 Slave adresin ve R/~W Bitlerinin Gönderilmesi
I2C3_DR registerine '0x01'(7:1 bitleri slave cihazın adresi, 0.bit yazma işleminin yapılacağını gösterir) yazılması ile slave cihaza adres ve R/~W bilgisi gönderilmiş olur.
2.2.4 Slave Cihazdan ACK biti beklenmesi
I2C3_SR1 registerinin 1. ve 7. bitlerinin '1', I2C3_SR2 registerinin 0., 1. ve 2. bitlerinin '1' olması ile gönderilerin adresin slave cihazın adresi ile eşlendiği anlaşılır.
2.2.5 Slave Cihazdan Veri Alınması
I2C3_SR1 registerinin 6.bitinin '1', I2C3_SR2 registerinin 2:1 bitlerinin '11' olması ile yeni bir verinin geldiği anlaşılır. I2C3_DR registerinden veri okunur.
2.2.6 NACK Gönderimesi
I2C3_CR1 registerinin 10. bitinin '0' yapılması ile ACK gönderimi kapatılmış olur (NACK).
2.2.7 Stop Bitinin Gönderilmesi
I2C3_CR1 registerinin 9. bitinin '1' yapılması ile start biti gönderilir.
2.3 I2C Master Algoritmasının Assembly ile yazılması
Assembly kodlarına buradan ulaşabilirsiniz.
2.4. Slave Cihaz için Donanımın Hazırlanması
Slave cihaz olarak Stm32f407vg mikrodenetleyicisine sahip Stm32f4 Discovery kit kullanıldı. Mikodenetleyici Master cihaz gibi 8Mhz(HSE) harici kristal ve PLL yardımı ile 168Mhz de çalışacaktır. Butonlar C portunun 6. ve 7. pinlerine, I2C iletişimi de I2C1 donanımı ve B portunun 6. ve 7. pinlerinden yapılacaktır. Slave cihazın donanım yapısı Master cihaza benzediğinden Slave cihazın donanım ayarlarını tekrardan yazmıyorum.
2.5. I2C Slave Algoritması
Slave cihazın algoritmasının akış diyagramı aşağıdaki gibidir.
2.5.1 Adres eşleşmesinin beklenmesi
I2C1_SR1 registerinin 1. ve 7. bitlerinin '1' ve I2C1_SR2 registerinin 2:1 bitlerinin '11' olması ile I2C1_OAR registerindeki slave cihaza atanan adresin eşlendiği anlaşılır.
2.5.2 ACK Gönderilmesi
I2C1_CR1 registerinin 10. bitinin '1' yapılması ile ACK gönderimi açılmış olur.
2.6. I2C Slave Algoritmasının Assembly ile yazılması
Assembly kodlarına buradan ulaşabilirsiniz.