4.14. CSI alapok¶
A csi modullal a Python kód a kamera érzékelőjét vezérli. Minden szkript, amely képkockát rögzít, ugyanazt a háromrészes alakot követi: az importok legfelül, az egyszeri konfiguráció középen, és egy while True ciklus legalul, amely egyenként húzza be a képkockákat a kamerából.
4.14.1. A jellemző ciklus¶
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. Mit csinál az egyes hívások¶
import csi, image, timeBehoz három modult. A
csiaz érzékelőt vezérli, azimagedefiniálja azImageosztályt, amelyet asnapshot()ad vissza, aztimepedig biztosítja a másodpercenkénti képkockák mérésére használttime.clock()segédfüggvényt.csi.CSI()Létrehoz egy
CSIpéldányt, amely egy fizikai kamerás érzékelőt csomagol be. A konstruktor lefoglalja a kamera perifériát, és rögzíti az érzékelőnkénti konfigurációt. Az egyetlen érzékelővel rendelkező kameráknak egyCSIpéldányuk van; a két érzékelővel rendelkező kameráknak (szín plusz hő, szín plusz esemény) kettő, amelyeket a konstruktor egycidargumentuma választ ki.csi0.reset()Tápfeszültséget ad és konfigurálja az érzékelőt. Alapértelmezés szerint impulzust ad az érzékelő reset lábára, majd beírja az érzékelő I2C regisztereit egy ismert kiindulási állapotba. A további konfigurációs hívások –
pixformat,framesize, az automatikus vezérlési gombok – további regiszterírásokat küldenek ugyanazon az I2C vezérlőbuszon.csi0.pixformat(csi.RGB565)Beírja azokat az érzékelőregisztereket, amelyek a kimeneti képpontformátumot választják ki. Az elérhető lehetőségek a képpontformátumok oldalon bemutatott formátumok:
RGB565,GRAYSCALE,BAYER,YUV422ésJPEGaz ezt támogató érzékelőkön.csi0.framesize(csi.QVGA)Beírja azokat a regisztereket, amelyek a kimeneti felbontást választják ki. A
QVGA320 × 240; a megnevezett méretek egészen aWQXGA2-ig (2592 × 1944, körülbelül 5 MP) terjednek az ezt támogató érzékelőkön. Egy egyéni(width, height)tuple is működik, amennyiben illeszkedik az érzékelő kimeneti képességeihez.clock = time.clock()Létrehoz egy clock segédet. A ciklusban minden
clock.tick()hívás rögzíti az iteráció kezdési idejét; atime.clock.fps()a közelmúltbeli ciklussebességet jelenti másodpercenkénti képkockákban.img = csi0.snapshot()Rögzít egy képkockát az érzékelőről, és
Imageobjektumként adja vissza. Érdemes közelebbről megnézni annak mechanikáját, ahogyan az a képkocka a memóriába kerül.
4.14.3. Hogyan tölti fel a snapshot a memóriát¶
Az érzékelő a érzékelőbuszok oldalon leírt képpontadat-buszon másodpercenként több száz megabájtos sebességgel szállítja a képpontokat – ez túlságosan gyors ahhoz, hogy a CPU képpontról képpontra szoftveresen másolja.
Ehelyett az MCU a közvetlen memóriahozzáférésre (DMA) hárítja az átvitelt – ez a CPU-tól független hardveres motor, amely a CPU bevonása nélkül másol bájtokat egyik helyről a másikra az MCU-n belül. A kamera bemeneti perifériája minden beérkező képpontbájtot egy kis chipen lévő FIFO-ba fog be; az MCU-oldalon futó ISP-szakaszok útközben feldolgozzák az adatot; a DMA-motor pedig a megfelelő képpont-eltolásnál a RAM-ban lévő képkocka-pufferbe írja a kész képpontokat. Ebben a láncban semmihez sincs szükség a CPU-ra, miután a DMA-csatornát beprogramozták.
Amikor a snapshot() meghívásra kerül:
A CSI meghajtó beprogramozza a DMA-motort a képkocka-puffer címével, az átvitel hosszával (egy képkockányi képpont) és egy visszahívással a DMA-kész megszakításhoz.
A meghajtó engedélyezi a kamera bemeneti perifériáját, és megvárja, amíg az érzékelő jelzi a következő képkocka kezdetét.
Ahogy az érzékelő kiküldi a képkockát, a periféria minden képpontbájtot átad az ISP-n keresztül a DMA-motornak, amely a következő képkocka-puffer eltolásnál a RAM-ba írja az eredményt. A CPU szabadon futtathat más kódot az átvitel alatt.
Amikor a képkocka utolsó képpontja megérkezik, a DMA kiváltja a kész megszakítását, a meghajtó becsomagolja a képkocka-puffert egy
Imageobjektumba, és asnapshot()visszaadja azt a felhasználói kódnak.
A visszaadott Image nem birtokol másolatot a képpontadatokról – a kamera valamelyik RAM-ban lévő képkocka-pufferére mutat. Hogy a kamera hány képkocka-puffert tart fenn, és hogy ezeket a DMA és a felhasználói kód között hogyan adják át a snapshot() minden hívásánál, attól a pufferelési módtól függ, amelyet az alkalmazás a framebuffers() segítségével választott ki.