لایه ی نرم افزاری CMSIS چیه و چه کاری برای ما میکنه؟
چجوری CMSIS رو در نرم افزار STM32CubeIDE به برنامه بیافزاییم؟

پهرست
– آشنایی با لایه ی نرم افزاری CMSIS
– افزودن CMSIS به برنامه در STM32CubeIDE
– بررسی فایل دستگاه (Device) در لایه ی نرم افزاری CMSIS
لایه ی نرم افزاری CMSIS چیه و چه کاربردی در برنامه نویسی میکروکنترلرهای STM32 داره؟
لایه ی نرم افزاری CMSIS چند تا فایل هست که نیازمندی های نخستین برای دسترسی به رجیسترها رو برای ما و همچنین برای کتابخونه ی HAL فراهم میکنه. فایل های مهم CMSIS :
- فایل اسمبلی startup : دربردارنده تابع reset_handler هست و همچنین آرایه ی آدرس های توابع رسیدگی کننده به اینترانپت ها .
- فایل دستگاه یا device : فایل header به نام device peripheral access یا فایل دسترسی به پریفرال های دستگاه ، نیازمندی ها برای دسترسی به رجیسترهای پریفرال های میکروکنترلر (پریفرال GPIO یا تایمر یا … ) رو برای ما فراهم میکنه. نیازمندی مون برای دسترسی پوینتر هست و این فایل پوینتر میسازه .
- فایل هسته یا core : فایل هدر دسترسی به CPU و هسته، نیازمندی ها برای دسترسی به پریفرالهای هسته (که در CPU هستند) و همچنین تابع هایی برای دستکاری این پریفرال ها برای ما فراهم میکنه.
- فایل های هدر کامپایلر هم نیازمندی های کامپایلر رو فراهم میکنند و کاربر کاری با اونها نداره.
- فایل سورس به نام system، ارزشمندی ندارد، و تنها برای تنظیمات کلاک است، که این کار را خودمان میکنیم و نیاز به CMSIS نیست. فایل header به نام system هم مهم نیست.

افزودن لایه ی نرم افزاری CMSIS به برنامه در STM32CubeIDE
هنگامی که یک پروژه با cube میسازید ، لایه ی نرم افزاری CMSIS در پروژه هست ، چون کتابخونه HAL هم برای دسترسی به رجیسترها به CMSIS نیاز داره . در ادامه میگم که اگر بخواهید که HAL بخشی از پروژه نباشه و تنها لایه ی نرم افزاری CMSIS در پروژه باشه باید چه کنید .
نرم افزار STM32CubeIDE رو باز کنید، نخست با پنجره launcher روبرو میشوند.
- یک پوشه برای workspace گزینش کنید. (پوشه ای که چند برنامه رو اونجا میذارید).
- سپس روی دکمه ی launch کلیک کنید.

در پنجره ی information center روی start new stm32 project کلیک کنید.

پنجره target selection باز خواهد شد، در این گام باید میکروکنترلری که میخواهید برنامه رو برای اون بنویسید گزینش کنید.
- در بخش part number نام میکروکنترلر رو بنویسید. من برای میکروکنترلر STM32F103C8 که روی برد blue pill هست، برنامه رو میسازم.
- میکروکنترلر دلخواه رو گزینش کنید.
- سپس روی دکمه ی next کلیک کنید.

در پنجره STM32 Project :
- نام برنامه رو بنویسید.
- گزینه ی targeted project type هم STM32Cube باشه. نمیخواهیم کتابخونه hal و نرم افزار Cube رو بکاربگیریم ولی برای اینکه لایه ی نرم افزاری CMSIS به برنامه افزون بشه ، باید از این راه بریم.
- در گام سوم روی دکمه finish کلیک کنید تا برنامه ساخته بشه.

فایل ioc ( فایل مربوط به Cube ) و تمام فایل های وابسته به کتابخونه hal رو پاک کنید. این فایل ها و پوشه هایی که باید پاک کنید رو در تصویر زیر دورشنون رو خط چین گذاشتم.

فایل main.c رو باز کنید و همه ی درونمایه ی این فایل رو پاک کنید. برای افزودن لایه ی نرم افزاری cmsis به برنامه ، تنها لازمه فایل stm32f1xx.h رو به آغاز فایل main.c افزون کنید. بعد از اون تابع main رو همچون کد زیر بنویسید.

با کلیک روی چکش، کد رو کامپایل کنید، هفت تا خطا = error داریم که در آینده نزدیک درست میشه.

خطای یکم برای include فایل main.h در فایل it هست که خب فایل main.h رو پاکش کردیم، include فایل main.h رو هم پاک کنید.

خطای دوم برای include شدن یکی از فایل های کتابخونه hal در فایل stm32f1xx.h هست، اون بخشی که با چهارگوش قرمز برجسته کردم، پاک کنید.

خطای سوم برای فراخوانی تابع HAL_IncTick در فایل it هست، فراخوانی این تابع رو هم پاک کنید.

برنامه رو دوباره کامپایل کنید، خطا و هشدار ( error و warning ) نداریم.

الان برنامه آماده است و میتونیم لایه ی نرم افزاری CMSIS رو هم در برنامه بکار بگیریم. ولی پیش از اینکه بکارگیری CMSIS رو آغاز کنیم، میخواهیم فایل های CMSIS رو کمی بیشتر بررسی کنیم.
در پنجره project explorer روی فایل main.c کلیک راست کنید و include browser رو از show in بگزینید، نمای include browser که با چهارگوش قرمز نشان دادم براتون باز میشه. در این نما، همه ی فایل های header که در فایل main.c، مستقیم یا غیرمستیم افزون شدن (include شدن) رو میبینید.
در نرم افزار STM32CubeIDE به این پنجره های میگن view ، برگردان فارسیش رو نوشتم نما.

همه ی فایل های هدر CMSIS که به برنامه افزوده شده اند رو در نمای include browser میبینید. و همچنین در نمای project explorer فایلهای header رو میبینید که به برنامه افزوده نشده اند. به یاد داشته باشید، که فایل های هدر تنها هنگامی بخشی از برنامه میشوند که به یک فایل سورس افزوده شوند.
شماری از فایل های هدر که در پوشه ی include هستند، تو برنامه نیستند و میشه اونها رو پاک کرد.
بررسی فایل device peripheral access layer header
لایه ی نرم افزاری CMSIS ، یکی فایل دستگاه ( device ) دارد، همه ی نامش :
- device peripheral access layer header file
- یا فایل هدر دسترسی ساز به رجیسترهای پریفرال های دستگاه.
در این نوشته هر جا گفتم فایل دستگاه بدانید که به چه می اندیشم. همه ی نامش خیلی دراز است و نمیشود بکار برد. در اینجا فایل دستگاه stm32f103xb.h است.
فایل دستگاه کدام نیاز ما را براورده میکند؟ نیاز به پوینتر و ماسک بیت.
- برای دسترسی به رجیسترها نیاز به پوینتر داریم.
- برای جدا کردن بیت های دلخواه برای خواندن یا نوشتن، به ماسک بیت نیاز داریم.
فایل دستگاه برای این نام دستگاه گرفته، چون برای هر دستگاهی متفاوته و مطابق با پریفرال های هر دستگاه نوشته شده . این فایل برای هر پریفرال یک پوینتر برامون میسازه و همچنین برای تمام بیت های تمام رجیسترها، برای ما ماسک بیت فراهم میکنه.
ساخت پوینتر در فایل دستگاه در CMSIS
برای ساخت پوینتر ، نیاز داریم به نشانی (آدرس) و نوع اون چیزی که در آدرس هست، ساخت نشانگر سه گام دارد:
- تعریف نوع استراکچر با typedef struct بر پایه ی ساختار رجیستر های پریفرال . ما رجیسترهای پریفرال رو مثل اعضای یک استراکچر فرضی در حافظه میبینیم. این نوع اون استراکچر فرضی هست که در آدرس رجیسترهای پریفرال ذخیره شده.
- نام دهی (با #define) به نشانی پایه ی پریفرال ( نشانی اولین رجیستر پریفرال نشانی پایه ی آن است ) . نشانی های پایه باید define شوند تا بعدا برای ساخت پوینتر از آنها استفاده شود.
- نام دهی (با #define) به پوینتر ، در قدم اول نوع اون چیزی که پوینتر آدرسش رو نگه میداره و در قدم دوم اندازه ی پوینتر رو ساختیم، الان باید خود پوینتر رو میسازیم و نام پریفرال رو روش میذاریم.
این سه تا کار رو با نمونه بیشتر روشن میکنم :
- در فایل دستگاه، برای رجیسترهای هر پریفرال یک گونه استراکچر شناسش شده. برای نمونه برای پیرارونگ های GPIO که هفت تا رجیستر 32 بیتی دارند، گونه ی GPIO_TypeDef شناسش (تعریف) شده که هفت تا زیرگروه 32 بیتی از گونه ی uint32_t داره که نام های زیرگروه ها هم، همسان با نام های رجیسترهای پیرارونگ GPIO هستند.

2. درباره ی پریفرال GPIOC ، پندارید که در نشانی پایه ی پریفرال GPIOC ( نشانی نخستین رجیستر ) یک استراکچر فرضی هست از گونه ی GPIO_TypeDef که هفت تا عضو 32 بیتی داره، همسان رجیسترهای پریفرال GPIOC. اگر به اعضای های این استراکچر دسترسی پیدا کنیم، به رجیسترهای پریفرال GPIOC دسترسی پیدا کردیم.
برای ساخت پوینتر به نشانی پایه پریفرال هم نیاز داریم. در بخش peripheral memory map برای همه ی پریفرالها ، نشانی های پایه، نام دهی شده اند. برای نمونه درباره ی پریفرال GPIOC ،نشانی نخستین رجیستر 0x40011000 هست که از جمع چند نشانی دیگر بدست آمده.

تا اینجا گونه ی اون استراکچر فرضی که در نشانی هست و خود نشانی رو CMSIS ساخته است، اکنون باید پوینتر رو بسازه.
3. برای ساخت پوینتر ، نخست مقدار اون رو مینویسه که همون نشانی پایه پریفرال هست. نوع پوینتر هم پیش از مقدار اون، در یک پرانتر نوشته میشه. در این نمونه:
مقدار پوینتر که مقدار آدرس هست = GPIO_Base.
نوع پوینتر = *GPIO_TypeDef .
برای اینکه خود پوینتر رو ، که ناخوانا هست در برنامه ننویسیم، پوینتر به هر پریفرال ، به نام اون پریفرال نام دهی شده. برای نمونه پوینتر به رجیسترهای پریفرال GPIOC ، به نام GPIOC نامگذاری شده .


برای خواندن و نوشتن در بیت های رجیستر ها، به ماسک بیت هم نیاز داریم. در بخش peripheral bit definition در فایل device لایه ی نرم افزاری CMSIS ، ماسک بیت برای همه ی بیت های همه ی رجیسترهای همه ی پریفرال ها نام دهی (#define) شده.
ماسک بیت ، یک عدد هم اندازه با رجیستر است که اون بیتی که میخواهیم بخوانیمش یا بنویسمش در آن 1 است .

