RTOS Kullanmadan yapmak istediğim birşey

Başlatan NaMcHo, 08 Temmuz 2013, 14:33:10

NaMcHo

Merhabalar,

//Ana döngü
while(1){
	if(Flag.Gorev1){
		fonk1();
	}
	
	if(Flag.Gorev2){
		fonk2();
	}
	.
    .
    .
}

Timer kesme(){
	anadongüde hesaplanan degerler registerlara yazılıyor...
	
	Flagların degerleri yazılıyor vs...
}


Yazılımlarım genelde yukarıdaki gibi oluyor,

1-) fonk1() işletilirken x. satırındayken  kesme geliyor ve kesme fonksiyonu içerisindeki işlemler tamamlandıktan sonra bir sonraki kesme gelmeden önce mutlaka işletilmisini istediğim bir fonksiyon olan fonk3() var bu durumda kesmeden çıktıktan sonra önce fonk3()'ü işlet daha sonra fonk1()'in x. satırından program akışını sürdür.

2-) Veya fonk1()'in x. satırından devam et ve sonra mutlaka fonk3'ü işlet ve normal program akışına devam et.

böyle birşeyi nasıl yapabilirim?

Kazım

#1
fonk(3) 'üde tmr kesmesi  içinde , kesme kodlarının ardına yazsan sonra çıksan zamanın yetiyor mu ? buna bir bak zamanlama kurtarırsa böyle yapabilirsin.

camby

#2
2 yol var :

1- Mutlaka işletilmesini istediğin fonksiyon3'ü kesme programı içinde işlet ve kesmeden öyle çık, kaldığın yerden devam et. Örneğin Bülent Hocanın kesme bölümlerini kesinlikle ASM yazarım demesinin sebebi bu. Yeni kesmeye hazır olunması için orada işlerin çabuk bir şekilde yapılıp çıkılması gerekiyor oradan.

2 - Kesme içerisinde yapılmaması gerekiyor ise ( kesmenin hemen açılması gerekiyordur ) :
     2.1 - Kesme içerisinde, kesmeden önce kalan program adresini stack alanından oku bir yere kaydet ve yerine fonksiyon3 ün başlangıç adresini kaydet ve kesme programı çalışsın. Kesme dönüşü program senin yazdığın yeni adrese dönecektir. Fonksiyon3'ün sonunda da dönmeden önce tekrardan stack adresini değiştir ve fonksiyon1'in yedeklenmiş adresini kullan. F3 bittiğinde dönüş olarak stack'te gördüğü adrese gidecektir. ( Stack alanı içindeki diğer elemanlara zarar vermemeye dikkat )
     2.2 - 2.1'den farklı olarak fonksiyon 2nin kaldığı yer yerine main gibi sabit bir yere dönebilirsin. Fonksiyon2 yarım kalır. Fonksiyon2'nin yarım kalması önemsiz ise bunları halledebilirsin.


ASM yazarken bol bol GOTO kullanıp , kesme girişi dönüşü stack alanlarını da değiştirerek istediğim yere atlayıp zıplıyordum.
Burada stack alanı olarak Program Counter'ın saklandığı stack alanından bahsediyorum. C'de verilerin saklandığı stack alanından bahsetmiyorum. C'de biraz daha dikkatli yapılmalı bu işlemler.


----------

Alıntı Yap2-) Veya fonk1()'in x. satırından devam et ve sonra mutlaka fonk3'ü işlet ve normal program akışına devam et.

Kesme geldiğinde bir bayrak işaretleyip , fonk1 sonunda da bu bayrağı kontrol edersen fonk3'ü işletebilirsin kesme gelip gelmemesine göre. Tabi fonk1'in ne kadar sürdüğünden emin olman lazım. Kesme gelmiş ancak fonk1 sonuna gelemeden tekrar kesme gelmiş ve fonk3 işletilememiş olabilir.

NaMcHo

#3
@camby 2.madde bahsettiğin stack olayı benim çözümüm aslında ama ben bunun C ile nasıl yapılabileceğini merak ediyordum o yüzden böyle bir soru sordum
Alıntı YapKesme geldiğinde bir bayrak işaretleyip , fonk1 sonunda da bu bayrağı kontrol edersen fonk3'ü işletebilirsin kesme gelip gelmemesine göre. Tabi fonk1'in ne kadar sürdüğünden emin olman lazım. Kesme gelmiş ancak fonk1 sonuna gelemeden tekrar kesme gelmiş ve fonk3 işletilememiş olabilir.
Bu tarz kontrolleri oldukça fazla yapıyorum :)

@graski Tüm hesaplama fonksiyonlarımın kaç usn'de hesaplandığına(ARM Cortex M4 için) zaten hep bakarım...Kesme fonksiyonu içinde kodları koşturmak bana göre değil.

Şöyle bir çalışmam olmuştu,

//Ana Döngü
while(1)
	{
		//while(ADC1->DR == 0);
		//PWM açma kapama islemini kesme icinde duty ve arr yazildiktan sonra yap...
		//ana dongude flag kullan ve kesme icinde kontrol et.
		if((ADC_GetITStatus(ADC1,ADC_IT_EOC) == SET))
		{
			ADC_ClearITPendingBit(ADC1,ADC_IT_EOC);
			voltaj_degeri=ADC_GetConversionValue(ADC1);
			//ADC_StopConversion(ADC1);
			voltaj_degeri=voltaj_degeri & 0x0000FF0;
			swFreq=voltaj_degeri/adc2freq;	//Cikisin temel harmonik bileseninin frekansi
			Motor.FreqRefA=swFreq;
		
			Kontrol.ADCDone=1;
			Kontrol.ADCStart=0;
			if((Motor.FreqRefA >= 1) & (Kontrol.PWMStart ==0))
			{
				Kontrol.PWMStart=1;
			}
		}
		
		
		//-------------------------------------MOTOR KONTROL--------------------------------//
		if((Kontrol.MotorStartUpDone == 0) & (Kontrol._100msDone == 1) & (Kontrol.PWMStart == 1))
		{
			if(Kontrol.CalculationDone == 0)			
			{
				TIM_Cmd(TIM14,DISABLE);
				
				Boost(&ARRSinusNum);
				Kontrol.CalculationDone=1;
				Kontrol._100msDone=0;
				
				if(Motor.CurrentFreq >= Motor.F_Boost)
				{
					//Artik lineer calismaya gecilcek
					Kontrol.MotorStartUpDone=1;
					Motor.CurrentFreq=Motor.F_Boost;
				}
				else if(Motor.CurrentFreq < 1)
				{
					TIM8->BDTR&=0x00FF;												//PWM kapatildi.
					ARRSinusNum.arr=0x05FF;										//Rasgele bir deger, sifir olmamali arr registeri
																										//kesmeye girmiyor cünki.
				}
				//Pot degeri sifirdan farkli olunca cikisi aktif et
				else
				{
					TIM8->BDTR|=(1<<15);					//Ana çikis aktif.
					if(sinCount==0){
						//Sadece 1.periyot icin lazim bu
						//ilk duty degerleride yazilsin
						TIM8->ARR=ARRSinusNum.arr;
						sinNumber=ARRSinusNum.sinNum;
					}
					PWMSTART;
				}
				
			}
			Kontrol.ADCStart=1;
		}
		
		//Lineer Hiz Kontrolü (V/f), Boost bölgesinden cikildi...
		else if((Kontrol._100msDone == 1) & (Kontrol.MotorStartUpDone == 1))
		{
			if(Kontrol.CalculationDone == 0)						//1 periyot tamamlanmadan yeni deger hesaplamasi baslamiyor
			{
				TIM_Cmd(TIM14,DISABLE);
				//* arr ve sinus adedi belirlenecek.
				MotorSpeedControl(&ARRSinusNum);
				if(Motor.CurrentFreq < 1 & Kontrol.PWMOutput == 0)
				{
					//Cikislari kapat ve arr'ye atama yapma cünki arr=0 olunca birdaha kesme olmuyor ve donuyor sistem
					ARRSinusNum.arr=0x05FF;
					//MOE disable
					TIM8->BDTR&=0x7FFF;						//PWM kapatildi.
					Kontrol.PWMOutput=1;					//PWM inaktif
				}		
				else if((Kontrol.PWMOutput == 1) & (Motor.CurrentFreq >= 1))
				{
					Kontrol.PWMOutput=0;				//PWM aktif
					//MOE enable
					TIM8->BDTR|=(1<<15);				//PWM Acildi..
				}
				Kontrol.CalculationDone=1;				
				Kontrol._100msDone=0;
				//ADC_StartConversion(ADC1);				//Bir sonraki adim icin adc cevrimi verisi aliniyor.
				
			}
			Kontrol.ADCStart=1;
		}
		
		
		if(Kontrol.SinCalculated == 0)
		{
			FindSinValues(ARRSinusNum,&SinValues,&sinCount,&Kontrol,&currentDegree,&sinNumber);
			//Bir sonraki sinus degeri icin hesaplama yapiliyor.
			if(Kontrol.SinCalcAtInt == 1){
				Kontrol.SinCalcAtInt=0;			
				FindSinValues(ARRSinusNum,&SinValues,&sinCount,&Kontrol,&currentDegree,&sinNumber);
			}				
			else
				Kontrol.SinCalculated=1;
		}
	}


Böyle bir ana döngüm vardı ve PWM kesme fonksiyonum ise şöyledi,
void TIM8_UP_TIM13_IRQHandler(void)
{
		static double dutyMul_1;
		static uint16_t arr_2=0;
		TIM_ClearITPendingBit(TIM8,TIM_IT_Update);
	
		if(Kontrol._1PeriodDone)	//calc'1 iç if yap...
		{
			if(Kontrol.CalculationDone)
			{
				//yeni duty carpani atamasi yapilacak
				dutyMul_1=dutyMul;	
				Kontrol.CalculationDone=0;
				TIM_Cmd(TIM14,ENABLE);				//100ms sayma baslasin
				if(ARRSinusNum.arr != 0)
					TIM8->ARR=ARRSinusNum.arr;
				else
					TIM8->ARR=0x05FF;
			}
			Kontrol._1PeriodDone=0;
		}
		
		//Eger ana dongude sinus degerleri hesaplanamissa kaldigi yerden devam et...
		if(Kontrol.SinCalculated == 0)
		{
			arr_2=TIM8->ARR>>1;
			if(Kontrol.EachSin.usinCalculated == 0)
			{
				//u fazi icin duty degerini hesapla.
				FindSinValues(ARRSinusNum,&SinValues,&sinCount,&Kontrol,&currentDegree,&sinNumber);
				//sifirla tüm bayraklari
				//Kontrol.EachSin=0;
			}
			else if(Kontrol.EachSin.wsinCalculated == 0)
			{
				//w fazi icin duty degerini hesapla.
				SinValues.vsin=arm_sin_f32(currentDegree+_120)*arr_2+arr_2;							//tempi tanimlama 
				Kontrol.EachSin.vsinCalculated=0;
				
				SinValues.wsin=arm_sin_f32(currentDegree+_240)*arr_2+arr_2;
				Kontrol.EachSin.wsinCalculated=0;
				//3 faz icinde duty degerleri belirlendi.

			}
			else if(Kontrol.EachSin.vsinCalculated == 0)
			{
				//v fazi icin duty degerini hesapla.
				SinValues.wsin=arm_sin_f32(currentDegree+_240)*arr_2+arr_2;							//tempi tanimlama 
				Kontrol.EachSin.wsinCalculated=0;
				//3 faz icinde duty degerleri belirlendi.

			}
			Kontrol.SinCalculated=0;										//Bir sonraki sin degerinin hesaplanacagi bildiriliyor
			Kontrol.SinCalcAtInt=1;
		}
		else
			Kontrol.SinCalculated=0;															//Bir sonraki sinus hesaplansin ana dongude
		
		//19.5usn sürüyor burasi
		TIM8->CCR1=(SinValues.usin*dutyMul_1)+DUTY_OFFSET;
		TIM8->CCR2=(SinValues.wsin*dutyMul_1)+DUTY_OFFSET;
		TIM8->CCR3=(SinValues.vsin*dutyMul_1)+DUTY_OFFSET;
		
		sinCount++;
		if(sinCount > sinNumber){
			sinCount=0;
			Kontrol._1PeriodDone=1;	
			sinNumber=ARRSinusNum.sinNum;			//Yeni Ornek sayisi atamasi yapiliyor 
		}
}


Kesme fonksiyonuna bakarsanız Kontrol.SinCalculated böyle bir bayrak kontrolü var bu kontrol ana döngüde istediğim hesaplamanın yapılıp yapılamadığını sorguluyor ve hatta bunuda parçalara ayırdım şöyleki,

3 adet faz için duty değeri hesaplıyorum örneğin ilk 2 faz hesaplanmış ise(ana döngüde) kesme içinde sadece 3.fazın kini hesaplayan bir yapı oluşturdum. Uygulama bu haliyle zaten sorunsuz çalışıyor.

Benim istediğim ise kesme içinde hiç kod görmemek... C ile bu işin yapılıp yapılamayacağını sorguluyorum sadece ve goto kullanmak istemiyorum.


Şöyle birşey yapılabilir belki,
Kesmeden çıkarken goto ile istediğim fonksiyona gidicem tabi bu işlemden önce kaldığım yerin adresini ve o ana kadar işlenmiş olan verileri kaydetmem gerekiyor(burası problem biraz :) ) ve ardından kaldığım yerden devam etmek için birşeyler yapmam gerekicek...

Ancak daha kompleks bir uygulama düşündüğümüzde sürekli bu tür şeylerle uğraşmak biraz itici geliyor... Daha güzel çözüm yolu/yolları arıyorum.

fractal

arkadaşlar herhangi bir kod satırının gerçekte ne kadar zamanda  işlediğini nasıl anlıyorsunuz?pin on off yaparak skop ile mi ölçüyorsunuz?yoksa teoirkmi?
Restantum cogniscutur Quantum deligutur

z

Artık çok basit işlemciler bile pipeline mekanizmasına sahipler. Sözkonusu mekanizmadan dolayı sorduğun sorunun cevabı çok kolay değil.

O anda işlenen asm komut ile bu komuttan hemen önce işlenmiş bir kaç asm komuta bakarak o an işlenen komutun kaç cycle olacağını hesaplayabilirsin. Eğer C komutlarının işleme süresini merak ediyorsan, bu işlem, zaten tek tek asm komutları sayıp pipeline kırılımı olup olmadığına da dikkat ederek hesap yoluyla tespit etmek çok meşagatli olur.

Bu zahmete girmek yerine  program parçacığının başında ve sonunda pir pini topgle edip elde edilen pals süresini scopla tespit etmek daha pratik.

Kullandığım yazılım geliştirme ortamının bu süreyi veren yazılımsal destekleri de olabilir. Bazı derleyiclerin komut bazında olmasa da kütüphane fonksiyonları için, fonksiyonun kaç cycle da işlendiğine dair bilgileri dokumanlarda verilebiliyor.

Bana e^st de diyebilirsiniz.   www.cncdesigner.com

hasankara

kodların ne kadar sürede işlendiğini isiste denetleyiciye .cof uzantılı dosyayı yüklettikten sonra breakpoint ler yerleştirerek iki breakpoint arasında sürekli çalıştır deyince altta parantez içinde yazan süre ile örnek olarak (212.00us elapsed) şeklinde takip edebiliyoruz. ancak isiste herşeyi simüle etme şansımız olmadığından dolayı bu durumlarda debug ile yada yazılımsal eklentiler ile süreleri takip edebiliriz.

daha önce başka bir muhabbette de bu fikrimi paylaşmıştım ki kesmelere karşı sıcak bakmıyorum demiştim. arkadaşın bahsettiği gibi kesmeden hemen sonra illa bir şeyler yapıp çıksın dediğimiz durumlar olabiliyor sonra kesme şişiyor sonra bakmışız ki kesmeden çıkılamayacak bir hale geldi programımız. şöyle bir şey önerebilirim muhtemelen sıcak bakmayacağın bir yöntem olur; ana döngüde genel kesmeyi her fonksiyon arasında sırasıyla aktif_deaktif yaptırırsak sadece istediğimiz aralıklarda kesme oluşur. her bu işlemin sonuna fonk3() çağırırsak tarifinize uygun birşeyler oluyor sanırım :). şimdi diyeceksin ki kesme nin ne anlamı kaldı direk fonksiyon olarak tanımlayıp sadece bu aralarda çağırırım dersen kesinlikle hak veririm bu demecine.

sana yaptığım bu öneri yazdığımız kodlar esnek olduğunda gayet kullanışlı oluyor. esneklikten kastım yazdığımız her fonksiyon da geçirilecek maksimum süreyi kısıtlamak. mesela lcd e veri yollayan bir fonksiyon içinde lcd_busy gibi yazacağımız fonksiyonların oluşturduğu ölü zamanların önüne geçerek bu amacımıza ulaşabiliriz. yani kesmeyi, çok hayati bir önem taşımadığı sürece yada olmazsa olmaz durumların dışında kullanmak biraz rahata kaçmak gibi geliyor bana.

https://www.picproje.org/index.php/topic,46980.0.html