درک و نحوه کار CMSIS مثال RCC_TypeDef
آموزش کار با CMSIS و ساختارهای مشابه
بنا به سوال پرسیده شده توسط یکی از اعضای سایت تصمیم گرفتم یک آموزش کامل رو برای درک این موارد پرسیده شده به صورت رایگان براتون قرار بدم .
در این آموزش ابتدا خود CMSIS را توضیح میدهیم و سپس به نحوه کار با قسمت های مورد نظر و درک عملکرد آن می پردازیم .
میکروکنترلر استفاده شده در این آموزش STM32F767 از شرکت St هست ولی با خواندن این قسمت متوجه خواهید شد که هیچ محدودیتی به هیچ میکروکنترلری که CMSIS از آن پشتیبانی می کند ندارید .
CMSIS که اینجا یاد میگیرد یک پله بالاتر از CMSIS هست که اکثرا در موردش حرف زده میشه .
CMSIS
که تو این لحظه دارم براش آموزش می نویسم ورژن 5.7.0
هست که به گفته خود سازنده :
یک تعداد لایه انتزاعی مستقل از شرکت های سازنده میکروکنترلر برای میکروکنترلر های مبتنی بر پروسسور های ARM Cortex هست . مثل همین STM32 هایی که این روزها علاقه مندان زیادی به خودش جذب کرده .
شاید الان با معنی انتزاعی بودن مشکل داشته باشید اما تو همین آموزش وقتی به آخر آموزش رسیدیم دوباره از این واژه استفاده می کنم و میبینید که کامل متوجه این موضوع خواهید شد .
خب از مزیت های این لایه های انتزاعی اینه که شما برای کار با تمام میکروکنترلر های مبتنی بر پروسسور ARM Cortex فقط با همین لایه ها سرکار دارید که بعد از این آموزش می بنید چقدر کارتون راحت کرده .
تو عکس زیر همه قسمت هایی که این بسته CMSIS به ما ارائه می کنه را به صورت قسمت بندی شده مشاهده می کنید :
اون کادر آبی رنگ که تو تصویر بالا مشاهده می کنید که نوشته شده CMSIS-Pack همین بسته ای هست که داریم در موردش صحبت می کنیم که میبینیم بین برنامه ای که ما می نویسیم و سخت افزاری که سازنده میکروکنترلر ارائه می کنه قرار می گیره . که ما تو این آموزش در مورد بعضی از قسمت های این بسته به شما آموزش خواهیم داد . مثلا در مورد CMSIS-Core و نحوه درک و عملکردش . ولی قبل از این بهتره ببینیم این بسته CMSIS چه ویژگی های داره ما به تعدایش اینجا اشاره می کنیم :
- ساختار این بسته به نحوی هست که قابلیت یاد گیری کار با میکروکنترلرهای مبتنی بر آرم رو انعطاف پذیر کرده و به راحتی می تونید با میکروهای مختلف از شرکت های سازنده متخلف کار کنید .
- قابلیت استفاده مجدد از کدهاتون بهتون میده که خیلی مفید هست و تو پیشبرد کاراتون بهتون بسیار کمک می کنه .
- مستقل بودن از لایه های کامپایلر که باعث میشه کامپایلر خودتون برای کامپایل کردن استفاده کنید .
- قوانین متعددی در نوشتن کدهای این بسته استفاده شده مثلا با
ANSI C (C99) و C++ (C++03)
سازگار هست . - از استاندارد typedef تعریف شده در stdint.h مربوط به ANSI C استفاده می کند .
- مطابقت داشتن با MISRA 2012 .
فعلا به گفتن همبن ویژگی ها بسنده می کنیم .
خب از تصویر بالا CMSIS-Core را در نظر بگیرید این قسمتی هست که به ما دسترسی برای کار با هسته پروسسور و واحد های جانبی ( peripherals) می دهد . از ویژگی های این قسمت :
- HAL و یا همان Hardware Abstraction Layer برای رجیسترهای Cortex-M مثل دسترسی به Systick , NVIC , SCB , MPU , FPU و … قرار داده شده .
- برای استثنائاتی که رخ میده و به ما ارسال میشه نام هایی اختصاص داده شده که باعث میشه مدیریت کردن این استثنائات راحت شود .
- متد هایی برای پیکره بندی اولیه .
- تعدادی تابع که مختص کار با CPU هست که در استاندارد های C وجود ندارد در این قسمت برای ما اضافه شده .و…
کامپایلرهایی که تست شده هستند روی این بسته CMSIS و می تونیم مطمئن ازشون استفاده کنیم عبارتند از :
Arm: Arm Compiler 5.06 update 6 (not for Cortex-M23/33/35P/55, Armv8-M, Armv8.1-M)
Arm: Arm Compiler 6.14
Arm: Arm Compiler 6.6.2 (not for Cortex-M0/23/33/35P/55, Armv8-M, Armv8.1-M)
GNU: GNU Tools for Arm Embedded 9.2.1 2019q4
IAR: IAR ANSI C/C++ Compiler for Arm 8.20.1.14183
( دقت شود کامپایلر هستند نه IDE می تونید از این کامپایلرها روی IDE های مختلف استفاده کنید . )
خب سوال پیش آمده را اینجا اضافه می کنیم تا وارد درک و کار کردن با این قسمت Core بشیم ( در واقع از مهمترین قسمت های کار با این Core داخل این سوال و جواب اینجا بیان شده ) :
“شروع سوال کاربر سایت “
سلام استاد
define PERIPH_BASE ((uint32_t)0x40000000)
#
define AHB1PERIPH_BASE (PERIPH_BASE + 0x20000)
#
define RCC_BASE (AHB1PERIPH_BASE + 0x3800)
#
define RCC ((RCC_TypeDef *) RCC_BASE)
#
همه اینا عمل define رو انجام داده ، اون uint32_t هم که یعنی اون عدد هگز یه مقدار 32بیتی هست که define شده.
در سه خط اول مگه همشون آدرس نیستن؟ پس چرا * نزاشته که اشاره گر بشن؟
چرا فقط توی خط چهارم از * استفاده کرده؟
چرا در خط چهارم از RCC_TypeDef استفاده کرده و * گذاشته؟ چرا مثل سه خط اول define نکرده؟
کلا مفهوم این RCC_TypeDef رو نفهمیدم؟
ممنون میشم که به سوالاتم جواب بدید.
من با AVR و کدویژن پروژه زیاد انجام دادم ولی چون کدویزارد داره دیگه درگیر این مسائل نشدم، الان خیلی خوشحالم که دارم از پایه و اساس یاد میگیرم، برای همین توی این مطالب پایه
مشکل دارم.
“پایان سوال کاربر سایت “
اول جاهایی که داخل “آموزش برنامه نویسی میکروکنترلرهای STM32 ” این موارد توضیح دادم میگم بعد دوباره اینجا میگم :
دقیقه 3 قسمت هفت آموزش شروع به گفتن همون چند define
اول می کنیم که اینا برای چی هستند .
دقیقه 9 همون ویدئو هفت یاد میدم اون define
آخری که تو سوال شما هست چی هست .
و دقیقه 12 همون RCC_TypeDef
که شما پرسیدی یاد میگیرید .
( نکته اگر سه قسمت اول آموزش که آموزش زبان برنامه نویسی C هست مخصوصا قسمت سوم رو ندیده باشید و بلد نباشید درست متوجه نمیشید تو قسمت هفت چی دارم میگم )
خب این که برا ویدئو بود . حالا اینجا دوباره توضیحش میدم :
با این 3 تا دیفاین که انجام شده :
define PERIPH_BASE ((uint32_t) 0x40000000)
#
defune AHB1PERIPH_BASE (PERIPH_BASE+0X00020000)
#
define RCC_BASE (AHB1PERIPH_BASE +0x3800)
#
آدرس RCC_BASE بدست آورده .
با دیفاین بعدی :
define RCC ((RCC_TypeDef*) RCC_BASE)
#
اومده گفته این عددی که ما بدست آوردیم ( تو 3 تا دیفاین فبلی ما 3 تا عدد باهم جمع کردیم بهش میگیم آدرس ) بیا این اول cast کن به یک RCC_TypeDef*
که بشه یک اشاره گر به این RCC_TypeDef
که چی بشه ؟
که بتونیم از مزیت های اون ساختار استفاده کنیم . حالا یک مورد کامل تر برات مثال میزنم که هم متوجه بشی چه اتفاقی داره تو این ساختار میفته هم متوجه بشی چرا بالا اومده Cast کرده به این :
دیتاشیت STM32F767 میگه آدرس RCC_Base
هست :
( صفحه 104 ) :
0x4002 3800
حالا بریم سراع Refrence Manual همین میکرو و قسمت مربوط به رحیسترهای RCC رو بیاریم
( صفحه 217 شروع جمع بندی رجیسترهای این واحد RCC میکرو stm32f767 هست )
فرض کن ما با رجیستر RCC_AHB1ENR
این میکرو کار داریم و میخوایم یه پریفرالی روکلاکش فعال کنیم آدرس این رجیستر 0x30
تا جلوتر هست از آدرس RCC_Base
( اولین خونه سمت چپ تصویر بالا جایی که قرمز کردم 0x30
) پس شد از اون آدرس شروع یا همون Base این RCC_AHB1ENR
رجیسترOffset
داره به اندازه 30 تا ( هگز ) .
خب حالا برگردیم به دیفاین هایی که داشتیم ما تا RCC_Base
آدرس با 3 تا define اول بدست آورده بودیم حالا باید 0x30
تا بریم جلو :
چندتاکار میتونیم بکنیم :
1-یکی اینکه اون define سومی بعدش ی Define دیگه بنویسیم بگیم به اضافه 0x30
یعنی میشه :
(این خط که از قبل داشتیم : )
define RCC_BASE (AHB1PERIPH_BASE +0x3800)
#
( و این خط جدید که خودمون اضافه می کنیم : )
define RCC_AHB1ENR_Nikelec (RCC_BASE +0x30)
#
(اینحا من یک Nikelec اضافه کردم که بدونی این راه پیش فرض کتابخانه ای که داری باهاش کار می کنی نیست و برای درک بهتر این کار انجام دادم )
بعدم بیایم مقدار بدیم که چون این یک عدد هست که مشخص کننده آدرس اون رجیستر RCC_AHB1ENR
هست که ما باهاش کار داریم(3 قسمت اول آموزش زبان C با مثال توضیح داده شده) ،پس باید از یک عدد خالی تبدیلش کنیم به یک آدرس اشاره گری که بفهمونیم( آقای کامپایلر شایدم خانم و بقیه قسمت های مرتبط ) این یک رجیستر هست که ما میخوایم داخلش مقدار بریزیم پس میایم cast می کنیم به یک اشاره گر و مقدارش میدیم :
نکته ای که اینجا باید گفته بشه واقعیت اتفاقی هست که در عمل چطور این عدد ریخته میشه داخل اون قسمت از حافظه میکروکنترلر و وظیفه کی هست که این هندل کنه .مثلا من بالا گفتم کامپایلر، این که این کامپایلر چطور این کار میکنه و چه فایل های دیگه ای به کمکش میاند و …. از این دست موارد مباحث متفاوتی هستند که تو آموزش معماری که روی سایت قرار دادم کامل توضیح داده شده اینجا فقط نوشتیم کامپایلر و رد شدیم که وارد همه اون جزئیات نخوایم بشیم و از مسئله اصلی دور نشیم .
خب این ی راهش اما کاری که خط چهارم کرده اومده گفته ما یک ساختار یا Structure داریم :
( این از فایل stm32f767xx.h آوردم اینجا : )
به این خط دقت کن :
اومده تهش به صورت کامت نوشته :Address offset: 0x30
یعنی وقتی این متغیر داخل این ساختار باهاش کار کنی به صورت خودکار 0x30
تا از آدرس Base مربوط به RCC جلو میریم حالا چطور :
1- این ساختار Cast شده به RCC_Base
ما تو define چهارم که شما نوشتید :
define RCC ((RCC_TypeDef*) RCC_BASE)
#
2- پس آدرس شروع این ساختار درواقع آدرس همون RCC_Base
میشه با اینکار . حالا شروع کن اندازه بایت هایی که این متغیرها ( فیلد های ساختار بگیم بهتره ) اشغال می کنند با هم جمع کن تا برسی به AHB1ENR
که تو تصویر قبلی دورش قرمز کردم .
چطوری :
هر کدوم از این فیلد ها یا متغیرهای داخل ساختار uint32_t
هستند یعنی 4 بایت اشغال می کنند . خب چهار بایت برا هر فیلد باهم جمع کن :CR+PLLCFGR+CFGR+CIR+AHB1RSTR+AHB2RSTR+AHB3RSTR+RESERVED0+APB1RSTR+APB2RSTR+RESERVED1[2]
تا اینجا شدند 12 تا رجیستر ( توجه کن فیلد آخر 2 خانه دارد ) که این 12 ضرب کن در 4 بایت میشه 48 این به هگز بنویس : 0x30
پس چی شد خودکار با کار کردن با این فیلد این ساختار RCC_TypeDef
رسیدیم به Offset
مورد نیازمون .
نکته ای که هست این ساختار RCC_TypeDef به تنهایی میشد یک نوع داده اما ما با نوشتن خط :
define RCC ((RCC_TypeDef*) RCC_BASE
#
اومدیم این ساختار نسبت دادیم به اون آدرس ( و برعکس این حمله بیشتر صادق هست یعنی آدرس نسبت دادیم به اون ساختار ولی برا درک بهتر حمله اول در نظر بگیرید )( اگر این کار نمی کردیم استفاده از این ساختار مثل تعریف یک متغیر معمولی توی حافظه بود و کمکی به ما نمی کرد و درواقع این ساختار به تنهایی کارا نیست .) حالا این آدرس ما مثل یک ساختار می مونه که اشاره میکنه به آدرس مورد نظر از حافظه ما ( که اینجا میشه رجیسترهای یک پریفرال )
این کار نسبت به راه اول مزیت زیاد داره مثلا :
یکیش الان برای دسترسی به این رجیستر کافیه از یک
->
استفاده کنی ( که تو آموزش زبان برنامه نویسی C کامل توضیح دادم این مورد )
دیگه اینکه کار با این ساختار برای توسعه خیلی راحت هست. چطور ؟نگاه کن به ساختار دوتا فیلد میبینی به اسم :RESERVED
اینا برای این اضافه شده که این ساختار در واقع همیشه بهمین منوال کار کنه و اگه تو میکرویی رجیستری اضافه بود جاش رزرو میذارند مثل همین الان و این ساختار همیشه فیلد :AHB1ENR
به اندازه 0x30
تا offset
خواهد داشت.
به اینکارا که انجام دادیم mapping حافظه میگیم . که البته این یک روش از mapping بود روش دیگه ای هم داریم که نیاز به توضیحش اینجا نیست .
من اینجا یک کار کردم که بهتره توضیح بدم :
اینکه از میکرو F7 مثال زدم که ببینید این آموزشی که روی سایت قرار دادم محدود به میکرو خاصی نیست منظورم دقیقا همین مورد هست که الان دیدید هیچ فرقی نمی کنه شما چه میکرویی انتخاب کنید.
تو آموزش F4 هست شما با F1 کار می کنی من F7 مثال زدم . حالا سری L,G یا … هر سری دیگه اصلا شما میکروت فلیپس NXP یا TexasInstrument باشه یا Atmel باشه روال کار همینه که اینجا گفتم . تو کره مریخ بری همین شکل هست و اصول و اساسش همین هست تو شرکت Google هم بری بخوای اینکار بکنی بهمین سبک هست به اسم ها توجه نکن .و حالا متوجه میشی این انتزاعی بودن به چه معنا بود که اول آموزش گفتم آخر بار متوحه میشی .
این مطلب حدود 15 دقیقه از قسمت هفتم آموزش برنامه نویسی میکروکنترلر های STM32 سایت Nikelec.ir است و اشتراک گذاری یا استفاده از مطالب نوشته شده در این سایت در سایت ها و کانال ها فقط با ذکر منبع رضایت داده شده است .
امام صادق علیه السلام می فرمایند:
«ان هذا العلم علیه قفل ومفتاحه المسالة; (15)
بر این دانش قفلی است که کلید آن، پرسش است .»