در قسمت قبل توضیحات کلی در مورد بخشهای سختافزاری برد sinux f1 دادیم و از این به بعد میخواهیم وارد بحث نرمافزاری و شناساندن سختافزار به نرمافزار شویم که یکی از این راهکارها Buildroot است پس باما همراه باشید.
بگذارید مقدمه را به این صورت شروع کنم، ما برای سیستمهای امبدد برای هر بردی باید یک ایمیج مخصوص به خودش را داشته باشیم یعنی نمیتوانیم ایمیج یک برد را برای برد دیگری استفاده کنیم (در اکثر موارد البته)، ممکن است این سؤال پیش بیاید که چگونه ما برای سیستمهای شخصی خودمان فقط یک ایمیج داریم که روی هر سیستمی با هر سختافزاری قابلنصب هست؟ واضحتر بگم، سی دی ویندوز ما میتواند برای نصب روی هر سیستمی با هر نوع cpu یا مقدار رم یا گرافیک نصب شود (در اینجا هم اکثر موارد).
اما چگونه ممکن است
جواب ما در bios است! در سیستمهای شخصی ما قطعهای به نام bios داریم که هر مادربردی این قطعه را دارد و امکان ندارد بایوس یک مادربرد را برای مادربرد دیگر استفاده کرد، چرا که بایوس اطلاعات سطح پایین سختافزار را مثل آدرس و میزان رم و میزان گرافیک را نگهداری میکند.
شاید با خودتون بگید که ما خودمون رم یا گرافیکهای مختلف را در مادربرد میزنیم پس بایوس مقدارش را از کجا میفهمه!؟ باید بگم که روی هر رم و کارت گرافیک یک چیپ هست که اطلاعات مثلاً ان رم را برای بایوس ارسال میکند و همه اطلاعات دیگر را در خودش دارد و هنگام روشن شدن سیستم این اطلاعات را برای سیستمعامل ارسال میکند تا بتواند خودش را راهاندازی کند.
اما در بردهای امبدد، ما چنین قطعهای نداریم! چرا؟! اصلاً چرا باید داشته باشیم؟؟! اسمش روش هست، سیستم امبدد، ما یک سیستم امبدد را برای یک کاربرد خاص استفاده میکنیم پس همه منابع و ارتباطات سختافزاری ما محدود، مشخص، و غیرقابل تغییر هستند، پس نیازی به چیزی مانند بایوس نداریم و اطلاعات سختافزاری ما (نام آن device tree است که در آینده به آن اشاره میکنیم) را هم در سیستمعامل قرار میدهیم و به همین دلیل آن ایمیج روی سختافزاری با منابع متفاوت قابلاجرا نیست (البته این فقط یک دلیل است و غیر از آن نوع پردازنده که خودش شامل چندین ویژگی میشود و دلایل دیگر هم هستند که توضیح آنها از هدف این مطلب دور است).
ابزار ها
این نکته را هم باید در نظر بگیرید که یک سیستمعامل نیاز به چندین نرمافزار دارد که تعداد آنها کم نیست، که نام آنها در لینوکس پکیج میباشد ، حالا در نظر بگیرید که دهها پکیج دارید که هرکدام از آنها ممکن است نیاز به چندین پکیج دیگر داشته باشند و هر کدام از آنها باید از جایی دانلود شوند، در کنار یکدیگر قابلاجرا باشند و تداخل نداشته باشند، کامپایل شوند و فایلهای خروجی آنها در پوشههای مشخص در فایلهای سیستم قرار بگیرند، اگر کمی بیشتر درباره این مراحل و مراحل دیگری که برای ساخت یک سیستمعامل کامل انجام شود فکر کنید شاید اصلاً از این کار منصرف شوید! به دلیل زمان زیادی که گرفته میشود و در بعضی موارد شاید غیرممکن باشد برای کاربر انسانی به همین دلیل ابزارهایی برای تسهیل این فرآیند آماده شده تا شما نگران آن نباشید!?
yocto و buildroot ازجمله این ابزارها هستند که البته یوکتو کاملتر هست و این کاملی بدون هزینه نیست، ازجمله آن میتوان به فضای زیادی که اشغال میکند اشاره کرد مثلاً در حالت عادی ممکن است برای ساخت ایمیج تنها برای یک برد حدود 100 گیگ فضا اشغال کند. اما buildroot سبکتر است و نسبت به یوکتو سادهتر میباشد. ما برای این برد از بیلد روت استفاده میکنیم.
لازم است برای درک بهتر buildroot چند مورد دیگر را هم بهصورت کوتاه و خلاصه توضیح دهیم:
1- toolchain
تولچین اولین چیزی است که برای امبدد لینوکس نیاز داریم و از آن برای کامپایل کدها استفاده میکنیم، و شامل ابزارهایی مثل کامپایلر، لینکر و کتابخانههای موردنیاز است.
یکی از مهمترین این کتابخانهها کتابخانه C است، همانطور که در شکل زیر میبینید c library رابط بین نرمافزارها و هسته سیستمعامل میباشد.
2- bootloader
بوت لودر دو وظیفه اصلی داره، اول راهاندازی اولیه سیستم و بعد از آن اجرای Kernel، همچنین device tree را برای کرنل آماده میکند. device tree همانطور که در بالا هم اشاره شد برای تعریف بخشهای سختافزار بهکار میرود هم ویژگیهای خود SOC و هم ویژگیها برد، مثلاً در آن بخش i2c را تعریف میکنیم و آدرس رجیستر های i2c رو مشخص کرده و میگوییم اگه دیتایی در i2c آمد به کدام درایور ارسال بشه و پینهای i2c کدام است (البته یکسری از مقداردهیها ارجاعی به بخش دیگر از device tree هستند).
3- kernel
وظیفه اصلی کرنل مدیریت منابع، ارتباط با سختافزار و آمادهسازی یک AP I برای برنامههای کاربر هست.
در شکل بالا یک نمای کلی از وظایف کرنل نشان داده شده. نرمافزارهایی که در بخش user space اجرا میشوند درخواستهایشان توسط c library به kernel space ارجاع داده میشود و از آنجا روی سختافزار اجرا میشود. خود Kernel دارای امکانات مختلفی هست که در زمان کامپایل، کانفیگ های آن مشخص میشود، بهطور مثال درایورهای مختلف میتواند در کرنل قرار داده شود که البته هرچه تعداد آنها بیشتر باشد، حجم کرنل بالاتر رفته و بهتبع زمان لود شدن آن بیشتر میشود.
4- root filesystem
ما همه بخشهای بالا را استفاده میکنیم تا درنهایت بتوانیم برنامه خودمان را اجرا کنیم، چیزی که در root file system قرار میگیرد. البته باید در نظر داشت که برای اجرای برنامه ما مسلماً باید بخشهای دیگری از سیستمعامل اجرا شده باشند، مثلاً درایور شبکه راهاندازی و به شبکه متصل شده باشند، یا صفحهنمایش ما راهاندازی شده و آماده نمایش اطلاعات باشد، خوب کرنل از کجا بداند چه برنامهای را اجرا کند؟! برای حل این مسئله ما برنامهای با نام init داریم که آدرس آن در فایل سیستم، هنگام لود کرنل توسط بوت لودر، به کرنل اعلام میشود.
برنامه init که خودش انواع مختلفی دارد، به ترتیب نرمافزارهایی که باید اجرا شوند را مشخص و اجرا میکند حتی میتوانید در فایل کانفیگ مشخص کنید که هر برنامه نیاز دارد، تا چه برنامههایی قبل از آن اجرا شوند یا اگر برنامهای بسته شد دوباره اجرا شود یا نه و … . همانطور که گفته شد یکسری از ابزارها خیلی نیاز هستند تا ما بتوانیم یک استفاده ساده از سیستم کنیم، مثلاً دستورات ls, cat, grep,mkdir, cd و غیره هر کدوم یک ابزار محسوب میشوند که ما در ترمینال آنها رو اجرا میکنیم، حالا برای راحتی کار و یک راهاندازی سبک، نرمافزاری آماده شده به نام busybox که در آن دستوراتی مثل مواردی که اشاره شد و خیلی بیشتر را تعبیه کردند با حجم بسیار کمتر، به قول خودشون 80 درصد ابزارهای کاربردی رو با 20 درصد کد پیادهسازی کردند.
حالا با اتمام مقدمهای طولانی به سراغ اصل مطلب میرویم!
buildroot چیست
تصویر بالا کل فرایندی که buildroot انجام میدهد را نشان داده، buildroot یکسری makefile و patch هست که فرایند تهیه یک محیط لینوکس را برای یک سیستم امبدد، ساده و خودکار میکند. درواقع یک تولچین، روت فایل سیستم، کرنل و uboot را برای برد ما آماده میکند و در آخر هم یک ایمیج که شامل همه این بخشها هست را به ما میدهد که فقط کافی است اون رو بریزیم روی sd و اجرا کنیم.
کامپایل buildroot
وقتشه که بریم سراغ اجرایی کردن دانسته هامون:
سیستمی که برای استفاده از buildroot نیاز داریم لازم نیست که مشخصههای خیلی بالایی داشته باشد اما دقت کنید که ما قرار است کامپایل کنیم و هرچه CPU قویتری داشته باشیم سریعتر کامپایل انجام میشود، به نظر من یک سیستم معمولی برای این کار هم مناسب است مثلاً با core i5، CPU یا core i7 نسل 4.
از بابت سیستمعامل هم، ترجیحاً استفاده از لینوکس بدون ماشین مجازی هست و بهتر است که لینوکس را روی سیستم بوت و استفاده کنید (اگه هم علاقه شدیدی به ویندوز دارید میتوانید از WSL 2 استفاده کنید و buildroot را با کمک آن استفاده کنید (دردسر هاش با خودتون?).
من هم خودم از توزیع Ubuntu نسخه 2018 استفاده میکنم و شما هم بهتره که همین کار را انجام دهید ، نکتهای که برای لینوکسیها ثابتشده است اینکه جدیدتر همیشه بهتر نیست (جدیدتر همیشه پر باگ تر است!) پس نسخه 2020 رو پیشنهاد نمیکنم.
حالا ترمینال را باز کرده و شروع میکنیم، اول از همه با دو دستور زیر پکیجهای مورد نیازمان را نصب میکنیم:
sudo apt install wget unzip build-essential git bc swig libncurses-dev libpython3-dev libssl-dev sudo apt install python3-distutils
حالا پروژه را دانلود کرده و وارد پوشه میشویم:
git clone https://github.com/mahdi2001h/buildroot-sinux cd buildroot-sinux
دقت کنید که لازم نیست هیچکدام از دستورات buildroot با sudo اجرا شود!
با دستور
make sisoog_sinux_f1_defconfig
کانفیگ های خود را اعمال میکنیم (منظور از کانفیگ ها نسخه کرنل و بوت لودر، پکیجهایی که باید نصب شوند و … است، کمی پایینتر در مورد آن صحبت شده).
حالا برای شروع فرآیند build دستور زیر را وارد میکنیم
make
این هم از خروجی دستور بالا در صورت درست بودن همه چیز
دستور make مراحل زیر را انجام میدهد:
- دانلود سورس کد ها
- کانفیگ و بیلد تولچین (یا استفاده از تولچینی که خود ما میدهیم)
- کانفیگ و بیلد پکیج هایی که مشخص کردیم
- بیلد کرنل
- بیلد بوت لودر
- ساخت root file system
- ساخت ایمیج نهایی
خروجی بیلد ما در پوشه output
قرار میگیرد که خودش شامل چند زیرپوشه میباشد:
- images: همه ایمیج های خروجی ما اینجا هستند (مثل ایمیج کرنل و بوتلودر و فایل سیستم) در واقع فایل هایی هستند که باید روی برد خودمان بریزیم.
- build: همه کامپوننت هایی که بیلد شدند در این پوشه هستند
- host: ابزار هایی که برای بیلد استفاده شدند و
sysroot
تولچین در این پوشه هستند ، مثلا میتوانید در پوشه host/bin به کراس کامپایلر دسترسی پیدا کنید و از آن برای کامپایل برنامه های خود ، استفاده کنید. - و…
کانفیگ buildroot
حالا نگاهی به فایل کانفیگ buildroot که استفاده کردیم میاندازیم و بخشهای مهم را بررسی میکنیم.
(منظور فایلsinux_f1_defconfig
است که در پوشه configs
قرار داره، البته که خود نامگذاریها و کامنت ها تا حدی گویای کاری است که انجام میدهند )
در بخش بوت لودر کانفیگ خودمان را توسط پارامتر BR2_TARGET_UBOOT_CUSTOM_CONFIG_FILE
مشخص کردیم تا از کانفیگ دیفالت جلوگیری شود. درBR2_TARGET_UBOOT_CUSTOM_DTS_PATH
دو مقدار را مشخص کردیم که یکی dtsi هست که بیشتر شامل ارجاع به فایل های دیگر (i از include میاد) و اطلاعات soc هست و dts که شامل اطلاعات بر اساس برد خودمان و بخش هایی که استفاده کردیم است.
در بخش kernel
هم نسخه کرنل و پچ هایی که باید روی کرنل اعمال شود مشخص شده و کانفیگ و …
دربخش fielsystem
مشخص شده که فایل سیستم ما با چه فرمت هایی ساخته شود (مثلا هم با فرمت ext2 برای ریختن روی sd card و هم فرمت لازم برای ریختن روی nand flash). در آخر هم پارامتری با نام BR2_ROOTFS_POST_IMAGE_SCRIPT
داریم که اسکریپتی را اجرا میکند که وظیفه ی اسکریپت این است که فایل های کرنل و بوت لودر و فایل سیستم را در کنار هم قرار میدهد و یک ایمیج میسازد که آن ایمیج را میتوانیم روی sd یا nand flash بریزیم.
در قسمت Target Package
هم پکیج هایی که میخواهیم نصب شوند را مشخص میکنیم لازم هست که پکیج ها با نامی که در اینجا مشخص شده اند در package در پوشه اصلی بیلدروت وجود داشته باشند.
با این دستور هم میتوانید به صورت گرافیکی کانفیگ های buildroot را اعمال کنید.
make menuconfig
در قسمت بعد به سراغ ساخت ایمیج و اجرای آن روی سختافزار میرویم.
دانلود رایگان شماتیک و PCB برد توسعه SINUX F1
فایل های طراحی را میتوانید به صورت رایگان از گیت هاب من دریافت کنید!
منبع:سیسوگ