4.14. CSI-basis¶
De csi-module is de manier waarop Python-code de camerasensor aanstuurt. Elk script dat een frame vastlegt volgt dezelfde driedelige vorm: imports bovenaan, eenmalige configuratie in het midden, en een while True-lus onderaan die frames één voor één van de camera ophaalt.
4.14.1. De typische lus¶
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. Wat elke aanroep doet¶
import csi, image, timeBrengt drie modules binnen.
csibestuurt de sensor,imagedefinieert deImage-klasse diesnapshot()retourneert, entimelevert detime.clock()-helper die wordt gebruikt om frames per seconde te meten.csi.CSI()Construeert een
CSI-instantie die één fysieke camerasensor omhult. De constructor claimt het camerarandapparaat en registreert de configuratie per sensor. Camera’s met een enkele sensor hebben éénCSI-instantie; camera’s met twee sensoren (kleur plus thermisch, kleur plus event) hebben er twee, elk geselecteerd door eencid-argument aan de constructor.csi0.reset()Voorziet de sensor van stroom en configureert deze. Standaard pulseert het de reset-pin van de sensor en schrijft het vervolgens de I2C-registers van de sensor naar een bekende beginstaat. Daaropvolgende configuratieaanroepen –
pixformat,framesize, de automatische-controleknoppen – sturen meer registerschrijfacties over dezelfde I2C-controlebus.csi0.pixformat(csi.RGB565)Schrijft de sensorregisters die het uitvoerpixelformaat kiezen. De beschikbare keuzes zijn de formaten die de pagina pixelformaten introduceerde:
RGB565,GRAYSCALE,BAYER,YUV422, enJPEGop de sensoren die het ondersteunen.csi0.framesize(csi.QVGA)Schrijft de registers die de uitvoerresolutie kiezen.
QVGAis 320 × 240; de benoemde groottes lopen op totWQXGA2(2592 × 1944, ongeveer 5 MP) op sensoren die ze ondersteunen. Een aangepaste(width, height)-tuple werkt ook, zolang die overeenkomt met de uitvoermogelijkheden van de sensor.clock = time.clock()Maakt een klokhelper. Elke aanroep van
clock.tick()binnen de lus registreert de starttijd van de iteratie;time.clock.fps()rapporteert de recente lussnelheid in frames per seconde.img = csi0.snapshot()Legt één frame van de sensor vast en retourneert het als een
Image. De mechaniek van hoe dat frame in het geheugen terechtkomt is een nadere blik waard.
4.14.3. Hoe snapshot het geheugen vult¶
De sensor levert pixels op de pixeldatabus die wordt beschreven in sensorbussen met snelheden van honderden megabytes per seconde – veel te snel voor de CPU om pixel voor pixel in software te kopiëren.
In plaats daarvan draagt de MCU de overdracht over aan Direct Memory Access (DMA) – een hardware-engine los van de CPU die bytes van de ene plaats naar de andere kopieert binnen de MCU zonder de CPU er ook maar bij te betrekken. Het camera-invoerrandapparaat vangt elke binnenkomende pixelbyte op in een kleine FIFO op de chip; de ISP-fasen die aan de MCU-zijde draaien verwerken de gegevens onderweg; en de DMA-engine schrijft de voltooide pixels naar een framebuffer in RAM op de bijbehorende pixeloffset. Niets in die keten heeft de CPU nodig zodra het DMA-kanaal is geprogrammeerd.
Wanneer snapshot() wordt aangeroepen:
De CSI-driver programmeert de DMA-engine met het adres van de framebuffer, de overdrachtslengte (de pixels van één frame), en een callback voor de DMA-klaar-interrupt.
De driver schakelt het camera-invoerrandapparaat in en wacht tot de sensor het begin van het volgende frame aangeeft.
Terwijl de sensor het frame uitstroomt, geeft het randapparaat elke pixelbyte door de ISP en verder naar de DMA-engine, die het resultaat naar RAM schrijft op de volgende framebuffer-offset. De CPU is vrij om tijdens de overdracht andere code uit te voeren.
Wanneer de laatste pixel van het frame aankomt, vuurt de DMA zijn klaar-interrupt af, omhult de driver de framebuffer in een
Image, en retourneertsnapshot()deze aan gebruikerscode.
De geretourneerde Image bezit geen kopie van de pixelgegevens – het wijst naar een van de framebuffers van de camera in RAM. Hoeveel framebuffers de camera bijhoudt, en hoe ze bij elke aanroep van snapshot() tussen de DMA en gebruikerscode worden doorgegeven, hangt af van de buffermodus die de toepassing heeft geselecteerd via framebuffers().