
في مقالة المهمة الثالثة والأخيرة ، سوف ألقي نظرة على هياكل بيانات Nucleus SE وأصف مكالمات RTOS API التي لم يتم تنفيذها في Nucleus SE ، بالإضافة إلى مشكلات التوافق الأخرى.
المقالات السابقة في السلسلة:
المادة رقم 12. خدمات للعمل مع المهامالمادة رقم 11. المهام: التكوين والمقدمة لواجهة برمجة التطبيقاتالمادة رقم 10. المجدول: الميزات المتقدمة والحفاظ على السياقالمادة رقم 9. المجدول: التنفيذالمادة رقم 8. Nucleus SE: التصميم الداخلي والنشرالمادة رقم 7. Nucleus SE: مقدمةالمادة رقم 6. خدمات RTOS الأخرىالمادة رقم 5. تفاعل المهام والمزامنةالمادة رقم 4. المهام وتبديل السياق والمقاطعاتالمادة رقم 3. المهام والتخطيطالمادة رقم 2. RTOS: البنية ووضع الوقت الحقيقي
المادة رقم 1. RTOS: مقدمة.
هياكل البيانات
تستخدم المهام هياكل بيانات مختلفة (في ذاكرة الوصول العشوائي وذاكرة القراءة فقط) ، والتي ، مثل كائنات Nucleus SE الأخرى ، هي مجموعة من الجداول التي يتوافق حجمها مع عدد المهام والمعلمات المحددة.
أوصي بشدة أن يصل رمز التطبيق إلى هياكل البيانات هذه باستخدام وظائف API ، وليس بشكل مباشر. هذا يتجنب الآثار الجانبية غير المرغوب فيها ، وعدم التوافق مع الإصدارات المستقبلية من Nucleus SE ، كما يبسط نقل التطبيق إلى Nucleus RTOS. من أجل فهم أفضل لرمز استدعاء الخدمة وعملية التصحيح ، يرد أدناه وصف تفصيلي لهياكل البيانات.
استضافت هياكل البيانات Kernel في ذاكرة الوصول العشوائي
تتضمن هياكل البيانات هذه:
NUSE_Task_Context [] [] - صفيف ثنائي الأبعاد من النوع
ADDR ، له صف واحد لكل مهمة. يعتمد عدد الأعمدة على بنية وحدة التحكم ويتم تحديده بواسطة رمز
NUSE_REGISTERS ، الذي تم تعريفه في
nuse_types.h . يتم استخدام هذا الصفيف من قبل المجدول لحفظ سياق كل مهمة وقد تم وصفه بالتفصيل في قسم "حفظ السياق" من المقالة رقم 10. لا يتم إنشاؤه إذا تم استخدام جدولة RTC.
NUSE_Task_Signal_Flags [] - صفيف من النوع
U8 ، يتم إنشاؤه إذا تم تمكين الإشارات ، ويحتوي على 8 إشارات إشارة لكل مهمة. ستتم مناقشة الإشارات في إحدى المقالات التالية.
NUSE_Task_Timeout_Counter [] عبارة عن صفيف من النوع
U16 ، ويتكون من طرح العدادات لكل مهمة ويتم إنشاؤه إذا
تم تنشيط استدعاء API
NUSE_Task_Sleep () .
NUSE_Task_Status [] - صفيف من النوع U8 ، يحتوي على حالات كل مهمة -
NUSE_READY أو تعليق الحالات. يتم إنشاؤه فقط إذا تم تنشيط تعليق المهمة.
NUSE_Task_Blocking_Return [] - صفيف من النوع U8 ، يتم إنشاؤه إذا تم تنشيط حظر استدعاء API. يحتوي على رمز إرجاع سيتم استخدامه بعد حظر مكالمات API. عادةً ما يحتوي على
NUSE_SUCCESS أو رمز يشير إلى إعادة تعيين الكائن (على سبيل المثال ،
NUSE_MAILBOX_WAS_RESET ).
NUSE_Task_Schedule_Count [] - صفيف من النوع
U16 ، يحتوي على عداد لكل مهمة ويتم إنشاؤه فقط إذا تم تنشيط عدد المجدول.
يتم تهيئة
NUSE_Task_Context [] [] بشكل أساسي
بالأصفار ، باستثناء الإدخالات المقابلة لسجل الحالة (سجل الحالة ، SR) ، عداد البرامج (عداد البرامج ، الكمبيوتر) ومؤشر المكدس (مؤشر المكدس ، SP) ، والتي يتم تعيينها للقيم الأولية (انظر "البيانات في ROM "أدناه) ،
ويتم تعيين أصفار
NUSE_Init_Task () لجميع تراكيب البيانات الأخرى عند بدء تشغيل Nucleus SE. ستحتوي إحدى المقالات التالية على قائمة كاملة بإجراءات بدء Nucleus SE مع وصفها.
فيما يلي تعريفات لبنى البيانات الموجودة في ملف nuse_init.c.

بيانات مستخدم ذاكرة الوصول العشوائي
يجب على المستخدم تحديد مكدس لكل مهمة (إذا لم يتم استخدام جدولة RTC). يجب أن تكون هذه صفائف
ADDR ، والتي يتم تعريفها عادة في
nuse_config.c . يجب وضع العناوين وحجم الأحجام في إدخالات المهام
NUSE_Task_Stack_Base [] و
NUSE_Task_Stack_Size [] ، على التوالي (انظر البيانات في ROM).
بيانات ROM
يخزن ROM من واحد إلى أربعة هياكل البيانات المتعلقة بالمهام. يعتمد المبلغ المحدد على المعلمات المحددة:
NUSE_Task_Start_Address [] عبارة عن صفيف من نوع
ADDR يحتوي على إدخال واحد لكل مهمة ، وهو مؤشر إلى نقطة إدخال الرمز للمهمة.
NUSE_Task_Stack_Base [] عبارة عن صفيف من نوع
ADDR يحتوي على إدخال واحد لكل مهمة ، وهو مؤشر إلى العنوان الأساسي
للمكدس للمهمة. يتم إنشاء هذا الصفيف إذا تم استخدام أي جدولة أخرى غير RTC.
NUSE_Task_Stack_Size [] عبارة عن صفيف من النوع
U16 له إدخال واحد لكل مهمة ، والذي يوضح حجم المكدس للمهمة (بالكلمات). يتم إنشاء هذا الصفيف إذا تم استخدام أي جدولة أخرى غير RTC.
NUSE_Task_Initial_State [] عبارة عن صفيف من النوع
U8 ، به إدخال واحد لكل مهمة ، والذي يعرض الحالة الأولية للمهمة. يمكن أن يكون
NUSE_READY أو
NUSE_PURE_SUSPEND . يتم إنشاء هذا الصفيف إذا تم تحديد دعم الحالة الأولية للمهمة.
تم التصريح عن تراكيب البيانات هذه
وتهيئتها (بشكل ثابت) في
nuse_config.c :

مقدار الذاكرة لتخزين بيانات المهمة (بصمة بيانات المهمة)
مثل جميع العناصر الأساسية لـ Nucleus SE ، يمكن توقع مقدار الذاكرة المطلوبة لتخزين البيانات.
حجم ROM (بالبايت) مطلوب لجميع مهام التطبيق:
NUSE_TASK_NUMBER * حجم (ADDR)بالإضافة إلى ذلك ، إذا تم تحديد أي جدولة أخرى غير RTC:
NUSE_TASK_NUMBER * (حجم (ADDR) +2)بالإضافة إلى ذلك ، إذا تم تحديد دعم الحالة الأولية للمهمة:
NUSE_TASK_NUMBERلتخزين البيانات في ذاكرة الوصول العشوائي ، يتم تحديد مقدار الذاكرة (بالبايت) من خلال المعلمات المحددة ، ويمكن أن يكون لها قيمة صفرية إذا لم يتم تحديد أي من المعلمات.
إذا تم تحديد جدولة أخرى غير RTC:
NUSE_TASK_NUMBER * تسجيلات NUSE * حجم (ADDR)بالإضافة إلى ذلك ، إذا تم تحديد دعم الإشارة:
NUSE_TASK_NUMBERبالإضافة إلى ذلك ، إذا تم تنشيط المكالمة إلى NUSE_Task_Sleep () API:
NUSE_TASK_NUMBER * 2بالإضافة إلى ذلك ، إذا تم تنشيط تعليق المهمة:
NUSE_TASK_NUMBERبالإضافة إلى ذلك ، إذا تم تنشيط حظر مكالمات واجهة برمجة التطبيقات:
NUSE_TASK_NUMBERبالإضافة إلى ذلك ، إذا تم تنشيط عداد المجدول:
NUSE_TASK_NUMBER * 2لم يتم تنفيذ مكالمات API في Nucleus SE
فيما يلي سبع مكالمات API متوفرة في Nucleus RTOS لم يتم تنفيذها في Nucleus SE.
إنشاء مهمة
ينشئ استدعاء API هذا مهمة تطبيق. لا يحتاج Nucleus SE إلى هذه الميزة لأنه يتم إنشاء المهام بشكل ثابت.
استدعاء النموذج:
STATUS NU_Create_Task (NU_TASK * مهمة ، CHAR * اسم ، VOID (* task_entry) (UNSIGNED ، VOID *) ، UNSIGNED argc ، VOID * argv ، VOID * stack_address ، UNSIGNED stack_size ، أولوية OPTION ، OPTION time_slice ، OPTION time_slice ، OPTION time_slice ، OPTION time_slice ،معلمات:
مهمة - يمكن استخدام مؤشر كتلة تحكم مهمة المستخدم كمقبض / رابط ("مقبض") لمهمة في مكالمات API أخرى ؛
name - يشير إلى اسم المهمة ، سلسلة مكونة من 7 أحرف بصفر تنتهي ؛
task_entry - تشير إلى وظيفة الإدخال للمهمة ؛
argc - عنصر بيانات غير موقّع يمكن استخدامه لتمرير المعلومات الأولية إلى المهمة ؛
argv - مؤشر يمكن استخدامه لنقل المعلومات إلى المهمة ؛
stack_address - يحدد المقطع الأولي للذاكرة لمكدس المهام ؛
stack_size - يشير إلى عدد البايتات في المكدس ؛
أولوية - تشير إلى قيمة الأولوية للمهمة: من 0 إلى 255 ، حيث تتوافق الأرقام الأقل مع الأولوية الأعلى ؛
time_slice - تشير إلى الحد الأقصى لعدد
شرائح الوقت التي يمكن أن تنقضي خلال هذه المهمة. تعطيل قيمة "0" تقسيم الوقت لهذه المهمة؛
وقائي - يشير إلى ما إذا كانت المهمة قد حلت محلها أم لا. قد تحتوي على قيم
NU_PREEMPT و
NU_NO_PREEMPT ؛
auto_start - يعرض الحالة الأولية للمهمة. يعني
NU_START أن المهمة جاهزة للتنفيذ ،
ويعني NU_NO_START أن المهمة معلقة.
القيمة المعادة:
NU_SUCCESS - يشير إلى اكتمال الخدمة بنجاح ؛
NU_INVALID_TASK - يشير إلى أن المؤشر إلى وحدة التحكم بالمهمة هو
NULL ؛
NU_INVALID_ENTRY - يشير إلى أن مؤشر وظيفة الإدخال للمهمة هو
NULL ؛
NU_INVALID_MEMORY - يشير إلى أن قطاع الذاكرة الذي تم تعيينه بواسطة معلمة stack_address هو صفر (
NULL ) ؛
NU_INVALID_SIZE - يشير إلى أن حجم المكدس المحدد غير كاف ؛
NU_INVALID_PREEMPT - يشير إلى أنه
تم تعيين المعلمة الأولية بشكل غير صحيح ؛
NU_INVALID_START - يشير إلى أنه
تم تعيين معلمة
auto_start بشكل غير صحيح.
حذف المهمة
تحذف مكالمة API هذه مهمة تطبيق تم إنشاؤها مسبقًا ويجب أن تكون
منتهية أو
منتهية . هذه المكالمة ليست ضرورية أيضًا لـ Nucleus SE ، حيث يتم إنشاء المهام بشكل ثابت ولا يمكن حذفها.
استدعاء النموذج:
STATUS NU_Delete_Task (مهمة NU_TASK *) ؛معلمات:
مهمة - مؤشر إلى كتلة التحكم بالمهمة
القيمة المعادة:
NU_SUCCESS - يشير إلى اكتمال الخدمة بنجاح ؛
NU_INVALID_TASK - يشير إلى أنه تم تعيين مؤشر المهمة بشكل غير صحيح ؛
NU_INVALID_DELETE - يشير إلى أن المهمة ليست في حالة منتهية أو منتهية.
احصل على مؤشرات المهام
تشكل مكالمة API هذه قائمة متسلسلة من المؤشرات لجميع المهام في النظام. ليست هناك حاجة في Nucleus SE ، حيث يتم تحديد المهام باستخدام فهرس بسيط ، وليس مؤشرًا.
استدعاء النموذج:
NU_Task_Pointers غير موقّعة (NU_TASK ** pointer_list ، غير مقيّدة بلا مؤشرات) ؛معلمات:
pointer_list - المؤشر على صفيف من مؤشرات
NU_TASK . سيتم تعبئة هذا الصفيف مع مؤشرات للمهام المثبتة في النظام ؛
max_pointers - الحد الأقصى لعدد المؤشرات التي يمكن وضعها في المصفوفة.
القيمة المعادة:
عدد مؤشرات
NU_TASK الموضوعة في الصفيف.
تغيير أولوية المهمة
يعطي استدعاء API هذا المهمة أولوية جديدة. في Nucleus SE ، ليس مطلوبًا ، لأن أولويات المهام ثابتة.
استدعاء النموذج:
OPTION NU_Change_Priority (NU_TASK * مهمة ، OPTION new_priority) ؛معلمات:
مهمة - مؤشر إلى كتلة تحكم مهمة ؛
new_priority - تعيين الأولوية من 0 إلى 255.
القيمة المعادة:
قيمة أولوية المهمة السابقة.
تغيير خوارزمية استباق المهام
يغير استدعاء API هذا الترتيب الذي تكون فيه المهمة قيد الازدحام. لا يحتاج Nucleus SE إليها لأنه يستخدم خوارزمية جدولة أبسط.
استدعاء النموذج:
OPTION NU_Change_Preemption (استباقية OPTION) ؛معلمات:
وقائي - خوارزمية
استباقية جديدة تقبل
NU_PREEMPT أو
NU_NO_PREEMPTالقيمة المعادة:
الخوارزمية السابقة لتزاحم مهمة.
تغيير شريحة وقت المهمة
يقوم استدعاء API هذا بتغيير الشريحة الزمنية لمهمة معينة. لا يحتاجها Nucleus SE ، حيث يتم إصلاح شرائح وقت المهمة.
استدعاء النموذج:
UNSIGNED NU_Change_Time_Slice (NU_TASK * مهمة ، UNSIGNED time_slice) ؛معلمات:
مهمة - مؤشر إلى كتلة تحكم مهمة ؛
time_slice - الحد الأقصى لعدد
شرائح الوقت التي يمكن أن تنقضي خلال هذه المهمة ؛ القيمة الصفرية لهذا الحقل تعطل قياس الوقت لهذه المهمة.
القيمة المعادة:
القيمة السابقة لكمية وقت المهمة.
إنهاء المهمة
تكمل مكالمة API هذه مهمة محددة. لا يحتاج Nucleus SE إلى هذا لأن الحالة
المُنهيّة غير مدعومة.
استدعاء النموذج:
STATUS NU_Terminate_Task (مهمة NU_TASK *) ؛معلمات:
مهمة - مؤشر إلى كتلة تحكم مهمة.
القيمة المعادة:
NU_SUCCESS - يشير إلى اكتمال الخدمة بنجاح ؛
NU_INVALID_TASK - يشير إلى أن مؤشر المهمة غير صحيح.
متوافق مع Nucleus RTOS
عند تطوير Nucleus SE ، كان أحد الأهداف الأساسية هو ضمان مستوى عالٍ من توافق الشفرة مع Nucleus RTOS. المهام ليست استثناءً ، ومن وجهة نظر المستخدم ، يتم تنفيذها بالطريقة نفسها التي يتم بها تطبيق Nucleus RTOS. هناك بعض المجالات غير المتوافقة حيث توصلت إلى استنتاج مفاده أن عدم التوافق هذا سيكون مقبولًا ، نظرًا لأن الرمز النهائي أسهل في الفهم ويمكنه استخدام الذاكرة بشكل أكثر كفاءة. ومع ذلك ، بالإضافة إلى حالات عدم التوافق هذه ، يمكن استخدام بقية مكالمات Nucleus RTOS API بشكل مباشر تقريبًا مثل مكالمات Nucleus SE. ستقدم إحدى المقالات التالية مزيدًا من التفاصيل حول الانتقال من Nucleus RTOS إلى Nucleus SE
معرفات الكائن
في Nucleus RTOS ، يتم وصف جميع الكائنات من خلال بنية بيانات (وحدات تحكم) من نوع معين. يعمل مؤشر وحدة التحكم هذه كمعرف للمهمة. في Nucleus SE ، قررت أن هناك حاجة إلى نهج مختلف للاستخدام الفعال للذاكرة. يتم وصف جميع كائنات kernel بمجموعة من الجداول في ذاكرة الوصول العشوائي و / أو ROM. يتم تحديد حجم هذه الجداول من خلال عدد أنواع الكائنات. معرف كائن معين هو الفهرس في هذه الجداول. لذا قمت بتعريف
NUSE_TASK على أنه يعادل
U8 . يعمل متغير من هذا النوع (وليس مؤشر) كمعرف للمهام. هذا عدم توافق صغير يسهل اكتشاف ما إذا تم نقل الرمز إلى Nucleus RTOS أو منه. عادة ما يتم تخزين معرفات الكائن ونقلها دون تغيير.
يدعم Nucleus RTOS أيضًا تسمية المهام. يتم استخدام هذه الأسماء فقط لتصحيح الأخطاء. لقد استبعدتهم من Nucleus SE لتوفير الذاكرة.
حالات المهمة
في Nucleus RTOS ، يمكن أن تكون المهام في إحدى الحالات العديدة:
تنفيذ أو
جاهز أو
معلق (مما يؤدي إلى عدم اليقين: المهمة في وضع الاستعداد أو حظرها بواسطة مكالمة API) أو
إنهاءها أو انتهائها.
يدعم Nucleus SE أيضًا الحالات
التنفيذية والجاهزة . يتم دعم جميع الخيارات
المعلقة الثلاثة اختياريًا. لا يتم
إنهاء وإنهاء . لا توجد مكالمات API لإكمال المهام. يجب ألا تُرجع وظيفة المهام الخارجية أبدًا قيمة سواء بشكل صريح أو ضمني (سيؤدي هذا إلى حالة
منتهية في Nucleus RTOS).
مكالمات API غير محققة
يدعم Nucleus RTOS 16 مكالمة مكتبية للعمل مع المهام. لم يتم تنفيذ 7 منها في Nucleus SE. وصفهم ، وكذلك سبب استبعادهم موصوفون أعلاه.
في المقالة التالية ، سنبدأ بإلقاء نظرة على إدارة ذاكرة RTOS.
نبذة عن الكاتب: يعمل Colin Walls في صناعة الإلكترونيات لأكثر من ثلاثين عامًا ، ويكرس معظم وقته للبرامج الثابتة. وهو الآن مهندس برامج ثابتة في Mentor Embedded (قسم من Mentor Graphics). غالبًا ما يتحدث كولين وولز في المؤتمرات والندوات ، مؤلف العديد من المقالات الفنية وكتابين عن البرامج الثابتة. يعيش في المملكة المتحدة.
مدونة كولين المهنية ، البريد الإلكتروني: colin_walls@mentor.com.