4.14. أساسيات CSI¶
الوحدة csi هي الطريقة التي يقود بها كود Python مستشعر الكاميرا. وكل برنامج نصي يلتقط إطاراً يتبع الشكل ثلاثي الأجزاء نفسه: عمليات الاستيراد في الأعلى، والإعداد لمرة واحدة في الوسط، وحلقة while True في الأسفل تسحب الإطارات من الكاميرا واحداً تلو الآخر.
4.14.1. الحلقة النموذجية¶
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. ماذا يفعل كل استدعاء¶
import csi, image, timeتستورد ثلاث وحدات. تتحكم
csiفي المستشعر، وتعرّفimageالصنفImageالذي تُرجعهsnapshot()، وتوفرtimeالأداة المساعدةtime.clock()المستخدمة لقياس عدد الإطارات في الثانية.csi.CSI()تبني نسخة
CSIتغلّف مستشعر كاميرا فيزيائياً واحداً. ويطالب الباني بالطرفية الخاصة بالكاميرا ويسجّل الإعداد الخاص بكل مستشعر. الكاميرات ذات المستشعر الواحد لها نسخةCSIواحدة؛ والكاميرات ذات المستشعرين (ملون مع حراري، ملون مع حدثي) لها نسختان، تُختار كل منهما بوسيطةcidالمُمرَّرة إلى الباني.csi0.reset()تشغّل المستشعر وتعدّه. تنبض افتراضياً بدبوس إعادة الضبط للمستشعر، ثم تكتب سجلات I2C للمستشعر إلى حالة بدء معروفة. وتدفع استدعاءات الإعداد اللاحقة --
pixformatوframesizeومقابض التحكم التلقائي -- مزيداً من عمليات كتابة السجلات عبر ناقل تحكم I2C نفسه.csi0.pixformat(csi.RGB565)تكتب سجلات المستشعر التي تختار تنسيق بكسل الخرج. والخيارات المتاحة هي التنسيقات التي قدّمتها صفحة تنسيقات البكسل:
RGB565وGRAYSCALEوBAYERوYUV422وJPEGعلى المستشعرات التي تدعمه.csi0.framesize(csi.QVGA)تكتب السجلات التي تختار دقة الخرج.
QVGAهي 320 × 240؛ والأحجام المسماة تصل إلىWQXGA2(2592 × 1944، نحو 5 ميغابكسل) على المستشعرات التي تدعمها. وتعمل أيضاً مجموعة(width, height)مخصصة، طالما أنها تتوافق مع قدرات خرج المستشعر.clock = time.clock()تنشئ أداة ساعة مساعدة. ويسجّل كل استدعاء لـ
clock.tick()داخل الحلقة وقت بدء التكرار؛ وتُبلّغtime.clock.fps()عن معدل الحلقة الأخير بعدد الإطارات في الثانية.img = csi0.snapshot()تلتقط إطاراً واحداً من المستشعر وتُرجعه على هيئة
Image. وتستحق آلية وصول ذلك الإطار إلى الذاكرة نظرة أقرب.
4.14.3. كيف تملأ اللقطة الذاكرة¶
يسلّم المستشعر البكسلات على ناقل بيانات البكسل الموصوف في نواقل المستشعر بمعدلات تبلغ مئات الميغابايتات في الثانية -- أسرع بكثير من أن يتمكن المعالج المركزي من نسخها بكسلاً بكسلاً برمجياً.
بدلاً من ذلك، يفرّغ الـ MCU عملية النقل إلى الوصول المباشر للذاكرة (DMA) -- وهو محرك عتادي منفصل عن المعالج المركزي ينسخ البايتات من مكان إلى آخر داخل الـ MCU دون إشراك المعالج المركزي إطلاقاً. تلتقط طرفية دخل الكاميرا كل بايت بكسل وارد في FIFO صغير على الشريحة؛ وتعالج البيانات أثناء مرورها أيُّ مراحل ISP تعمل على جانب الـ MCU؛ ويكتب محرك DMA البكسلات النهائية في مخزن الإطارات في RAM عند إزاحة البكسل المقابلة. ولا يحتاج أي شيء في تلك السلسلة إلى المعالج المركزي بمجرد برمجة قناة DMA.
عند استدعاء snapshot():
يبرمج مشغّل CSI محرك DMA بعنوان مخزن الإطارات، وطول النقل (ما يعادل بكسلات إطار واحد)، ودالة رد نداء لمقاطعة اكتمال DMA.
يُمكّن المشغّل طرفية دخل الكاميرا وينتظر أن يشير المستشعر إلى بدء الإطار التالي.
أثناء بثّ المستشعر للإطار، تمرّر الطرفية كل بايت بكسل عبر الـ ISP ثم إلى محرك DMA، الذي يكتب النتيجة في RAM عند إزاحة مخزن الإطارات التالية. ويكون المعالج المركزي حراً لتشغيل كود آخر أثناء النقل.
عند وصول آخر بكسل في الإطار، يطلق DMA مقاطعة اكتماله، فيغلّف المشغّل مخزن الإطارات في
Image، وتُرجعهsnapshot()إلى كود المستخدم.
لا تمتلك Image المُرجَعة نسخة من بيانات البكسل -- بل تشير إلى أحد مخازن إطارات الكاميرا في RAM. أما عدد مخازن الإطارات التي تحتفظ بها الكاميرا، وكيفية تبادلها بين DMA وكود المستخدم في كل استدعاء لـ snapshot()، فيعتمد على وضع التخزين المؤقت الذي اختاره التطبيق عبر framebuffers().