اولویت وقفه در میکروکنترلرهای STM32 و کلاً اولویت وقفه ها در میکروکنترلرها، از نکات مهم راه اندازی وقفه هاست. اولویت وقفه ها در میکروکنترلر، مربوط به اتفاق افتادن یک یا چند وقفه در حین اجرای روتین یک وقفۀ دیگر و یا اتفاق افتادن دو یا چند وقفه به صورت همزمان است. اگر یک روتین وقفه در حال اجرا باشد، و وقفه ای با اولویت بالاتر اتفاق بیفتد، روتین وقفۀ اول رها می شود، اجرای روتین وقفۀ دوم شروع می شود و پس از اتمام اجرای روتین وقفۀ دوم، اجرای روتین وقفۀ اول ادامه می یابد. در غیر این صورت روتین وقفۀ دوم پس از اتمام اجرای روتین وقفۀ اول، اجرا می شود. اگر هم روتین دو یا چند وقفه، همزمان با هم آمادۀ اجرا شدن باشند، ترتیب اجرای آنها بر اساس اولویت وقفه است. در برخی میکروکنترلرها، مثل میکروکنترلرهای AVR، اولویت وقفه ها ثابت است. مثلاً اولویت وقفۀ خارجی شمارۀ 1 از وقفۀ خارجی شمارۀ 2 بالاتر است. اما در برخی میکروکنترلرهای دیگر مثل میکروکنترلرهای STM32، اولویت وقفه ها را می توانیم تغییر دهیم. در Reference manual میکروکنترلرهای STM32، در جداولی تحت عنوان Vector table، وقفه ها دارای اولویت های پیش فرض هستند. اما اولویت برخی از این وقفه را می توان تغییر داد. در این نوشته مباحث مربوط به اولویت وقفه ها درمیکروکنترلرهای STM32 سری F1 می پردازیم. پردازندۀ این میکروکنترلرها ARM Cortex-M3 است و مطالب این نوشته، برای اغلب میکروکنترلرهایی با پردازندۀ ARM Cortex-M3 صادق است. البته برای جزئیات بیشتر باید به دیتاشیت، رفرنس منوال یا یوزر منوال میکروکنترلرها و یا اسناد مربوط به پردازندۀ میکروکنترلر مراجعه کنیم. برای میکروکنترلرهای STM32F1، باید به سند PM0056 مراجعه کنیم. توجه کنید که مطالب این نوشته می تواند برای میکروکنترلرهای دیگر با پردازنده های ARM دیگر هم مفید باشد.
راه اندازی وقفه خارجی در STM32
تصویر 1 – جدول Vector مربوط به وقفه های میکروکنترلرهای دستۀ Connectivity line سری STM32F1
مفاهیم اولویت وقفه در میکروکنترلرهای STM32
موضوع اول، دو نوع اولویت Preempt و Sub برای وقفه های STM32 است. در حالت عادی، Preempt priority تعیین کنندۀ اولویت وقفه هاست. اما وقتی که دو یا چند وقفه دارای Preempt priority یکسان باشند، Sub priority تعیین کنندۀ اولویت وقفه هاست. اگر هم چند وقفه دارای Preempt priority و Sub priority یکسان باشند، اولویت پیش فرض تعیین شده در جدول Vector در Reference manual میکروکنترلر، تعیین کنندۀ اولویت آنهاست. موضوع دوم، انواع اجرا شدن روتین وقفه ها نسبت به هم است. حالت اول زمانی است که یک روتین وقفه در حال اجراست و وقفه های دیگر اتفاق می افتند. در این صورت اگر Preempt priority وقفۀ جدید از وقفۀ قبلی بالاتر باشد، روتین وقفۀ قبلی رها و روتین وقفۀ جدید اجرا می شود. سپس روتین وقفۀ قبلی ادامه پیدا می کند. حالت دوم، آماده بودن دو یا چند روتین وقفه برای اجرا شدن به صورت همزمان است. که در این حالت روتین وقفه ها به ترتیب اولویت، پشت سر هم اجرا می شوند. در ادامه این حالات را بررسی می کنیم. موضوع سوم این که برای تعیین اولویت وقفه ها 4 بیت وجود دارد. و وقفه های میکروکنترلرهای STM32F1 می توانند دارای Preempt priority بین صفر تا 15 باشند. هر چه مقدار عددی که در این بیت ها قرار می گیرد، کمتر باشد، اولویت Preempt وقفه بالاتر است. موضوع چهارم این است که برای Sub priority بیت های مجزا وجود ندارد. همان 4 بیت مربوط به Preempt priority می تواند تفکیک شود و تعدادی بیت به Sub priority اختصاص داده شود. در این صورت از تعداد بیت های Preempt priority کاسته و به تعداد بیت های Sub priority اضافه می شود. بنابراین تعداد اولویت های Preempt و Sub به تعداد بیت های آنها محدود می شود.
تصویر 2 – اجرای روتین های وقفه های تو در تو ناشی از اتفاق افتادن وقفه با اولویت بالاتر
حالات اجرای روتین وقفه ها و Preempt priority و Sub priority
حالات اولویت وقفه در میکروکنترلرهای STM32 به صورت زیر است:
- روتین وقفه ای در حال اجراست و وقفه های دیگر اتفاق بیفتند. اگر وقفه های جدید دارای Preempt priority بالاتر باشند، روتین وقفۀ قبلی رها و روتین وقفۀ جدید اجرا می شود. پس از آن، روتین وقفۀ قبلی ادامه می یابد. در غیر این صورت اگر وقفه های جدید نسبت به وقفۀ در حال اجرا، دارای Preempt priority برابر یا پایین تر باشند، به حالت تعلیق در می آیند تا روتین وقفۀ قبلی تمام شود.
- اگر روتین چند وقفه بخواهند همزمان با هم اجرا شوند. مثلاً در زمانی که یک وقفه در حال اجرا بوده و حین اجرای آن، چند وقفه به حالت تعلیق درآمده اند. و حالا که روتین وقفۀ قبلی تمام شده، روتین وقفه های جدید می خواهند همزمان اجرا شوند. یا این که چند وقفه همزمان اتفاق بیفتند. در این صورت روتین وقفه ای که Preempt priority آن بالاتر باشد زودتر اجرا می شود. اگر هم Preempt priority آنها یکسان باشد، روتین وقفه با Sub priority بالاتر زودتر اجرا می شود. اگر Sub priority آنها هم با یکدیگر برابر باشد، روتین وقفه ای زودتر اجرا می شود که اولویت پیش فرض آن بالاتر باشد.
- اگر روتین وقفه ای در حال اجرا باشد و دو یا چند وقفه همزمان اتفاق بیفتند. در این صورت Preempt priority آنها نسبت به وقفۀ در حال اجرا تعیین کننده است. یا وقفۀ در حال اجرا رها می شود و وقفه هایی با Preempt priority بالاتر آمادۀ اجرا می شوند. یا این که Preempt priority آنها کمتر از وقفۀ در حال اجراست و به حالت تعلیق در می آیند.
تصویر 3 – اولویت وقفه در میکروکنترلرهای STM32، مثال از اولویت وقفه ها
رجیسترهای اولویت وقفه در STM32
برای تعیین اولویت وقفه در میکروکنترلرهای STM32، باید به رجیسترهای واحدهای System control و NVIC مقداردهی کنیم. اولین رجیستر که مربوط به تعیین تعداد بیت های Preempt priority و Sub priority است، رجیستر AIRCR است. این رجیستر را می توانیم در سند PM0056 در بخش رجیسترهای SCB مشاهده کنیم. بیت های 8 تا 10 تحت عنوان PRIGROUP می توانند مقادیری بین 3 تا 7 بگیرند. در این صورت 5 حالت برای بیت های Preempt priority و Sub priority به وجود می آید. که این 5 حالت را در جدول زیر ملاحظه می کنید. Group priority همان Preempt priority است. حالت پیش فرض، همان مقدار 11 است که هر چهار بیت مربوط به اولویت وقفه، به Preempt priority اختصاص دارد. حالت دوم، مقدار 100 است که سه بیت با ارزش از چهار بیت به Preempt priority اختصاص دارد. بیت کم ارزش هم به Sub priority. در بقیۀ حالات هم از بیت های اختصاص داده شده به Preempt priority کم می شود و به Sub priority اضافه می شود. در حالت آخر هم همۀ 4 بیت، به Sub priority اختصاص دارد.
جدول 1 – تعداد بیت های اختصاص داده شده به Preempt priority و Sub priority
با مقداردهی به بیت های PRIGROUP از رجیستر AIRCR، تعیین می کنیم که از 4 بیت مربوط به اولویت در وقفه ها چه تعداد بیت به Preempt priority اختصاص یابد و چه تعداد بیت به Sub priority. که در این صورت 4 بیت مربوط به اولویت همۀ وقفه ها به شکلی که می خواهیم تفکیک می شوند.
تصویر 4 – اولویت وقفه در میکروکنترلرهای STM32، بیت های اختصاص داده شده به اولویت Sub و اولویت Preempt
رجیسترهای مربوط به اولویت وقفه های STM32
رجیسترهای اولویت وقفه در میکروکنترلرهای STM32، رجیسترهای IPRx بخش NVIC هستند. هر کدام از این رجیسترها به 4 بایت تقسیم شده اند و هر بایت مخصوص یکی از وقفه هاست. بیت های IP[0] تا IP[67]، مربوط به وقفه های شمارۀ 0 تا 67 است. که در جداول Vector در Reference manual، این شماره وقفه ها در ستون Position قرار دارد. برای مثال پوزیشن وقفۀ خارجی شمارۀ 3 در میکروکنترلرهای دستۀ Connectivity line برابر 9 است. پس بایت مربوط به اولویت آن، یعنی IP[9] بیت های 8 تا 15 در رجیستر IPR2 است. اما دقت داشته باشید که بیت های مربوط به اولویت وقفه ها، 4 بیت با ارزش این بایت هاست. بنابراین در مقداردهی رجیستری، باید به این موضوع توجه شود. این 4 بیت را برای رجیسترهای IPRx به صورت تصویر زیر با مستطیل های سبز رنگ مشخص کرده ایم. 4 بیتی که با مستطیل زرد مشخص شده، 4 بیت کم ارزش این بایت ها هستند و نباید مقداردهی شوند.
تصویر 5 – رجیسترهای مربوط به اولویت وقفه ها در STM32
تعیین اولویت وقفه ها با توابع CMSIS
تعیین اولویت وقفه در میکروکنترلرهای STM32 با مقداردهی مستقیم به رجیسترها کار سردرگم کننده ای است. در کتابخانه های CMSIS، توابع NVIC برای این کار وجود دارند. تابع NVIC_SetPriorityGrouping مقادیر 0 تا 4 را دریافت می کند و 0 تا 4 بیت را به Sub priority تخصیص می دهد (1). تابع دیگر NVIC_SetPriority است (2) که دو ورودی دارد. ورودی اول وقفۀ مورد نظر و ورودی دوم، عددی بین 0 تا 15 است. این عدد در بیت های 4 تا 7 بایت های IP[x] قرار می گیرد (4 بیت مربوط به اولویت وقفه). و توجه داشته باشید مقداری که قرار می دهیم، بدون توجه به این که چند بیت مربوط به Preempt priority و چند بیت مربوط به Sub priority است، در این بیت ها قرار می گیرد. مثلاً فرض کنید دو بیت را به Preempt priority و دو بیت را به Sub priority اختصاص داده ایم. اگر ورودی تابع را 7 (یعنی 0111) بدهیم، مقدار Preempt priority برابر 1 و Sub priority برابر 3 می شود. برای این موضوع هم می توانیم از تابع NVIC_EncodePriority استفاده کنیم (3). ورودی اول این تابع تعداد بیت های اختصاص داده شده به Sub priority (همان ورودی تابع NVIC_SetPriorityGrouping) است. ورودی دوم آن، مقدار Preempt priority و ورودی سوم آن، مقدار Sub priority است. خروجی این تابع هم عددی است که باید در 4 بیت مربوط به اولویت وقفه قرار بگیرد. بنابراین خروجی این تابع را در ورودی دوم تابع NVIC_SetPriority قرار می دهیم. مثال هایی را در قطعه کد زیر ملاحظه می کنید.
نکته: تابع NVIC_SetPriorityGrouping حتماً اجرا شود. چون ممکن است پس از ریست میکروکنترلر، تعدادی بیت به اشتباه به Sub priority اختصاص داده شود. ترتیب اجرای توابع نیز به صورت مثال های زیر است.
1: NVIC_SetPriorityGrouping(PirorityGrouping: 0 ~ 4); // To assign bits to Sub priority
2: NVIC_SetPriority(IRQn, Priority: 0 ~ 15); // Assign priority to IRQn
3: uint32_t NVIC_EncodePriority(PirorityGrouping: 0 ~ 4, PreemptPriority, SubPriority);
// Example 1
NVIC_SetPriorityGrouping(2); // 2 bits for Sub priority and 2 bit for Preempt priority
NVIC_SetPriority(EXTI3_IRQn, 7); // 0111: Preempt priority = 1, Sub priority = 3
NVIC_EnableIRQ(EXTI3_IRQn); // Enable external interrupt 3
// Example 2
NVIC_SetPriorityGrouping(2); // 2 bits for Sub priority and 2 bit for Preempt priority
NVIC_SetPriority(EXTI3_IRQn, NVIC_EncodePriority(2, 1, 3)); // Preempt priority = 1, Sub priority = 3
NVIC_EnableIRQ(EXTI3_IRQn); // Enable external interrupt 3
تصویر 6 – مقدار بیت های مربوط به اولویت وقفۀ خارجی شمارۀ 3 در رجیستر IPR2 با اجرای یکی از مثال های بالا
نتایج اولویت وقفه در میکروکنترلرهای STM32
- اولویت اتفاق افتادن وقفه در STM32 و میکروکنترلرهای دیگر، از مباحث مهم مدیریت منابع وقفه و راه اندازی وقفه هاست.
- مباحث مربوط به اولویت وقفه در ARM Cortex-M3 و در کل ARM Cortex-M تقریباً شبیه یکدیگر است.
- اگر وقفه ای در حال اجرا باشد و وقفۀ دیگری با اولویت بالاتر اتفاق بیفتد، اجرای وقفۀ اول رها و وقفۀ دوم اجرا می شود. پس از اجرا شدن وقفۀ دوم، اجرای وقفۀ اول ادامه می یابد.
- اگر دو یا چند وقفه همزمان با هم اتفاق بیفتند، ترتیب اجرا شدن آنها را اولویت آنها تعیین می کند.
- وقفه ها در برخی میکروکنترلرها، مثل میکروکنترلرهای AVR، دارای اولویت ثابت هستند. اما در برخی میکروکنترلرهای دیگر، مثل میکروکنترلرهایی با پردازندۀ ARM Cortex-M، می توان اولویت وقفه ها را تغییر داد.
- در راه اندازی وقفه در STM32 باید دقت شود که دو نوع اولویت Preempt و Sub وجود دارد.
- برای وقفه ها دو نوع اجرا شدن نسبت به یکدیگر وجود دارد. یا در حین اجرای یک وقفه، وقفه های دیگری اتفاق بیفتد، یا چند وقفه آمادۀ اجرا شدن باشند.
- تنها وقفه ای که می تواند اتفاق بیفتد و وقفۀ در حال اجرا را متوقف کند، وقفه با اولویت Preempt بالاتر است. پس از اتمام اجرای وقفۀ دوم، اجرای وقفۀ اول ادامه می یابد.
- برای تعیین اولویت وقفه ها در میکروکنترلرهای STM32F1، تنها 4 بیت وجود دارد. که این 4 بیت در حالت پیش فرض به Preempt priority اختصاص دارد. با مقداردهی به بیت های 8 تا 10 رجیستر AIRCR از بخش SCB، می توان از بیت های Preempt priority کاسته و به بیت های Sub priority اضافه کرد.
- رجیسترهای مربوط به اولویت وقفه ها در STM32، رجیسترهای IPRx در بخش NVIC هستند.
- مقداردهی به رجیسترهای مربوط به اولویت وقفه در STM32 مشکل است. بنابراین می توان از توابع CMSIS استفاده کرد.
آموزش های یوبرد مرتبط با این نوشته:
- فیلم آموزش وقفه در STM32
- فیلم آموزش ARM STM32 مقدماتی
- فیلم آموزش وقفه خارجی در AVR
- فیلم آموزش میکروکنترلرهای AVR مقدماتی
- فیلم آموزش وقفه در آردوینو
- فیلم آموزش آردوینو مقدماتی
خیلی مفید بود تشکر
سلام. خواهش میکنم. لطف دارید
خیلی ممنونم
سلام. خواهش میکنم
سلام
ممنون از مطالب مفیدی که ارائه میدید
در جایی از متن فرمودید اجرای همزمان وقفه ها :
"اگر وقفه ای در حال اجرا باشد، وقفۀ دوم می تواند در دو حالت نسبت به وقفۀ اول اجرا شود. یا قبل و بعد وقفۀ اول اجرا شود و یا همزمان با وقفۀ اول اجرا شود."
سوال اینکه مگر امکان اجرای همزمان هم در STM32-F1 وجود دارد؟
سلام. خیلی ممنون. لطف دارید. بله این امکان وجود داره. دو وقفه دقیقاً همزمان با هم اتفاق بیفتن.
واقعا جامع و مفید بود
خیلی ممنون
تشکر. نظر لطفتونه.