پیادهسازی Custom Bootloader در میکروکنترلرهای STM32: چرا، چه زمانی و چگونه؟
یکی از جذابترین و پرکاربردترین قابلیتهای میکروکنترلرهای ARM Cortex-M، از جمله خانواده STM32، امکان مدیریت و تقسیمبندی حافظه فلش (Flash Memory) برای اجرای برنامههای مستقل است. در حالت عادی، وقتی کدی را روی میکروکنترلر پروگرام میکنیم، برنامه از ابتدای حافظه (آدرس 0x08000000) شروع به اجرا میکند. اما اگر بخواهیم کنترل بیشتری روی روند بوت شدن سیستم داشته باشیم چه؟ اینجاست که پای Custom Bootloader (بوتلودر سفارشی) به میان میآید.
در این مقاله بررسی میکنیم که چه زمانی به بوتلودر اختصاصی نیاز داریم و چگونه میتوانیم معماری اجرای چندگانه (Multi-Application) را روی یک میکروکنترلر STM32 پیادهسازی کنیم.
چرا و چه زمانی به Custom Bootloader نیاز داریم؟
دلایل متعددی برای استفاده از یک بوتلودر سفارشی در پروژههای صنعتی و تجاری وجود دارد:
- بروزرسانی از راه دور (OTA Updates): اگر دستگاه شما در یک محیط صنعتی یا دور از دسترس نصب شده باشد، نمیتوانید برای هر آپدیت نرمافزاری، دستگاه پروگرامر را به آن متصل کنید. یک بوتلودر میتواند فریمور جدید را از طریق وایفای، بلوتوث، RS485 یا CAN دریافت کرده، در بخش دیگری از حافظه ذخیره کند و سپس سیستم را با آپدیت جدید راهاندازی نماید (In-Application Programming یا IAP).
- معماری دوگانه (Dual Firmware): گاهی نیاز است یک سختافزار واحد بتواند در دو حالت کاملاً متفاوت کار کند. به جای ادغام دو برنامه حجیم و پیچیده که ممکن است باعث تداخل یا کمبود رم (RAM) شوند، میتوانید دو برنامه مستقل بنویسید و بوتلودر وظیفه سوئیچ بین آنها را (مثلاً با خواندن یک پین سختافزاری یا یک متغیر در EEPROM) بر عهده بگیرد.
- تستهای کارخانهای (Factory Testing): میتوانید اپلیکیشن اول را به برنامههای تست سختافزار در خط تولید اختصاص دهید و اپلیکیشن دوم، فریمور نهایی مشتری باشد.
- سیستمهای حساس به خطا (Fail-Safe): در دستگاههای حیاتی (مثل تجهیزات پزشکی یا هوافضا)، بوتلودر میتواند در صورت خراب شدن فریمور اصلی، سیستم را از روی یک فریمور پشتیبان (Backup) راهاندازی کند.
راهکار عملی: پیادهسازی معماری سهبخشی (یک Bootloader و دو Application)
برای درک بهتر، فرض کنید یک میکروکنترلر با ۱۲۸ کیلوبایت حافظه فلش داریم و میخواهیم سیستم را طوری طراحی کنیم که در لحظه روشن شدن، وضعیت یک دیپسوئیچ سختافزاری (مثلاً پین PA0) را بخواند و بر اساس آن، اپلیکیشن ۱ یا اپلیکیشن ۲ را اجرا کند.
ما حافظه را به این شکل تقسیم میکنیم:
- Bootloader: شانزده (16) کیلوبایت اول (آدرس
0x08000000تا0x08003FFF) - Application 1: پنجاه و شش (56) کیلوبایت (آدرس
0x08004000تا0x08011FFF) - Application 2: پنجاه و شش (56) کیلوبایت (آدرس
0x08012000تا0x0801FFFF)
بخش اول: برنامهنویسی Bootloader
پروژه بوتلودر یک پروژه عادی STM32 است که وظیفه اصلی آن پرش (Jump) به آدرس حافظه اپلیکیشن هدف است. ابتدا در تنظیمات کامپایلر (مثلاً پنجره Options for Target در Keil)، آدرس شروع فلش (IROM1) را روی 0x08000000 و حجم آن را 0x4000 تنظیم کنید.
سپس در فایل main.c، ساختار پرش را به شکل زیر تعریف کنید:

نکته ایمنی مهم: قبل از پرش، حتماً باید وقفهها، به خصوص تایمر SysTick، غیرفعال شوند (HAL_DeInit). در غیر این صورت، به محض ورود به برنامه جدید و قبل از مقداردهیهای اولیه آن، یک وقفه سرگردان میتواند باعث کرش کردن سیستم (HardFault) شود.
در نهایت، در تابع main() و قبل از حلقه while(1)، شرط پرش را مینویسیم:

بخش دوم: پیکربندی اپلیکیشنهای هدف (App 1 و App 2)
وقتی پردازنده به آدرس جدید پرش میکند، باید بداند که جدول بردارهای وقفه (Vector Table) سیستم دیگر در آدرس پیشفرض صفر نیست و جابجا شده است.
برای اپلیکیشن اول:
- در تنظیمات کامپایلر، آدرس شروع (Start address) را
0x08004000و Size را0xE000تنظیم کنید. - وارد فایل
system_stm32g4xx.c(یا متناسب با سری میکروکنترلر خود) شوید، کامنت خط#define USER_VECT_TAB_ADDRESSرا بردارید و آفست را تنظیم کنید:

برای اپلیکیشن دوم: دقیقاً همین مراحل را تکرار کنید، با این تفاوت که در تنظیمات کامپایلر آدرس شروع 0x08012000 تنظیم میشود و مقدار VECT_TAB_OFFSET در فایل سیستم برابر با 0x00012000U خواهد بود.

نحوه پروگرام کردن صحیح فایلها
اکنون سه فایل اجرایی مجزا دارید. برای پروگرام کردن آنها روی میکروکنترلر بدون پاک شدن فایلهای دیگر، از نرمافزار STM32CubeProgrammer استفاده کنید:
نکته طلایی: اگر خروجی کامپایلر شما فایل
.hexاست، نیازی به تنظیم دستی آدرسها ندارید، زیرا فرمت HEX آدرسهای پایه را درون خود دارد. تنظیم دستی فقط برای فایلهای.binالزامی است.
- ابتدا کل حافظه را پاک کنید (Full chip erase).
- تیک گزینه Skip flash erase before programming را فعال کنید تا برنامههای قبلی پاک نشوند.
- فایل Bootloader را در آدرس
0x08000000پروگرام کنید. - فایل App 1 را در آدرس
0x08004000پروگرام کنید. - فایل App 2 را در آدرس
0x08012000پروگرام کنید.
با ریست کردن میکروکنترلر، سیستم از آدرس پایه (بوتلودر) شروع به کار کرده و به صورت کاملاً یکپارچه و امن به برنامه مورد نظر شما تغییر مسیر میدهد. این معماری پایهای است که میتوانید با اضافه کردن پروتکلهای ارتباطی (UART, USB, CAN)، آن را به یک سیستم آپدیت نرمافزاری (OTA) تمامعیار تبدیل کنید.










