4.14. CSI:n perusteet¶
csi-moduuli on tapa, jolla Python-koodi ohjaa kamerasensoria. Jokainen kehyksen kaappaava skripti noudattaa samaa kolmiosaista rakennetta: tuonnit ylhäällä, kertaluonteinen konfigurointi keskellä, ja while True -silmukka alhaalla, joka hakee kehyksiä kamerasta yksi kerrallaan.
4.14.1. Tyypillinen silmukka¶
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ä kukin kutsu tekee¶
import csi, image, timeTuo kolme moduulia.
csiohjaa sensoria,imagemääritteleeImage-luokan, jonkasnapshot()palauttaa, jatimetarjoaatime.clock()-apurin, jota käytetään kehysten sekuntinopeuden mittaamiseen.csi.CSI()Rakentaa
CSI-instanssin, joka kääräisee yhden fyysisen kamerasensorin. Konstruktori varaa kameran oheislaitteen ja tallentaa sensorikohtaisen konfiguraation. Yhden sensorin kameroilla on yksiCSI-instanssi; kahden sensorin kameroilla (väri plus lämpö, väri plus tapahtuma) on kaksi, joista kukin valitaan konstruktorincid-argumentilla.csi0.reset()Käynnistää ja konfiguroi sensorin. Oletuksena se pulssittaa sensorin reset-nastaa, sitten kirjoittaa sensorin I2C-rekisterit tunnettuun aloitustilaan. Seuraavat konfigurointikutsut –
pixformat,framesize, automaattisäätönupit – työntävät lisää rekisterikirjoituksia saman I2C-ohjausväylän kautta.csi0.pixformat(csi.RGB565)Kirjoittaa sensorirekisterit, jotka valitsevat ulostulon pikselimuodon. Saatavilla olevat vaihtoehdot ovat ne muodot, jotka pikselimuodot -sivu esitteli:
RGB565,GRAYSCALE,BAYER,YUV422jaJPEGniillä sensoreilla, jotka sitä tukevat.csi0.framesize(csi.QVGA)Kirjoittaa rekisterit, jotka valitsevat ulostuloresoluution.
QVGAon 320 × 240; nimetyt koot ulottuvat ainaWQXGA2-kokoon (2592 × 1944, noin 5 MP) niillä sensoreilla, jotka niitä tukevat. Mukautettu(width, height)-monikko toimii myös, kunhan se vastaa sensorin ulostulokyvykkyyksiä.clock = time.clock()Luo kelloapurin. Jokainen
clock.tick()-kutsu silmukan sisällä tallentaa iteraation aloitusajan;time.clock.fps()raportoi viimeaikaisen silmukkanopeuden kehyksinä sekunnissa.img = csi0.snapshot()Kaappaa yhden kehyksen sensorista ja palauttaa sen
Image-oliona. Sen mekaniikka, miten kyseinen kehys päätyy muistiin, ansaitsee lähemmän tarkastelun.
4.14.3. Miten snapshot täyttää muistin¶
Sensori toimittaa pikselit pikselidataväylällä, joka kuvataan kohdassa sensoriväylät, satojen megatavujen sekuntinopeudella – aivan liian nopeasti, jotta CPU ehtisi kopioida pikseli pikseliltä ohjelmistossa.
Sen sijaan MCU siirtää siirron suoramuistinkäytölle (DMA) – CPU:sta erilliselle laitteistomoottorille, joka kopioi tavuja paikasta toiseen MCU:n sisällä ilman CPU:n osallistumista lainkaan. Kameran syöttöoheislaite nappaa kunkin saapuvan pikselitavun pieneen sirun sisäiseen FIFO:on; mitkä tahansa MCU:n puolella suoritettavat ISP-vaiheet käsittelevät datan matkan varrella; ja DMA-moottori kirjoittaa valmiit pikselit RAM:issa olevaan kehyspuskuriin vastaavaan pikselisiirtymään. Mikään tuossa ketjussa ei tarvitse CPU:ta sen jälkeen kun DMA-kanava on ohjelmoitu.
Kun snapshot() kutsutaan:
CSI-ajuri ohjelmoi DMA-moottorin kehyspuskurin osoitteella, siirron pituudella (yhden kehyksen verran pikseleitä) ja takaisinkutsulla DMA-valmis-keskeytystä varten.
Ajuri ottaa kameran syöttöoheislaitteen käyttöön ja odottaa, että sensori signaloi seuraavan kehyksen alun.
Kun sensori virtauttaa kehystä ulos, oheislaite luovuttaa kunkin pikselitavun ISP:n läpi ja edelleen DMA-moottorille, joka kirjoittaa tuloksen RAM:iin seuraavaan kehyspuskurisiirtymään. CPU on vapaa suorittamaan muuta koodia siirron aikana.
Kun kehyksen viimeinen pikseli saapuu, DMA laukaisee valmis-keskeytyksensä, ajuri kääräisee kehyspuskurin
Image-olioon, jasnapshot()palauttaa sen käyttäjäkoodille.
Palautettu Image ei omista kopiota pikselidatasta – se osoittaa yhteen kameran kehyspuskureista RAM:issa. Kuinka monta kehyspuskuria kamera pitää, ja miten ne luovutetaan DMA:n ja käyttäjäkoodin välillä jokaisella snapshot() -kutsulla, riippuu puskurointitilasta, jonka sovellus on valinnut framebuffers() -metodin kautta.