تصحيح أخطاء وبرمجة وحدات التحكم الدقيقة atmega328 و stm32f303 من خلال أي واجهة ، مثل jtag

تتناول هذه المقالة أول مشروع مفتوح المصدر لي بعنوان "repl" (رابط إلى المستودع أدناه). تتمثل فكرة هذا المشروع في السماح لمبرمج وحدة التحكم الدقيقة بتصحيح أخطاء البرنامج في وحدة التحكم الدقيقة من خلال أي من واجهاته ، بينما لا يختلف تصحيح الأخطاء كثيرًا عن التصحيح من خلال واجهة jtag. كان من الممكن إيقاف البرنامج ، وتحديد نقاط التوقف ، وعرض السجلات ، والذاكرة ، عن طريق التصحيح الإرشادي للبرنامج.



أول ما يتبادر إلى الذهن هو إنشاء تطبيق 2x ، أحد الخيوط مسؤول عن واجهة تصحيح الأخطاء ، والآخر مسؤول عن برنامج المستخدم ، وهو ما قمت به. يتم التبديل بين الخيوط على جهاز توقيت ، ولكل مؤشر ترابط مكدس خاص به. قررت عدم استخدام مجموعة من الأدوات لكتابة واجهة تصحيح الأخطاء. يجب استخدامهما 2 مختلفين ، أو عند العمل مع كومة ، قم بالتبديل باستمرار إلى مؤشر ترابط واحد.



كانت الفكرة الأولى لتنفيذ تصحيح الأخطاء الإرشادية هي تقليل الوقت بين مقاطعات المؤقت بما يكفي بحيث يمكن تنفيذ تعليمة واحدة فقط. أظهر هذا الخيار عمله المثالي على متحكم Atmega328p ، والحقيقة هي أن الحد الأدنى من الوقت بين المقاطعات لـ Atmega هو ساعة معالج واحدة ، أي تعليمات ، بغض النظر عن عدد دورات الساعة المطلوبة لتنفيذه ، ستنتهي دائمًا إذا بدأ تنفيذه.



لسوء الحظ ، عندما قمت بالتبديل إلى stm32 ، لم يعمل هذا الخيار ، لأن نواة Cortex-M يمكنها مقاطعة تنفيذ التعليمات في المنتصف ، وبعد ذلك ، عند العودة من المقاطعة ، ابدأ في تنفيذها مرة أخرى. ثم قررت جيدًا ، لا توجد مشاكل ، سأزيد فقط عدد دورات الساعة بين المقاطعات حتى يتم تنفيذ التعليمات ، ثم عثرت على مشكلة أخرى ، يتم تنفيذ بعض التعليمات فقط مع التعليمات التي تتبعها أو لم يتم تنفيذها على الإطلاق ، وللأسف لا يمكن حل هذه المشكلة ، لذلك قررت أن تغيير جذري في النهج.



قررت محاكاة هذه التعليمات. للوهلة الأولى ، تبدو فكرة كتابة محاكي Cortex M core ، وحتى المحاكي الذي يتناسب مع ذاكرة وحدة التحكم الدقيقة ، فكرة رائعة. لكنني أدركت أنني لست بحاجة إلى محاكاة جميع التعليمات ، ولكن فقط تلك المرتبطة بعداد البرنامج ، لم يكن هناك الكثير منها. كل الباقي يمكنني ببساطة الانتقال إلى موقع ذاكرة آخر وتنفيذ هناك ، وحتى يتم تنفيذ تعليمة واحدة فقط ، أضف تعليمة الانتقال "ب" بعدها.



ثم جاء دور نقاط التوقف ، من أجل تنفيذها قررت استخدام تعليمة تنفذ while (1) ؛ المنطق. نستبدل التعليمات الموجودة على العنوان حيث نريد وضع نقطة التوقف وانتظار مقاطعة المؤقت. أفهم أن شيئًا ما مثل التعليمات التي من شأنها أن تطرح استثناء سيكون أفضل ، لكنني أردت إنشاء نسخة عالمية. عند تنفيذها ، نستبدل هذه التعليمات مرة أخرى. الخيار الجيد هو تنفيذ البرنامج في ذاكرة الوصول العشوائي للميكروكونترولر ، وإلا فإن ذاكرة فلاش المتحكم لن تدوم طويلاً. ولكن في هذه المرحلة ، كنت قد انتهيت بالفعل من كتابة محاكي تعليمات لـ stm32 وقررت لماذا لا أكتب نفس المحاكي لـ Atmega328 وكتبه. الآن لا تحتاج إلى استبدال التعليمات مرة أخرى ، يمكن محاكاتها.



من أجل تكوين صداقات مع بيئة وقت التشغيل ، أردت أولاً كتابة عميل gdb الخاص بي. لسوء الحظ ، يدعم واجهتين للعمل مع بيئة تطوير متكاملة. الأمر متروك لها لتقرر أي بيئة تطوير متكاملة يجب استخدامها. تنفيذ كلاهما (بدا لي الأول بسيطًا جدًا ، والثاني ليس جيدًا) ، بالإضافة إلى أنه كان عليّ دمج المصادر مع البرامج الثابتة ، والتي بدت لي فكرة غير جيدة جدًا. لذلك قررت أن أكتب gdbserver الخاص بي ، ولحسن الحظ لم يكن هناك سوى بروتوكول واحد وكان بسيطًا جدًا.



كانت الواجهة الأولى التي قررت تنفيذها هي GSM. كجهاز إرسال واستقبال ، قررت استخدام SIM800 ، كخادم ، خادم يدعم php. كانت الفكرة الرئيسية هي أنه بعد وصول طلب نشر من وحدة التحكم الدقيقة ، احتفظ بالاتصال بالميكروكونترولر لمدة 30 ثانية واتصل بقاعدة البيانات كل 100 مللي ثانية ، إذا ظهرت البيانات ، أرسلها كرد على الطلب وانتظر الطلب التالي من المتحكم الدقيق.



أظهر الاتصال الأول لعميل gdb بالخادم وجود عدد كبير جدًا من الطلبات من عميل gdb إلى الخادم باستخدام أمر الإيقاف المؤقت أو الخطوة. لذلك ، تقرر دمج كل هذه الطلبات في طلب واحد كبير للمتحكم الدقيق ، ولهذا فهمت منطق هذه الطلبات وتعلمت كيفية التنبؤ بها. الآن لم يتم تنفيذ هذه الأوامر بهذه السرعة ، أود أن يكون أسرع ، لكن يمكن تحمله.



كانت الواجهة التالية هي USB ، بالنسبة إلى متحكم Atmega328 ، قررت استخدام مكتبة V-usb. للعمل مع USB ، قمت بإعادة كتابة منطق أمر التشغيل. الآن لم يبدأ المتحكم الدقيق بعد هذا الأمر تشغيل البرنامج في انتظار أمر الإيقاف المؤقت ، فقد بدأ تشغيله لمدة ثانية واحدة ، ثم تم إرسال أمر تشغيل جديد إليه ، إلخ. هذا المنطق ضروري لأن أقوم بتعطيل الواجهة أثناء تشغيل البرنامج. لإنقاذ نفسي من مشكلة كتابة برنامج تشغيل ، قررت استخدام برنامج تشغيل قياسي. نظرًا لإخفاء ميزات الاتصال الحصول على تقرير الميزة ، تم إخفاء تقرير ميزة المجموعة.



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



لتقليل هذا الاختلاف ، قررت إعادة تسمية أقسام مصفوفة .text و .data و .bss و .contructors لجزء من برنامج المستخدم (يختلف الاسم العام باختلاف وحدات التحكم الدقيقة) ووضعها في الذاكرة بعد البرنامج الرئيسي مباشرةً.



كان علي أيضًا كتابة الوظائف الخاصة بي لتهيئة هذه الأقسام. الآن ، في معظم الحالات ، يكون تغيير البرنامج الصغير مساويًا لتغيير ثنائي صغير يساوي كمية صغيرة من البيانات التي يتم نقلها. نتيجة لذلك ، غالبًا ما تومض وحدة التحكم الدقيقة بشكل أسرع من عمل أوامر RUN و STEP و PAUSE.



وأخيرًا ، فيديو عن العمل:



تصحيح أخطاء Stm32 عبر واجهة USB.





تصحيح أخطاء STM32 عبر واجهة gsm.





تصحيح أخطاء Atmega328 عبر واجهة USB.





تصحيح أخطاء Atmega328 عبر واجهة gsm.





مستودع Git



All Articles