برای اعمال تنظیمات میکروکنترلر STM32 ، رجیستر ها باید تغییر کنند. رجیستر یک محتوای 8 ، 16 یا 32 بیتی بدون علامت هست با آدرسی مشخص. مقدار بیت های رجیستر عملکرد بخشی از میکروکنترلر رو مشخص میکنه. در این مقاله قدم به قدم در سه مرحله آموزش میبینید، در زبان سی چطور به محتوای حافظه و رجیسترها دسترسی پیدا میکنیم.
پیشنیاز:
مقاله کاربرد عملگرهای بیتی برای تغییر بیتها
فهرست
– دسترسی به رجیستر در قالب اعضای استراکچر
– دسترسی به بیت رجیسترها با بیت فیلد
ویدئوی آموزش مبانی برنامه نویسی رجیستری STM32 در کانال یوتوب pointer-x
ساخت پوینتر برای هر رجیستر
فرض کنید یک رجیستر 16 بیتی در آدرس 0x40000000 وجود داره. چجوری میشه مقدار رجیستر رو خوند یا تغییر داد؟
به پوینتری با مقدار 0x40000000 و نوع *uint16_t نیاز داریم. مثلا اسم پوینتر هست p، با قرار دادن علامت استریسک قبل از پوینتر، به محتوای آدرس دسترسی داریم.
تعریف p* ، تعریف خود p هم هست ( یک عبارت همزمان تعریف دو چیزه). نوع پوینتر هم در تعریف پوینتر قبل از اسمش نوشته شده:
پوینتر ثابت
جمع بندی روش اول
رجیستر اعضای استراکچر فرضی
روش بهتری هم وجود داره. بجای اینکه هر رجیستر رو یک 32 بیتی جدا در نظر بگیریم. همه ی رجیسترهای یک پریفرال رو، عضو یک استراکچر فرضی در نظر میگیریم. مثلا پریفرال GPIOC هفت عدد رجیستر 32 بیتی داره که از آدرس 0x40011000 شروع شدن. فرض میکنیم یک استراکچر که 7 عضو 32 بیتی داره در آدرس 0x40011000 قرار داره.
نوع متغیر استراکچر GPIO_Type رو مطابق رجیسترهای پریفرال های GPIO طراحی میکنیم و با استفاده از این نوع متغیر یک پوینتر میسازیم برای دسترسی به استراکچر فرضی از نوع GPIO_Type که در آدرس 0x40011000 قرار داره.
با قراردادن عملگر پیکان بعد از پوینتر به استراکچر، میتونیم به اعضای استراکچر که رجیسترهای پریفرال GPIOC هستنید دسترسی پیدا کنیم.
برای خواناتر شدن کد میتونیم، پوینتر به استراکچر رو define کنیم.
این روش CMSIS استاندارد هست برای دسترسی به رجیسترها ، در فایل دیوایس CMSIS این چیزها وجود داره که بتونیم به رجیسترها دسترسی داشته باشیم و برنامه نویسی رجیستری انجام بدیم.
1. تعریف آدرس اولین رجیستر پریفرال ها ( base address )
2. تعریف نوع متغیر استراکچر قالب رجیسترهای هر پریفرال
3. تعریف پوینتر برای دسترسی به رجیسترهای هر پریفرال
دسترسی به بیت رجیسترها با بیت فیلد
در دو روش قبلی برای دسترسی به رجیسترها، نوع خود رجیستر همیشه اینتیجر 32 بیتی بوده و برای تغییر بیت ها چند نیازمندی وجود داره:
- فرایند صفر کردن و یک کردن بیت ها متفاوت هست.
- به ماسک بیت نیاز هست.
فرض کنید با روش قبلی قراره بیت های MODE1 در رجیستر CRL از پریفرال GPIOC رو 0b01 کنیم. یعنی قراره بیت 5 صفر و بیت 4 یک بشه. در قدم اول هر دو بیت صفر میشن و به ماسک بیت های MODE1 نیاز هست. در قدم دوم بیت 4 باید یک بشه که ماسک بیت 4 نیاز هست.
در روش سوم به عملگرهای بیتی و ماسک بیت نیازی نیست و مستقیما با عملگر = میتونیم بیت فیلد هارو تغییر بدیم. رجیستر CRL، تعداد 16 بیت فیلد 2 بیتی داره که اولی MODE0 و آخری CNF7 هست. مطابق بیت های این رجیستر یک نوع متغیر استراکچر تعریف میشه که اعضاش بیت فیلد هستند.
حالا فرض میکنیم در آدرس رجیستر CRL، بجای اینتیچر 32 بیتی، یک استراکچر از نوع CRL_Type وجود داره که البته 32 بیتی هست. در استراکچری که در مرحله قبل قالب رجیستر های پریفرال GPIO طراحی شده بود، نوع رجیستر CRL رو از uint32_t به CRL_type تغییر میدم .
با دسترسی به اعضای این استراکچر به بیت فیلد های رجیستر دسترسی مستقیم پیدا میکنیم. قرار بود بیت 4 یک و بیت 5 صفر بشه، یعنی در بیت های MODE1 عدد یک نوشته بشه. در یک مرحله و با عملگر = میشه عدد یک رو در این دو بیت نوشت و به ماسک بیت و عملگر های بیتی نیازی نیست.
به مقدار 32 بیتی بدون علامتی که در آدرس 0x4001000 هست، یک بار بصورت اینتیجر و یک بار استراکچر دسترسی پیدا کردیم. اگر بخواهیم همزمان قابلیت هر دو دسترسی رو داشته باشیم به یونیون نیاز هست. توضیحات مربوط به این قسمت رو در ویدئو ببینید.
CMSIS و بیت فیلد
لایه ی نرم افزاری CMSIS استاندارد که کتابخونه hal از اون استفاده میکنه بیت فیلد نداره و دسترسی به رجیسترها 32 بیتی هست. ولی شرکت آرم که CMSIS رو ارائه میده فایل هایی هم ارائه میده با دسترسی به بیت فیلد. دلیل اینکه از این فایل ها کمتر استفاده میشه به تفاوت کد اسمبلی نوشته شده توسط کامپایلر های مختلف برای دسترسی به بیت فیلد در حافظه است.