قبل بضعة أيام كان لدي الحماقة في الوعد المحجوب بخفض وظيفة عن ميلاندر ... حسنًا ، دعنا نحاول.
كما تعلمون بالفعل ، هناك شركة Milander روسية ، والتي ، من بين أمور أخرى ، تنتج ميكروكنترولر على أساس ARM Cortex-M. بناءً على إرادة القدر ، أُجبرت على التعرف عليهم بإحكام ،
وعرفت الألم .
ويرد وصف جزء صغير من هذا الألم الناجم عن العمل مع RS-485 أدناه. أعتذر مقدمًا إذا مضغت كثيرًا على المفاهيم الأساسية ، ولكني أردت جعل هذا المقال متاحًا لفهم جمهور أوسع.
سأقوم أيضًا بالحجز مقدمًا أنني تعاملت فقط مع عامي 1986 و 1991 و1891 ، ولا يمكنني التحدث بثقة عن الآخرين.
TL دتفتقر Milandrovsk UART إلى مقاطعة "Transmit Complete" ، العكاز هو "وضع اختبار الاسترجاع" ، أي وضع الصدى. ولكن مع الفروق الدقيقة.
الدخول
تعد واجهة RS-485 (المعروفة أيضًا باسم EIA-485 ، على الرغم من أنني لم أسمع بها مطلقًا في الحياة اليومية) واجهة غير متزامنة أحادية الاتجاه مع طوبولوجيا ناقل. ينص هذا المعيار على الفيزياء فقط - أي مستويات الجهد ومخططات التوقيت - ولكنها لا تحدد بروتوكول التبادل والحماية من أخطاء الإرسال والتحكيم وما شابه.
في الواقع ، RS-485 هو مجرد UART أحادي الاتجاه مع مستويات أعلى من الجهد التفاضلي. هذا البساطة هو ما يضمن شعبية RS-485.
لتحويل UART إلى RS-485 ، يتم استخدام الدوائر الدقيقة المحولة الخاصة ، مثل MAX485 أو 5559IN10AU (من نفس Milander). إنهم يعملون "بشفافية" تقريبًا للمبرمج ، حيث يمكنهم فقط اختيار الوضع الصحيح لتشغيل الرقاقة - الاستقبال أو الإرسال. يتم ذلك باستخدام الأرجل nRE (وليس تمكين إخراج المستقبِل) و DE (تمكين خرج التشغيل) ، والتي يتم ، كقاعدة عامة ، دمجها والتحكم فيها بواسطة إحدى ساق جهاز التحكم الدقيق.
رفع هذه الساق يحول الشريحة إلى ناقل الحركة ، ويخفضها إلى الاستقبال.
وفقًا لذلك ، كل ما هو مطلوب من المبرمج هو رفع هذه المحطة RE-DE ونقل العدد المطلوب من البايتات وخفض الساق وانتظار الإجابة. يبدو بسيطا بما فيه الكفاية ، أليس كذلك؟
الكالينجيون
المشكلة
يجب خفض هذه الساق في وقت يتم فيه نقل جميع وحدات البايت المرسلة بالكامل إلى الخط. كيفية التقاط هذه اللحظة؟ للقيام بذلك ، تحتاج إلى التقاط الحدث "Transmit Complete" (اكتمل الإرسال) ، الذي يولد كتلة UART في متحكم دقيق. بالنسبة للجزء الأكبر ، يتم تعيين الأحداث قليلاً في بعض طلب التسجيل أو المقاطعة. للوقوف على الإعداد قليلاً في السجل ، يجب أن يتم استقصاء السجل ، أي استخدام رمز مثل هذا:
while( MDR_UART1->FR & UART_FR_BUSY ) {;}
هذا إذا استطعنا إيقاف البرنامج تمامًا حتى يتم نقل جميع وحدات البايت. كقاعدة عامة ، لا يمكننا تحمل هذا.
الانقطاع في هذا الصدد أكثر ملاءمة ، لأنه يصل من تلقاء نفسه ، بشكل غير متزامن. في المقاطعة ، يمكننا أن نتجاهل بسرعة RE-DE والعمل بأكمله.
بالطبع ، إذا استطعنا القيام بذلك ، فلن يكون هناك أي ألم ، ولن يكون هذا المنشور كذلك.
والحقيقة هي أنه في كتلة UART ، التي يضعها Milander في جميع ميكروكنترولر الخاصة به على Cortex-M (حسب علمي) ، لا يوجد أي انقطاع لحدث "Transfer Complete". لا يوجد سوى العلم. وهناك مقاطعة "العازلة من الارسال فارغة." والبايت المقاطعة ، بطبيعة الحال.
لا يزال لديكمجموعة من المقاطعات الأخرى ووضع FIFO ، في رأيي ، عديمة الفائدة تمامًا. إذا كان أي شخص يفهم سبب الحاجة إليه ، فيرجى إخبارنا!
تكمن المشكلة في أن "المخزن المؤقت للإرسال فارغ" - وهذا لا ينطبق على الإطلاق على "إكمال النقل". بقدر ما أفهم جهاز UART الداخلي ، يعني الحدث "Buffer Empty" أن هناك مساحة حرة واحدة على الأقل في المخزن المؤقت للمرسل. حتى لو كان هذا المكان واحدًا فقط (على سبيل المثال ، مخزن مؤقت بحجم بايت واحد) ، فهذا يعني فقط أنه تم نسخ آخر بايت تم نقله إلى سجل الإزاحة الداخلي ، والذي ستخرج منه هذه البايتة إلى الخارج ، فشيئًا فشيئًا.
باختصار ، حدث "المخزن المؤقت للمرسل فارغ" لا يعني أن جميع وحدات البايت قد تم إرسالها بالكامل. إذا أغفلنا RE-DE في هذه اللحظة ، فسوف "نقطع" مجموعتنا.
ماذا تفعل؟
ريبوس
بالطبع ، هذا الحل ليس لطيفًا جدًا. إذا لم نتمكن من حظر هذه العلامة ، فعلينا التحقق منها بشكل دوري. للتحقق من ذلك بشكل دوري ، يجب عليك سور حديقة كاملة (خاصةً إذا كنت ترغب في كتابة وحدة محمولة ، وليس فقط حل هذه المشكلة لمرة واحدة).
إذا كنت تستخدم نوعًا من RTOS ، فمن أجل هذا التطهير ، يتعين عليك بدء مهمة منفصلة بالكامل ، والاستيقاظ في حالة انقطاع ، وتعيينها ليست أقل أولوية ، أو المتاعب ، باختصار.
ولكن ، على ما يبدو ، حسنا ، تعذب مرة واحدة ، ثم نستخدم ونفرح. لكن لا.
لسوء الحظ ، لا يكفي أن نتجاهل RE-DE بصرامة بعد إرسال جميع البايتات إلى النهاية. نحن بحاجة إلى خفضه
ليس بعد فوات الأوان . لأننا لسنا وحدنا في الحافلة. على الأرجح ، يجب أن تصل رسالتنا إلى نوع من الإجابة من مشترك آخر. وإذا تجاهلنا RE-DE بعد فوات الأوان ، فلن نتحول إلى وضع الاستلام ونفقد بعض وحدات بت الاستجابة.
يعتمد الوقت الذي يمكننا فيه تحمل تكلفة "تعريض مفرط" لساق RE-DE بشكل أساسي على سرعة النقل (معدل البث بالباود) وعلى سرعة الجهاز الذي نتواصل معه على الحافلة.
في حالتي ، كانت السرعة منخفضة نسبيًا (57600 باود) ، وكان الجهاز شديد الرقة. وأحيانًا حدث أن الجواب فقد قليلاً أو اثنين.
عموما ، ليس حلا جيدا.
الموقت
الخيار الثاني الذي يتبادر إلى الذهن هو استخدام جهاز توقيت الأجهزة. بعد ذلك ، في المقاطعة "إفراغ المخزن المؤقت للإرسال" ، نبدأ مؤقتًا مع مهلة مساوية لوقت إرسال بايت واحد (يتم حساب هذه المرة بسهولة من baudrate) ، وفي المقاطعة من الموقت ، نخفض الساق.
طريقة جيدة وموثوقة. الموقت فقط هو أمر مؤسف. تقليديا لا يوجد الكثير منهم في ميلاندرا - قطعتين أو ثلاث قطع.
وضع حلقة
إذا كنت تقرأ بعناية تلك. وصف على UART -
على سبيل المثال ، لعام 1986 BE91T - يمكنك ملاحظة هذه الفقرة القصيرة جدًا:
( ) 1 LBE UARTCR.
إذا هؤلاء. إذا لم تقرأ الوصف ، فيمكن تحقيق التأثير نفسه تقريبًا عن طريق تقصير أرجل أجهزة RX و TX.
الأفكار بصوت عالومن المثير للاهتمام ، أين هذا نوع من حلقة؟ عادة ما يسمى هذا الوضع "صدى" ، ولكن حسنا.
الفكرة كالتالي - قبل إرسال البايت الأخير في الحزمة ، تحتاج إلى تنشيط وضع "الاسترجاع". ثم يمكنك الحصول على مقاطعة لتلقي البايت الأخير الخاص بنا في الوقت الحالي عندما يزحف بالكامل إلى الحافلة! حسنا ، تقريبا.
في الممارسة العملية ، اتضح أن المقاطعة على الاستقبال يتم تشغيلها في وقت أبكر مما ينبغي ، حوالي ثلث الفاصل الزمني للبت. أنا لا أعرف ما يرتبط هذا ؛ من المحتمل أنه في وضع اختبار الحلقة لا تحدث أي عينات حقيقية للخط ، وربما لا يأخذ وضع الحلقة في الاعتبار آخر نقطة توقف. لا اعرف على الرغم من ذلك ، لا يمكننا حذف RE-DE فور دخول هذه المقاطعة ، لأن هذه هي الطريقة التي "نقطع بها" جزء الإيقاف أو جزء منه عن آخر بايت.
بالمعنى الدقيق للكلمة ، لا يمكننا أو لا نعتمد على نسبة سرعة الواجهة (أي مدة الفاصل الزمني بت واحد) وتردد متحكم دقيق ، لكنني لم أستطع الوصول إلى تردد 80 ميغاهرتز بمعدل سرعة البث بالباود 57600.
خيارات أخرى ممكنة.
إذا كنت لا تستطيع الاستطلاع على علامة UART_FR_BUSY عن فاصل زمني واحد - في الواقع ، حتى أقل قليلاً ، لأن الدخول في الفحوصات الأولية والفحصية يستغرق أيضًا وقتًا - فسيتم العثور على الحل. لسرعة 57600 ، سيكون الحد الأقصى لوقت الاقتراع 18 ميكروثانية تقريبًا (فاصل زمني واحد بت) ، في الممارسة العملية - حوالي 5 ميكروثانية.
بالنسبة لأولئك المهتمين ، أقتبس رمز معالج المقاطعة بأكمله. void Handle :: irqHandler(void) { UMBA_ASSERT( m_isInited ); m_irqCounter++;
إذا كنت تستطيع تحمل العبور (التحكم المثالي) بين أرجل RX و TX ، فكل شيء على ما يرام.
لسوء الحظ ، اليوم لا أستطيع تقديم خيارات أخرى.
هذا كل شيء بالنسبة لي. إذا كان أي شخص يعرف طرقًا أخرى لحل هذه المشكلة ، فيرجى مشاركتها في التعليقات.
أيضًا ، وأغتنم الفرصة وتغيير قواعد Habr ، أريد الترويج لموقع StartMilandr ، والذي هو عبارة عن مجموعة من المقالات حول Microcontrollers. لسبب غير واضح ، يمكنك جوجل جوجل فقط عن طريق الصدفة.
وبطبيعة الحال ، تذكر وجود
شوكة في المكتبة الطرفية القياسية ، والتي ، على عكس المكتبة الرسمية ، يتم إصلاح الخلل وهناك دعم gcc.