OV7670 amatör uygulamalar için kullanılabilecek yaygın ve ucuz bir kamera. STM32F103 ile kullanmak üzere yaptığım çalışmaları paylaşacağım.
Bilindiği gibi STM32F103 ün 20kB lık RAM kapasitesi en mütevazi boyutlarda bir fotoğrafı saklamaya dahi yetmiyor. Ben ise desen tanıyan bir kod geliştirmek istiyorum, bir şekilde boyut problemini aşabilir miyim bakacağım.
Bu ilk yayında kameranın SCCB protokolu ile kontrolunu ele alacağız.
PROJE KURULUMU
Kamerayı STM32F103RB tabanlı Minikit modülümle kullanacağım. Bu modülün üzerine SPI arayüzlü bir TFT de takılabiliyor.
OV7670 i mikro denetleyici modülüne bağlayabilmek için fotoda görülen beyaz renkli adaptör kartını hazırladım, aksi halde kameradan çıkan 18 adet jumper kablo bağlantısı ile boğuşmaktan asıl iş ile ilgilenmek mümkün olmayacaktı.
Bu kartı EAGLE da tasarlayıp, CarbideCopper ile CNC kodlarını ürettim, masa üstü CNC de de kart üretimini yaptım. Bu bir günlük bir iş oldu ama başka yolu da yok.
KAMERAYA ERİŞİM ARAYÜZÜ
Kameranın 2×18 yani 18 pinli bir konnektörü var :
- 3V3 ve GND pinleri
- SCLK ve SDIO pinleri (SCCB arayüzü)
- XCLK pini
- VSYNC ve HREF pinleri
- PCLK pini
- D0 .. D7 8 adet piksel çıkış pini
- RESET ve PWDN pinleri
Bu pinlerden SCLK ve SDIO pinleri SCCB (Serial Camera Control Bus) olarak adlandırılan arayüze ait. Bu arayüz üzerinden kameranın 200 e yakın dahili kontrol kayıtçısına (registerine) erişiliyor.
VSYNC, HREF, PCLK ve D0..D7 pinleri üzerinden görüntüye ait piksel verilerini okuyoruz.
XCLK pini üzerinden kameranın çalışması için gereken saat sinyalini uyguluyoruz.
Diğer 4 pinin adları üzerlerinde zaten.
SCCB PROTOKOLU HAKKINDA
Kameranın kontrol kayıtçılarına erişmemizi sağlayan SCCB protokolu bildiğimiz I2C protokoluna çok benziyor, sadece ACK bitlerinde farklılıklar var. Anladığım kadarı ile Philips’e I2C protokolu için lisans ödemekten kaçınmak için böyle bir yola gitmişler. Yüksek hız gerektirmeyen bu arayüz üzerinden sadece 2 tel ile iletişim sağlanabiliyor. Protokol aynen I2C de olduğu gibi bir start biti ile başlayan 8 bitlik veri transferi, bunu izleyen bir don’t Care biti (Aslında ACK biti) ve en sonunda da bir Stop bitinden ibaret.
Pek çok uygulama geliştiricisi kameranın bu girişine mikro denetleyicinin I2C aracını kullanarak da erişiyor. Ama ben “bit bang” dedikleri teknikle yazdığım kod parçacıkları ile çalışmayı tercih ettim. Bu yayında o kodları paylaşacağım.
KAMERANIN ÇALIŞTIRILMASI
Kamera’ya 3V3 ve GND bağlantıları ile beslemesini verip XCLK pini üzerinden de 8 ila 24MHz arası bir saat sinyali uygulayınca çalışmaya ve görüntüye ait piksel bilgilerini vermeye başlıyor. Bu esnada PWDN pini “0” seviyesinde RESET pini de “1” seviyesinde tutulmalı.
XCLK sinyalini STM32 Mikro denetleyicisinin ana osilatör çıkışı olan PA8 – MCO pininden alıyorum. Piksel bilgileri D0 .. D7 pinlerinden 8 bit paralel formda alınıyor, bu akışı VSYNC, HREF ve PCLK sinyalleri ile senkronize olarak okuyabiliyoruz. 2 adet 8 bitlik veri bize bir adet RGB 565 piksel çerçevesini veriyor. Bu yayında piksel bilgilerinin okunmasını ele almayacağız.
STM32 YAPILANDIRMALARI
STM32 yi 72 MHz de çalışacak şekilde ayarlayıp, MCO çıkışını etkinleştiriyoruz. Bu durumda 8 MHz lik osilatör çıkışı PA8 e veriliyor. Bu da OV7670 in XCLK girişine bağlı.
Pin ayarları da aşağıdaki gibi. OV7670 in piksel bilgilerini alacağımız D0..D7 pinlerinin sırasız ve rasgele gibi görünen dağılımının nedeni kamera adaptör kartının PCB tasarımından kaynaklanıyor. PCB deki konnektörleri birbirini kesmeyen yollarla bağlayabilmek için böyle oldu. Yoksa kodlama kolaylığı açısından, bunların aynı GPIO portun pinlerine sıralı olarak bağlanmaları çok daha kullanışlı olurdu.
SCCB ÜZERİNDEN İLETİŞİM KODLARI
Ana programın başında PWDN ve RESET pinlerinin ayarlarını yapıyoruz.
Bunu SCCB arayüzünü test etmek üzere birkaç kayıtçıya yazıp okuduğumuz kod grubu izliyor. Burada resim frekansını ve çözünürlüğünü seçecek şekilde kamera ayarlarını yapıyoruz. Yazdığımız byteları geri okuyarak kodun çalışıp çalışmadığını kontrol ediyoruz. Olabildiğince küçük ve yavaş bir format seçeyim ki bunun ardından resim bilgilerini okurken zorlanmayayım istedim. (15 FPS ve 176×144).
KULANILAN FONKSİYONLAR
SCCB iletişim fonksiyonlarımı sccb.c adlı dosyaya koydum. Bunların ilk üçü her bir okuma yazma fazının başında sonunda kullandığımız Start, Stop ve NACK kod parçacıkları.
Bunların ardından OV7670 a 8 bitlik veri yazan/okuyan iki fonksiyon.
KAYITÇIDAN VERİ OKUMAK
SCCB üzerinden herhangi bir kayıtçının içeriğini okumak için önce okunacak kayıtçının seçimi için iki byte’lık bir yazma aşaması var. Bu byte’lardan ilki OV7670’in adresi olan 7 bitlik 0x21 “slave adresi” nin sonuna “0” eklenerek gönderiliyor. Yani 0x21 i 1 bit sola kaydırarak, 2 ile çarpmak anlamına geliyor, 0x42 gönderiyoruz. İkinci byte’da kayıtçının 8 bitlik adresi.
Ardından seçilmiş olan bu kayıtçıyı okumak için OV7670 adresini bu defa sonuna okuma komutu olan “1” ekleyerek 8 bit olarak gönderiyoruz. Bunu 8 bitlik kayıtçı adresinin gönderilmesi izliyor. Ondan sonra SDIO pinimizi INPUT konumuna getirerek OV7670 den gelen 8 bitlik veriyi geri okuyoruz.
Bunun sonucunda aşağıdaki sinyal akışını elde ediyoruz. Her bir sinyal bölümünde etkin olan program kodlarını sadeleştirilmiş olarak şeklin üzerine ekledim.
KAYITÇIYA VERİ YAZMAK
SCCB üzerinden bir kayıtçıya veri yazmak için OV7670 ın adresi olan 7 bitlik 0x21 kodunun sonuna yazma komutu olan “0” bitini ekleyerek gönderiyoruz, ardından 8 bitlik kayıtçı adresini, onun da ardından 8 bit olarak yazmak istediğimiz veriyi gönderiyoruz.
Bu kodun her 8 bitlik gönderimin sonunda verinin sağlıklı olarak alındığını kontrol ettiğini görebilirsiniz. Bu kodun sonucu aşağıdaki diyagramda göründüğü gibi oluyor.
SONUÇ
Böylece SCCB üzerinden OV7670 kayıtçılarını okuyup ayarları değiştirmek üzere bunlara yeni bir şeyler yazabilir duruma geldik.
Sırada daha çetin bir işlem var, görüntüye ilişkin pikselleri okuyup bunlar üzerinde bir şeyler yapmak. Pikselleri TFT de görüntülemek işin en kolay kısmı. Ama bunun ötesi bayağı zorlayıcı. Zira STM32F103 de piksel bilgilerini saklayacak kadar RAM yok. Bunun için TFT nin kendisinden yararlanacağız. Şimdiye kadar TFT ile tek yönlü iletişimim vardı, sadece yazıyor, geriye birşey okumuyordum. Şimdi ise TFT nin SPI Miso çıkışını da kullanmaya başlamak gerekecek.
Buna vakit ayırabileceğim zamana kadar, OV7670 i bir kenara bırakıyorum.
Her yazınız gibi sade ve Öğretici bir makale olmuş hocam, devamını merakla bekliyorum.
Merhaba, Delay_10us(delay) fonksiyonuna parametre olarak ne göndermemiz gerekiyor. delay değişkeninin değeri nedir?Delay_10us(1) yazdığımda 10us lik bir gecikme mi yapmış olurum? 10us lik bir timer kurmak gerekecek sanırım. Şimdiden teşekkür ederim. Verdiğiniz kıymetli bilgiler için de ayrıca teşekkürler.
Tolga Bey merhaba,
Evet, parametreyi 1 verdiğinizde 10µs gecikme veriyor. Benim kodlarımda buna atadığım değer “5”.
Selamlar,