03

زمان بندی نرم افزار نهفته

در بسیاری از بخش های نرم افزار نهفته نیاز است که بخشی از کد به صورت دوره ای با دوره اجرای مشخص اجرا شود. مثال های زیر از جمله این موارد است :

  • چشمک زدن یک نمایشگر
  • اجرای دیبانس بر روی ورودی دیجیتال یک کلید فشاری
  • نمونه برداری از مبدل آنالوگ به دیجیتال و اجرای فیلتر بر روی آن
  • ذخیره کردن اطلاعات در حافظه
  • اجرای حلقه های کنترلی
  • اجرای منطق سطح بالای نرم افزار (مانند ماشین حالت)
  • ارسال دوره ای اطلاعات بر روی پورت سریال
  • چک کردن شرایط رخ دادن یک رویداد
  • . . .

این کاربردها را می توان به دو دسته تقسیم کرد :

  • دوره زمانی اجرا باید دقت بالایی داشته باشد یا با یک رویداد دیگر (داخلی یا بیرونی) همزمانی داشته باشد. مانند حلقه های کنترلی، فیلترهای دیجیتال و نمونه برداری از ورودی آنالوگ. در این کاربردها باید از ابزارهای زمان بندی دقیق مانند اینتراپت ها و کرنل (در صورتی که فرکانس اجرا خیلی بالا نباشد) استفاده کرد.
  • دوره زمانی اجرا دقت بالایی نیاز ندارد. مانند چشمک زدن یک نمایشگر، دیبانس و ارسال دوره ای اطلاعات بر روی پورت سریال. در این کاربردها لزوما نیاز به اینتراپت نیست. بلکه می توان در کنار بقیه کدها در اینتراپت ها و یا در حلقه های اولویت پایین مانند while در main و یا در تسک های اولویت پایین (در صورت استفاده از کرنل) کد را اجرا کرد.

در مورد دسته دوم (دوره زمانی با دقت پایین) که اتفاقا در بسیاری از کاربردها، تعداد آن بیشتر از دسته اول (دوره زمانی با دقت بالا) است، باید به وسیله ای بتوان این زمان بندی ها را اجرا کرد. در زیر به برخی از روش های مورد استفاده بدین منظور اشاره می شود :

از آنجایی که در این مطلب به دفعات از مفهوم عنصر اجرایی استفاده می شود، مفهوم آن در زیر نوشته شده است.

[! ] عنصر اجرایی “عنصر اجرایی” بخشی از نرم افزار است که قابلیت اجرا دارد. کدهای نوشته شده در نرم افزار تنها زمانی اجرا میشوند که در یکی از این عناصر به صورت مستقیم یا غیر مستقیم فراخوانی شوند. کلا سه نوع عنصر اجرایی در نرم افزار نهفته داریم :

  • نقطه ورود (Entry Point) : اولین جایی در کد است که توسط پردازشگر اجرا میشود. در زبان c این نقطه همان تابع main است.
  • اینتراپت
  • تسک (در صورت استفاده از کرنل)

[! ] طراحی لایه اجرا “طراحی لایه اجرایی” به مهنی تعیین تعداد، زمان بندی و اولویت این عناصر اجرایی در نرم افزار نهفته است.

استفاده از یک عنصر اجرایی برای هر زمان بندی

یکی از راه های مرسوم آن است که برای هر یک از این بخش های کد که باید به صورت دوره ای اجرا شوند، یک عنصر اجرایی (اینتراپت یا تسک) با دوره زمانی مورد نظر و با اولویت پایین ایجاد کرده و کد را داخل آن اجرا کرد.

نقاط قوت :

  • استقلال زمان بندی بخش های مختلف کد نقاط ضعف :
  • برای هر بخش از کد یک عنصر اجرایی لازم است که به معنی منابع بیشتر سخت افزاری (تایمر) یا نرم افزاری (تسک) مورد نیاز است.
  • نیاز به کرنل (در صورت استفاده از تسک)

استفاده از عنصر اجرایی مشترک

در این روش، یک عنصر اجرایی با دوره اجرای برابر با “بزرگترین مقسوم علیه مشترک تمام دوره های زمانی مورد نیاز” باید ایجاد شود. سپس با استفاده از یک متغیر به عنوان شمارنده برای هر بخش از کد، زمان بندی مورد نیاز برای هر بخش ایجاد شود. به عنوان مثال فرض کنید سه تابع وجود دارد که به ترتیب باید هر 20 میلی ثانیه یکبار، هر 30 میلی ثانیه یکبار و هر 40 میلی ثانیه یکبار اجرا شوند. در این صورت باید یک المان اجرایی با دوره زمانی 10 میلی ثانیه تعریف کرد و با استفاده از یک متغیر برای هر یک از کدهای بالا، به ترتیب پس از 2 بار، سه بار یا چهار بار ورود به المان اجرایی، یکبار باید تابع مربوطه فراخوانی شود.

				
					
int Func1_Counter = 0;
int Func2_Counter = 0;
int Func3_Counter = 0;

//This RunTime(Interrupt or Task) run every 10ms
void RunTime()
{
	Func1_Counter++;
	if(Func1_Counter >= 2)
	{
		Func1_Counter = 0;
		Func1();
	}
	
	Func2_Counter++;
	if(Func2_Counter >= 3)
	{
		Func2_Counter = 0;
		Func2();
	}

	Func3_Counter++;
	if(Func3_Counter >= 4)
	{
		Func3_Counter = 0;
		Func3();
	}
}
				
			

نقاط قوت :

  • استفاده از تنها یک عنصر اجرایی نقاط ضعف :
  • تاثیر بقیه بخش های نرم افزار در دقت اجرای این بخش. از آنجایی که عنصر اجرایی مورد استفاده در این روش اولویت پایینی دارد، در صورتی که تغییری در بخش های دیگر نرم افزار انجام شود، روی زمان بندی اجرای عنصر اجرایی و به تبع آن روی زمان اجرای ت وابع تاثیر می گذارد.
  • در صورتی که زمان بندی عنصر اجرایی تغییر داده شود، در تمام کدهای شمارنده ها باید تغییر داده شود تا متناسب با زمان بندی جدید درست عمل کنند.

استفاده از حلقه while یا تسک اولویت پایین

این روش شبیه استفاده از یک عنصر اجرایی مشترک است، با این تفاوت که این عناصر اجرایی، زمان بندی اجرایی مشخصی نداشته و هر موقع که پردازشگر مشغول بخش دیگری از نرم افزار نباشد، این بخش ها را اجرا می کند. برای ایجاد زمان بندی های مورد نیاز در این روش، باید یک دوره اجرای حلقه با وجود تمام بخش های دیگر نرم افزار اندازه گیری شده و با استفاده از آن و استفاده از متغیر به عنوان شمارنده، زمان بندی های مورد نظر را اجرا کرد. نقاط قوت :

  • بسیار ساده نقاط ضعف :
  • عدم دقت و تکرارپذیری در زمان بندی
  • تغییر تمام زمان بندی ها با تغییر در هر بخش از کدهای نرم افزار
  • پیچیدگی و ناپایدار تنظیم زمان بندی های بخش های مختلف کد

استفاده از یک یا چند عنصر اجرایی به همراه ابزارهای اندازه گیری زمان

روش دیگر، استفاده از هر یک از روش های بالا یا تلفیق آنها به همراه استفاده از ابزارهای اندازه گیری زمان است.

[! ] اندازه گیری زمان در نرم افزار نهفته از آنجایی که در نرم افزار نهفته، اجرای بخش های مختلف کد در زمان بندی های مشخص اهمیت بسیاری دارد، یکی از پایه ای ترین ابزارهای مورد نیاز در این زمینه، ابزارهای اندازه گیری زمان در نرم افزار نهفته است. در این مورد در مطلب ؟؟؟؟ توضیحات کافی داده شده است.

در این روش از ابزار اندازه گیری زمان تیک و ماژول کرونو به عنوان پیاده سازی شده این روش استفاده می شود. در هر یک از عناصر اجرایی، با استفاده از ابزارهای اندازه گیری زمان، مشخص می شود که آیا زمان اجرای این بخش از کد فرا رسیده است یا نه. در این روش هر چه زمان اجرای عنصر اجرایی با زمان بندی لازم برای هر یک از کدها فاصله بیشتری داشته باشد (سریعتر باشد)، کدها با زمان بندی دقیتری اجرا می شود. هر چه این فاصله کمتر باشد، خطای زمان بندی اجرای کدها افزایش می یابد. در کد زیر مثالی بدین منظور نوشته شده است :

				
					
sChrono Func1_Chrono;
sChrono Func2_Chrono;
sChrono Func3_Chrono;

...
fChrono_StartTimeout(&Func1_Chrono, 20);
fChrono_StartTimeout(&Func2_Chrono, 30);
fChrono_StartTimeout(&Func3_Chrono, 40);
...

//Interrupt, Task or EntryPoint(main->while)
void RunTime()
{
	if(fChrono_IsTimeoutMs(&Func1_Chrono))
	{
		fChrono_StartTimeout(&Func1_Chrono, 20);
		Func1();
	}
	
	if(fChrono_IsTimeoutMs(&Func2_Chrono))
	{
		fChrono_StartTimeout(&Func2_Chrono, 30);
		Func2();
	}

	if(fChrono_IsTimeoutMs(&Func3_Chrono))
	{
		fChrono_StartTimeout(&Func3_Chrono, 40);
		Func3();
	}
}
				
			

نقاط قوت :

  • زمان بندی کدها ارتباطی با زمان بندی عنصر اجرایی مورد استفاده ندارد.
  • حجم پردازش پردازشگر تاثیری بر روی دقت اندازه گیری زمان ندارد. نقاط ضعف :
  • نیاز به تیک جهت اندازه گیری زمان
  • دقت اجرای زمان بندی ها بستگی به اختلاف مقیاس زمان بندی های مورد نیاز و زمان اجرای عنصر اجرایی مادر دارد.

جمع بندی

در نرم افزار نهفته، بخش هایی زیادی از کد وجود دارد که لازم است با دوره اجرایی مشخص ولی با دقت پایین اجرا شوند. برای اجرای این کدها با زمان بندی های مشخص، روش های مختلفی وجود دارد و هر کدام نقاط قوت و ضعفی دارند. در میان روش های ذکر شده، کاملترین و زیباترین روش، استفاده از یک یا چند عنصر اجرایی به همراه ابزار اندازه گیری زمان است.

ماژول runtime_scaler

ماژول runtime_scaler، از تعدادی ماکرو تشکیل شده که با استفاده از ماژول کرونو، ابزارهایی را برای اجرای بخش هایی از کد با زمان بندی های متفاوت فراهم می کند. این ماژول علاوه بر استفاده از تمام مزایای ذکر شده در این سند، ماکروهایی را ایجاد کرده است که به زیبایی و خوانایی کد کمک شایانی می کند. در زیر، کد نوشته شده در مثال آخر با این ماکروها بازنویسی شده است:

				
					//Interrupt, Task or EntryPoint(main->while)
void RunTime()
{
	RUN_EVERY_MS_(Func1, 20)
	{
		Func1();

		RUN_END_;
	}

	RUN_EVERY_MS_(Func2, 30)
	{
		Func2();

		RUN_END_();
	}

	RUN_EVERY_MS_(Func3, 40)
	{
		Func3();

		RUN_END_();
	}
}
				
			
برچسب‌ها: بدون برچسب

دیدگاه شما چیست؟

آدرس ایمیل شما منتشر نخواهد شد، فیلدهای الزامی علامت گذاری شده اند.