روشهای برنامهنویسی تأثیر بسزایی در سرعت اجرای برنامه خواهند داشت. فرض کنید قصد دارید 64 کانال مجزای PWM با فرکانس 10 کیلوهرتز ایجاد کنید، با دقت 8 بیتی هر PWM. در نگاه اول پیادهسازی با استفاده از میکروکنترلر حتی میکروکنترلرهای قدرتمندی چون ARM غیرممکن به نظر میرسد و ممکن است برای پیادهسازی آن به سراغ FPGA بروید یا کلاً از پیادهسازی چشمپوشی کنید؛ اما با روشهای صحیح برنامهنویسی و تسلط به میکروکنترلر بهراحتی میتوان این بحث را با استفاده از یک میکروکنترلر STM32F103 انجام داد.
شاید برای شما مفید باشد: آموزش FPGA
شناخت محدودیتهای موجود و داشتن مهارت برنامهنویسی به ما کمک میکند که قادر به طراحی بهینه باشیم و از قبل بدانیم چهکاری ممکن و چهکاری غیرممکن است. در این مقاله دو مبحث را موردبررسی قرار میدهیم: تأثیر روشهای مختلف برنامهنویسی و حالتهای مختلف اپتیمایز (Optimize) بر عملکرد و سرعت اجرای برنامه.
در این مقاله با استفاده از میکروکنترلر STM32F103VET6 از مجموعه سریهای ARM Cortex-M3 ساخت شرکت ST سعی داریم نشان دهیم که روشهای مختلف برنامهنویسی و اپتیمایزهای مختلف چه تأثیری در روند اجرای برنامه دارند. برای این اندازهگیری، از یک روش ساده و همیشگی استفاده خواهیم کرد: تغییر وضعیت یک پایه؛ هرچه فرکانس ایجادشده بیشتر باشد، یعنی عملکرد بهینهتر و سریعتر برنامه.
همچنین از کامپایلر GCC که یک کامپایلر قدرتمند و متنباز است استفاده خواهیم کرد.
این آزمایش را میتوان توسط دو روش مختلف انجام داد:
- استفاده مستقیم از CPU برای تغییر وضعیت پایه
- استفاده از انتقالدهنده DMA
که در ادامه نتایج هر دو روش را بررسی میکنیم. استفاده از آی سی های ARM این اجازه را به ما میدهد که برنامه به زبان C را بدون استفاده از هیچ کتابخانهای و بهصورت ساده و مبتدی روی آن پیاده کنیم.
تنظیمات کلاک سیستم:
کلاک سیستم میتواند فرکانسهای مختلفی بین 48 و 72MHz داشته باشد که تنظیمات فلش روی کلاک سیستم تأثیرگذار است:
1 2 3 4 | These bits represent the ratio of the SYSCLK (system clock) period to the Flash access time. 000 Zero wait state, if 0 < SYSCLK ≤ 24 MHz 001 One wait state, if 24 MHz < SYSCLK ≤ 48 MHz 010 Two wait states, if 48 MHz < SYSCLK ≤ 72 MHz |
سرعت تغییر وضعیت STM32F1
یکی از روشهای ساده برای کپی کردن اطلاعات از مموری به روی GPIO استفاده از حلقهی for است:
1 2 3 4 5 6 7 8 9 10 | { u8 buffer[8] = {0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00}; while(1) { for(u32 i=0; i<8; i++) { GPIOD->ODR = buffer[i]; } } } |
در فرکانس 48MHz بدون تنظیمات flash wait states، در حالت بهینهسازی نشده (O0)، به فرکانس بیش از 1MHz دست پیدا میکند. در زمان اجرای برنامه در زمانهای ری استارتِ حلقهی while، شکافی در سرعت اجرا ایجاد میشود که به دلیل پاک شدن PipeLine در هنگام اجرای دستورات شرطی و پرشی است:
مجدداً برای فرکانس 48MHz بدون تنظیمات flash wait states آزمایش را تکرار میکنیم ولی این بار بهینهسازی O2 را اعمال میکنیم. به فرکانس 1.8 MHz دست پیدا میکند. در شکل نیز دیده میشود که شکافهای ایجادشده توسط حلقهی while حذف شدهاند:
وقتیکه تنظیمات فلش را روی 2 wait states قرار دهیم، بدون اعمال بهینهسازی عملکرد CPU کاهش مییابد: (here -O0)
با تنظیم فلش روی 2 wait states و اعمال بهینهسازی O2 عملکرد CPU نسبت به بدون تنظیمات فلش کاهش مییابد: (here -O2)
این بار فرکانس را روی 72MHz تنظیم میکنیم و آزمایشها را تکرار میکنیم. در حالت بدون تنظیمات flash wait states و بدون بهینهسازی عملکرد CPU بهبود مییابد: (here -O0)
با تنظیم فلش روی 2 wait states و اعمال بهینهسازی O2، عملکرد CPU در فرکانس 72MHz نسبت به فرکانس 42MHz بهبود مییابد: (here -O2)
در حالت بهینهسازی نشده، حلقهی for در اجرای برنامه تأخیر ایجاد میکند. برای حل این مسئله دستورات برنامه را بدون استفاده از حلقهی for مینویسیم:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | { u8 buffer[8] = {0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00}; while(1) { GPIOD->ODR = buffer[0]; GPIOD->ODR = buffer[1]; GPIOD->ODR = buffer[2]; GPIOD->ODR = buffer[3]; GPIOD->ODR = buffer[4]; GPIOD->ODR = buffer[5]; GPIOD->ODR = buffer[6]; GPIOD->ODR = buffer[7]; } } |
در این برنامه با تنظیم فرکانس سیستم، بر روی 72MHz میتوانیم به فرکانس 3.6MHz دست یابیم. البته تأثیر حلقهی while همچنان باقی است:
در فرکانس 72MHz مشابه حالت قبل اما با بهینهسازی O2 عملکرد CPU به طرز چشمگیری به 18MHz بهبود مییابد. قابلتوجه است که 18MHz بالاترین سرعت GPIO بیانشده در دیتاشیت آن است.
ارسال اطلاعات توسط DMA به GPIO :
روش دیگری برای کپی اطلاعات از SRAM روی GPIO استفاده از (DMA (Direct Memory Access است. DMA بدون استفاده از CPU اطلاعات را از A روی B کپی میکند.
1 2 3 4 5 6 7 8 9 10 11 12 13 | u8 buffer[8] = {0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00}; /* DMA setup */ RCC->AHBENR |= RCC_AHBENR_DMA1EN; /* channel 1: mem:8bit -> peri:8bit */ DMA1_Channel1->CNDTR = 8; DMA1_Channel1->CMAR = (uint32_t)buffer; DMA1_Channel1->CPAR = (uint32_t)&(GPIOD->ODR); DMA1_Channel1->CCR = 0; DMA1_Channel1->CCR = DMA_CCR1_MEM2MEM | DMA_CCR1_PL | DMA_CCR1_MINC | DMA_CCR1_CIRC | DMA_CCR1_DIR | DMA_CCR1_EN; while(DMA1_Channel1->CNDTR); |
در واقع، به دلیل استفاده از حلقهی while در انتهای برنامه، روش DMA بدون استفاده از بهینهسازی بهاندازهی CPU سریع عمل نمیکند. در زمان استفاده DMA برای انتقال اطلاعات به GPIO ،اطلاعات خواستهشده از روی دیتا باس خوانده میشوند.
این بار حلقه while را با یک حلقه for بدون شرط جایگزین میکنیم تا تفاوت را مشاهده کنیم:
1 2 | //while(DMA1_Channel1->CNDTR); for(;;) {} |
در این حالت نتیجه با حالت استفاده از CPU مشابه می شود (3.6MHz):
قابلذکر است که تمامی آزمایشهای DMA بدون اعمال بهینهسازی انجام میشود؛ زیرا با اعمال بهینهسازی O2 نتایج مطلوبی حاصل نمیشود:
جمعبندی:
با توجه به آزمایشهای انجامشده ملاحظه شد که STM32F1 با اعمال بهینهسازی O2 و بدون استفاده از دستور حلقهی for میتواند به فرکانس 18MHz در GPIO دست پیدا کند (البته اعمال بهینهسازی O3 نتایج بهتری را تولید نمیکند).
برای حالت انتقال اطلاعات توسط DMA اگر از 32 بیت DMA برای خواندن اطلاعات از SRAM استفاده شود ممکن است بتوان به نتایج بهتری دستیافت.
مقدمه : Zeus
سلام وقت به خیر مطلب مفیدی بود ممنون
سوال در مورد flash wait state دارم. مطابق اولین تصویری که قرار دادید، آیا وابسته به SYSCLK هست یا به طور جداگانه قابل تنظیم هست. و اگر جداگانه قابل تنظیم هست، تاخیر بیشتر تو دسترسی به فلش (اگر درست متوجه شده باشم) چه مزیتی داره؟
خیلی ممنون جناب زئوس
سلام دوست عزیز
تنظیم رجسیتر flash wait state با توجه مقدار کلاک دریافتی cpu انجام میشه ؛ اما برای چی هست این موضوع !
همونطور که حدس میزنید فرکانس کاری FLASH به پای فرکانس کاری cpu نمی رسه برای همین مجبوریم دسترسی cpu به flash رو مقداری محدود کنیم تا flash بتونه بدرستی کار کنه ؛ اگر چنین کاری رو انجام ندیدم ممکنه میکرو درست کار نکنه و با مشکل مواجه بشه ؛ برای همین فرکانس دسترسی به falsh رو در فرکانس های بالا کاهش میدیم که سیستم بدرستی کار کنه.
کل دیتاشیت ها رو بزارین
منظور شما رو از دیتاشیت متوجه نمیشم !
میشه لطفا منبع دیتاشیت رو بدین
منبع مطلب انتهای مطلب گذاشته شده
با سلام
اینجا چون while چنین شرطی داشته، به نسبت for بدون شرط بهینه تر بوده؟ دقیق تر بخوام بگم اینه که آیا سرعت چرخش در (;;)for بیشتر از (1)while است؟
فکر نکنم فرقی بکنه البته برای این که بشه دقیق گفت باید اسمبلی تولید شده رو مقایسه کرد ! ولی فکر کنم در آخر هر دو سینکس یه Jamp ختم میشن و عملیات شرطی صورت نمیگرده
درود بر شما
مطابق مطالب دیتاشیت DMA از gpio ها پشتیبانی نمیکند .یعنی به طور مستقیم دیتا رو نمیشه از حافظه به روی رجیستر GPIO انتقال داد. dma در این میکروها فقط شامل spi و usart و usb و i2s و timer و خود مموری میکرو میشه.
البته برای انتقال سریع داده ها روی gpioشرکت st یه مقاله گذاشته بود که از dma و timer و gpio واسه انتقال استفاده میکرد.
خوب ، GPIO در رده حافظه سیستم (RAM ) قرار میگیره و DMA بهشون دسترسی داره !
توصیه میکنم یک بار چک کنید به صورت عملی ! همونطور که خودتون هم اشاره کردید خود شرکت st در این خصوص مستندات قرار داده
سلام مقایسه خوبی بود
من متوجه منظورتون از اعمال بهینه سازی o2 یا غیره متوجه نشدم که این بهینه سازی رو به چه شکل انجام میدید؟ایا منظور بهینه سازی توسط کامپایلر هسش؟ اونوقت چه کامپایلری iar ، keil ..ممنون میشم این مورد رو توضیح بدید
سلام دوست عزیز
بله درست متوجه شدید ، بهینه سازی کد توسط کامپایلر انجام میشه.
در ابتدای مقاله نوشته شده که از کامپایلر GCC استفاده خواهیم کرد ، کامپایلر Gcc یک کامپایلر متن باز و رایگان هست که دارای 5 سطح اپتیمایز است ، O0,O1,O2,O3,Os ، ما کلید های مختلف از این سطح رو مورد بررسی فرار دادیم
البته کامپایلر های IAR و Keil هم داری سطوح اپتیمایز کد هستند که توی تنظیمات پروژه قادر به تغییر اونها هستید.
خیلی ممنونم ..عذر میخوام اخر وقت بود پیام رو خوندم به اخر مطلب که رسیدم یادم رفت اصن کامپایلر چی بوده براهمین مجدد پرسیدم … اگر امکانش باشه بخش های بهینه سازی رو تو همون کامپایلرهای keil و iar بررسی کنید
خواهش میکنم دوست عزیز
ما تمام تلاشمون اینه که فرهنگ استفاده از نرم افزار های متن باز رو جا بندازیم و ثابت کنیم که هیچی از نرم افزار های تجاری کم ندارند که هیچ حتی بهتر هم هستند
ولی چشم اگر فرصت شد حتما این موارد رو هم تست میگیریم