4.14. Grunderna i CSI¶
Modulen csi är hur Python-kod styr kamerasensorn. Varje skript som fångar en bildruta följer samma tredelade form: importer högst upp, engångskonfiguration i mitten och en while True-slinga längst ner som hämtar bildrutor från kameran en i taget.
4.14.1. Den typiska slingan¶
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. Vad varje anrop gör¶
import csi, image, timeTar in tre moduler.
csistyr sensorn,imagedefinierar klassenImagesomsnapshot()returnerar, ochtimetillhandahåller hjälpfunktionentime.clock()som används för att mäta bildrutor per sekund.csi.CSI()Konstruerar en
CSI-instans som omsluter en fysisk kamerasensor. Konstruktorn tar i anspråk kamerakringutrustningen och registrerar den sensorvisa konfigurationen. Kameror med en enda sensor har enCSI-instans; kameror med två sensorer (färg plus termisk, färg plus händelse) har två, var och en vald med ettcid-argument till konstruktorn.csi0.reset()Strömsätter och konfigurerar sensorn. Som standard pulsar den sensorns reset-stift och skriver sedan sensorns I2C-register till ett känt startläge. Efterföljande konfigurationsanrop –
pixformat,framesize, autostyrningsrattarna – skickar fler registerskrivningar över samma I2C-styrbuss.csi0.pixformat(csi.RGB565)Skriver de sensorregister som väljer utdatapixelformatet. De tillgängliga valen är de format som sidan pixelformat introducerade:
RGB565,GRAYSCALE,BAYER,YUV422ochJPEGpå de sensorer som stöder det.csi0.framesize(csi.QVGA)Skriver de register som väljer utdataupplösningen.
QVGAär 320 × 240; de namngivna storlekarna går upp tillWQXGA2(2592 × 1944, ungefär 5 MP) på sensorer som stöder dem. En egen(width, height)-tupel fungerar också, så länge den stämmer med sensorns utdataförmåga.clock = time.clock()Skapar en clock-hjälpare. Varje anrop till
clock.tick()inuti slingan registrerar iterationens starttid;time.clock.fps()rapporterar den senaste slinghastigheten i bildrutor per sekund.img = csi0.snapshot()Fångar en bildruta från sensorn och returnerar den som en
Image. Mekaniken bakom hur den bildrutan hamnar i minnet är värd en närmare titt.
4.14.3. Hur snapshot fyller minnet¶
Sensorn levererar pixlar på pixeldatabussen som beskrivs i sensorbussar med hastigheter på hundratals megabyte per sekund – alldeles för snabbt för att CPU:n ska kopiera pixel för pixel i mjukvara.
I stället avlastar MCU:n överföringen till Direct Memory Access (DMA) – en hårdvarumotor skild från CPU:n som kopierar bytes från en plats till en annan inuti MCU:n utan att alls involvera CPU:n. Kameraingångskringutrustningen fångar varje inkommande pixelbyte i en liten FIFO på chippet; de ISP-steg som körs på MCU-sidan bearbetar data på vägen igenom; och DMA-motorn skriver de färdiga pixlarna till en bildbuffert i RAM vid motsvarande pixeloffset. Inget i den kedjan behöver CPU:n när väl DMA-kanalen har programmerats.
När snapshot() anropas:
CSI-drivrutinen programmerar DMA-motorn med bildbuffertens adress, överföringslängden (en bildrutas värde av pixlar) och ett återanrop för DMA-klart-avbrottet.
Drivrutinen aktiverar kameraingångskringutrustningen och väntar på att sensorn ska signalera starten på nästa bildruta.
När sensorn strömmar ut bildrutan skickar kringutrustningen varje pixelbyte genom ISP:n och vidare till DMA-motorn, som skriver resultatet till RAM vid nästa bildbuffertoffset. CPU:n är fri att köra annan kod under överföringen.
När bildrutans sista pixel anländer utlöser DMA:n sitt klart-avbrott, drivrutinen omsluter bildbufferten i en
Image, ochsnapshot()returnerar den till användarkoden.
Den Image som returneras äger inte en kopia av pixeldata – den pekar på en av kamerans bildbuffertar i RAM. Hur många bildbuffertar kameran håller, och hur de lämnas mellan DMA:n och användarkoden vid varje anrop till snapshot(), beror på det buffringsläge som tillämpningen har valt via framebuffers().