4.14. CSI temelleri

csi modülü, Python kodunun kamera sensörünü sürme şeklidir. Bir çerçeve yakalayan her betik aynı üç parçalı yapıyı izler: en üstte içe aktarmalar, ortada tek seferlik yapılandırma ve en altta kameradan çerçeveleri teker teker çeken bir while True döngüsü.

4.14.1. Tipik döngü

import csi, image, time

csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.QVGA)

clock = time.clock()
while True:
    clock.tick()
    img = csi0.snapshot()
    # process img here
    print(clock.fps())

4.14.2. Her çağrının yaptığı şey

import csi, image, time

Üç modülü içe aktarır. csi sensörü kontrol eder, image snapshot() tarafından döndürülen Image sınıfını tanımlar ve time, saniye başına çerçeveyi ölçmek için kullanılan time.clock() yardımcısını sağlar.

csi.CSI()

Tek bir fiziksel kamera sensörünü saran bir CSI örneği oluşturur. Yapıcı, kamera çevre birimini talep eder ve sensöre özgü yapılandırmayı kaydeder. Tek sensörlü kameraların bir CSI örneği vardır; iki sensörlü kameraların (renkli artı termal, renkli artı olay) ise her biri yapıcıya verilen bir cid argümanıyla seçilen iki örneği vardır.

csi0.reset()

Sensörü besler ve yapılandırır. Varsayılan olarak sensörün sıfırlama pinini darbeler, ardından sensörün I2C yazmaçlarına bilinen bir başlangıç durumu yazar. Sonraki yapılandırma çağrıları – pixformat, framesize, otomatik kontrol düğmeleri – aynı I2C kontrol veri yolu üzerinden daha fazla yazmaç yazması iter.

csi0.pixformat(csi.RGB565)

Çıkış piksel biçimini seçen sensör yazmaçlarını yazar. Mevcut seçenekler piksel biçimleri sayfasının tanıttığı biçimlerdir: RGB565, GRAYSCALE, BAYER, YUV422 ve destekleyen sensörlerde JPEG.

csi0.framesize(csi.QVGA)

Çıkış çözünürlüğünü seçen yazmaçları yazar. QVGA 320 × 240’tır; adlandırılmış boyutlar, destekleyen sensörlerde WQXGA2 (2592 × 1944, yaklaşık 5 MP) değerine kadar çıkar. Sensörün çıkış yetenekleriyle hizalandığı sürece özel bir (width, height) demeti de çalışır.

clock = time.clock()

Bir clock yardımcısı oluşturur. Döngü içindeki her clock.tick() çağrısı yineleme başlangıç zamanını kaydeder; time.clock.fps() son döngü hızını saniye başına çerçeve olarak bildirir.

img = csi0.snapshot()

Sensörden bir çerçeve yakalar ve onu bir Image olarak döndürür. O çerçevenin belleğe nasıl ulaştığının mekaniği daha yakından incelenmeye değerdir.

4.14.3. snapshot belleği nasıl doldurur

Sensör, pikselleri sensör veri yolları içinde açıklanan piksel-veri yolunda saniye başına yüzlerce megabayt hızında teslim eder – CPU’nun yazılımda piksel piksel kopyalaması için fazlasıyla hızlı.

Bunun yerine MCU, aktarımı Doğrudan Bellek Erişimi‘ne (DMA) devreder – CPU’dan ayrı, baytları CPU’yu hiç dahil etmeden MCU içinde bir yerden başka bir yere kopyalayan bir donanım motoru. Kamera giriş çevre birimi, gelen her piksel baytını küçük bir yonga üzeri FIFO’ya yakalar; MCU tarafında çalışan ISP aşamaları verileri geçiş sırasında işler; ve DMA motoru tamamlanmış pikselleri RAM’deki bir framebuffer’a karşılık gelen piksel ofsetine yazar. DMA kanalı programlandıktan sonra bu zincirde hiçbir şeyin CPU’ya ihtiyacı yoktur.

snapshot() çağrıldığında:

  1. CSI sürücüsü, DMA motorunu framebuffer’ın adresi, aktarım uzunluğu (bir çerçevelik piksel) ve DMA-tamamlandı kesmesi için bir geri çağırma ile programlar.

  2. Sürücü, kamera giriş çevre birimini etkinleştirir ve sensörün bir sonraki çerçevenin başlangıcını bildirmesini bekler.

  3. Sensör çerçeveyi akıttıkça, çevre birimi her piksel baytını ISP’den ve oradan DMA motoruna geçirir; DMA motoru sonucu RAM’de bir sonraki framebuffer ofsetine yazar. CPU, aktarım sırasında başka kod çalıştırmakta serbesttir.

  4. Çerçevenin son pikseli geldiğinde, DMA tamamlandı kesmesini ateşler, sürücü framebuffer’ı bir Image içine sarar ve snapshot() onu kullanıcı koduna döndürür.

Döndürülen Image, piksel verisinin bir kopyasına sahip değildir – RAM’deki kamera framebuffer’larından birine işaret eder. Kameranın kaç framebuffer tuttuğu ve her snapshot() çağrısında bunların DMA ile kullanıcı kodu arasında nasıl el değiştirdiği, uygulamanın framebuffers() aracılığıyla seçtiği arabelleğe alma moduna bağlıdır.