تسارع MicroPython

MicroPython هو تطبيق لغة برمجة Python لأجهزة التحكم الدقيقة التي تمكن جمهور هذه اللغة باستخدام قواعد بناء الجملة المألوفة ومبادئ البرمجة للعمل مع أجهزة الحوسبة الصغيرة.

في عملي ، استخدم MicroPython لنموذج أولي ، واختبار الأفكار بسرعة وإنشاء مواقف صغيرة. بفضل برنامج REPL وصياغته البسيطة ، يعد MicroPython مثالياً لمشاريع DIY وللتدريس في البرمجة.

عندما يتعلق الأمر بتفاعل أجهزة الكمبيوتر مع العالم الحقيقي ، فإنني مهتم دائمًا بسرعة تفاعلها. في بعض الحالات ، استخدام تكنولوجيا المعالجات الدقيقة ، على سبيل المثال في مجال إنترنت الأشياء ، سرعة رد فعل الجهاز ليست مهمة للغاية. لا يوجد فرق كبير عند تشغيل صفارة الإنذار: 10 ميكروثانية بعد اكتشاف الحركة أو 10 مللي ثانية.

لكن في بعض الجوانب ، تكون السرعة وفترة رد الفعل مهمة ويثور سؤال حول ما إذا كان يجب استخدام MicroPython. لقد أجريت القليل من البحث ، وهو مستوحى من الفيديو من خطاب خالق MicroPython Damien George. تساءلت عن مدى سرعة استجابة البرنامج المكتوب في Micropython لتأثير المدخلات.

سيكون الجهاز التجريبي هو متحكم ESP8266 ، على لوحة NodeMcu مع إصدار MicroPython esp8266-2018511-v1.9.4.



سوف أضغط على الزر وأن أسجل على مرسمة الذبذبة فارق التوقيت بين الضغط وظهور 3.3 فولت على الساق الأخرى للمعالج الدقيق. يتم كل قياس 15 مرة ، يتم أخذ المتوسط ​​(كما هو موضح في الرسوم البيانية) ويتم حساب الانحراف المعياري (شريط أسود في الرسوم البيانية).

اختبار رقم 1.


إذا قمت بحل هذه المشكلة "بشكل مباشر" ، فسيبدو البرنامج بسيطًا:

import machine import time o = machine.Pin(5, machine.Pin.OUT) #D1 out i = machine.Pin(4, machine.Pin.IN) #D2 in while 1: if i.value(): o.value(1) time.sleep(0.1) o.value(0) 

شكل الموجة النموذجي مع مثل هذا البرنامج يشبه هذا:



هنا وعلى أشكال الطول الموجي الأخرى ، الإشارة "الزرقاء" هي الدبوس بالزر ، دبوس الاستجابة "الأخضر". مع 15 التكرار ، يتم الحصول على الصورة التالية:



في المتوسط ​​، يبلغ وقت رد الفعل حوالي 310 ميكروثانية ، والحد الأقصى هو 356 ،s ، وليس بسرعة كبيرة ، ولكن بالنسبة لبعض التطبيقات يكون مقبولًا تمامًا.

اختبار رقم 2


يمكنك تسريع الكود القياسي "خارج الصندوق" من خلال التعامل مع المقاطعة.

 import machine import time o = machine.Pin(5, machine.Pin.OUT) #D1 out i = machine.Pin(4, machine.Pin.IN) #D2 in def f(_): o.value(1) time.sleep(0.1) o.value(0) i.irq(trigger=machine.Pin.IRQ_RISING, handler=f) 

والصورة هي كما يلي:




والحد الأقصى لوقت الاستجابة هو 306 μs.

يعطي استخدام المقاطعات زيادة في سرعة حوالي 20 ٪ ، ولكن في الوقت نفسه يعطي انتشار كبير نوعا ما في وقت الاستجابة.

اختبار رقم 3


إذا كانت السرعات التي تم الحصول عليها غير كافية ، فإن الخطوة التالية هي استخدام البناء micropython.native @ ، مما يجعل من الممكن تحويل رمز Python إلى رمز الجهاز الأصلي. ولكن هناك بعض القيود .

خيار الكود:

 import machine import time o = machine.Pin(5, machine.Pin.OUT) #D1 out i = machine.Pin(4, machine.Pin.IN) #D2 in @micropython.native def f(): while 1: if i.value(): o.value(1) time.sleep(0.1) o.value(0) f() 

نمط استجابة نموذجي على الموجي:



مقارنة بالطريقة السابقة ، يتم مضاعفة التسارع تقريبًا:



أطول وقت استجابة هو 128 μs.

اختبار رقم 4


تتمثل الخطوة التالية في البحث عن MicroPython "سريع" في استخدام @ micropython.viper بناء والوصول إلى سجلات المعالج الدقيق مباشرة (يمكن العثور على عناوين التسجيل هنا .

 import time @micropython.viper def f(): O = ptr32(0x60000300) #  GPIO ESP8266 while 1: s = ((O[6] & 0x10) >> 4) #    4  if s: O[1] = 0x20 # 5  time.sleep(0.1) O[2] = 0x20 # 5  f() 

ونتيجة لذلك ، تسارعت الاستجابة بشكل ملحوظ:



زمن الاستجابة صغير جدًا ولا يمكن مقارنته بطرق أخرى (بحد أقصى 820 ns):





إذا لم يكن ذلك كافيًا ، فيمكنك استخدام أداة إدراج المجمّع من خلال @ micropython.asm_thumb decorator. مع هذه الطريقة ، لا يبقى الثعبان بشكل خاص (وتضيع المزايا العالية المستوى لبيثون) ، وإذا كانت هناك حاجة إلى سرعات أعلى ، فمن الأفضل استخدام أجهزة أخرى ، على سبيل المثال FPGA (حيث يمكن لبيثون أن يكون مفيدًا أيضًا ، انظر هنا وهنا ).

UART


إذا كانت هناك حاجة لنقل الكثير من المعلومات بعد حدث ما ، يمكنك استخدام واجهة UART التسلسلية.

خذ على سبيل المثال خيارين للتنفيذ.

الأول هو من خلال معالجة المقاطعة:

 import machine i = machine.Pin(4, machine.Pin.IN) #D2 in ua = machine.UART(1) ua.init(1000000) def f(_): ua.write(b'\x01') i.irq(trigger=machine.Pin.IRQ_RISING, handler=f) 

والاستجابة الموجي:



وقت الاستجابة الأقصى هو 248 μs.
والاختبار الثاني من خلال الافعى:

 import machine import time i = machine.Pin(4, machine.Pin.IN) #D2 in ua = machine.UART(1) ua.init(1000000) @micropython.viper def f(): O = ptr32(0x60000300) while 1: if ((O[6] & 0x10) >> 4): ua.write(b'\x01') time.sleep(0.1) f() 

والشكل الموجي في الاختبار الثاني:



الحد الأقصى لوقت الاستجابة مع هذا الرمز هو 71 μs.
متوسط ​​زمن التفاعل في اختبارين:



يتم تحقيق تسارع التفاعل بسبب الكشف السريع عن تأثير المدخلات في الاختبار الثاني.

استنتاج


يسمح لك MicroPython باستخدام أشياء مميزة للغات عالية المستوى (OOP ، معالجة الاستثناءات ، تصورات القائمة والقوائم ، إلخ) عند برمجة المتحكمات الدقيقة ، وإذا لزم الأمر ، تسريع رمز Python "الكلاسيكي" بشكل كبير.

Source: https://habr.com/ru/post/ar448702/


All Articles