المقابس لا مفر منها عند تطوير أي برنامج. في إحدى الزخارف ، يمكن لخمسة سنتات سخيّة أن تتسبب في مشاكل الأجهزة ، لكن هذه أغنية منفصلة. لكن كمائن مبرمجة بحتة ، عندما تتعثر في مكان فارغ على ما يبدو ... بالنسبة لي هناك ثلاثة أنواع منها.
أسهل طريقة هي عندما يكون الفهم اليدوي أو القياسي أو ، على سبيل المثال ، إجراء تكوين مكتبة الحديد. من الواضح هنا: لم يتم استنفاد جميع التحركات ، والصبر والعمل ، وخمس أو تجربتين أخريين ، وسيأتي إلى الحياة. الذبذبات و tyk العلمية للمساعدة.
اختيار مقسم تردد لإعدادات حافلة CANوالأسوأ من ذلك ، عندما تكون المشكلة هي خطأ مطبعي أو خطأ في المنطق ، لا يمكنك رؤية نقطة فارغة حتى تتجول في هذا المكان عشرين مرة بأعينك وتصحيح الأخطاء خطوة بخطوة. ثم فجر ، ضربة قوية إلى الجبين ، صرخة ، "حسنًا ، أنت من باباي!" ، التحرير. إنه يعمل.
وجهة نظر ثالثة قاتمة: خلل راسخ في مكتبة أجنبية والزحف عند مفترق طرق بالحديد. تثير عواطف شكسبير الضوء الثابت للشاشة. "لماذا لا يستطيع النظام أن يتصرف بهذه الطريقة ، لأنه لا يمكن أبدًا! حسنا حقا! آه؟! " كلا. تلقي ، علامة.
ونتيجة لذلك ، فإن الواقع أوسع وأوسع وأوسع من المتوقع. بعض الأمثلة:
التاريخ رقم 1. MicroSD محرك أقراص فلاش والعمل DMA
تاريخ
تحتاج إلى تفريغ البيانات إلى ملف على بطاقة SD. بالطبع ، ليس لدي وقت ولا رغبة في كتابة نظام الملفات وبرنامج تشغيل SDIO بنفسي ، لذلك آخذ المكتبة المكتملة. أنا وضعت للحديد ، وكل شيء يعمل بشكل جيد. في البداية ثم اتضح أن البيانات يتم تسجيلها بشكل عشوائي: وحدات التخزين دقيقة ، ولكن في الملفات نفسها ، يتم تكرار أزواج منفصلة من وحدات البايت الثلاثية ، ثم تختفي دون أي انتظام. ليس جيد!
تبدأ التجارب. أنا أكتب بيانات الاختبار - كل شيء على ما يرام. أنا أكتب القتال - نوع من الشيطان. أقوم بتغيير حجم المخازن المؤقتة للبيانات ، وتكرار عمليات التنظيف ، وقوالب البيانات غير مجدية. في المخازن المؤقتة نفسها ، كل شيء دائمًا ممتاز ، والبيانات الموجودة في الذاكرة هي ما تحتاجه في كل مكان. ومع ذلك ، مواطن الخلل على محرك أقراص فلاش - هنا هم.
استغرق الأمر بضعة أيام لحفر الكلب.
التشخيص
كانت المشكلة في تفاعل المكتبة مع أجهزة
DMA .
بطاقات SD لها خصوصية: يتم كتابتها فقط في كتل من 512 بايت. للقيام بذلك ، تقوم المكتبة بتخزين البيانات في صفيف 512 بايت ، وعند تعبئتها يتم التدفق من هناك عبر DMA إلى الفلاش. ولكن!
إذا قمت بنقل جزء أكبر من <512xN + من المساحة الفارغة في المخزن المؤقت للمكتبة> إلى السجل ، فإن المكتبة (من الواضح ، حتى لا تدفع الذاكرة للخلف وللأمام) تقوم بذلك: إنها تغذي المخزن المؤقت الخاص بها ، وتكتبه إلى الفلاش ، ويتم طرح وحدات البايت 512xN التالية مباشرةً في DMA الخاص بي من المخزن المؤقت الخاص بي! حسنًا ، إذا تم ترك شيء ما غير مكتمل - فسيتم نسخه مرة أخرى لوحده ، حتى المرة التالية.
سيكون كل شيء على ما يرام ، ولكن وحدة تحكم DMA تتطلب أن يتم وضع البيانات في الذاكرة محاذاة على حدود 4 بايت. يتم دائمًا محاذاة المخزن المؤقت للمكتبة ، وتضمن اللغة ذلك. ولكن مع أي عنوان ، بعد نسخ جزء من البيانات ، فإن الـ 512xN المتبقية مع بايت صغير يبدأ بي - الله يعلم. ولا تتحقق المكتبة من هذا على الإطلاق: يتم تمرير العنوان ، كما هو ، إلى وحدة تحكم DMA.
"أرسلوا شيئًا أخرقًا ... كلب معه." وحدة التحكم بصمت إعادة تعيين 2 بت أقل من العنوان المرسلة. ويبدأ النقل.

يتم استبدال العنوان ، في البداية ليس مضاعف 4 ، بعدة فويلا - حتى آخر ثلاث بايت من المخزن المؤقت للمكتبة تتم إعادة كتابتها إلى الملف مني ، ويتم فقدان نفس عدد البايتات من المخزن المؤقت الخاص بي دون تتبع. ونتيجة لذلك ، يكون إجمالي حجم البيانات صحيحًا ، وتتم العمليات بسلاسة ، ولكن القرص هراء.
علاج
اضطررت إلى إضافة مخزن مؤقت آخر مباشرة قبل استدعاء وظيفة تسجيل الأجهزة. إذا لم يكن عنوان الكتابة هو مضاعف 4 ، فسيتم نسخ البيانات إليه أولاً. في الوقت نفسه ، زاد متوسط السرعة بسبب اختيار معقول لحجم المخزن المؤقت. بالطبع ، استغرق الأمر ذاكرة ، ولكن ما هو 4 كيلو بايت لسبب وجيه ، عندما يكون لديك تحت تصرفكم - 192 بلا حدود!
التاريخ رقم 2. وقت التشغيل وحفنة
فاتحة
بعد التغيير التالي ، بدأ البرنامج في الانخفاض ، وبطريقة ما سقط بشدة ، وألقى المعالج في معالج
Hard Fault . وألقى بها هناك مباشرة بعد البداية ، حتى قبل تنفيذ عملية التنفيذ () ، أي أنه لم يتم تنفيذ سطر واحد من الشفرة.
الانطباع الأول هو "القندس قد مات ، الرقاقة هي للاستبدال". ثم أعطى مبرمج البلوط. ولكن لا ، فإن الإصدار القديم من البرنامج الثابت يعمل بثبات ، ولكن الإصدار الجديد يقع بثبات في بعض أعماق التجميع الغامضة بين الإطلاق ورمزي. لم يكن لدي أي افتراضات أي نوع من البدعة كان هذا.
الفصل 1
ساعد الإنترنت في مشاهدة كيفية الحصول على بعض المعلومات الإضافية على الأقل. تم إجراء googled لإجراء تحليل عواقب التقصير الثابت: حالة السجلات ، مكدس التفريغ. انتهيت. استخدامها.
اتضح أنه تعطل بسبب خطأ في العملية على الحافلة. قررت أن هذا الوصول غير المتوازن مرة أخرى - مشكلة من نفس النوع كما في القصة الأولى ، ولكن من منظور مختلف. لكن العكس هو المكان الذي حدث فيه الخطأ. وقد نشأت داخل مكتبة وقت التشغيل ، أي في الكود ، والتي ، من الناحية النظرية ، كانت تُمسك مثل كدمات القطة في يوم مشمس.
وأظهر استمرار التحليل أن خلل هو نتيجة لمحاولة تهيئة المتغيرات الساكنة المحلية.
انحدار غنائيبالمناسبة ، نظرًا للشفرة المفككة ، اكتشفت في وقت واحد إجابة لسؤال طرحته أحيانًا على نفسي ، لكنني كنت كسولًا جدًا من الوصول إلى google على الفور: كيف يتم حل الموقف عندما يتمكن 2 من مؤشرات الترابط أو أكثر من محاولة تهيئة مثل هذا المتغير في نفس الوقت. اتضح أنه في هذه الحالة ، يقوم المترجم بترتيب التهيئة باستخدام الإشارات ، مما يضمن أن مؤشر ترابط واحد فقط في كل مرة سيخضع للإجراء بأكمله ، والباقي سينتظر حتى ينتهي الأول.
لقد تم توحيد هذا السلوك منذ الإصدار C ++ 11. هل تعلم انا لا.
الفصل 2
بمجرد أن يتم تشغيل وقت التشغيل في بناء المتغيرات ، يكون له أيضًا استدعاء المدمرات عند الانتهاء من البرنامج (حتى لو لم يكمل البرنامج العمل بالفعل ، وهو المعيار المطلق للميكروكونترولر). للقيام بذلك ، يحتاج إلى مكان لتخزين المعلومات حول جميع المتغيرات التي تمكن من التهيئة.
هذا صحيح في المكان الذي يتم فيه تخزين هذه المعلومات في قائمة داخلية ، فقد انخفض وقت التشغيل أيضًا. نظرًا لأن وظيفة malloc () ، والتي تم من خلالها تخصيص الذاكرة لعناصر هذه القائمة والتي ، وفقًا للمعيار ، تنتج كتل مضمونة لتكون محاذاة
على الأقل في حدود 8 بايت ، بعد عدد n من المكالمات الناجحة ، فإنها تنتج قطعة غير محاذاة في هذا الحد.

التغييرات في التعليمات البرمجية الثابتة الجديدة كسر malloc؟! ولكن كيف يكون هذا ممكنًا؟ لم أقم بإعادة تحديد malloc بالضبط ، وأنا شخصياً لا أحتاج إليه في أي مكان آخر!
مفيدة في خيارات برنامج التحويل البرمجي ، للبحث عن بعض الكلمات الأساسية ، المساعدة ، ولكن قيل بوضوح في كل مكان:
يضمن malloc () إخراج الذاكرة محاذاة على طول الحدود الأساسية. أو مؤشر فارغ في حالة عدم وجود ذاكرة كافية .
الفصل 3
لفترة طويلة تمسكت في الكود ، ووضعت نقاط توقف ، وعانيت ولم أفهم شيئًا ، حتى في وقت ما لم تتكدس ونظرت إلى العناوين التي أعادتها malloc بعناية. قبل ذلك ، كان التحليل بأكمله هو معرفة ما إذا كان الرقم الأخير من العنوان هو 0x4. والآن بدأ في المقارنة بالكامل بين العناوين الأخرى الصادرة عن المكالمات المتتالية إلى malloc.
وأوه ، معجزة!
جميع المكالمات الناجحة الصادرة عناوين من مساحة ذاكرة الوصول العشوائي (0x20000000 وأقدم لهذا الحجر) ، وزيادة متتابعة من الاتصال إلى الدعوة. وأول واحد غير ناجح عاد 0x00000036. وهذا يعني أن العنوان ليس فقط أنه لم يتم محاذاته ، ولكن أيضًا لم يكن في مساحة عنوان ذاكرة الوصول العشوائي على الإطلاق! حاول المعالج كتابة شيء هناك وسقط بشكل طبيعي.
والمثير للدهشة ، حتى لو تصرف malloc () وفقًا للمعيار وأعيد صفرًا إذا لم تكن هناك مساحة كافية ، فلن يكون هذا قد تغير أي شيء بمعنى تعطل البرنامج (ما لم يتم توضيح سبب الخطأ مسبقًا). لا تزال القيمة التي يتم إرجاعها بواسطة malloc غير محددة بأي حال ، ولكن يتم تنفيذها فورًا. هذا في وقت التشغيل.
خاتمة
زيادة حجم الكومة في ملف التكوين ، وتم إصلاح كل شيء.
لكن قبل تلك اللحظة لم أفكر في حجمها. إذا كان الجحيم استسلم لي ، فكرت. على أي حال ، لدي كل المتغيرات والكائنات إما ثابتة أو على المكدس. لذا ، فقط بالقصور الذاتي ، تركت 0x300 بايت تحته ، حيث يتم تخصيص بعض وحدات التخزين أسفل الكومة في جميع مشاريع القوالب. ولكن لا ، لا يزال وقت تشغيل C ++ يحتاج إلى ذاكرة مخصصة ديناميكيًا وبكميات ملحوظة وفقًا لمعايير وحدات التحكم.
عش وتعلم.