Zaman buldukca hoby calismasi olarak multitasking yapan cekirdek kodlari kendim yazacagim.
Multitasking temellerini anlatan kitaplari okumak simdilik zoruma gidiyor. Sorularima verilecek cevaplar isimi kolaylastiracak.
Su anda kafami kurcalayan tek konu tasklar arasi veri aktarimi. (Bu konu, Delphide yazmaya calistigim tasklarda basimi agritmisti)
Bu konudaki bilgileri ozetleyebilirmisiniz?
Oncelikle mevcut yapilari arastirmak ve kitaplari okumak lazim. Fakat elzem birkonu olmadigi icin simdilik useniyorum.
Bu veri aktarim sekillerinin her birine bir kac satirda aciklama yapilirsa sevinirim.
(Forum agizi ile bu soyle yazilir. Bu baslik altinda bu bilgileri toplayalim derli toplu olsun diger arkadaslar da yararlansin. Projenin son halini yayinlayacagim.) Yerlerse. :)
Bak bir iki ay sonra bir kac satirda yazilabilecek hale getirirsem yazarim ha...
bunalmış hocam,
multitasking olayı donanımsal değil midir ?
Tek çekirdekli işlemciler ile multitasking ne kadar mümkündür?
iki çekirdekli işlemcide 2 işlemi yapabilmek için iki çekirdeğe bölmek gerekmez mi ?
Multitasking bu değilmidir?
Teşekkür ederim.
Cift cekirdek tek cekirdege gore isleri daha hizlandirir. Cunku gercek anlamda nerede ise paralel islem yapan islemcin var demektir.
Fakat task sayisi ile cekirdek sayisi arasinda alaka kurulmamali.
Kodlarda buyuk degisiklik yapmadan her biri ayri islemcilerde kosacak projelerinizi cok hizli bir islemcide kosacak sekle donusturebilirsin. Yada bir islemcide kosacak karmasik bir programi kucuk parcaciklara bolup her birini ayri tasklar seklinde kosturabilirsin. Boylece program uzerinde degisiklik yaparken diger bolumlerin olumsuz etkilenmesinin onune gecebilirsin.
http://ww1.microchip.com/downloads/en/AppNotes/00585b.pdf (http://ww1.microchip.com/downloads/en/AppNotes/00585b.pdf)
Guzel bir dokuman
Alıntı yapılan: bunalmis - 08 Ekim 2011, 12:29:05
(Forum agizi ile bu soyle yazilir. Bu baslik altinda bu bilgileri toplayalim derli toplu olsun diger arkadaslar da yararlansin. Projenin son halini yayinlayacagim.) Yerlerse. :)
Haha :D Böyle birşey de var değil mi hakikaten...
Alıntı yapılan: Seçkin ALAN - 08 Ekim 2011, 14:26:21
bunalmış hocam,
multitasking olayı donanımsal değil midir ?
Tek çekirdekli işlemciler ile multitasking ne kadar mümkündür?
iki çekirdekli işlemcide 2 işlemi yapabilmek için iki çekirdeğe bölmek gerekmez mi ?
Multitasking bu değilmidir?
Teşekkür ederim.
Bahsettiğiniz multiprocessing. Multitasking birdenfazla işlemin tek cpu kaynağını paylaşması.
@Gerbay
Multitaskingle aslinda isim yok. Tasklar arasi veri aktarimi problemi hosuma gitti. Bu problemle ugrasmak istedim. Hoby iste.
@Gerbay, Zorluk acisindan ikisi arasinda fazla bir fark yok gibi.
------------------------------------------------------------------------------
En iyisi adim adim gitmek. Oncelikle hic veri aktarimini ise katmadan temel bir probleme cozum olacak cekirdegi yazmak lazim.
Amerikayi kendim kesfetmeye karar verdim. Elin gavuru ne yapmisla ilgilenmeyecegim.
Temel problemi soyle tanimliyorum.
A ve B olmak uzere iki islemcimiz farkli iki program kosturmaktadir.
Bu islemciler harici clock kaynagi ile beslenmekte fakat, harici clock donanimi her 10ms de sadece bir islemciyi beslemektedir. Aciklamak gerekirse A islemcisi 10ms boyunca kod kostururken B islemcisi beklemekte, 10ms sonunda A islemcisi beklemekte ve bu kez B islemcisi kod kosturmaya baslamaktadir.
Simdi, elimizde A ve B den en az iki kat hizli, bol portlu bir islemci olsun. Bu islemci uzerinde A islemcisine ait olan kodlari kosturalim, 10ms sonunda A kodlarinin isletimine ara verip B islemcisine ait kodlari kosturalim ve bu boyle devam etsin...
Bu multitask programlamanin en basit hali gibi gorunuyor.
A ve B arasinda herhangi bir veri aktarimi yok, A ve B ayni cevre birimlerini kullanmiyor.
Mesela P1 portu A yazilimina, P2 portu B yazilimina ayrilmis olsun. Ramda 0x1000....0x1FFF, A yazilimina, 0x2000...0x2FFF, B yazilimina ait olsun gibi.
A ve B islemcilerinin islettigi kodlari tek bir islemcide isletmeyi becerdikten sonra bir sonraki problemimiz A ve B islemcilerinin clock kaynagindaki dur kalki kaldirmak ve ayni performansi tek islemcili sistemde elde etmek ve mesela A ve B islemcilerinin port pinlerini yazilimla Toggle ederek duduk otturmek probleminin aynisina tek islemcili yapida cozum getirmek olabilir.
Cekirdek kodlarinin yaziminda C ciler ASM'den medet ummak zorundalar diyebilirmiyiz acaba?
Alıntı yapılan: bunalmis - 09 Ekim 2011, 14:08:50
Cekirdek kodlarinin yaziminda C ciler ASM'den medet ummak zorundalar diyebilirmiyiz acaba?
Hayir.
Guzel.
Basit olarak contex saving olayini c kullanip asm kullanmadan nasil yapabiliriz?
Malesef Gerbay malesef. Bugune kadar tanidigim sozde C cilerin alayi takım tutma fanatikliğinde C tutuyor ASM den nefret ediyor.
Benim acaip multitaskingim geldi. http://ww1.microchip.com/downloads/en/AppNotes/00585b.pdf (http://ww1.microchip.com/downloads/en/AppNotes/00585b.pdf) deki aciklamalardan cekirdek yazmaya calisacagim.
Sorularimi da burda soracagim. Fakat daha guzel bir dokuman biliyorsaniz link verebilirmisiniz?
Bir kac tane tasktan olusan bir program yaziyor olalim.
Interuptlar bu tasklarin disinda ayri bir taskmidir?
Bu tasklarin biribirine gore onceliginin olmasi ne demektir? Interrupt task ise oncelikle bunlarin onceliginden mi bahsedilmek isteniyor?
Taskdan taska gecisim, timer tickle olusturulmus zaman araligi belirlemiyormu? Eger oyleyse task onceligi anlamsiz olmuyormu?
Tasklara ayrilan surelerin birbirinden farkli olmasi istenen bir seymidir?
Bir task kendine ayrilan zamandan daha once isini bitirirse diger taska gecilmelimidir? Gecilmeliyse bunun dezavantaji varmidir?
Gecilmeliyse timer icerigi modifiye edilmelimidir?
Bir task kendine ayrilan zamandan daha once isini bitirirse arta kalan zaman bir sonraki taska hibe mi edilir?
Tasklar 1,2,3,4 gibi numaralanmis olsun. Tasklar 1,2,3,4,1,2,3,4 diye isleme alinmazlar mi? Bu siralama hic bozulmazmi bozulursa kim nicin bozar?
Tasklarin donanimsal registerlerle oynama gibi bir luksu olabilirmi?
Yoksa bunlar ayri bir tasktan mi talep edilir? Boyleyse bu isleri cok yavaslatmaz mi?
Tasklar boyle bir lukse sahipse sistemin crash olmamasi program (tasklari) yazanin yukumlulugundemidir?
Creating a Multitasking Kernel for the COP8 Microcontroller
http://www.national.com/an/AN/AN-1099.pdf
Writing Operating System
http://faculty.kfupm.edu.sa/ics/salah/091/ics531/resources.html
http://faculty.kfupm.edu.sa/ics/salah/091/ics531/handouts/ch47.pdf
JamesM's kernel development tutorials
http://www.jamesmolloy.co.uk/tutorial_html/9.-Multitasking.html
Multitasking Fundamentals //// bu slaytlar konuya sizin yaklaştığınız gibi yaklaşıyor
http://www.ida.liu.se/~TDDC31/files/OS_TDDC31_Le2.pdf
netten bunlar çıktı
merak edenler için keyword multitasking fundamentals
Aslinda oncelikle su soruyu sorayim. Belki de gavurun ne yaptigiyla ilgilenmeye gerek kalmaz.
3 ayri islemci ile proje yapmis olalim.
1. islemci, ortam sicakligini olcuyor olsun.
2. islemci, PID ile isiticinin voltajini ayarlasin.
3. islemci 1. ve 2. islemcilerle rs232 uzerinden haberlessin ihtiyac duyulan veri trafigini yonetsin, ayrica ekranda ortam sicakligini, isitici voltajini gostersin.
Simdi bu 3 islemciye yazilacak kodlar birbirinden tamamen bagimsiz 3 ayri proje demektir.
Eger ben bu 3 projeyi tek bir proje gibi yeni bastan yazip tek bir islemci icine gommek yerine,
Tek bir islemci icine 1. 2. 3. islemci kodlarini tamamen bagimsiz fonksiyonlar seklinde yazsam,
Bu fonksiyonlari F1, F2,F3 olarak isimlendirsem.
F1 calismaya baslasa timer int geldiginde F1 durdurulup F2 calismaya baslasa, gene timer int gelince F2 durup F3 calissa ve bu boyle dongude kalsa
Bu projenin cekirdek kodlarini yazsam os mu yazmis olacagim.
Burada adi gecen F1, F2 ve F3 task mi olacak?
F1, F2 ve F3, mesela ortak kullanilan F4 fonksiyonunu cagirsa bu F4 fonksiyonuna bu os camiasinda ozel bir ad veriliyormu?
Doğru yaklaşımlar... Yazdıklarınız aslında çekirdek temel işlemleri. Bir OS temeli. Bu sorular OS öğrenmek için çok güzel ,önce neden OS yazılması gerekliliğine takılmak lazım ki hangi nedenlere bağlı olarak OS ler yazılmış. Yani bazı problemler olmuş ve çözümler gerekmiş..
Alıntı yapılan: bunalmis - 06 Kasım 2011, 01:13:51
Aslinda oncelikle su soruyu sorayim. Belki de gavurun ne yaptigiyla ilgilenmeye gerek kalmaz.
3 ayri islemci ile proje yapmis olalim.
1. islemci, ortam sicakligini olcuyor olsun.
2. islemci, PID ile isiticinin voltajini ayarlasin.
3. islemci 1. ve 2. islemcilerle rs232 uzerinden haberlessin ihtiyac duyulan veri trafigini yonetsin, ayrica ekranda ortam sicakligini, isitici voltajini gostersin.
Simdi bu 3 islemciye yazilacak kodlar birbirinden tamamen bagimsiz 3 ayri proje demektir.
Eger ben bu 3 projeyi tek bir proje gibi yeni bastan yazip tek bir islemci icine gommek yerine,
Tek bir islemci icine 1. 2. 3. islemci kodlarini tamamen bagimsiz fonksiyonlar seklinde yazsam,
Bu fonksiyonlari F1, F2,F3 olarak isimlendirsem.
F1 calismaya baslasa timer int geldiginde F1 durdurulup F2 calismaya baslasa, gene timer int gelince F2 durup F3 calissa ve bu boyle dongude kalsa
Bu projenin cekirdek kodlarini yazsam os mu yazmis olacagim.
Burada adi gecen F1, F2 ve F3 task mi olacak?
F1, F2 ve F3, mesela ortak kullanilan F4 fonksiyonunu cagirsa bu F4 fonksiyonuna bu os camiasinda ozel bir ad veriliyormu?
Alıntı yapılan: gerbay - 06 Kasım 2011, 17:58:55
hocam preemptive multitasking de yüksek öncelikli task bir event ya da device beklerken bir sonraki task a geçilir. sizin bahsettiğiniz olay "round-robin" diye geçiyor. mesela windows, linux gibi sistemler round-robin kullanırlar.
VxWorks, Integrity gibi "hard real-time" RTOS lar default olarak preemptive scheduling yaparlar ama "round-robin scheduling yap" diye konfigüre edilebilirler..
Burda bir taskin yuksek oncelikli olmasi ne demek? Bu soru hala cevapsiz kaldi
Bir ornekle aciklayabilirmisin?
Nihayet ilk RTOS cekirdegimi yazdim. Aslinda dilim RTOS demeye varmiyor ama ARM cipi icinde istediginiz kadar CPU olusturabiliyorsunuz.
Her bir CPU icin bagimsiz kod yazabiliyor ve bunlari kosturabiliyorsunuz. Tabiki su anda bir bebek rtos dan bahsediyoruz. Tasklar arasinda veri alisverisine bu asamada hic kafa yormadim.
Ilk deneme programimda STM32F kitimizdeki Arm islemci icine 4 cpu gomdum. Her bir cpu, kart uzerindeki 4 ledden sadece birisi ile ilgileniyor. 1ms lik zaman araliklarinda aktif oluyorlar. Asagidaki scop goruntusunde 2 CPU nun ledleri on off eden sinyalleri var.
(http://www.cncdesigner.com/STM/BabyRtos.JPG)
Baby RTOS'un ve 4 CPU nun acik kodlari asagida.
/*
Baby RTOS, STM32F-Discovery kiti uzerindeki ARM çip
uzerınde birden fazla CPU ile calisma yapmak icin gelistirilmektedir.
PICPROJE - Bülent ÜNALMIŞ
*/
#include "STM32F4xx.h"
#define Adres(Reg, adr) ldr Reg, =__cpp((unsigned)&adr)
#define STK_CTRL (*((volatile unsigned int*) 0xE000E010))
#define STK_LOAD (*((volatile unsigned int*) 0xE000E014))
#define STK_VAL (*((volatile unsigned int*) 0xE000E018))
#define CpuSayisi 4
void Cpu1(void);
void Cpu2(void);
void Cpu3(void);
void Cpu4(void);
struct Regs{int R4,R5,R6,R7,R8,R9,R10,R11,R13;};
struct Regs CpuReg[CpuSayisi];
int CpuNo;
int STK=-1;
int Radr;
/*****************************************************************************************************
CPU PLL ile 168Mhz de kosturulur
AHB frekansý 168 Mhz
APB1 frekansý 42 Mhz
APB2 frekansý 84 Mhz
*****************************************************************************************************/
void SystemInit()
{
unsigned int i;
for (i=0;i<0x00100000;i++); // OSC oturtma ve kurtarma rutini
RCC->CFGR |= 0x00009400; // AHB ve APB hizlarini max degerlere set edelim
RCC->CR |= 0x00010000; // HSE Xtal osc calismaya baslasin
while (!(RCC->CR & 0x00020000));// Xtal osc stabil hale gelsin
// RCC->PLLCFGR = 0x07405408; // PLL katsayilarini M=8, N=336, P=2 ve Q=7 yapalim
RCC->PLLCFGR = 0x07402A04; // PLL katsayilarini M=4, N=168, P=2 ve Q=7 yapalim
RCC->CR |= 0x01000000; // PLL calismaya baslasin (Rehber Sayfa 95)
while(!(RCC->CR & 0x02000000)); // Pll hazir oluncaya kadar bekle
// FLASH->ACR = 0x00000705; // Flash ROM icin 5 Wait state secelim ve ART yi aktif edelim (Rehber Sayfa 55)
FLASH->ACR = 0x00000605; // Flash ROM icin 5 Wait state secelim ve ART yi aktif edelim (Rehber Sayfa 55)
RCC->CFGR |= 0x00000002; // Sistem Clk u PLL uzerinden besleyelim
while ((RCC->CFGR & 0x0000000F) != 0x0000000A); // Besleninceye kadar bekle
RCC->AHB1ENR |= 0x0000000F; // GPIO A,B,C,D clock'u aktif edelim
GPIOD->MODER = 0x55000000; // GPIOD nin 15, 14, 13, 12 pinleri cikis tanimlandi (LEDler icin)
GPIOD->OSPEEDR= 0xFFFFFFFF; // GPIOD nin tum cikislari en yuksek hizda kullanacagiz
}
void __asm JMP(int Adr)
{
BX R0
}
int __asm PSR()
{
MRS R0,XPSR
ORR R0,#0x01000000
BX LR
}
int __asm CStack()
{
MOV R0,R13
BX LR
}
/*****************************************************************************************************
STS TICK COUNTER AHB FREKANSINDA (168 MHZ) KOSACAK
*****************************************************************************************************/
void RTOSInit()
{
CpuNo=0;
STK_LOAD= 0X00029040; // 165E6/1000=168000 TICK TIME 1 mili saniye
// STK_LOAD= 0X00029040>>1; // 165E6/1000=168000 TICK TIME 500 mikrosaniye
STK_VAL = 0X00029040; // TIMER GERIYE DOGRU BU DEGERDEN BASLASIN
STK_CTRL&=~0x00010000; // Count Flagi silelim,
STK_CTRL|= 0x00000007; // int enb ve count enb yapalim, clk kaynagini AHB yapalim
JMP(Radr);
}
void __asm SysTick_Handler()
{
Adres(R3,CpuNo); ; R3=Cpu No Adres
LDR R1,[R3] ; R1=Cpu No
MOV R2,#36
MUL R2,R1
Adres(R0,CpuReg[0])
ADD R2,R0
STR R4, [R2,#00] ; R4
STR R5, [R2,#04] ; R5
STR R6, [R2,#08] ; R6
STR R7, [R2,#12] ; R7
STR R8, [R2,#16] ; R8
STR R9, [R2,#20] ; R9
STR R10,[R2,#24] ; R10
STR R11,[R2,#28] ; R11
STR R13,[R2,#32] ; SP
ADD R2,#36
ADD R1,#1 ; CpuNo++
MOV R0,#CpuSayisi
CMP R1,R0
STRLT R1,[R3]
MOVGE R1,#0
STRGE R1,[R3]
LDREQ R2,=__cpp((unsigned)&CpuReg[0])
Adres(R0,STK_CTRL)
LDR R1,[R0,#0X00]
BIC R1,#0X00010000
STR R1,[R0,#0X00]
LDR R4, [R2,#00] ; R4
LDR R5, [R2,#04] ; R5
LDR R6, [R2,#08] ; R6
LDR R7, [R2,#12] ; R7
LDR R8, [R2,#16] ; R8
LDR R9, [R2,#20] ; R9
LDR R10,[R2,#24] ; R10
LDR R11,[R2,#28] ; R11
LDR R13,[R2,#32] ; SP
BX LR
}
void CpuInit(int No, int Adr, int Stack)
{
int* P;
if (STK==-1)
{
STK=CStack();
Radr=Adr|1;
}
else
{
STK-=Stack;
CpuReg[No].R13=STK;
P=(int*) STK;
*P=0; P++; // R0
*P=0; P++; // R1
*P=0; P++; // R2
*P=0; P++; // R3
*P=0; P++; // R12
*P=Adr|1 ; P++; // Return Adres
*P=Adr|1 ; P++; // PC
*P=PSR() ; // PSR
}
}
int main()
{
CpuInit(0,(int)&Cpu1,0x100);
CpuInit(1,(int)&Cpu2,0x100);
CpuInit(2,(int)&Cpu3,0x100);
CpuInit(3,(int)&Cpu4,0x100);
RTOSInit();
while(1);
}
void Cpu1()
{
volatile int i;
while(1)
{
GPIOD->ODR|=0x1000;
for(i=0;i<0x000100;i++);
GPIOD->ODR&=~0x1000;
for(i=0;i<0x000100;i++);
}
}
void Cpu2()
{
volatile int i;
while(1)
{
GPIOD->ODR|=0x2000;
for(i=0;i<0x000100;i++);
GPIOD->ODR&=~0x2000;
for(i=0;i<0x000100;i++);
}
}
void Cpu3()
{
volatile int i;
while(1)
{
GPIOD->ODR|=0x4000;
for(i=0;i<0x000100;i++);
GPIOD->ODR&=~0x4000;
for(i=0;i<0x000100;i++);
}
}
void Cpu4()
{
volatile int i;
while(1)
{
GPIOD->ODR|=0x8000;
for(i=0;i<0x000100;i++);
GPIOD->ODR&=~0x8000;
for(i=0;i<0x000100;i++);
}
}
Hayırlı olsun hocam =)
Süper bir başlangıç,
Bundan sonrasını geliştirmek çok daha mümkünatlı ! :)
yalnız Cpu yerine Task desek daha isabetli olabilir.....
(http://www.cncdesigner.com/STM/4Ceker.JPG)
Açıkcası cpu mu demem lazım task mı demem lazım bilmiyorum. Baby RTOS'un yaptığı iş yukarıdakine benziyor.
4 Adet PICi'ın Xtal inp bacağına sırayla harici clk veriyorsunuz. Herhangi bir anda sadece 1 PIC16F84 çalışıyor.
Anahtarın dönme hızı örnekte 1ms.
Yukarıdaki bloktan yola çıktığım için görevlere task değil de CPU dedim. Arada fark varmı? Varsa fark nedir?
Yukarıdaki blok şemaya göre CPU ların öncelikleri hakkında konuşursak;
Her işlemci çalışmak için sırasını beklemek zorunda. (Ben hala öncelik kısmında takıldım.)
Herhangi bir anda int gelirse, int muhtemelen (test etmedim) cevaplanacaktır. Çünkü aslında bir 5. işlemci daha var bu 5. işlemci (ARM'ın kendisi oluyor) intların yönetimiyle ilgileniyor.
Birisi bu RTOS'u bir anlatsa.
Bunalmış hocam,
Bir task'a sen illa ki 1 ms zaman geçireceksin demek yerine,
sen max 1 ms zaman harcayabilirsin demek daha iyi görünüyor....
Çünkü !
O TASK fonksiyonu o andaki görevini çok hızlı bir şekilde icra edebilir. (genellikle de öyle olur)
Ve schedular o TASK'tan sonra gelen TASK'ı çalışması için tetiklemeli...
yani TASK fonksiyonunda Delay komutu kullanıldığı anda, (bazı başka özel olaylarda da)
gerekli olan ayarlamalar yapılıp schedular'a geçmeli ve oradan da yeni TASK'a...
Bence şu çok önemli bir konu,
Bir TASK fonksiyonu işlemleri genellikle çok hızlı bir şekilde bitirilip
- delay,
- olay bekleme ve
- uzun bir string gönderme gibi işlemlerde bekliyor.
Bu noktalarda schedular TASK ları gözden geçirip başka birisini çalıştırmalı.
Ayrıca şu ana kadar anladığım kadarı ile görev değişimleri,
TASK içindeki değişim noktaları ile sağlanıyorsa buna Cooperative Rtos,
TASK içindeki değişim noktaları ve Timer Int ile sağlanıyorsa buna da Preemptive Rtos deniyor.
Cooperative Rtos yapılırsa bazı taskların hiç bir zaman çalışmama durumu olamazmı?
1-2-3 iki çalışsın- 2-3 bir çalışsın 1-2-3 bidaha ben 3 .... 4'e hiç sıra gelmeyebilir.
Schedular için çok fazla sayıda yöntem var.
Cooperative Schedular yine TASK ları 1.2.3.4.5.6... diye işaret eder ama
işaret edilen TASK ın çalışma şartı gerçekleşmeyince
(delay bitmemiş, olay gerçekleşmemiş vs ise) kod yine Schedular a dönecektir.
Gerçi bu durumda SuperLoop tan ne farkı kalıyor ?
A,B,C,D,.... şeklinde tasklardan oluşan bir programımız var. B,C,D den bahsetmeyeceğim fakat A Taskının görevi aşağıda.
Klavyeden basılan tuş ASCI A tuşuysa, bu andan itibaren 10 ms içinde de seri porttan da ASCI B verisi gelirse LED1'i yak 100ms sonra LED'i söndür.
Tasklara max 1ms zaman ayrılan bir sistemde bu programı nasıl yazarsınız? Gerekiyorsa A,B,C,D ye ilave yeni tasklar oluşturabilirsiniz.
Bu programı X bir ROS için yazabilirmisiniz?
seri portu başka TASK lar kullanıyor mu ?
Her iki durum için de iki ayrı örnek olursa süper olur.
Zor olursa hayır tek task kullanıyor.
RTOS kullananları burası açmadı galiba.
Baby RTOS'a aşağıda bahsettiğim eklenti yapılırsa pek çok proje gerçekleştirilebilir.
Şayet aktif taskımız, belli bir olayı bekleme noktasına geldiyse, şartlı bir döngü içinde olayın gerçekleşip gerçekleşmediğini zaman harcayarak test etmek yerine ben görevimi bitirdim ve artan zamanımı bir sonraki taska hibe ediyorum derse;
Bir sonraki task artık 1ms değil örneğin 1.5ms aktif olacaktır. Bu da daha çok işlem yapabilmesi demektir. Eğer yeni taskımız da işini ayrılan zamandan daha önce yapıp bir olayı bekleme aşamasına gelirse bu task da artan zamanını bir sonraki taska hibe edebilir.
Bu da gözle görülür bir performans artışına neden olur.
Alıntı yapılan: bunalmis - 09 Kasım 2011, 15:18:02
RTOS kullananları burası açmadı galiba.
Baby RTOS'a aşağıda bahsettiğim eklenti yapılırsa pek çok proje gerçekleştirilebilir.
Şayet aktif taskımız, belli bir olayı bekleme noktasına geldiyse, şartlı bir döngü içinde olayın gerçekleşip gerçekleşmediğini zaman harcayarak test etmek yerine ben görevimi bitirdim ve artan zamanımı bir sonraki taska hibe ediyorum derse;
Bir sonraki task artık 1ms değil örneğin 1.5ms aktif olacaktır. Bu da daha çok işlem yapabilmesi demektir. Eğer yeni taskımız da işini ayrılan zamandan daha önce yapıp bir olayı bekleme aşamasına gelirse bu task da artan zamanını bir sonraki taska hibe edebilir.
Bu da gözle görülür bir performans artışına neden olur.
Kesinlikle bu şekilde olmalı hocam :)
Üstteki soru işareti için biraz düşünmek irdelemek lazım.
Sorduğum soru klasik yöntemle tek cpu için yazdığımız program olsaydı bir iki dakikada kodları yazar bitirirdik.
RTOS'a geçince neyi düşüneceğiz? Eğer bu basit soru için bu kadar düşünürsek baba bir proje bizi çok yormazmı?
TASK_A(){
while(1){
if(kbhit() && getch()=='A'){
delay_os_ms(10);
if(kbhit() && getch()=='B'){
out_led=1;
delay_os_ms(100);
out_led=0;
}
}
}
}
TASK_A()
{
while(1)
{
if(kbhit() && getch()=='A')
{
delay_os_ms(10);
if(kbhit() && getch()=='B')
{
out_led=1;
delay_os_ms(100);
out_led=0;
}
}
}
}
Kodu anladım. Gerçi tam cevap olmadı galiba. Soruda klavyeden A harfi geldiğinde 10 ms içinde B harfi gelecekmi diyordum ama olsun. (Mevcut örnekte 10ms bekleyip ardından bakıyoruz) Buna ayrca kafa yoralım.
Yukarıdaki örnekte 10ms lik delayi başlattığımızda diğer tasklar sırayla işlemeye başlıyor. Delay başladıktan sonra 10ms dolduğunda o an işleyen task her neyse işi kesiliyor ve bahse konu delay rutininin bir alt satırına mı geliniyor?
Yoksa bu satıra tekrar geldiğimizde mesela 14 ms olabiliyormu?
sorunuzun cevabı Rtos'un preemptive veya non-preemptive olmasına göre değişiyor.
Eğer ki 1 ms de 1 kere schedular çalışıyorsa(yani preemptive ise) ve bu görev diğer TASK'lardan öncelikli ise
elbette bu TASK en kötü 10+1 ms sonra çalışmaya devam eder.
Eğer ki non-preemptive bir RTOS ise bu görevin çalışması için o anda çalışmakta olan TASK ın sonlanmasını beklemek zorundayız.
Mesala schedular süreleri genelde 1mS oluyor(RoundRobin Algoritmasında). Bu sabitlenmiş süreyede kuantum süresi diyorlar, burada anlaşılacağı üzere performans direk kuantum süresi ile ilgili.
Round Robbin vs terimler yeni yeni sekillenmeye basladi. Asagidaki sitenin icerigi hosuma gitti.
http://www.bilgisayarkavramlari.com/2008/11/19/round-robin/ (http://www.bilgisayarkavramlari.com/2008/11/19/round-robin/)
STM32F için RTOS çalışması güzel gidiyor ve yakında Baby sıfatından kurtulacak.
Pis adını verdiğim RTOS'un özellikleri (Picproje İşletim Sistemi)
Her 1ms de Task geçişi,
Arta kalan zamanı bir sonraki Task'a hibe etme,
Düşük öncelikli Task'ların yüksek öncelikli Task'lar tarafından durdurulup çalıştırılması,
Tick rutinine kullanıcı kodu ekleyerek her 50 mikrosaniye de bir kritik zamanlı işlerin soft olarak kontrolu,
Tasklar arası veri aktarımı (Henüz yöntem belirlenmedi)
Interruptlar.
Şimdiden belirtmek gerekirse, C kütüphanelerinden hazır fonksiyonlardan bazıları çağrılırsa sistem muhtemelen çökecektir. Mevcut RTOS'larda bu durum nasıldır?
Bu özelliklere sahip PİS'in üstesinden gelemeyeceği bir uygulama ne olabilir?
Alıntı yapılan: bunalmis - 11 Kasım 2011, 09:53:14Şimdiden belirtmek gerekirse, C kütüphanelerinden hazır fonksiyonlardan bazıları çağrılırsa sistem muhtemelen çökecektir. Mevcut RTOS'larda bu durum nasıldır?
Neden çöker ?
Bu, tamamen kütüphane fonksiyonunun nasıl yazıldığına bağlı. Eğer sözkonusu kütüphane fonksiyonunda, stack haricinde ilave olarak global yada statik değişken kullanma yoluna gidilmişse;
Tasklardan birisi bu fonksiyonu çağırmışsa;
Fakat fonksiyon tamamlanamadan task geçişi olursa;
Sonra gelen tasklar da aynı fonksiyonu kullanırsa
reentry problemi oluşacağından sistem çöker.
Benimkisi varsayımdan ibaret. Eğer kütüphane fonksiyonları, RTOS çalışmasında da kullanılsın diye yazıldıysa zaten sorun olmaz.
Hali hazır RTOSlarda;
Kullanıcı programları user modda çalışacak diye zorlama varmı?
Her ne kadar RTOS açık kod olduğu için engel olunamasa da kullanıcı programlarının Privileged seviyesinde kod yazımına izin veriliyormu?
Asla crash olmayan RTOS uygulamaları için bu tip sınırlamalar yapılmalı diye düşünüyorum.
Baby RTOS çekirdegini, CM4 islemciyi CM3 gibi dusunup yazdigimdan Floating Point islemcinin varligini tamamen unutmuşum.
Haliyle Baby RTOS FPU uygulamalarında kullanılırsa sistem çökecekti.
Simdiki RTOS'da bu sorun giderildi ve yeni özellikler eklendi.
Task sayısı arttırıldıkça startup_stm32f4xx.s dosyasındaki Stack_Size değeri arttırılmalı. CM4 işlemci, CM3 işlemciye oranla
daha fazla hayati register içerdiğinden task geçişlerinde daha fazla stack alanı gerekiyor. Bu konu hatırda tutulmalı.
RTOS her 1 mili saniyede bir Task degistiriyor ilave olarak 2 temel fonksiyonu var.
1. fonksiyon, Delay(T) fonksiyonu, milisaniye cinsinden Taskı beklemeye alıyor
2. fonksiyon ise Hibe() fonksiyonu, Task süresinin bitmesini beklemeden bir sonraki taska geçiş sağlar.
RTOS Cekirdeginin kaynak kodlari
// STM32F Discovery kiti icin geliitirilmiş RTOS cekirdeği
// www.picproje.org, Bülent Ünalmış
#define Adres(Reg, adr) ldr Reg, =__cpp((unsigned)&adr)
#define STK_CTRL (*((volatile unsigned int*) 0xE000E010))
#define STK_LOAD (*((volatile unsigned int*) 0xE000E014))
#define STK_VAL (*((volatile unsigned int*) 0xE000E018))
char Task=0;
char HibeFlag=0;
struct T{int SP, Adr;};
struct T TaskTablo[TaskSayisi];
int PK[TaskSayisi][TaskSayisi];
unsigned int Dly[TaskSayisi];
void __asm RTOSInit()
{
Adres(R0,TaskTablo[0])
LDR R1,=TaskSayisi
MOV R2,SP
MOV R3,#0X00
L1 SUB R2,R3
LDR R3,[R0,#0]
STR R2,[R0,#0]
ADD R0,#8
SUBS R1,#1
BNE L1
Adres(R0,TaskTablo[1])
LDR R1,=TaskSayisi-1
L2 ; LDR SP,[R0] // Bu komut hataliymis (errata)
LDR R3,[R0]
MOV SP,R3
MRS R2,FPSCR
PUSH {R2}
MOV R2,#0
PUSH {R2}
VPUSH {S15}
VPUSH {S14}
VPUSH {S13}
VPUSH {S12}
VPUSH {S11}
VPUSH {S10}
VPUSH {S9}
VPUSH {S8}
VPUSH {S7}
VPUSH {S6}
VPUSH {S5}
VPUSH {S4}
VPUSH {S3}
VPUSH {S2}
VPUSH {S1}
VPUSH {S0}
MRS R2,XPSR
ORR R2,#0x01000000
PUSH {R2} // PSR
LDR R2,[R0,#4]
PUSH {R2} // R15 PC
PUSH {R2} // R13 LR
PUSH {R12} // R12
PUSH {R3} // R3
PUSH {R2} // R2
PUSH {R1} // R1
PUSH {R0} // R0
PUSH {R4-R11}
STR SP,[R0]
ADD R0,#8
SUBS R1,#1
BNE L2
Adres(R0,TaskTablo[0])
LDR R3,[R0]
MOV SP,R3
Adres(LR,TaskTablo[0]+4)
LDR LR,[LR]
Adres(R0,Task)
STR R1,[R0]
Adres(R0,STK_CTRL)
LDR R1,=0X00029040
STR R1,[R0,#0X04] ; STK_LOAD=0X00029040
LDR R1,=0X00010007
LDR R2,[R0,#0X00]
BIC R2,R1
ORR R2,#7
STR R2,[R0,#0X00]
NOP
BX LR
}
int SysTick_Handler_(int NSP,int SVC)
{
int i;
TaskTablo[Task].SP=NSP;
if (STK_CTRL & 0x00010000)
{
STK_CTRL&=~0x00010000; // Count Flagi silelim,
for(i=0;i<TaskSayisi;i++)
{
if(Dly[i]) Dly[i]--;
}
if(HibeFlag==0)
{
Task++; if (Task>=TaskSayisi) Task=0; // Sonraki taski harekete gecirelim
}
else if(HibeFlag==2)
{
HibeFlag=0; // Ayni task devam etsin
}
}
else // Hibe var
{
if(HibeFlag==1)
{
Task++; if (Task>=TaskSayisi) Task=0; // Sonraki taski harekete gecirelim
HibeFlag=2;
}
}
return(TaskTablo[Task].SP);
}
void __asm SysTick_Handler()
{
PRESERVE8
PUSH {R4-R11}
MOV R0,SP
PUSH {LR}
Adres(R1,SysTick_Handler_)
BLX R1
POP {LR}
MOV SP,R0
POP {R4-R11}
BX LR
}
void __asm SVC_Handler()
{
B SysTick_Handler
}
void __asm Hibe()
{
Adres(R0,HibeFlag)
MOV R1,#1
STRB R1,[R0]
SVC #0
BX LR
}
void Delay(unsigned int T)
{
Dly[Task]=T;
while(Dly[Task]) Hibe();
}
void PostaGonder(int VarAdr, int Alici)
{
while(PK[Task][Alici]) Hibe(); // Alicinin Postakutusu dolu
PK[Task][Alici]=VarAdr; // Alicinin Posta kutusuna Posta atildi
}
int PostaBekle(int Gonderen)
{
while(PK[Gonderen][Task]==0) Hibe(); // Postacidan mektup bekle
return(PK[Gonderen][Task]); // Gelen verinin adresini oku
}
int PostaVarmi(int Gonderen) // Mektup almak isteyen bakar
{
return(PK[Gonderen][Task]); // Mektup gelmismi
}
void Selamlar(int Gonderen) // Sevgilim, mektubunu almistim
{ // fakat diger hatunlar beni cok oyaliyor
PK[Gonderen][Task]=0; // ancak okuyabildim, opuyorum
}
Kart uzerindeki LEdleri yakip sonduren program icin SystemInit() fonksiyonumuz
#include "STM32F4xx.h"
/***********************************************************************
CPU PLL ile 168Mhz de kosturulur
AHB frekansi 168 Mhz
APB1 frekansi 42 Mhz
APB2 frekansi 84 Mhz
***********************************************************************/
void SystemInit()
{
unsigned int i;
for (i=0;i<0x00100000;i++); // OSC oturtma ve kurtarma rutini
RCC->CFGR |= 0x00009400; // AHB ve APB hizlarini max degerlere set edelim
RCC->CR |= 0x00010000; // HSE Xtal osc calismaya baslasin
while (!(RCC->CR & 0x00020000));// Xtal osc stabil hale gelsin
// RCC->PLLCFGR = 0x07405408; // PLL katsayilarini M=8, N=336, P=2 ve Q=7 yapalim
RCC->PLLCFGR = 0x07402A04; // PLL katsayilarini M=4, N=168, P=2 ve Q=7 yapalim
RCC->CR |= 0x01000000; // PLL calismaya baslasin (Rehber Sayfa 95)
while(!(RCC->CR & 0x02000000)); // Pll hazir oluncaya kadar bekle
// FLASH->ACR = 0x00000705; // Flash ROM icin 5 Wait state secelim ve ART yi aktif edelim (Rehber Sayfa 55)
FLASH->ACR = 0x00000605; // Flash ROM icin 5 Wait state secelim ve ART yi aktif edelim (Rehber Sayfa 55)
RCC->CFGR |= 0x00000002; // Sistem Clk u PLL uzerinden besleyelim
while ((RCC->CFGR & 0x0000000F) != 0x0000000A); // Besleninceye kadar bekle
RCC->AHB1ENR |= 0x0000000F; // GPIO A,B,C,D clock'u aktif edelim
GPIOD->MODER = 0x55000000; // GPIOD nin 15, 14, 13, 12 pinleri cikis tanimlandi (LEDler icin)
GPIOD->OSPEEDR= 0xFFFFFFFF; // GPIOD nin tum cikislari en yuksek hizda kullanacagiz
}
RTOS kullanarak 4 ledi farklı zamanlarda yakıp söndüren 4 adet task.
#define TaskSayisi 4
#include "STM32F4xx.h"
#include "RTOS.c"
#include "MyInit.c"
void Cpu1(void);
void Cpu2(void);
void Cpu3(void);
void Cpu4(void);
/****************************************************************
Startup kodundaki Stack_Size EQU 0x00000400
satiri Stack_Size EQU 0x00000800
olarak degistirilmeli
****************************************************************/
int main()
{
// Alttaki ilk satir
// 0.Task Cpu1 fonksiyonunu ve 512 byte Stack alanini kullanacak demektir
TaskTablo[0].Adr=(int)&Cpu1; TaskTablo[0].SP=512;
TaskTablo[1].Adr=(int)&Cpu2; TaskTablo[1].SP=512;
TaskTablo[2].Adr=(int)&Cpu3; TaskTablo[2].SP=512;
TaskTablo[3].Adr=(int)&Cpu4; TaskTablo[3].SP=512;
RTOSInit(); // Artik main satiri ile isimiz kalmadi tasklar kosmaya basladi
}
/****************************************************************
1. Task, yesil ledi 1 sn de flash eder
****************************************************************/
void Cpu1()
{
volatile int i;
while(1)
{
GPIOD->ODR|=0x1000;
Delay(1000);
GPIOD->ODR&=~0x1000;
Delay(1000);
}
}
/****************************************************************
2. Task, kavunici ledi 2 sn de flash eder
****************************************************************/
void Cpu2()
{
volatile int i;
while(1)
{
GPIOD->ODR|=0x2000;
Delay(2000);
GPIOD->ODR&=~0x2000;
Delay(2000);
}
}
/****************************************************************
3. Task kirmizi ledi 1 sn de flash eder
****************************************************************/
void Cpu3()
{
volatile int i;
while(1)
{
GPIOD->ODR|=0x4000;
Delay(4000);
GPIOD->ODR&=~0x4000;
Delay(4000);
}
}
/****************************************************************
1. Task mavi ledi 1 sn de flash eder
****************************************************************/
void Cpu4()
{
volatile int i;
while(1)
{
GPIOD->ODR|=0x8000;
Delay(8000);
GPIOD->ODR&=~0x8000;
Delay(8000);
}
}
İyi RTOS'lar.
extern unsigned int SysTime;//SysTickin aynalanmış hali.
unsigned int TaskFlag;
TASK_A(){
while(1){
if(kbhit() && getch()=='A')TaskFlag=SysTime;
if((kbhit() && getch()=='B') && ((SysTime-TaskFlag)<10) {
out_led=1;
delay_os_ms(100);
out_led=0;
}
}
}
Oluşabilecek tek sıkıntı, SysTime set reset yapılmadan taşmaya giderse ve aynı değerlere yaklaşırsa hata durumu oluşabilir. İlave bir flag kontrolü mekanizması ile bu sorun çözülür elbette.
void PostaGonder(int VarAdr, int Alici)
{
while(PK[Task][Alici]) Hibe(); // Alicinin Postakutusu dolu
PK[Task][Alici]=VarAdr; // Alicinin Posta kutusuna Posta atildi
}
int PostaBekle(int Gonderen)
{
while(PK[Gonderen][Task]==0) Hibe(); // Postacidan mektup bekle
return(PK[Gonderen][Task]); // Gelen verinin adresini oku
}
int PostaVarmi(int Gonderen) // Mektup almak isteyen bakar
{
return(PK[Gonderen][Task]); // Mektup gelmismi
}
void Selamlar(int Gonderen) // Sevgilim, mektubunu almis hatta okumustum
{ // fakat diger hatunlar beni cok oyaliyor
PK[Gonderen][Task]=0; // ancak simdi sana yazabiliyorum, opuyorum
}
RTOS'a yukaridaki 4 fonksiyonu ekleyince artik tasklar diledikleri gibi birbirlerine veri gonderebilir hale geldiler.
Deneme programi asagida
#define TaskSayisi 4
#include "STM32F4xx.h"
#include "RTOS.c"
#include "MyInit.c"
void Cpu0(void);
void Cpu1(void);
void Cpu2(void);
void Cpu3(void);
/****************************************************************
Startup kodundaki Stack_Size EQU 0x00000400
satiri Stack_Size EQU 0x00000800
olarak degistirilmeli
****************************************************************/
int main()
{
// Alttaki ilk satir
// 0.Task Cpu1 fonksiyonunu ve 512 byte Stack alanini kullanacak demektir
TaskTablo[0].Adr=(int)&Cpu0; TaskTablo[0].SP=512;
TaskTablo[1].Adr=(int)&Cpu1; TaskTablo[1].SP=512;
TaskTablo[2].Adr=(int)&Cpu2; TaskTablo[2].SP=512;
TaskTablo[3].Adr=(int)&Cpu3; TaskTablo[3].SP=512;
RTOSInit(); // Artik main satiri ile isimiz kalmadi tasklar kosmaya basladi
}
/****************************************************************
0. Task, yesil ledi flash eder
****************************************************************/
void Cpu0()
{
volatile int i=300;
while(1)
{
GPIOD->ODR^=0x1000;
PostaGonder((int)&i,2); // 2. Task'a i degerini yolla
Delay(i);
i+=100;
if (i>1000) i=300;
}
}
/****************************************************************
1. Task, kavunici ledi flash eder
****************************************************************/
void Cpu1()
{
volatile int i=300;
while(1)
{
if (PostaVarmi(2)) // 2. Tasktan mektup varmi?
{
i=(*(int*)(PostaBekle(2))); // 2. Taskdan gelen mektubu Posta kutusundan al
Selamlar(2); // 2. Task, mektubunu aldim geregini yaptim
PostaGonder((int)&i,3); // 3. Task'a i degerini yolla
}
GPIOD->ODR^=0x2000;
Delay(i);
}
}
/****************************************************************
2. Task kirmizi ledi flash eder
****************************************************************/
void Cpu2()
{
volatile int i=300;
while(1)
{
if (PostaVarmi(0))
{
i=(*(int*)(PostaBekle(0))); // 0. Taskdan Posta Bekle
Selamlar(0); // 0. Task, mektubunu aldim geregini yaptim
PostaGonder((int)&i,1); // 1. Task'a i degerini yolla
}
GPIOD->ODR^=0x4000;
Delay(i);
}
}
/****************************************************************
3. Task mavi ledi flash eder
****************************************************************/
void Cpu3()
{
volatile int i=300;
while(1)
{
if (PostaVarmi(1))
{
i=(*(int*)(PostaBekle(1))); // 1. Taskdan Posta Bekle
Selamlar(1); // 1. Task, mektubunu aldim geregini yaptim
}
GPIOD->ODR^=0x8000;
Delay(i);
}
}
http://emrahcom.blogspot.com/2009/04/gercek-zamanl-bir-linux-masal.html (http://emrahcom.blogspot.com/2009/04/gercek-zamanl-bir-linux-masal.html)
Yukaridaki linkte adigecen Linus'le benzer yanim var galiba...
Bu başlığı açarken, RTOS denen olayı, bir işlemci içinde aynen aşağıdaki resimde görüldüğü gibi birden fazla kodun kosturulması olarak algılıyordum.
(http://www.cncdesigner.com/STM/4Ceker.JPG)
Nitekim bu resimdeki tabloyu STM32F407 içine gömdüm ve tamı tamına yukarıdaki sistemi elde ettim. Hatta biraz daha ilerletip 4 işlemci arasında veri aktarımını da sağladım.
Fakat oluşturduğum bu sisteme RTOS denemeyeceğini yavaş yavaş anlamaya başladım. Yukarıdaki resimdeki tabloya isim vermek gerekirse ne denir bilemiyorum.
Yukarıdaki tabloda clock sinyalini sıra ile dağıtan şalteri ilk başlarda sabit hızda çevirtiyordum. Daha sonraları, o an için çalışan işlemci bekleme yapacaksa boşu boşuna beklemesin şalteri ileri çevisin nasıl olsa systemtick counter her 1ms de sayıyor kendine tekrardan sıra geldiğinde geçen zamanı tick count değerinden anlar dedim.
Böylece işlemci ölü bekleme yaparak (şalter bende kalarak) zaman kaybetmek yerine şalteri bir adım çevireyim de diğer işlemciler çalışsın mantığı, işleri bir hayli hızlandırdı.
Fakat bu bile resimdeki tabloya RTOS ünvanını veremedi.
Anladığım kadarıyla, RTOS birden fazla taskı zamanda ötelemeli olarak koşturabilmeli (bunu becerdik), fakat gerektiğinde tek bir taskı tüm prosesor gücü ile kullanabilmeli, buna rağmen CPU diğer tasklarlarla da muhakkak ilgilenmeli. Biraz tezat durum ama durum buna gidiyor.
Bundan sonra daha fazla bir şey yapamayacağım çünkü RTOS nediri bilmeden bu çekirdeği iyileştirmem imkansız.
Yukarıda verdiğim çekirdek kodlarını birbiri ile alakası olmayan zamanda kritik işler yapmayan uygulamalarda gönül rahatlığyla kullanabilirsiniz.
Yukarıdaki resimde bir işlemciye sıranın gelip kod koşturabilmesi için TxN (burada N, işlemci sayısı, T de anahtarın konum değiştirme zamanı) mili saniye gerekmektedir.
Uygulamamızda N=4 T=1ms olduğundan kritik bir olaydan en geç 4 mili saniye sonra haberimiz olabilir.
Bu olaya müdahale edebilmek için 1ms zamanımız vardır. Eğer 1ms zaman çerçevesi içinde müdahale edemezsek en kötü ihtimalle 3 ms sonra tekrar müdahale şansımız olacaktır.
168Mhz de koşan bir işlemci için yukarıdaki tablo ve hesaplanan rakamlar çok komik değerler. Acı ama gerçek. RTOS bu olamaz. Değildir de.
Sanırım RTOSda böyle komik durumlar olmaz.
4 Taskdan oluşan son flaşör örneğinde o nolu task diğer tasklara flaş süresini i değişkeni üzerinden bildirmektedir.
Her task arasında 1 ms lik fark vardır. 3ms lik gecikme gözle farkedilemez. Fakat program işletildiğinde ledler hep birlikte değil sanki değişik zamanlarda doğru flaş süresi ile flaş etmekteler.
Sorumuz 0. task flaş süresini diğer tasklara bildirdikten sonra ledlerin hepsi nasıl aynı anda flaş ettirilebilir?
Alıntı yapılan: bunalmis - 14 Kasım 2011, 11:42:45
4 Taskdan oluşan son flaşör örneğinde o nolu task diğer tasklara flaş süresini i değişkeni üzerinden bildirmektedir.
Her task arasında 1 ms lik fark vardır. 3ms lik gecikme gözle farkedilemez. Fakat program işletildiğinde ledler hep birlikte değil sanki değişik zamanlarda doğru flaş süresi ile flaş etmekteler.
Sorumuz 0. task flaş süresini diğer tasklara bildirdikten sonra ledlerin hepsi nasıl aynı anda flaş ettirilebilir?
Çoğu kayan yazıda gördüğümüz yazı kayarken oluşan "eğilme" efekti bu ledlerin farklı zamanlarda sürülmesinden kaynaklanmakta,
yani bahsettiğiniz "gerçek" bir problemdir.
Eğer sorunuzdaki gibi her TASK arasında 1 ms fark var ise aynı anda açmak yada kapatmak pek mümkün görünmüyor....
Soruda dikkatinize getirmek istediğim nokta 4 taskı birden aynı pozisyona getirmek ve ledleri aynı anda yakmalarını sağlamak.
Aynı andan kastım; Task1 ledi yakti. 1ms sonra Task2 ledi yaktı. 1ms sonra Task 3 ledi yaktı. 1ms sonra Task4 ledi yaktı gibi.
Task1 örneğin 3 nolu taska flash süresini bildirdi. Task3 bu süreyi Task2 ye bildirdi. Task2 Task1 e bildirdi. Ancak bu esnada Taskların birbiri ile senkronizasyonu kaçtı. Fakat anlaşma işlemi bittiğinde her bir task ledleri hangi hızda yakıp söndireceklerini biliyorlar.
Geriye sırayla ledlere on-off sinyali vermek kalıyor.
İşlemci SysTick referans olarak farklı durumlar için farklı quantalara sahip türev SysTickler oluşturulabilir ve bütün tasklar bunu referans alabilir.
Atıyorum SysTick time 100us olsun ve SysTickFlas<5*SysTick> olsun
Bütün tasklar birbirlerine timing bilgilerini aktarırken, referans alınacak olan SysTick türevinide(SysTickFlas) belirtirse, bilgi aktarımını alan task o SysTicki(SysTickFlas) referans alarak görevini icraya başlar ve hepsi aynı kaynağı referans aldığı için sapma oluşmaz.
1. Task 1sn beklemeye geçti.
2. Task 2sn beklemeye geçti.
3. Task 3sn beklemeye geçti.
4. Task 4sn beklemeye geçti.
Delay sonunda hepsi de anlaşssın aynı anda ledlerini yaksınlar. Kim ne kadar bekleme yapıyor diğer taskların haberi yok.
OSA Rtos ile diğer taskları bozmadan 50usn kadar task çalıştırabildim. Daha düşük değerler diğer taskları bozuyor. (10MIPS bir işlemcide)
210MIPS bir işlemci için 1msn çok fazla bir değer.
Bunalmış sana gönderdiğim OSA çekirdeğinin kodlarını inceledin mi ?
Kodlara baktım fakat birşey anlamadım.
Bu konuyu anlamam için öğretmenden dinlemem lazım. Kendi başıma debelenip duruyorum.
Şu anda oluşan çekirdeği RTOS'a çevirmek için neler eklenmeli ne özellikler kazandırılmalı tarzında problemleri bilmiyorum.
1ms değerini öylesine seçtim. Timer reload değeri ile belli bir limit dahilinde istendiği kadar aşağılara çekilebilir.
Alıntı yapılan: bunalmis - 14 Kasım 2011, 14:24:33
1. Task 1sn beklemeye geçti.
2. Task 2sn beklemeye geçti.
3. Task 3sn beklemeye geçti.
4. Task 4sn beklemeye geçti.
Delay sonunda hepsi de anlaşssın aynı anda ledlerini yaksınlar. Kim ne kadar bekleme yapıyor diğer taskların haberi yok.
Global Char bir değişkenimiz(TaskKontrol) ve atıyorum 4 taskımız olsun.
Herhangi bir task işlem başlatırken beraber TaskKontrol e 0x0F yüklesin. Daha sonra atıyorum 3. task işini bitirince değişkenimizin 3. bitini 0 yapsın. 2. task işini bitirince 2. bitini 0 yapsın... Bütün tasklar sürekli olarak TaskKontrol ü kontrol etsin ve sıfır olduğu anda türev SysTick i referans alarak senkronize bir şekilde icraya başlasın. Herhangi bir taska ilave veya öncelikli görev aktarılırsa TaskKontrole 0xF yüklesin ve olay baştan başlasın.
Katana bu çözümü yukarıdaki çekirdek için mi önerdin yoksa RTOSlarda kullanılan bir yöntem miydı bu?
RTOS ları daha önce incelemiş değilim. Kullanılan bir yöntemmidir bilmiyorum.
Kendi projelerimde, farklı etkileri hızlı bir şekilde kontrol etmek ve müşterek veya sıralı yapılması gereken fonksiyonların işletilmesi için bu yöntemi kullanıyorum. Bu durum içinde gayet uygun, çünki kendi projelerimde de benzer sorunlar için bu yöntemi kullanıyorum.
http://efe.ege.edu.tr/~sinanyil/embedded/rtos/RTOS.ppt#256,1,Gerçek (http://efe.ege.edu.tr/~sinanyil/embedded/rtos/RTOS.ppt#256,1,Ger%C3%A7ek) Zamanlı İşletim Sistemleri (RTOS)
RTOS konusunda kitaplardan elde ettigim kisa notlari bu baslikta not tutacagim.
Herhangi bir anda sadece bir task calisir. Diger tasklar ya beklemededir (hazir durumda) yada bloke durumdadir. Benim cekirdekte, herhangi bir anda sadece bir task calisir. Diger tasklarin tamami beklemede (hazir durumda) dir.
Bir task kendini sleep ile bloke edebilir. Benim cekirdekte, bir task kendi zamanini hibe ederek beklemeye gecer.
Isletim sistemi calismakta olan bir taski (process); calisma zamani doldugu icin keser ve hazir durumuna alir. Bizde de boyle.
Bir process (task), I/O islemlerine ihtiyac duydugunda bloke durumuna gecer. Bizde boyle bir durum yok.
Daha yuksek oncelikli bir process, hazir kuyrugunda en uc noktaya geldiyse isletilen task kesilirerek beklemeye alinir ve kuruktaki sozkonusu task isletime alinir. Bizde boyle bir sey yok.
Scheduler (ileri zamanlarda yapilacak isleri planlayici), yeni bir processi calistirmak icin, belli bir algoritmaya gore (mesela round-robin) hazir durumdaki (bekleme durumundaki) tasklardan birisini secer. Bizde boyle bir durum sozkonusu değil.
Bloke durumundaki bir process, bloke olmasina neden olan olayin tamamlanmasi ardindan hazir duruma gecer.
Sleep ile bloke olmus bir task, wakeup ile uyandirilarak hazir duruma gecirilebilir.
http://hem.bredband.net/stafni/developer/rtbasics.htm (http://hem.bredband.net/stafni/developer/rtbasics.htm)
RTOS konusunda kafam çok karışmıştı, okuduğum dokümanlar ve sorduğum sorulara aldığım cevaplar sonucunda RTOS cekirdeginin asagidaki gibi davranmasi gerektigine karar verdim.
Uygulama programının bileşenlerini küçük fonksiyonlar (tasklar) olarak yazacağız. (Klavyeyi tara, Ekranda göster, hesapla vs)
- Bir tablo oluşturup tabloda bu fonksiyonların her birine öncelik sıralaması atayacağız. Bu tablo, taskın uyuyup uyumadığı, beklemede olup olmadığı gibi bilgileri de saklayacak.
- Çalışan bir fonksiyon, şu durumlarda uykuya geçecek;
Sleep komutu işletirse,
Delay komutu işletirse,
I/O işlemi yapmak isterse,
Kilitlenebilir bir değişkenin kilidinin kitli olduğunu öğrendiğinde,
Görev sıralayıcı, isterse.
- Bir fonksiyon (task) daha yüksek öncelikli bir fonksiyon tarafından yasaklı yada serbest hale getirilebilecek
--------------------------------------------------------------------------------------------------
Görev sıralayıcı, en yüksek öncelikli task varsa onu, yok eşit öncelikli tasklar varsa hakkaniyetli olmak şartıyla en çok hakeden taskı koşturacak.
Task yukarıda anlatılan sebeplerle uyutulmadığı sürece çalışacak.
Bir task uyuduğunda;
Görev sıralayıcı, sırada bekleyen tasklardan çalışmayı hak eden taskı seçecek ve bu kez onu çalıştıracak.
--------------------------------------------------------------------------------------------------
Bir taskı uyumaya zorlayan neden ortadan kalkarsa ya da interrupt ya da bir event oluşursa, o an çalışmakta olan taskın önceliği, uyuma nedeni ortadan kalkmış taskın önceliğinden daha düşükse, çalışmakta olan task beklemeye alınacak daha önce uyumaya zorlanmış öncelikli taskımız kaldığı yerden çalışmaya başlayacak.
Bu durumda RTOS uygulama programının (kullanıcı programının) tasarımı, lojik devrelerin senkron lojik tasarımıyla büyük benzerlikler göstermektedir. RTOS çekirdeği de senkron lojik tasarımındaki kuralları işleten yazılım olacak demektir ki yapacağı işler durum geçişlerini tespit etmek, çıkış tablolarını elde etmektir
Nasıl senkron lojik devre tasarımlarında her bir olay (girişlerdeki yada durumlardaki değişiklik) bir durumdan bir diğer duruma geçmeye neden oluyorsa RTOS'da da bir taskdan bir diğer taska geçiş benzer mekanizmalarla sağlanacak. Burada en buyuk is gorev siralayiciya dusmekte
Nasıl senkron lojik tasarımda ölü bölgeler oluşmus ve çalışan sistem o durumlardan birine düştügunde sistem bloke oluyorsa aynı durum RTOS uygulamasında da var.
RTOS denen problem, yukarıdaki gibi tanımlanırsa daha etkili CPU gücünü olması gereken fonksiyonda yoğunlaştıran gerektiği yerde bir o fonksiyonu terk edip bir başka fonksina yoğunlaşan yapı kurulmuş olacaktır.
-----------------------------------
RTOS, karmaşık bir programın küçük ve kolay anlaşılır kodlar şekilde yazılmasına imkan tanır. Fakat konvansiyonel yöntemlerle yazılmış bir programa kıyasla, RTOS da yazılmış program daha yavaş çalışacaktır. (Ana programa ilave olarak çekirdek kodlarının da işletimini gerekiyor) Fakat buna istisna olacak durumlar da çıkabilir.
RTOS uygulaması klasik usullerle yazılmış kodlara kıyasla daha fazla RAM istese ve daha yavaş çalışsa dahi, anlaşılırlık, bakım kolaylığı gibi sebeplerden ötürü RTOS tercih sebebidir.
Üstteki yazımda;
"Görev sıralayıcı, en yüksek öncelikli task varsa onu, yok eşit öncelikli tasklar varsa hakkaniyetli olmak şartıyla en çok hakeden taskı koşturacak"
şeklinde bir ifade kullanmıştım. Şu anda Hakkaniyetli olmak şartıyla çalışmayı en çok hakeden taskın bulunması probleminin çözümünde takıldım kaldım.
Geçmişte bir takım olaylar gelişti, Bazı düşük öncelikli tasklar durduruldu araya yüksek öncelikli tasklar girdi ve şu anda geçmişte yarıda kesilen düşük öncelikli taskları kaldıkları yerden çalıştırma aşamasına geldik. Elimizde tek bir yarıda kesilmiş task olsa işimiz çok kolay olurdu.
Diyelimki aynı öncelikli tasklardan birincisi Delay komutu işletti, sıra 2. taska geldi, bu da delay işletti ..... n'ci task da delay komutu işletti bu esnada araya yüksek öncelikli tasklar girdi onların işlemi yapıldı vs vs ve nihayetinde geçmişte de Delay çalıştırmış tüm taskların delay süreleri tam da bu anda bitmiş olsun.
Şimdi, n tane task içinden çalışmayı en çok hakeden taskı arayıp bulmamız lazım.
Elimde her bir taskın seceresini tutan blok var. Hangi task ne durumda, önceliği ne, şu ana kadar kaç kez çalıştı, ne zaman beklemeye alınmıştı vs vs vs
Tüm bu durumları değerlendirip çalışması gereken taskı adil bir şekilde bulacak yazılım RTOS'un kalbi niteliğinde.
Ancak bu yazılımın uzun zamanda çalışmasını gerektirecek kodlar içermesi RTOS'un kalitesini düşürür.
-------------------------------------------------------------------
Şimdi hangi task çalışmalı sorusunun cevabını arayan program parçacığı konusunda ne düşünüyorsunuz?
Nasıl bir algortima kurmalıyız?
bu noktaya gelmiş biri için algoritma zor olmamalı...
görevlerin önceliği belli olduğuna göre...
yanılıyormuyum..?
Buraya kadar olan kisimlar cerez niteliginde ve asil problem bence bu. (Belki de bu kisimdaki hakkaniyet'e gereginden fazla onem veriyorum ve bu konuda hataliyim)
Gecmiste durdurulmus fakat simdi calismaya hazir N tane ayni oncelikte task olsun.
Amacimiz bu tasklardan birisini secip calistirmak.
Oncelik dersen hepsi ayni oncelikte. Bazilari su ana kadar 3 kez calismis bazilari 5 kez bazilari 10 kez.
Yazik su task sadece 3 kere calismis bunu calistiralim desek bakiyoruz 10 kez calisan task da cok onceden delay komutuna baslamis zamani dolmus.
Kafam burada karisti iste.
Bir de şöyle bir durum var.
Kesilen tasklar stackda bayağı bir register saklanmasına neden oluyor. Çok sayıda task varsa stağı şişirmek de tehlikeli.
Amaçlardan birisi de stağı olabildiğince boş tutmak olmalı.
Hangi task ne zaman beklemeye alındı bilgisi de kritik. 1ms lik timer ticklerinde 32 bitlik bir değişken 50 gün geçmişi saklayabilir. Bu kadar da abartma denilebilir.
Bir sistem 50 günde muhakkak kapatılıp açılır dersek anlarım.
yazılan rtos ne işe yarayacak?
RTOS ne işe yarar?
Şu anda sadece hobby.
rtos nedir yazılarında diyor ya; otomobil, uzay gemisi, özel cihazlar..
bu durumda her görevin önceliği cihazın çalışması ile ilgili diye düşündüm..
RTOS kullanmak icin illaki otomobil yada ucakla ugrasmak gerekmiyor.
Her hangi bir programi ya klasik usulde ya da RTOS uzerinde kosacak sekilde yazarsin.
Bu basit bir led yakip sondurme programi dahi olabilir.
@bunalmis hocam os dersinden hatırladığım kadarıyla bu konuda çok değişik yaklaşımlar mevcuttu. Doğrusu hangisi bilmiyorum. Seçenek sunup uygulamaya göre konfigure edilmeli olabilir.
Mesela en çok bekleyen taska öncelik verilebilir. veya önceki çalışma durumlarından istatistikler tutulup işlemciyi en az tutup sonra bırakan taska öncelik verilebilir. Bu söylediklerim muhtemelen PC lerimizde çalışan OS lar için. Ticari RTOS ların yöntemini bilmiyorum. Ben de merak ettim.
Gerbay
preemptive calisiyoruz. Task0 en yuksek oncelikli, digerleri daha dusuk ve hepsi ayni oncelik seviyesinde.
Task0 calismaya basladi fakat bir noktada donanimdan bir sey beklemeye baslasin. Task1 isletilecek,
Task1 osdelay isletsin. Task2 isletilecek,
Task2 osdelay isletsin. Task3 isletilecek,
Task3 osdelay isletsin. Task4 isletilecek,
Task4 osdelay isletsin. Taskn isletilecek...
Burada Donanim veriyi hazir etsin.
Task0 calisti ve isi bitti diyelim.
Tam bu anda Task1,Task2,Task3,Task4 delay sureleri de bitmis olsun.
Task1,Task2,Task3,Task4 den hangisine geri donecegiz?
Sirayla tasklari calistiran projem yarim kalmisti projeyi bu gunlerde tekrardan ele aliyorum.
Acik kaynak kodlari Keilde denemek isterseniz link: http://www.cncdesigner.com/wordpress/?p=3102 (http://www.cncdesigner.com/wordpress/?p=3102)
Programin yaptigi is Tasklari sira ile calistirmaktan ibaret.
System Tick conter her 1 ms de int uretiyor ve calisan task yarida kesiliyor bir sonraki yarida kalmis task isletilmeye baslaniyor ve bu boyle devam ediyor.
Aklima bir sorun geldi ve simdi nasil cozecegimi arastiriyorum.
Normalde isler ornegin 2 task icin asagidaki gibi yuruyor.
Task1 -->SystemTickInt-->Task2-->SystemTickInt-->Task1
Sorun surada olusacak;
Task1 -->Xint--->SystemTickInt-->Task2-->SystemTickInt-->Yarim kalmisXint-->Task1
Daha acik yazacak olursak;
Task1 isletirlirken herhangi bir X interrupt harekete gecsin.
Bu durumda Task1 yarida birakilir ve ilgili interrup rutini isletilmeye baslar.
int rutini islerken daha hala int rutini icindeyken System Tick int gelirse int rutinimiz de yarida birakilir ve system Tick int rutinine atlanir.
System Tick bir sonraki Task olan Task2 parametrelerini islemci registerlerine yukler ve Task2 ye gecisi yaptirir.
Task2 tekrardan System Tick int ile kesilince bu kez Task1 parametreleri islemci registerlerine yuklenir ve Task1 kosturulur.
Burada Task1 aslinda X interrupt ile kesildiginden yarim kalmis olan Xinterrupt rutinine devam edilir ve bitiminde yarida kalmis Task1 rutini isler.
Bu bir sorundur. Cunku cevaplanmaya baslamis herhangi bir int, task gecisi nedeniyle yarida birakilmis ve ancak tum tasklar isledikten sonra interrupt rutini calismasina devam edecektir.
Hocam ama bahsettigim sorunumda soyle bir durum var. Task islerken int gelirse bu interrupt islenirken bunu da Timer Tick int keserse (Timer Tick bir exception) bu durumda yazdigim cekirdek kodlar yarim kalmis interrupti task gecisi oldugu icin tamamlamayacak.
Ustelik Stack alani switch edildiginden inta girildiginde yapilan context saving islemi dikkate alinmadigindan (cekirdegimdeki bug) cekirdek cokuyor. Neyse sorunu tespit ettim bir sekilde cozerim.
Sorunun cozumu icin artistik bir kod yazmam gerekecek.
problemimiz;
A kullanici programi I ve J birer interrupt.
Eger A, I tarafindan kesilirse I'ya ait int rutini isletecegiz ve bu rutinin en sonunda X diye bir fonksiyonu cagiracagiz.
Eger A, J tarafindan kesilirse J de I tarafindan kesilirse I nin sonunda X fonksiyonunu cagirmayacagiz once J nin yarida kesilen kismini islettirecegiz ardindan yarim kalan I int rutininde X fonksiyonunu cagiracak noktaya gelecegiz.
I_Rutini
.....
.....
Herhangi bir interrupt rutininin kesilmesine neden oldukmu?
Evet ise, kestigin Interrupt rutinlerini tamamlat.
X fonksiyonunu cagir.
hazır konu ile ilgilenen arkadaşlarımı bulmuşken bende bazı hedeflerimden bahsetmek isterim. güzel bir beyin fırtınası ile iyi şeyler ortaya çıkabilir diye düşünüyorum. biraz konunun ortasından girmiş gibi olacağım ama lafı uzatmadan sadede getirmek istiyorum.
zaman.h:
// Calculate the timer tick period
#define SYS_FREQ GetSystemClock()
#define PB_DIV 1
#define PRESCALE 256
#define TOGGLES_PER_SEC 8
#define T2_TICK (SYS_FREQ/PB_DIV/PRESCALE/TOGGLES_PER_SEC)
unsigned int timer_count;
//_/__/___/____/_____/______/_______/________/_________/__________/
#define mmxreg 20
#define s1hz 0
#define lcd_bsy 1
#define pipeline 2
#define ucgn_ef1 3
#define sys_hz 4
#define i2cwdt 5
#define btn1_sur 6
#define btn2_sur 7
#define btn3_sur 8
#define anim1 9
#define ldrsn 10
#define adcoku 11
unsigned int rdelay_msn[mmxreg];
extern void zaman_sayac(void);
extern void zaman_init(void);
//_/__/___/____/_____/______/_______/________/_________/__________/
zaman.c :
#include "zaman.h"
#include <GenericTypeDefs.h>
#include <plib.h>
#include "HardwareProfile.h"
#include "USB/usb.h"
#include "USB/usb_device_generic.h"
#include "user.h"
//_/__/___/____/_____/______/_______/________/_________/__________/
void zaman_sayac(void){
unsigned char i=0;
while(TMR2>625){TMR2=TMR2-625;
for(i=0;i<mmxreg;i++)if(rdelay_msn[i]>0)rdelay_msn[i]--;}}
//_/__/___/____/_____/______/_______/________/_________/__________/
void zaman_init(void){
//*** TMR2 ***
OpenTimer2(T2_ON|T2_PS_1_64, T2_TICK);
}
main:
int main ( void )
{
zaman_init();
while(1)
{
// rutinsel zaman sayaç kontrolü yapılır
zaman_sayac();
// sistem çalışır ledi (1hz)
if(rdelay_msn[s1hz]==0){rdelay_msn[s1hz]=500; mLED_6_Toggle();}
}
} // main
burada bir çok işlem paralel olarak yürütülmekte ancak kafa karıştırmasın diye bir çoğunu sildim. zaman.h danda bu anlaşılabilir zaten. çalıştırmakta olduğum kodlardan alıntı yaptığımı da belirteyim.
şimdi; ana döngüde ki sistem çalışır ledi işlemini açıklayayım hızlıca, rdelay_msn[s1hz] dizisinin s1hz inci hücresindeki sayısal değer 0 ise bu hücreye 500 yüklenip led toggle ediliyor. zaman_sayac(); fonksiyonu ile her bir hücre 1ms de bir otomatik birer azaltılıyor. bu sayede 500 ms geçtiği anlaşılıp ona göre karar veriliyor.
farkettiyseniz, amaca tam şekilde hizmet ediyor olsada yazım şekli bana da pek hoş gelmiyor. yani sıradan bir delay(500); diyemiyoruz da önce yazılımsal olarak zaman.h kütüphanesinden bir hücre tayin edip o hücreyi sadece o amaç için kullanılır kılıyoruz. bunun yerine öyle bir fonksiyon oluşturayım ki önce nerden kullandığımı farketsin ona göre tayin işlemleri yapsın. biraz call_return için kullanılan stack gibi bir yapı elde edilebilir gibi düşündüm. ya da otel ve odaları muhabbetini duymuştum ona benzer bir yapı kurmayı hedefliyorum. bu işin bir standartı var mıdır? yada nasıl yapılabilinir konusunda ki fikirlerinizi duymak mutluluk verir.
Alıntı yapılan: z - 29 Ağustos 2013, 21:39:13
....Sorunun cozumu icin artistik bir kod yazmam gerekecek.......
Karsi karsiya kaldigim problem (interruptin System Tick ile kesilmesi, System Tick ile Task degistirme asamasinda kesilen interupt rutininde islenmemis kodlarin oylece kalmasi) zaten OS yapisinda bilinen bir problemmis. Neyseki cozumu de var.
Cozum: The Definitive Guide To The ARM CORTEX M3 (Second Edition) Sayfa 128
Bir diger aciklama ise http://embeddedgurus.com/state-space/2011/09/whats-the-state-of-your-cortex/ (http://embeddedgurus.com/state-space/2011/09/whats-the-state-of-your-cortex/)
Alıntı yapılan: z - 30 Ağustos 2013, 15:55:50
Karsi karsiya kaldigim problem (interruptin System Tick ile kesilmesi, System Tick ile Task degistirme asamasinda kesilen interupt rutininde islenmemis kodlarin oylece kalmasi) zaten OS yapisinda bilinen bir problemmis. Neyseki cozumu de var.
Cozum: The Definitive Guide To The ARM CORTEX M3 (Second Edition) Sayfa 128
Bir diger aciklama ise http://embeddedgurus.com/state-space/2011/09/whats-the-state-of-your-cortex/ (http://embeddedgurus.com/state-space/2011/09/whats-the-state-of-your-cortex/)
sayin hocam saygida kusur etmek istemem ama bahsettiginiz problemin cevabi bu son mesajiniz olamaz.
cunki siz (gercekten) cok bilinen RTOS interrupt nesting problemini tarif ediyorsunuz, verdiginiz referans(aciklama) ise yine cok bilinen arm cortex-m serisinde (muhtemelen chip tasarimcisinin esrar/eroin/alkol karisimi bir maddenin etkisi altndayken) yaptigi interrupt tasarimindan olan bir garip durum. Yani genel bir probleme ozel bir aciklama getiriyorsunuz.
RTOS interrupt nesting icin kullanilan cesitli methodlar var, isr nesting counter kullanmak, isr lar icin ozel/tek stack kullanmak, isrdan dondukten sonra scheduleri ancak daha yuksek oncelikli "ready" task varsa yapmak, isrin tamamini critical section icine almak. isr kodunun onune/sonuna bu teknik(ler)i kullanan prologue/epilogue kod yazmak vb
siz 2011 kasinda bu konuda kaynak arastirmak istemiyorum, hemde hobi olarak yapacagim dediginiz icin daha once bu baslikta mesaj yazmamistim ama goruyorum, sizde bir takim kitaplari okumaya baslamissiniz. onun icin affiniza siginarak bu yorumu yaptim.
Hocam ne kusur etmesi estagfurullah.
Karsi karsiya oldugum Tick Timer'in yarida kestigi interrupt problemine cozum olarak Cortex islemcide zaten PendSV seklinde bir cozum varmis.
Bu cozumden henuz haberdar oldum ve verdigim linkte PendSV icin kisa bir hatirlatma yapmis ardindan da cortexlerdeki bir bugdan sozetmis.
Su anda, RTOS cekirdegi nedir nasil yaziliri anlatan kitaplari okumak yerine problemleri ele alis felsefem geregi Bulent Tasklari islemciye nasil sirayla kosturur buna nasil cozum getirir seklinde yol katediyorum.
Daha onceleri hic karsilasmadigim bir interrupt sorunu ile karsilasinca interruptlari nasil yonetirim konusunda arastirma yapmaya basladim.
Henuz cozum uretmemis olsam da RTOS yazarlarin karsilastigi problemi kendi kendime kesfetmis oldugum icin acaip mutluyum.
Aslinda siz bir RTOS kursu duzenleseniz hepimiz icin cok iyi olacak.
Alıntı YapAslinda siz bir RTOS kursu duzenleseniz hepimiz icin cok iyi olacak.
Aman hocam sayin Niyazi saralin basina gelenlerden sonra kurs ver sonra mahkemeyle ugras benim yasimda maddi manevi alinamiyacak kadar buyuk bir risk.
Ama benimde gonlumden bildiklerimi ogrenmek isteyenlere aktarmak geciyor.
Keske mba yapmaktansa doktorami yarida birakmasaydim, universitenin birinde egitmen filan olur, seminerler workshoplar filan yapardim.
Bu konuyu hortlatmanın zamanı geldi.
(http://www.cncdesigner.com/STM/4Ceker.JPG)
En son yukarıdaki gibi bir düzeneği yapmıştım. Sonra ilgilenemedim.
Şimdi tekrar ele alıp kaldığım yerden devam etmek istiyorum.
Aslında oturup en basitinden bir RTOS öğrenip bir kaç kod yazıp ardından bu projeye devam etmem lazım fakat forumdan yardım bekliyorum.
Çalışmamın son halinde 8 taneye kadar task oluşturup her birini sırayla koşturabiliyordum.
Daha da öteye gitmedim.
Tasklar arası veri alışverişinde aşılması gereken sorunlar olduğunu gördüm ve bunlarla alakalı olarak Semafor ve Mutex gibi kavramların olduğunu duyduydum.
RTOS kullananları, öncelikle semafor ve mutex konusunda aydınlatılmaları için davet ediyorum.
Hocam Semaphore shared bir bölgeye aynı anda birden fazla taskın erişememesi için kullanılır mesela aşağıdaki örnek üzerinden gidecek olursak,
'Micrium'un sayfasından alıntı'
void Task1 (void *p_arg)
{
OS_ERR err;
CPU_TS ts;
while (DEF_ON) {
:
OSSemPend(&MySem, (1)
0, (2)
OS_OPT_PEND_BLOCKING, (3)
&ts, (4)
&err); (5)
switch (err) {
case OS_ERR_NONE:
Access Shared Resource; (6)
OSSemPost(&MySem, (7)
OS_OPT_POST_1, (8)
&err); (9)
/* Check "err" */
break;
case OS_ERR_PEND_ABORT:
/* The pend was aborted by another task */
break;
case OS_ERR_OBJ_DEL:
/* The semaphore was deleted */
break;
default:
/* Other errors */
}
:
}
}
Burda OSSemPend fonksiyonu çağırıldığında eğer bu semaphore u alan başak bir task yoksa OS_ERR_NONE case işletilir ve shared resource a erişilir.İş bitince de semaphore release edilir.Bu şekilde shared resource a aynı anda birden fazla task ın erişmesi engellenir.
Mutex'in kullanımı ve kullanım amacı semaphore a çok benzer fakat mutex priority inversion denen olayın oluşmasını da engeller.Priority inversion ını da bir örnek üzerinden anlatırsak:
Mesela düşük orta ve yüksek önceliğe sahip sırasıyla A,B ve C adında tasklarımız olsun. ilk olarak A taskı çalışssın ve x semaphore unu alsın.Semophore u daha release etmeden de C taskının çalışma zamanı gelmiş olsun C taskı daha yüksek öncelikli olduğu için A taskını preempt eder.C taskı da bir resource a erişmek için yine x semaphore una ihtiyaç duysun tabi x semaphore u A taskında olduğu için scheduler tekrardan A taskına switch eder.Bu sıra da yine A taskı x semaphore u bırakmadan B taskının zamanı gelmiş olmuş doğal olarak B taskının priority si daha yüksek olduğu için yine A taskı preempt edilir.B taskının işi bitir A taskına geri dönülür A taskının da x semaphore u ile işi bittikten sonra C taskına switch edilir ve C taskı işini bitirir,
Şimdi burda ne olmuş oldu:
C taskı en yüksek önceliğe sahip olmasına rağmen B taskı C taskının çalışmasını engellemiş oldu.Bu olaya da priority inversion denir.
İşte semaphore yerine mutex kullanınca şöyle bi olay oluyor.
A taskı x mutex ine sahipken C taskı tarafında preempt edilirse A taskının priority si C taskının priority sine eşitlenir.Bu sayede araya başka task giremez.
O zaman Semafor için şöyle diyebilirmiyiz?
Global değişkenlerimiz var. Tasklar bunları ortaklaşa kullanacaklar.
Sırası gelen task golabal değişkene bir bakıyor üzerinde rahatsız etmeyin diyor. Task görevi bir sonrakine devrediyor.
Bir sonraki bakıyor yahu bu mesgul levhasını ben koyduydum işimi görüyüm de millette kullansın diyor işini bitirip meşgul levhasını kaldırıyor.
Benzetim tamı tamına doğrumudur?
Aynen hocam.
Bu bahsettigimiz semaphore resource management icin kullanilan semaphore du.
Bir de senkronizasyon amaciyla kullanilan semaphore var.Micrium da tasksemaphore diye geciyor.
Ornegin bir uart ISR imiz olsun.ISR mesgul etmemek icin gelen datalari baska bir task icinde handle etmek isteyelim. Budurumda taskin basinda belli bi semaphore u bekleriz. Gerekli data gelince o semaphore u ISR in icinde release ederiz. Boylece ISR i sadece sadece gelen datalari biriktirmek icin kullaniriz.
Sunu da belirteyi: Resource management icin kullanilan semaphore yeri eger shared data miktari az ise interruplar disable etme metodu da kullanilabilir. Ornegin tek bir instruction i semaphore ya da mutex ile koruma altina almak yerine interruptlari disable daha sonra da enable edebiliriz. Bu islem daha az islem gucu gerekirdiginden boyle durumlarda tercih edilebilir.
Peki semaphoru doğru anladıysam semaphore kullanarak yapamayacağım işler olabilirmi?
Yani sadece semaphore mekanizması ile proje yapamazmıyız?
Birde pic gibi minik microlar için RTOS benzeri şeyler yazmışlar. Bu bahsettiklerinizin hepsini bu rtoslar yapabiliyormu?
Yani mutex, semaphore, Cooperative Schedule, Round Robbin vs vs...
Eğer böyle yaparsanız RTOS olmaz.
DOS Multitasker olur :D :D :D
Alıntı yapılan: z - 24 Kasım 2015, 20:07:42
Peki semaphoru doğru anladıysam semaphore kullanarak yapamayacağım işler olabilirmi?
Yani sadece semaphore mekanizması ile proje yapamazmıyız?
Birde pic gibi minik microlar için RTOS benzeri şeyler yazmışlar. Bu bahsettiklerinizin hepsini bu rtoslar yapabiliyormu?
Yani mutex, semaphore, Cooperative Schedule, Round Robbin vs vs...
Hocam kasteddiğiniz işler neler mesela?
Diğer rtos'ları çok bilmiyorum ama freertos fena değildir ve bir çok platformu destekler.
Her 1 ms de task geçişi yapsam, bir de global takas değişkenlerime semaphore özelliği eklesem elde edeceğim yapı ile şöyle bir proje yapamazsın diyebilirmisin demek istiyorum?
Yani ilave olarak neler neler daha olması lazım? Acil durumlarda hangi tasktan hangisine geçileceği sıralamasını her taskın belirleme şansı da var.
Hocam yapabilirsiniz.
Fakat message queue,event,gibi mekanızmalarla yapmak istediğiniz şeyleri daha kolay bir şekilde gerçekleştirebilirsiniz.Yukarıda da bahsettiğim gibi bazı durumlarda mutex de kullanmanız gerekebilir.Yani bu şekilde peşin konuşmak biraz yanlış olur.Projenin gidişatına göre ancak belli olur neyi kullanıp kullanmayacağınız.
Kafamı karıştıran konu bu mutexdi scheduleydi bu gibi kavramları koda dökmeye kalktıkça çekirdek büyümeye başlayacak bu da gecikmelere neden olacak.
Acaba RTOS sistemlerde 3..5 mikrosaniye zamandan sayılmayan ihmal edilebilir değerlermi?
Alıntı yapılan: z - 25 Kasım 2015, 08:36:43
Kafamı karıştıran konu bu mutexdi scheduleydi bu gibi kavramları koda dökmeye kalktıkça çekirdek büyümeye başlayacak bu da gecikmelere neden olacak.
Acaba RTOS sistemlerde 3..5 mikrosaniye zamandan sayılmayan ihmal edilebilir değerlermi?
http://wiki.chibios.org/dokuwiki/doku.php?id=chibios:metrics (http://wiki.chibios.org/dokuwiki/doku.php?id=chibios:metrics)
Ölçülebilir olması önemli bu gecikmelerin.