بسم الله الرحمن الرحيم
الحمد لله رب العالمين والصلاة والسلام على أشرف المرسلين، بفضل الله وتوفيقه نقدم لكم الدرس الثالث بسلسلة دروس تعلم برمجة الأنظمة المدمجة والميكروكنترولر STM32 المعتمد على نواة ARM Cortex-M4
بعنوان
تعرف على البنية البرمجية لمعالجات ARM Cortex-M4 ومبدأ عملها
نستكمل اليوم حديثنا عن البنية البرمجية لمعالجات ARM Cortex-M4 وكيف يقوم هذا المعالج بتنفيذ تعليمات البرنامج بمزيد من التفصيل، وحتى الان الدروس مازالت نظرية وعلى الرغم من عدم استحسان البعض هذا الأمر ولكن التعرف على المعالج ومبدأ عمله من الاومور الهامة قبل الدخول واستخدام هذه المعالجات.
في البداية أحب ان أوصي ببعض الكتيبات الهامة من شركة أرم حول معالجات ARM Cortex-M4 وهي تعتبر المرجع الرئيسي والمهم لمن أراد التعمق ومعرفة المزيد.
- دليل المستخدم العام للمعالج Cortex-M4 Generic User Guide
- الدليل المرجعي التقني للمعالج Cortex-M4 Technical Reference Manual
- الدليل المرجعي لبنية ARM®v7-M Architecture Reference Manual
والان نستكمل الشرح مع
أوضاع تشغيل البرنامج
يتم تشغيل وتنفيذ البرنامج بالمعالج Cortex-M4 من خلال وضعين للتشغيل وهما Thread mode أو Handler mode حيث يتم في حالة Thread mode بتنفيذ البرنامج بصورة طبيعة كالمعتاد ويبدأ دائما المعالج في التنفيذ بعد اعادة تشغيلة Reset. أما في الوضع Handler mode فهو الوضع الذى ينتقل له المعالج في حالة الرد على المقاطعات Interrupts وبعد الانتهاء يرجع المعالج مرة اخرى للوضع العادي Thread mode كما هو موضح بالصورة الأتية.
صلاحيات البرنامج
هناك نوعين من صلاحيات البرنامج أحدهما Unprivileged وتعني عدم وجود أي امتيازات للبرنامج فقط يتم التشغيل بالصورة العادية ويمنع البرنامج من استخدام الاوامر MSR أو MRS وهي أوامر خاصة للكتابة بمسجلات المعالج كما يمنع البرنامج من من الدخول لتوقيت النظام أو لوحدة المقاطعات NVIC أو لمجموعة التحكم بالنظام system control block، كما يكون له صلاحيات مقيدة للتعامل مع الذاكرة والأجهزة الطرفية peripherals.
أما النوع الأخر من الصلاحيات وهو Privileged حيث يمنح البرنامج جميع الصلاحيات. ويرجى ملاحظة انه دائما عندما يكون المعالج في وضع Handler mode يمنح جميع الصلاحيات أما عندما يكون في الوضع Thread mode يتم التحكم في الصلاحيات من خلال المسجل CONTROL.
أذا كان وضع تشغيل البرنامج Unprivileged فانه من غير الممكن الكتابة بالمسجل CONTROL ولذلك الطريقة الوحيدة للرجوع للوضع Privileged عن طريق عمل supervisor call باستخدام تعليمة SVC ,i وهذه التعليمة تستخدم غالبا في حالة وجود نظام تشغيل لطلب استخدام موارد النظام.
الشكل التالي يوضح أوضاع تشغيل البرنامج والصلاحيات المتاحة بكل وضع
المسجلات
نرى في الصورة السابقة مجموعة المسجلات الموجودة بالمعالج Cortex-M4 وهي مجموعة مسجلات عامة R0-R12 ومسجل مؤشر المكدس Stack Pointer ومسجل الربط Link Register وعداد البرنامج Program Counter ومسجل حالة البرنامج PSR Program status register ومجموعة مسجلات للتعامل مع المقاطعات Exception mask registers بالاضافة للمسجل الخاص بالتحكم CONTROL.
الجدول الاتي يحتوي نوع كل مسجل وصلاحية الوصول كذلك قيمته بعد عمل اعادة التشغيل
المسجلات العامة R0-R12
طبعا أى عملية يقوم بها المعالج لابد أن تكون المسجلات العامة طرفا فيها فمثلا عمليه جمع رقمين تتم عن طريق ايجاد الرقمين من مكان تخزينتهم بالمسجلات وليكن مثلا R1 و R2 ثم جمعهم والنتيجة يتم تخزينها في مسجل أخر وليكن مثلا R3.
مؤشر المكدس Stack Pointer
تعتمد معالجات Cortex-M4 على أثنين من المكدسات Stacks أحدهما المكدس الرئيسي main stack والأخر مكدس العملية process stack و المكدس Stack هو مكان محدد في ذاكرة الرام يقوم المعالج فيه بتخزين البيانات الخاصة للدالة في حالة استعداء دالة اخرى لحين الرجوع مرة اخرى لها وبالأضافة لبعض البيانات الأخرى، بالمعالج Cortex-M4 يكون ال Stack تنازلي والمسجل stack pointer يشير دائما لأخر مكان بالذاكرة تمت الكتابة به.
فمثلا لو فرضنا ان مكان المكدس Stack يبدأ من أخر مكان بالذاكرة ومؤشر المكدس Stack Pointer يشير الي هذا العنوان أى انه لا توجد اى بيانات داخل المكدس Stack والأن إذا أراد المعالج الكتابة داخل المكدس stack فسيقوم أولا بتقليل العنوان ليشير الي المكان الجديد الذى ستتم الكتابة فيه وسيكون هو المكان القبل الأخير وبعدها يقوم بعملية الكتابة، وبذلك يشير دائما مؤشر المكدس Stack Pointer للمكان الذي تمت به أخر عملية كتابة، أما اذا أراد المعالج القراءة من المكدس stack فسيقوم بقراءة البيانات اولا وبعدها سيقوم بزيادة العنوان ليشير مرة أخرى لأخر مكان تمت الكتابة به. وللعلم فعملية الكتابة داخل المكدس stack تسمي push وعمليه القراءة تسمي pop.
الجدول الأتي يوضح أوضاع المعالج ومتى يتم استخدامهم للصلاحيات ونوع المكدس stack المستخدم.
مسجل الربط Link Register
يحتوي هذا المسجل علي بيانات الرجوع لكل دالة فرعية ولنفرض ان المعالج يقوم الان بتنفيذ دالة معينة وداخل هذه الدالة استعداء لدالة اخرى فسيتم حفظ عنوان الدالة الحالية في مسجل الربط قبل الذهاب للدالة الأخرى وعند الانتهاء من تنفيذها يجد المعالج عنوان الدالة الاصلية في مسجل الربط ويقوم بالعودة لها مرة اخرى واستكمال تنفيذ البرنامج.
عداد البرنامج Program Counter
يتم فيه حفظ عنوان مكان البرنامج الذى سيتم تنفيذه بعد الأنتهاء من التعليمة الحالية ويستخدم لتحويل مسار البرنامج ولكن غير مستحب عمل ذلك وكبديل يمكن استخدام تعليمة branching، عادة يبدأ المعالج بتنفيذ البرنامج من العنوان 0x00000004 حيث يحتوي على جدول المقاطعات vector table أما العنوان 0x00000000 فيحتوي على stack pointer فاذا كان برنامجنا في عنوان أخر فيجب كتابة هذا المسجل بالعنوان الأخر ليعرف المعالج من أين سيبدأ تنفيذ البرنامج.
مسجل حالة البرنامج PSR Program status register
يحتوي على ٣ طبقات APSR و IPSR و EPSR كما موضح بالصورة الاتية
تحتوي طبقة APSR على حالة تطبيقات البرنامج وخاصة عند استخدام العمليات الحسابية فيمكننا معرفة اذا حدثت عملية قسمة على الصفر أو Overflow لمتغير معين. الطبقة الثانية وهي للمقاطعات IPSR ويكون فيه رقم المقاطعة الحالية. أما الطبقة EPSR فيقوم المعالج فيها بتخزين حالة تنفيذ البرنامج الحالية مثلا هل يقوم بتنفيذ تعليمة يمكن مقاطعتها أم لا.
مجموعة مسجلات التعامل مع المقاطعات Exception mask registers
هذه المسجلات مخصصة للتعامل مع المقاطعات فمثلا المسجل PRIMASK يمكن استخدامه لمنع المقاطعات التي لها اولوية يمكن تعديلها وأقل أولوية يمكن مقاطعتها يتم تحديدها في المسجل BASEPRI أما المقاطعات التي لا يمكن تعديل أولويتها فيمكن ايقافها باستخدام FAULTMASK وللعلم فالمقاطعات الخاصة بالمعالج لا يمكن ايقافها.
المسجل الخاص بالتحكم CONTROL
هذا المسجل يقوم بتحديد نوع المكدس المستخدم وصلاحيات الوصول للبرنامج.
تقسيم الذاكرة
يقوم المعالج بعمل خريطة كاملة للعناوين المتاحة تصل حتى ٤ جيجا، يتم فيها تخصيص عنوان ومساحة محددة لكل ذاكرة او نهاية طرفية فمثلا هذه الخريطة تحتوي على عنوان الرام والروم والنهايات الطرفية الخاصة بالمتحكم كما نرى في الصورة التالية
ونلاحظ بعض العناوين الهامة
-
عنوان البداية لذاكرة الروم الذى يتم تخزين البرنامج بها هو 0x00000000 وأكبر مساحة يمكن استخدامها ٥١٢ ميجا بايت طبعا تختلف على حسب ذاكرة الروم او الفلاش المتاحة في كل متحكم فمثلا بالمتحكم stm32F429 ذاكرة الفلاش ٢ ميجا بايت.
-
يكون دائما مخزن في العنوان 0x00000000 عنوان المكدس بالرام والمكان الذى يليه وهو 0x00000004 يكون مخزن به جدول المقاطعات ويسمى vector table وتقوم شركة ST بتقسيم هذه المساحة لمتحكمات STM32 فمثلا يتم دائما بوضع أكواد البرنامج بداية من العنوان 0x0800 0000 وهو مخصص لذاكرة الفلاش flash memory كما موضح بالصورة الاتية
-
عنوان البداية لذاكرة الرام هو 0x20000000
-
عنوان البداية للنهايات الطرفية مثل UART أو ADC هو 0x40000000
-
عنوان ذاكرة الرام الخارجية مثل الموجودة في لوحة ديسكفري هو 0x60000000 حيث يمكن لمعالجات Cortex-M تنفيذ البرنامج والتعامل مع البيانات الموجودة على ذاكرة خارجية وهذه الذاكرة تكون مفيدة في حالة التعامل مع أنظمة التشغيل او تطبيقات الملتيميديا.
خاصية Bit-Banding
من المميزات الرائعة بمعالجات ARM Cortex-M4 حيث يتم التحكم ببت واحد عن طريق الكتابة لورد كاملة word والورد تعني ٤ بايت. فاذا اردنا مثلا تغيير قيمة بت معين وليكن البت ٢ لمتغير موجود بالذاكرة رام فالمعالج يقوم اولا بعملية قراءة للورد الذى يحتوي عليها هذا المتغير وجلب قيمته ثم تغييرها وبعد ذلك يتم كتابتها مرة اخرى وهذا يستغرق ٣ دورات واذا حدثت مقاطعة اثناء هذه العملية سيكون الوضع غير جيد.
وبفضل خاصية Bit-Banding يمكن اتمام العملية السابقة بخطوة واحدة فقط عن طريق الكتابة مباشرة لورد كاملة بمكان أخر ويتم أوتوماتيكيا تغيير البت الذى أردناه، الفكرة هنا ان المعالج ٣٢ بت يتعامل أسرع مع ورد كلمة وليس بت محدد.
نرى في الصورة الاتية الاماكن المخصصة لعمليات Bit-Banding للرام كما هناك ايضا منطقة Bit-Banding مخصصة للنهايات الطرفية.
نرى Bit band region للرام عند العنوان الاتي 0x20000000 ومساحتها ١ ميجا وما يعادلها وهي منطقة Bit band alias عند العنوان 0x22000000 ومساحتها ٣٢ ميجا وذلك لان كل ورد تحتوي على ٣٢ بت. ولحساب عنوان منطقة Bit band alias المقابل لمنطقة Bit band region نستخدم المعادلة الاتية:
bit_word_addr = bit_band_base + (byte_offset x 32) + (bit_number x 4)
فمثلا اذا اردنا الوصول للبت رقم ٢ من العنوان 0x20000000 نقوم بحساب عنوانها في منطقة Bit band alias كما يلي:
bit_band_base = 0x22000000
byte_offset = 0x20000000 - 0x20000000 = 0
bit_word_addr = 0x22000000 + 0*32 + (0x2 x 0x4) = 0x22000008
والان نقوم بكتابة الورد الموجودة بالعنوان الاتي 0x22000008 بالقيمة صفر أو واحد فقط طبعا لانها تمثل بت وأوتوماتيكيا سيتم تغيير البت الثاني بالعنوان 0x20000000
سنقوم بعمل مثال تطبيقي على Bit-Banding لاحقا عند التعامل مع الهاردوير.
ونستكمل حديثنا عن البنية البرمجية لمعالجات ARM Cortex-M4 في الدرس القادم ان شاء الله والي اللقاء.
الدرس في صورة فيديو