مقدمه
در بیشتر آموزشهایی که تا کنون دربارهی امبدد (embedded) سیستمها داشتهایم و در پروژههایی که با هم آموخته و انجام دادهایم، غالبا از بوردهای میکروکنترلری مانند انواع بوردهای آردوینو استفاده کردهایم. برای استفاده از اینگونه بوردها کافیست که کاربر اینترفیسهای آنالوگ و دیجیتال بورد موجود را به درستی متصل کند، برنامهی کنترل را نیز در غالب دستورات نرمافزاری نوشته و روی بورد آپلود کند تا کار کنترل انجام شود. زمانی که این بورد راهاندازی شود، پردازندهی مرکزی آن دستورات موجود را به ترتیب خوانده و با سرعتی که برای کلاک آن تعیین شده است، اجرا میکند. به این ترتیب میتوان گفت که خلاصهی کار این بوردهای کنترلر این است که در هر لحظه از زمان در حال اجرای یک دستور مشخص هستند.
در بسیاری از پروژههای مربوط به سیستمهای نهفته، استفاده از این میکروکنترلرها مناسب بوده و عملکرد مطلوب سیستم را مختل نمیکند. به عبارت دقیقتر، اجرای تک تک و جداگانهی دستورات که رویهی این بوردها است، با توجه به فرکانس بالای کلاک آنها معمولا توسط انسان غیر قابل تشخیص است و در مجموع یک فرآیند یکپارچه به عنوان خروجی دیده میشود.
اما برخی پروژههای بزرگتر نیز وجود دارند که در آنها اجرای موازی و همزمان چند دستور در هر لحظه از زمان از اهمیت بالایی برخوردار است. در چنین کاربردهایی استفاده از میکروکنترلرها بسیار پیچیده یا اگر بخواهیم رک باشیم، تقریبا غیرممکن است.
اینجا جایی است که FPGAها (Field-Programmable Gate Arrays) به کمک ما آمدهاند. گونهی دیگری از پلتفرمهای محاسباتی که عملکردی کاملا متفاوت با میکروکنترلرها دارند.
یک بورد میکروکنترلر آردوینو (سمت چپ) و یک Altera FPGA (سمت راست)
مهمترین تفاوت میکروکنترلرها و FPGAها در شیوهی کانفیگ آنهاست. درمیکروکنترلرها مجموعهای از دستورات را داریم که با توجه به ویژگیهای مشخص و از پیش تعیین شدهی میکروها نوشته شده و به صورت متوالی تفسیر و اجرا میشوند. اما در FPGAها خود کاربران این امکان را دارند که کانفیگ سیستم را خودشان تعیین کنند. یعنی در اینجا ما دیگر با یک مجموعه دستورات که بخواهند به صورت متوالی تکرار شوند و کاری را انجام دهند سر و کار نداریم، بلکه برنامههایی که برای FPGAها نوشته میشوند، در واقع طرحوارهای هستند که توصیف میکنند برای آنکه وظیفهای که مورد نظر ماست انجام بگیرد، سختافزار مدار چگونه باشد و چه تنظیماتی داشته باشد. این سختافزار توسط گیتهای منطقی و واحدهای کوچک حافظهای که در درون FPGAها تعبیه شدهاند، پیادهسازی و اجرا میشود. این واحدهای درونی از مدارهای ترانزیستوری ساخته شدهاند.
از آنجا که پیادهسازی پروژهها و سیستمها در بستر FPGA چیزی جز طراحی و اتصالات سختافزاری نیست، پس میتوان گفت که FPGAها قابلیت اجرای موازی دارند. مثلا فرض کنید که میخواهیم سیستمی طراحی کنیم که وظیفهی آن خواندن میزان افت ولتاژ دو سر یک مقاومت نوری، خواندن ورودی یک سنسور اثر هال (hall-effect) و برقراری ارتباط UART با یک دستگاه دیگر است. اگر بخواهیم این سیستم را با میکروکنترلر پیادهسازی کنیم، بلوک دیاگرام عملکردی آن چنین خواهد بود.
دقت کنید که میکروکنترلر taskهای مختلف را به صورت متوالی و سریال اجرا میکند. اما اگر بخواهیم همین سیستم را با FPGA پیادهسازی کنیم، به راحتی میتوانیم برای هر کدام از این taskها یک مدار جداگانه در نظر بگیریم و به این ترتیب به سیستم این امکان را بدهیم که بتواند هر سه کار را به صورت همزمان انجام دهد. بلوک دیاگرام پیادهسازی با FPGA به این صورت خواهد بود.
لازم است در همین لحظه تذکر دهیم که مثال فوق یک توصیف بسیار ساده از تفاوت میان عملکرد میکروکنترلرها و FPGAهاست. در واقعیت ممکن است تنظیمات داخلی FPGAها نیز بسته به نوع پروژه و هدف آن ایجاد کند که در مواردی از پیادهسازیها متوالی نیز استفاده شود و یا میکروکنترلرها نیز تا حدودی برای بهبود عملکرد بتوانند دستوراتی را با تدابیری ویژه به صورت موازی انجام دهند. نکتهی بسیار مهمی که باید به عنوان تفاوت این دو پلتفرم به ذهن بسپارید، این است که معماری آنها برای پیادهسازی و اجرا یک وظیفهی یکسان چگونه است، میکروکنترلرها این وظیفه را در غالب مجموعهای از دستورات پشت سر هم پیادهسازی میکنند و FPGAها مدار سختافزاری مورد نیاز برای اجرای آن دستور را توصیف و پیادهسازی میکنند.
بوردهای توسعهی مختلفی برای FPGAها در بازار وجود دارند که در میان آنها برخی نیز ماژولهایی هستند که برای کارهای مقدماتی مناسباند. به عنوان مثال شرکتهای Digilent و Xilinx بوردهای Arty و Basys را ارائه میدهند و Embedded Micro بورد Mojo V3 را که ما در این آموزش قصد داریم از Mojo V3 استفاده کنیم. این بورد قیمت مناسبی دارد و در مقایسه با دو بورد دیگری که نام بردیم مزیتهایی هم دارد. مثلا اینکه تعداد پین هدرهای آن زیاد است و میتوان اینترفیس ماژولهای خارجی بیشتری را با آن برقرار کرد. همچنین Embedded Micro آموزشهای متعددی را برای استفادهی افراد و به خصوص تازهکارها آماده و عرضه کرده است که بسیار مفید هستند. یک نمونه از این آموزشها را در بخش مراجع در انتهای این آموزش برای شما قرار دادهایم.
بورد Mojo V3
در ادامهی این آموزش ما دو پروژهی مختلف را با هم بررسی میکنیم. ابتدا با یک مثال بسیار ساده شروع میکنیم تا شما را با شیوهی برنامهنویسی برای Mojo آشنا کنیم. بعد از آن به سراغ یک مثال پیچیدهتر میرویم که پیادهسازی سختافزاری PWM خواهد بود.
ما برای برنامهنویسی Mojo از زبان توصیف سختافزار وریلاگ (verilog) استفاده میکنیم. وریلاگ زبان بسیار پرکاربردی است که در صنایع هم از آن استفاده میشود. بنابراین اگر شما آموزش این جلسه را به خوبی یاد بگیرید، به راحتی میتوانید با سایر بوردهای FPGA نیز کار کنید.
- مقاله مرتبط مفید: آموزش FPGA و Verilog برای تازه کارها!
بسیار خب، برای اجرای این پروژهها به سختافزارها و نرمافزارهای زیر نیاز داریم.
سختافزارهای مورد نیاز
- بورد Mojo V3
- کابل میکرو USB
- یک PC دارای سیستمعامل ویندوز یا لینوکس (متاسفانه از Mac نمیتوان استفاده کرد چون توسط بورد پشتیبانی نمیشود)
- LED رنگی
- یک عدد مقاومت ۱۵۰ اهم یا چیزی در همین حدود (برای محدود کردن جریان LED)
- دو عدد مقاومت ۱۰ کیلو اهمی (به عنوان مقاومت پول دان برای کلید)
- برد بورد و سیمهای برد بوردی
نرمافزارهای مورد نیاز
- Mojo Loader (برای آپلود کردن کدها بر روی بورد)
- ISE Design Suite (با استفاده از این IDE کدهای وریلاگ را نوشته و سنتز میکنیم)
- Mojo Base Project (کلیت پروژه با استفاده از این نرمافزار ساخته میشود)
اجازه دهید پروژه اول را اینطور تعریف کنیم، یک LED و دو کلید داریم و میخواهیم LED زمانی روشن شود که هر دو کلید فشار داده شده باشند. در قدم اول باید توجه داشته باشیم که این سیستم یک سیستم دیجیتال است. چون هم ورودی که ولتاژ دریافتی از کلید است و هم خروجی که ولتاژ LED است، هر دو تنها یکی از دو مقدار ۰ یا ۳.۳ ولت را میتوانند بپذیرند. بنابراین میتوانیم ولتاژ ۰ را متناظر با ۰ منطقی و ولتاژ ۳.۳ را هم متناظر با ۱ منطقی در نظر بگیریم. به این ترتیب خیلی ساده، تمام ولتاژهایی که میتوانند در این سیستم وجود داشته باشند را با مقادیر باینری جایگزین و سادهسازی کردهایم. در حقیقت، این ۰ و ۱ منطقی شیوهای برای بیان ولتاژهای high و low در سیگنالهای سیستم هستند.
میتوانیم تمام مقادیر ممکن برای ورودیهای ناشی از کلیدها و خروجی متناظر LED را با سیستم باینری به صورت جدول زیر خلاصه کنیم.
اگر از قبل با مدارهای منطقی و جبر بولی آشنایی داشته باشید، در یک نگاه تشخیص میدهید که جدول فوق در حقیقت یک گیت AND است. در گیت AND خروجی تنها زمانی ۱ میشود که هر دو ورودی گیت ۱ باشند. یعنی دقیقا همین عملکردی که ما برای مدارمان در نظر گرفتهایم، LED تنها زمانی روشن شود که هر دو کلید فشار داده شوند.
خبر خوب اینکه در مدارهای منطقی انواع و اقسام گیتهای مختلف وجود دارند که خروجی آنها تحت تابع و ترکیب بخصوصی از ورودیها محاسبه میشود. اگر از قبل با آنها آشنا هستید که چه بهتر اما اگر نه، ما یک لینک خوب را در این مورد در قسمت منابع در انتهای آموزش برایتان آماده کردهایم که میتوانید به آن سر بزنید.
در اولین مرحله، LED و کلیدها را مطابق شماتیک مداری زیر به Mojo وصل میکنیم.
نمودار اتصال Mojo و LED و دو کلید فشاری
حالا آماده هستیم که برای Mojo برنامه بنویسیم. ISE را باز کنید و در آن base project که دانلود کردید را باز کنید. صفحهای که مشاهده میکنید مانند تصویر زیر است.
در قسمت سمت چپ این پنجره، یک مجموعه آیتم را میبینید که به صورت سلسله مراتبی لیست شدهاند. در این لیست، بر روی آیتمی که نام آن .mojo_top.v است دابل کلیک کنید تا باز شود. میبینید که در قسمت سمت راست صفحه یک کد وریلاگ باز شده است.
اجازه دهید مقداری در مورد وریلاگ و ساختار این کد صحبت کنیم. نخستین نکتهای که باید در مورد وریلاگ بدانید این است که این زبان یک زبان برنامهنویسی به معنای متداولی که از زبانهای برنامهنویسی در ذهن وجود دارد نیست. همانطور که گفتیم، FPGAها به گونهای طراحی و ساخته میشوند که سختافزار داخلی آنها قابل طراحی و قابل کانفیگ شدن به مدارهای مختلف است. در اینجا زبان وریلاگ در حقیقت مانند یک واسطه میان کاربر و آن نرمافزاری است که میخواهیم با آن سختافزار داخلی FPGA را پیاده سازی و کانفیگ کنیم. (مثلا در اینجا ما از نرمافزار ISE استفاده میکنیم)
اگر قدری دقیقتر صحبت کنیم، کد وریلاگ توسط این نرمافزار خوانده شده و به یک سری الگوریتم که در آنها مشخص میشود برای برآورده شدن عملکرد مورد نظر، سختافزارهای این مدار چگونه باید باشند؛ ترجمه میشود. به وریلاگ زبان توصیف سختافزار یا به اختصار HDL نیز گفته میشود.
هر کد وریلاگ از مجموعه ماژولهایی ساخته میشود که با یکدیگر ارتباط و اینترفیس دارند. برای تقریب ذهن میتوانید ماژولهای وریلاگ را معادل با توابع در سایر زبانهای برنامهنویسی در نظر بگیرید. هر ماژول میتواند دارای تعداد ورودی و تعدادی خروجی باشد و کدی که داخل هر ماژول وجود دارد، توصیف میکند که خروجیهای این ماژول چگونه براساس ورودیها و تغییرات آنها ساخته شده و تغییر میکنند. میتوان این ماژولهای مختلف برای هر مدار را در فایلهای مختلف Verilog .v نوشت.
مثلا در این پروژه هم میبینید که فایلهای v. مختلف برای عملکردهای مختلفی مانند SPI و … وجود دارند. فایل mojo_top.v ماژول اصلی و مرکزی است که توصیف میکند مدار ما در نهایت چه سختافزار و عملکردی دارد. خوشبختانه خود ISE آنقدر باهوش هست که فایل ماژول اصلی را از زیرماژولها تشخیص دهد. همانطور که میبنیید در سلسله مراتبی که در سمت چپ صفحه وجود دارد نیز این فایل را بالاتر از بقیه قرار داده است.
در کنار فایلهای v. یک فایل دیگر را هم با پسوند ucf. میبینید. ucf مخفف User Constraints File است. در این فایل کاربر نام ورودی/ خروجیها و اتصالات آنها (I/O) و پینهای متصل به هر کدام را مشخص میکند. ما میخواهیم کارمان را دقیقا با همین فایل شروع کنیم. آن را در لیست سمت چپ صفحه پیدا کرده و روی آن دابل کلیک کنید تا در سمت راست صفحه پنجرهی آن باز شود.
اگر به فایل دقت کنید میبینید که ورودی/ خروجیهای مختلفی در آن وجود دارد. هر کدام از این ورودیها نام ارتباطاتی که از قبل بر روی بورد وجود دارند را مشخص میکنند. مثلا اتصالات باسها و LEDهای موجود بر روی خود بورد. به انتهای فایل بروید و آنجا اینتر بزنید تا یک خط جدید تولید شود. میخواهیم دو ورودی برای کلیدها و یک خروجی برای LED تعریف کنیم. برای این کار کافیست از فرمت بقیهی ورودی/خروجیها که در خود فایل وجود دارد استفاده کنیم.
بنابراین میتوانید عبارت مربوط به هر کدام از ورودی/خروجیهای موجود را کپی کرده و آن را سه بار در انتهای فایل، یعنی جایی که میخواهیم ورودی/خروجیهای خودمان را بنویسیم، paste کنید. دقت کنید که عبارتها با کلمهی NET شروع میشوند.
حال باید برای هر کدام از آنها دو قسمت را تغییردهید؛ یکی عبارت میان ” “ را و دیگری عددی که بعد از P قرار میگیرد و نشاندهندهی شماره پین است. پینهای ۱۴ و ۲۱ را به عنوان ورودی کلیدها و پین ۲۶ را برای خروجی LED تعیین میکنیم. بنابراین عبارات ما به این شکل خواهند بود.
NET “button_a” LOC = P14 | IOSTANDARD = LVTTL; NET “button_b” LOC = P21 | IOSTANDARD = LVTTL; NET “led_external” LOC = P26 | IOSTANDARD = LVTTL;
فقط دقت داشته باشید که پینهایی که انتخاب میکنید، نباید در ورودی/خروجیهایی که از قبل در فایل UCF تعریف شدهاند استفاده شده باشد.
در نهایت فایل UCF شما چنین شکلی خواهد داشت.
حالا که ما نام سیگنالها و اتصالات آنها را متناسب با پروژه خودمان تعریف کردهایم، اکنون میتوانیم کد اصلی پروژه را بنویسیم و در آن مشخص کنیم که رفتار LED به عنوان تابعی از ورودیها چگونه است. احتمالا میتوانید حدس بزنید که برای این کار باید به سراغ mojo_top برویم.
در قسمت بالای این فایل کلمهی module را میبینید که پس از آن نام ماژول آورده شده است. در اینجا این نام همان mojo_top است. پس از آن نیز لیستی از سیگنالهای ورودی و خروجی ماژول را میبینیم که تعریف شدهاند. ما باید نام ورودیها و خروجی پروژه خودمان را به این لیست اضافه کنیم. به این منظور میتوانیم در انتهای لیست سیگنالها این خطوط را بیاوریم.
input button_a, input button_b, output led_external
هدر ماژول به این شکل خواهد بود.
بسیار خب تا این لحظه ما سیگنالهای ورودی و خروجی را در لیست پورتها اضافه کردهایم و به هر کدام یک پین اختصاص دادهایم. در فایل اصلی تابع نیز مشخص کردهایم که هر کدام از این سیگنالها ورودی یا خروجی هستند. تنها کاری که باقی مانده و حالا باید انجام بدهید این است که توضیح دهیم LED ما تحت چه شرایطی باید روشن شود. یعنی حالتهایی را که سیگنال مربوط به آن روی ۱ منطقی (LED : ON) و یا ۰ منطقی (LED : Off) قرار میگیرد، مشخص کنیم. در بخشهای قبلی گفتیم که عملکردی که از LED در این پروژه انتظار داریم، دقیقا مشابه عملکرد یک تابع AND است. در وریلاگ برای مشخص کردن گیت AND از علامت && استفاده میکنیم. بنابراین میتوانیم AND دو ورودی را به شکل زیر نوشته و مقدار حاصل شده را به سیگنال خروجی assign کنیم.
assign led_external = button_a && button_b;
کافیست که خط فوق که عملکرد پروژه ما را مشخص میکند، به انتهای فایل ماژول اضافه کنیم.
خطوطی که از قبل در فایل موجود هستند مربوط به SPI و LEDهای خود بورد و … هستند که در این پروژهی ساده ما فعلا با آنها کاری نداریم.
ماژول کامل شده به این شکل میشود.
برای آنکه برنامهی نوشته شده را روی FPGA بریزیم باید یک فایل bin. بسازیم. خوشبختانه ISE خودش هم کد ما را سنتز میکند (خطاهای آن را در صورت وجود پیدا کرده و تستهای لازم را بر روی کد انجام میدهد)، هم آن را تفسیر و پیادهسازی میکند (یعنی مشخص میکند که توصیفات ما از مدار معادل چه گیتهای منطقیای هستند و مدار را به آنها ترجمه میکند) و در نهایت فایل bin. را برای ما میسازد. برای اینکه این کارها انجام شوند، بر روی Generate Programming File که در گوشهی سمت چپ، پایین وجود دارد دابل کلیک کنید.
در طی پروسهی تولید فایل bin. ممکن است ISE تعداد warning با موضوع missing یا unrouted بودن netها به شما بدهد. این هشدارها چندان حیاتی نیستند و پیادهسازی ما بر روی FPGA را تحت تاثیر قرار نمیدهند. علت تولید این هشدارها این است که ما در پروژهی خود از تمام سیگنالهایی که در فایل UCF تعریف شده بودند استفاده نکردهایم.
در صورتی که پروسهی تولید فایل bin. با موفقیت به پایان برسد، ISE دقیقا کنار همان گزینهای که برای شروع فرآیند روی آن دابل کلیک کرده بودیم، یک تیک سبز رنگ قرار میدهد.
اکنون فایل آماده است که آن را بر روی بورد Mojo آپلود کنیم. اما قبل از آن یک بار دیگر چک کنید که کلیدها و LED را مطابق شماتیکهای مدار که بالاتر قرار داده بودیم، به بورد و پینهای درست هرکدام متصل کرده باشید.
نرمافزار Mojo Loader را باز کنید و USB پورت متناظر با Mojo را انتخاب کنید. حالا فایل bin. که توسط ISE تولید شده است را هم انتخاب کنید. برای پیدا کردن آن میتوانید به فولدر /syn/ در مسیر ذخیرهی پروژهی خود بروید. پس از آنکه آن را باز کردید، دکمه Load را که در سمت راست پایین پنجره وجود دارد بزنید و منتظر بمانید تا فرآیند بارگذاری کد بر روی بورد به اتمام برسد.
زمانی که فرآیند با موفقیت کامل شد، میتوانید عملکرد پروژه را بر روی بورد تست کنید. LED باید تنها زمانی روشن شود که شما هر دو کلید را فشار داده باشید. اگر همینطور است، به شما تبریک میگوییم، پروژهی شما به درستی انجام گرفته است.
برای انجام پروژهی PWM میتوانید قسمت دوم این آموزش را دنبال کنید، بورد Mojo و مقدمات FPGAها – قسمت دوم
- منبع: ترجمه از سایت deviceplus.com
منبع: عکس شاخص از سایت enjoy-digital.fr
امیدواریم این آموزش برای شما مفید واقع شده باشه.
اگر این نوشته برایتان مفید بود لطفا کامنت بنویسید.