Kendimize ait RTOS Yazımı, Multitasking hakkında

Başlatan bunalmis, 08 Ekim 2011, 11:35:31

Veli B.

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.

z

#46
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);
          } 
}


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

z

#47
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.

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.
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

z

#48
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?






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

Erol YILMAZ

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....



z

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.



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

Veli B.

İş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.

z

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.
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

EMG81

#53
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 ?

z

#54
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.
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

Veli B.

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.

z

Katana bu çözümü yukarıdaki çekirdek için mi önerdin yoksa RTOSlarda kullanılan bir yöntem miydı bu?
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

Veli B.

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.

z

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

z

#59
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.
Bana e^st de diyebilirsiniz.   www.cncdesigner.com