در قسمت اول از آموزش STM32 با توابع LL، در رابطه با پردازنده و میکروکنترلر صحبت کردیم و به تفاوتهای میکروکنترلر و پردازنده پرداختیم. همچنین گفته بودیم که خود شرکت ARM فقط طراح پردازنده است، نه میکروکنترلر و سه دستهی مهم از پردازندههای نوین این شرکت را با ذکر جزئیات و کاربردها بررسی کردیم. درنهایت در قسمت اول، میکروکنترلرهای شرکت ST که یکی از استفادهکنندگان پردازندههای ARM است را با ذکر انواع میکروکنترلرهای مبتنی بر این نوع پردازندهها معرفی کردیم. اگر به یاد داشته باشید گفتیم که شرکت ST دو دسته میکروکنترلر 8 بیتی و 32 بیتی دارد که میکروکنترلرهای 32 بیتی آن مدنظر ما بودند. در ادامه قصد داریم کمی به همین 8 بیتی یا 32 بیتی بودن میکروکنترلرها و پیکرهبندی میکروکنترلرهای STM32 بپردازیم.
8 بیتی یا 32 بیتی؟
اگر این آموزش را دنبال میکنید بهاحتمالزیاد با مفهوم بیت آشنا هستید و از بابت مفهوم بیت مسئلهای نیست. وقتی میگوییم پردازندهای n بیتی است یعنی اینکه رجیسترهای آن پردازنده n بیتی هستند. حال شاید سؤال کنید که رجیستر چیست؟ رجیستر از کنار هم قرار دادن چندین بیت تشکیل میشود. پس وقتی 32 بیت را برای پردازندههای ARM بهکار میبریم یعنی اینکه درون این پردازندهها رجیسترهای 32 بیتی وجود دارند.
خب تا بحث در مورد بیت و رجیستر است اجازه بدهید همین ابتدای کار به یک مفهوم مرتبط با این موضوع نیز اشارهکنیم.
مفهوم دیگری به نام Flag یا پرچم نیز وجود دارد که میتواند دربرگیرندهی یک یا چند بیت باشد. درواقع به بیتهایی Flag اطلاق میشود که نشاندهندهی وضعیت خاصی باشند، پس مرسوم نیست که به هر بیتی Flag بگویند، اگرچه خود فلگ چیزی بهجز بیت نیست. به عنوان مثال اگر بیت چهارم و پنجم رجیستر A مقدار 1 منطقی را داشتند یعنی اینکه فلان واحد جانبی مشغول به پردازش دیتای قبلی است و نمیتوان دیتای جدیدی را به این واحد فرستاد. یا اگر بیت هفتم رجیستر B مقدار 0 منطقی را داشت یعنی اینکه در شمارندهی شما سرریز رخداده است.
مزایای 8 بیتی یا 32 بیتی
در نگاه اول به نظر میرسد که هرچقدر تعداد بیتهای رجیسترها بیشتر باشد پردازندهی قویتری داریم، گرچه در بهتر بودن پردازندهها بررسی تنها رجیستر معیار کافیای نمیباشد، اما خب بهصورت کلی میتوان گفت که همان نگاه اولیه تقریباً درست است و هرچقدر تعداد رجیسترها بیشتر باشد پردازنده میتواند در ابعادی قویتر باشد.
بهعنوانمثال یکی از مزایا این است که هرچه تعداد بیتهای رجیستر بیشتر باشد میتواند فضای بیشتری را آدرسدهی کند. در حقیقت زیاد بودن تعداد رجیستر مملو از مزایاست، اما خب شاید بعضیها زمانبر بودن پیکرهبندی اینهمه رجیستر را اگر بخواهند در سطح رجیستر کار کنند، جز معایب بدانند.
نحوهی پیکرهبندی میکروکنترلر
ما قصد داریم قبل از اینکه به کد نویسی و ابزارهای آن و همچنین ابزارهای پیکرهبندی بپردازیم به خود این موضوع که میکروکنترلر چگونه و با چه روشهایی برای هدف خاصی تنظیم یا پیکرهبندی میشود بپردازیم.
اینکه میکروکنترلر برای هدف خاصی تنظیم شود چیزی جز اینکه در رجیسترهای مختلف آن 0 یا 1 منطقی را بنویسیم نیست، به همین سادگی؟ خیر داستان به همین سادگی هم نیست، اگر تعداد بیتها ده تا یا صد تا بود این حرف میتوانست درست باشد، اما مسئله اینجاست که تعداد این رجیسترها بسیار زیادتر از تعدادی است که در بالا ذکر شد و هرکدام در آدرس خاصی قرار دارند. بهعلاوه اینکه کارهای کنترلی فراوان، دستورات خود پردازنده و بسیاری از موارد دیگر وجود دارد که همه و همه مسئلهساز است.
پس راهحل چیست؟ یک راهحل این است که مستندات میکروکنترلر مربوطه را از سایت شرکت سازنده دانلود کنیم و با توجه به مستندات، فایلهایی برای کانفیگ اولیه میکروکنترلر بنویسیم و سپس اقدام به راهاندازی یک واحد جانبی بکنیم.
فکر کردید که اگر با روش بالا بخواهید فقط یک LED را خاموش و روشن کنید، چقدر زمان لازم است؟
در خوشبینانهترین حالت اگر دانش زبان C خوبی داشته باشید و معماری و سختافزار را نیز به خوبی بشناسید. در وهلهی اول این کار میتواند چندین ساعت طول بکشد.
برای خاموش و روشن کردن یک LED چندین ساعت!
بله درست متوجه شدید این کار میتواند چندین ساعت طول بکشد. اگر مثل من این راهحل را غیرمنطقی میدانید با ما همراه باشید تا راهحل بهتری را به شما معرفی کنیم.
یک راهحل مناسب این است که شرکتهای سازنده معمولاً آدرس رجیسترها و مقادیری که برای هر هدف خاص قرار است درون این رجیسترها قرار بگیرد را با ساختارها و اسامی مناسبی طبق استاندارد خاصی دستهبندی کرده و در اختیار ما قرار میدهند و همینطور خیلی از تنظیمات و کارها را در قالب ماکرو یا تابع به ما ارائه میدهند. و زمانی که ما پروژه را میسازیم بهصورت خودکار تمامی موارد بالا همراه با پروژه ایجاد میشوند و ما میتوانیم از آنها استفاده کنیم.
پس اکنون علاوه بر اینکه مشکل راهحل قبلی حل شد، توابع و ماکروهای زیادی نیز در اختیارداریم که میتواند کار ما را خیلی سریعتر کند. خود این راهحل به چندین روش مختلف قابلاستفاده است که در ادامه هرکدام از این روشها را شرح میدهیم. پس بهطور خلاصه ما دو راهحل داشتیم که یکی از آنها را بنا به دلایل ذکرشده گفتیم که مناسب نیست و آن را کنار گذاشتیم و راهحل دیگر خود شامل چندین روش میشود که قرار شد این روشها را بررسی کنیم.
روشهای پیکرهبندی میکروکنترلرهای STM32
در ادامه هرکدام از روشها را با ذکر جزئیات بررسی میکنیم و درنهایت با دلایلی منطقی یک روش را برای ادامهی کار برخواهیم گزید.
Register
در این نوع پیکرهبندی میکروکنترلر stm32 هیچ تابعی وجود ندارد و ما فقط از همان ساختارها و اسامیای که شرکت سازنده در اختیارمان قرار داده است استفاده میکنیم و در اصل تنها در رجیسترها مقادیر 0 یا 1 منطقی را قرار میدهیم. حال شاید از خود بپرسید که این روش هم مثل همان راهحل اولی بود که گفتیم مناسب نیست و از ما کلی وقت میگیرد. خیر، در این روش درواقع فایلهای اولیه و ماکروهای از پیش تعریفشدهای وجود دارد که ما از آنها استفاده میکنیم.
بهعنوان یک مثال ساده، در این روش اگر قرار باشد در یک رجیستر 32 بیتی مقداری را بنویسیم از یک ماکرو استفاده میکنیم و فقط یک عبارت مانند عبارت “LL_GPIO_PIN_1” را در رجیستر قرار میدهیم. اما اگر قرار بود از راهحل اول استفاده بکنیم باید یک عبارت مانند عبارت “11110000111100001111000011110000” یا معادل هگز آنکه برابر با “0xF0F0F0F0” است را در رجیستری که آدرسش را هم باید خودمان تنظیم کنیم، بنویسیم.
مثال بالا کوچکترین مزیتی است که این روش نسبت به راهحل اول دارد، و با بررسی جزئیات به مزیتهای بیشتری پی خواهیم برد.
توابع (Low Layer)LL
در این روش دیگر بهصورت مستقیم با رجیسترها کار نخواهیم کرد و فقط از توابعی به نام توابع LL استفاده خواهیم کرد که خود این توابع با توجه به آرگومانهای ورودیشان، رجیسترها را مقداردهی میکنند. با فراخوانی هرکدام از این توابع عملاً بخشی از یک واحد جانبی راهاندازی میشود. برای اینکه یک واحد جانبی بهطور کامل راهاندازی شود باید با یک توالی خاص از چندین توابع LL استفاده کنیم.
توابع (Hardware Abstraction Layer)HAL
در این نوع توابع که در بالاترین سطح ممکن است، با سطح رجیستر خیلی فاصلهداریم و عملاً بهندرت از رجیسترها استفاده میکنیم، اگرچه دسترسی به رجییسترها در این سطح بدون هیچ مشکلی ممکن است و با استفاده از ماکروهایی میتوانیم به رجیسترها دسترسی داشته باشیم. وقتیکه از یک تابع HAL استفاده میکنیم علاوه بر اینکه خودش رجیسترهای یک بخش را تنظیم میکند، در اکثر موارد بسیاری از کارهایی که در توابع LL باید خود کاربر انجام میداد را نیز انجام میدهد.
مثلاً اگر قرار بود در توابع LL، از 5 تابع استفاده کنیم و کمی هم توابع زبان C را بهکار میبردیم تا یک واحد جانبی راهاندازی شود، ممکن است تمامی این کارها با یک تابع HAL انجام شود.
توابع (Standard peripheral libraries)SPL
توابع SPL در سطح میانی قرار دارند و میتوان گفت سطحی بین LL و HAL را دارا هستند. البته این توابع دیگر بهروزرسانی نمیشوند و بهتر است که شما هم از این توابع استفاده نکنید. منطقی است که وقتی خودتان از هرکدام از توابع مختلفی که در بالا به تشریح آنها پرداختیم استفادهای نداشتید، به خوبی مفهوم توضیحات بالا را درک نکنید. پس اجازه بدهید که با یک مثال، موضوع را به خوبی شرح بدهیم.
فرض کنید میخواهیم رشتهی “Kamin” را بر روی پورت سریال بفرستیم.
در توابع LL پسازاینکه تنظیمات اولیه پورت سریال را انجام دادیم و همچنین آن را فعال کردیم ابتدا باید کارکتر ‘K’ از این رشته را بر روی پورت سریال قرار بدهیم و منتظر بمانیم که آیا ارسال به اتمام رسیده است یا خیر، و اگر ارسال انجام شد کارکتر ‘a’ و سپس تکرار همین روند تا آخرین کارکتر. اما وقتی با توابع HAL کار میکنیم پسازاینکه تنظیمات اولیه را انجام دادیم و پورت را فعال کردیم، تمام رشتهی “Kamin” را در ورودی تابع مربوطه قرار میدهیم و خود تابع تمامی کارهایی که در توابع LL لازم بود خودمان انجام بدهیم را با زمانبندی مناسب برای ما انجام میدهد.
توابع HAL بهقدری همهچیز را آماده کردهاند که اگر به خوبی آنها را بررسی کنید، میبینید که در بعضی موارد اگر شما سهواً یا از روی ندانستن اشتباهی انجام داده باشید، آن اشتباه را اگر ممکن باشد و تشخیص بدهد، برایتان تصحیح میکند. اکنونکه هرکدام از انواع راهحلها، روشها و توابع را با ذکر جزئیات بررسی کردیم، وقت آن است که طبق قولی که داده بودیم با ذکر دلایل منطقی یک روش را برای ادامهی راه انتخاب کنیم.
منطقاً هرکدام از این روشها برای هدف خاصی مناسب هستند، و اینگونه نیست که یک روش کاملاً ناکارآمد و بهدردنخور باشد. بهعنوانمثال اگر هدف سرعت برنامه باشد، توابع HAL اصلاً توصیه نمیشوند و رجیستری بهترین انتخاب است. در نقطهی مقابل اگر هدف سرعت توسعهی پروژه باشد و سرعت برنامه مدنظر نباشد، بهترین انتخاب توابع HAL هستند و رجیستری اصلاً توصیه نمیشود.
اما هدف ما چیست؟
چون هدف آموزش است، بهتر است که ابتدا تا جای ممکن در سطوح پایین کارکنید، مفاهیم را به خوبی بشناسید و بر آنها مسلط شوید، بعد که کمی پیشرفت کردید و مهارتتان بیشتر شد، میتوانید از سطوح بالا نیز استفاده کنید تا سرعت توسعه بالاتر برود. توابع HAL به این دلیل که تنها با فراخوانی یک تابع کنترل کار را بهدست میگیرند و غالب کار را خودشان انجام میدهند و برنامهنویس را درگیر با سختافزار و جزئیات برنامهنویسی نمیکنند برای هدف ما مناسب نیستند.
از سمت دیگر رجیستری نوشتن برنامه هم به دلیل اینکه شمارا بیشازاندازه درگیر تنظیم رجیسترهای زیاد موجود در میکروکنترلر میکند و ممکن است تمرکزتان از مفهوم و اصلکاری که قرار است انجام بدهید دور شود نیز انتخاب مناسبی برای کار ما نیست. انتخاب ما توابع LL خواهد بود که در ادامهی این مجموعه آموزشی بهصورت مفصل با این نوع توابع و نحوهی بهکارگیری آنها آشنا خواهیم شد.
شاید هنوز در انتخاب توابع LL تردید داشته باشید، به همین خاطر قبل از اینکه این قسمت را بهپایان برسانیم، میخواهیم نتیجهی یک تست عملی بین توابع LL و توابع HAL را ارائه بدهیم. اما چون هنوز با ابزارهای برنامهنویسی و پیکرهبندی آشنا نشدیم فقط نتیجهی تست را ارائه میدهیم و توضیحات تکمیلی در قسمت مربوطه ارائه خواهد شد.
به نمودار زیر که سرعت پین میکروکنترلر با استفاده از توابع LL و HAL را نشان میدهد دقت کنید:
حتماً شما هم از این نتیجه شگفتزده شدهاید! پشت پردهی این اختلاف سرعت فاحش دلایل زیادی وجود دارد که ما همهی این دلایل را در قسمتهای آتی بررسی خواهیم کرد، پس با ما همراه باشید.
در قسمت سوم ساخت پروژه با استفاده از نرمافزار STM32CubeMX را آموزش میدهیم و یک کد ساده را با استفاده از نرمافزار Keil خواهیم نوشت و بهصورت عملی با استفاده از پروگرامر، برنامه را بر روی برد پروگرام خواهیم کرد.
خودم کد یک چشمک زن ساده با میکروکنترلر STM32F030F4P6 رو یکبار با HAL و یکبار با LL کامپایل کردم.
از نظر مصرف حافظه FLASH فقط چند صد بایت اختلاف بود و هر دو حدود ۳۸ درصد FLASH رو مصرف کردن، اما از نظر مصرف RAM نتیجه جالب بود ، کد کامپایل شده با LL حدود ۱۵ درصد RAM مصرف میکرد، در حالی که کد کامپایل شده با HAL حدود ۳۰ درصد RAM مصرف میکرد، یعنی عملا ۲ برابر!
و اینجاست که میشه بهینگی LL رو نسبت به HAL متوجه شد.
ضمن اینکه این نتایج رو از طریق Build Analyzer نرم افزار CubeIDE به دست آوردم.
ممنون از آموزش خوبتون
سوالی که دارم اینه آیا استفاده از توابع LL تاثیری در میزان RAM استفاده شده دارد یا خیر؟
سلام دوست عزیز
بله به نسبت کتابخانه hal رم کمتری استک بگیم دقیقتره مصرف خواهد شد
خیلی خوب و کامل توضیح میدید
تشکر فراوان
سپاس مهدی نازنین.
سلام فونیکس 🙂
درجه یک و عالی بود!
موفق باشی ؛)
سلام سعید جان. خوشحالم از اینکه این مقاله برای شما مفید واقع شده است.
با سلام
بسیار عالی بود سپاسگزارم
سلام شهناز عزیز. سپاس از نظر مثبت شما.
امکانش هست برای cube ide هم اموزش نصب و راه اندازی قرار بدید؟
به احتمال زیاد یه نگاهی هم به CubeIDE خواهیم داشت، اما تمرکز اصلی بر روی Keil خواهد بود.
پیرو پیام قبلی منظورم لینک دانلود بود یوزر منوال های hal و ll بود اگر ممکنه تو سایت برای دانلود قرار بدید
با تشکر
قرار داده شد دوست عزیز. هماکنون میتوانید دانلود بفرمائید.
سلام امکانش هست یوزر منوال توابع llبرای سری f0 و f1 رو قرار بدید؟تو سری های مختلف تفاوت دارن این توابع؟
سلام دوست عزیز. از طریق لینکهای زیر دانلود بفرمائید.
سری F1:
https://www.st.com/resource/en/user_manual/dm00154093-description-of-stm32f1-hal-and-lowlayer-drivers-stmicroelectronics.pdf
سری F0:
https://www.st.com/resource/en/user_manual/dm00122015-description-of-stm32f0-hal-and-lowlayer-drivers-stmicroelectronics.pdf
بله تو هر سری ممکنه امکانات میکروکنترلر متفاوت باشه که متناسب با اون امکانات براش توابع وجود داره.
سلام
تشکر ویژه از اینکه همت دارید تا این دوره رو کامل ارائه کنید.
سوالی که داشتم این توابع CMSIS برای همه مدل ها NXP ST ATMEL و برای هر مدلی از اونا وجود داره ؟ و اینکه این توابع در چه سطحی از نظر سرعت اجرا و راحتی پیاده سازی می باشد ؟
و سوال دیگه اینکه (یه کم عجله دارم ??) فایل ها سورس این توابع LL برای همه میکرو ها هست و اینکه برای STM این فایل ها برای هر میکرو رو از کجا میشه اورد که در پروژه ها همون از اونا استفاده کنیم.
سوال دیگه هم اینکه شما گفتید در جلسه بعد با cubeMX کار می کند مگ خروجی اون توابع HAL نیست ؟ یعنی میشه ترکیبی کار کرد ؟
سلام علی عزیز، بله استاندارد CMSIS برای هر میکروکنترلر سری Cortex فارغ از اینکه ساخت کدام شرکت است، وجود دارد.
در رابطه با سرعت و راحتی پیادهسازی هم که در مقاله توضیح دادیم، اگر باز سوالی داشتید بپرسید.
توابع LL متاسفانه برای همهی میکروها وجود نداره، اگر اشتباه نکنم برا سری F4 وجود نداره (باید یه بررسی بکنم) شما وقتی پک نرمافزاری را برای هر سری مثل سری F1 در CubeMX یا هر جای دیگر دانلود میکنید، در اون پک نرمافزاری مثالها و کدهای مختلفی وجود دارد که میتونید از اونا استفاده کنید.
در مقاله بعد توضیح میدهیم، داخل نرمافزار CubeMX میشه انتخاب کرد که خروجی با چه توابعی ساخته شود.
خیلی ممنون
من اینو از خود سایت ST دانلود کردم به نظر شما مرجع کاملی برای HAL و LL هست؟
https://www.st.com/resource/en/user_manual/dm00154093-description-of-stm32f1-hal-and-lowlayer-drivers-stmicroelectronics.pdf
تنها مرجع برای کار با این توابع برای سری F1 فقط همین فایل هستش چیز دیگهای نیست که. نگران نباشید در قسمتهای آتی هر آن چیزی که برای کار با این میکروکنترلرها نیاز باشه را معرفی میکنیم.
سلام
علی بود
فقط میشه تفاوت cubeMx و cubeIDE رو بگید چیه؟
ممنون
درود بر شما دوست عزیز. CubeMX یک سری تنظیمات و پیکرهبندی اولیه را برای ما انجام میدهد و در نهایت از همین تنظیمات و پیکرهبندیهای اولیه به ما خروجی میدهد. خروجی برای نرمافزارهایی مثل Keil، IAR و …
CubeIDE علاوه بر کارهایی که CubeMX انجام میدهد، در خود نرمافزار میتوان کد را ویرایش و کامپایل هم کرد و نیازی به استفاده از خروجی و نرمافزار دیگر نیست.
سلام .
منتظر قسمت هایی بعدی هستم . چون مرجع اموزش کتابخانه LL حتی به زبان انگلیسی هم کم گیر میاد
ممنون
سلام علی عزیز. سپاس از لطف شما. بله علیرغم اهمیتی که این توابع دارند حتی در سایتها و مراجع انگلیسی زبان هم کمتر به این موضوع پرداخته شده است. یا بهتر است بگوییم که اصلا پرداخته نشده است و کاری که قرار است ما در سیسوگ انجام بدهیم تا به حال در هیچ سایت انگلیسی زبانی گفته نشده است.
سلاو خسته نباشید
تشکر می کنم بابت آموزش بسیار خوبتون …
لطفا در مورد توابع cmsis هم کمی صحبت کنید
تشکر
سلام و خسته نباشید واقعا عالی دارید پیش میرید…
فقط اگر امکانش هست کمی هم در مورد توابع cmsis صحبت کنید…
تشکر فراوان
سلام نوید نازنین. در واقع Cortex Microcontroller Software Interface Standard (CMSIS) همانطوری که از اسمش پیداست یک استاندارد هستش، یک اینترفیس نرمافزاری استاندارد برای میکروکنترلرهای سری Cortex که لایهی بالای سختافزار را شامل میشود و باعث میشه که کدنویسی برای ما راحتتر بشه.
دقت شود که این استاندارد با توابعی مثل HAL یا LL اشتباه گرفته نشود، CMSIS شامل یک سری فایلها مثل درایورها یا راهاندازهای پریفرالها یا یک سری فایل برای ارتباط و دسترسی به Core و …
کاری CMSIS این بود که ما را از سروکله زدن با رجیسترها، آدرسها و کلا لایههای سختافزاری که میتونه از میکروکنترلری به میکروکنترلر دیگه تغییر کنه راحت کنه. و اطلاق اسم تابع با عملکردی شبیه به توابع HAL یا LL برای CMSIS اشتباه است.
سلام
ممنون که وقت میذارید و این دورهی خیلی خوب رو تهیه می کنید.
فقط نمی شه آموزش رو با STM32CubeIDE پیش ببرید؟
ممنون
سلام دوست عزیز. حقیقتا چون جامعه آماری که از نرمافزار Keil استفاده میکنند بسیار بیشتر است، Keil را انتخاب کردیم. حالا بنا به درخواستتان سعی میکنیم STM32CubeIDE و حتی شاید IAR را هم در کنارش آموزش بدهیم.