Elektronik Devreler Projeler Elektronik ve biraz daha fazlası İletişim - Araçlar - Dikkat - Topluluk
Elektronik / Elektronik Kaynakları/

OSA RTOS

Sponsorlu Bağlantılar

Dünya çapında geniş kitlelerce kullanılan, giriş seviyesi için oldukça yeterli, 8-16bit PIC mikrodenetleyicilerden, AVR ve STM’e kadar geniş bir alanda kullanılabilen, Türkiye’nin ilk Türkçe kullanım kılavuzu ve açıklamalarına sahip RTOS’u OSA’nın tüm kullanım detaylarını ve açıklamalarını bu başlık altında bulabileceksiniz.

OSA Nedir?

OSA, Microchip PIC10, PIC12, PIC16, PIC18, PIC24, dsPIC serileri, Atmel AVR 8-bit ve STMicroelectronics STM8 mikrodenetleyicileri için tasarlanmış kooperatif çoklu gerçek zamanlı işletim sistemidir (RTOS).

RTOS programcıyı görevlerdeki (task) sorunlara (algoritmik, matemtetiksel vb.) odaklarken diğer olaylar hakkında endişelenmemesini sağlar. Diğer ikincil olaylar OSA kernel’i tarafından işletilir:

  • paralel süreçler arası geçiş (örneğin keypad taraması, LCD’ye yazı yazdırma, röleleri kapama/açma);
  • zaman aşımı denetimi ve gecikmeleri sayma;
  • önceliği yüksek çalışmaya hazır görevi (task) bulup işleme alma;
  • farklı görevler (task) arası data alışverişini semaforlar, mesajlar ve kuyruklar kullanarak gerçekleştirme.

OSA’daki tüm olaylar basit C fonksiyonlarıdır. Bu fonksiyon içerisinde görev bağlama anahtarlarından en az birini içeren sonsuz bir döngü içermelidir. Örnek bir görevin (task) fonksiyonu aşağıdaki gibi olacaktır:

void SimpleTask (void)
{
    for (;;)        // Sonsuz Döngü
    {
        OS_Yield();   // Koşulsuz görev anahtarlaması
    }
}

Derleyiciler

OSA RTOS aşağıdaki tablolardan görüleceği üzere bir çok mikrodenetleyiciyi ve bunları programlamak için kullanılan derleyicileri desteklemektedir.

ose-derleyici

Kısıtlamalar

OSA RTOS’un kullanımında derleyiciye göre değişen çeşitli kısıtlamalar bulunmaktadır.

  • HT-PICC HT-PIC18

– Kesme fonksiyonunun başında OS_EnterInt (FSR’yi kaydeder) ve çıkarken de OS_LeaveInt (FSR’yi geri yükler) servisini kullanınız. OS_EnterInt mutlaka kesme fonksiyonunun başında ve OS_LeaveInt ise sonunda olmalıdır.

void interrupt int_routine (void)
{
    char var1, var2;
    int var3;

    // Yerel değişkenler tanımlandıktan sonra FSR'yi kaydetmeliyiz:
    OS_EnterInt();
    /*...*/
    /* Interrupt bayraklarına bakılıyor */
    /*...*/

    // Kesme fonksiyonunun sonunda FSR'leri geri yüklemeliyiz:
    OS_LeaveInt();
}

– Bu servisler FSR değerini (htpicc18 için FSR0) HT-PICC bunu yapmadığında kaydeder ve geri yükler.

  • Microchip C18

– Prosedürel soyutlama (procedural abstraction) optimizasyonunu kullanamazsınız.
– Multi-bank stack modelini kullanamazsınız.

  • Microchip C30

– Prosedürel soyutlama (procedural abstraction) optimizasyonunu kullanamazsınız (derleyici komutu “-mpa”).

  • PIC10-12 Entegreler

– PIC10F ve PIC12F serisi mikrodenetleyiciler kullanırken mesaj işaretçilerin (pointer) boyutları, basit mesajlar ve sayıcı semaforlarda 1 byte’a eşit olmalıdır.

  • mikroC PRO for PIC16

– PIC18 serileri için Version 2.50 PRO ya da daha yükseği gereklidir.
– PIC12 ve PIC16 serileri için Version 3.00 PRO ya da daha yükseği gereklidir.

-Dinamik sayıcılar (timers), mesjalar ve mesaj kuyrukları RAM bölgesinde bank2 ve bank3’e atanamaz. Problemin nedeni microC PRO’nun bu bölgeleri kendisine ayırmasındandır. Bu durumda listelenen değişkenlerin tanımlama yerlerini değiştirebilirsiniz. (Bu kısıtlama yakında çözülecektir)

  • CCS PICC

– Versiyon 4.104’dan beri derleyicide bir hata bulunmaktadır. Bu hatadan dolayı derleyici OSA’yı kullanarak programı derlememektedir. Bunun için lütfen diğer versiyonları kullanınız. (OSA bu versiyonlarla test edildi: 4.023, 4.069, 4.084, 4.099, 4.102, 4.105)

  • IAR (AVR and STM8)

– Sadece C-mode’da çalışır, C++ ile çalışmaz.
– Cross-call optimizasyonu kapalı olmalıdır.

  • WinAVR

– OSA ve proje klasörleri aynı mantıksal sürücü üzerinde (örneğin “C:\…”) olmalıdır.

  • STM8

– ROM’u 64k ve altı olan mikrodenetleyiciler desteklenmektedir.

OSA Tanımlamaları

Proje Oluşturmak

OSA’yı uygulamalarınızda kullanabilmeniz için aşağıdaki adımları uygulamanız gerekmektedir:

1) IDE kullanarak projenizi oluşturun. Projenize “osa.c” dosyasını ekleyin. (osa. tüm sistem değişkenlerini ve fonksiyon tiplerini bünyesinde barındırmaktadır);

2) Proje klasörünüzde OSAcfg.h dosyasını oluşturunuz. Bu dosya OSA’nın derleme parametrelerini (kaç tane görev (task) kullanılacak, sayıcı tipleri vb.) belirlemek için kullanılır. En basit durumda bu dosya boş olabilir. Ayrıca OSAcfg_Tool programını kullanarak bu dosyayı oluşturabilir veya üzerinde değişiklik yapabilirsiniz;

3) OSA servisini kullanacak her dosya için “#include” ile bu dosyayı tanımlayınız;

4) Projenize aşağıdaki iki dizini ekleyiniz:

  • OSAcfg.h bulunduğu konumu ve
  • osa.h’ın bulunduğu konumu;

5) main() fonksiyonunun başlangıcında OS_Init() servisini çağırın;

6) main() fonksiyonunun sonunda ise OS_Run() servisini çağırın.

Değişik IDE ve Platformlar İçin Notlar

MPLAB

  • osa.c dosyasını eklemek için Workspace ekranına sağ tıklayıp, “Add file..” kısmını seçiniz.
  • Include-paths kısmını project option’da bulup osa.c klasörünü ekleyiniz: menu “Project/Build options/Project…”, tab “Directories”.

MPLAB ve HT-PICC

  • MPLAB’ın eski versiyonları HTPICC için Include yeri belirtmede sadece mutlak yer izni tanırken farklı yer göstermenize izni vermemektedir.
  • PRO-version için : Doğru bilgileri compiler’a sunmak için tüm görev (task) fonksiyonları OS_Task_Define() ile tanımlanmalıdır.
void main (void)
{
OS_Init();
...
OS_Task_Define(Task_Buttons);
OS_Task_Define(Task_LEDs);
OS_Task_Define(Task_LCD);
...
OS_Task_Create(Task_Buttons);
OS_Task_Create(Task_LEDs);
OS_Task_Create(Task_LCD);
}

MPLAB ve Mplab C18

  • Kütüphane yolunu tanımlayınız: Bunun için “Project/Build options/Progect…” yolundaki “Directories” sekmesinden, “Library Search Path”‘e tıklayıp kütüphane dosyasını ekleyiniz.(Örneğin: c:\mcc18\lib).
  • Proje ayarları penceresinden “MPLAB C18” sekmesini, kategoriden de “Optimization”u ve “Procedural absraction” sekmesini kaldırın.
  • Linker dosyasını eklemeyi unutmayın: “Linker Script” klasörüne sağ tıklayın, “Workspace” penceresinden ‘.lkr’ dosyasını kullandığınız denetleyiciye göre seçin (bkz. “MCC18\lkr”)

MPLAB ve Mplab C30

  • Proje ayarları penceresinden “MPLAB C30” sekmesini, kategoriden de “Optimization”u ve “Procedural absraction” sekmesini kaldırın.

CCS

  • osa.c dosyasını projenize eklemeyiniz.
  • Derleyiciye doğru klasör ağını tanıtmak için tüm görevler (task) main() fonksiyonunda OS_Task_Define() servisiyle tanıtılmalıdır.
void main (void)
{
OS_Init();
...
OS_Task_Define(Task_Buttons);
OS_Task_Define(Task_LEDs);
OS_Task_Define(Task_LCD);
...
OS_Task_Create(Task_Buttons);
OS_Task_Create(Task_LEDs);
OS_Task_Create(Task_LCD);
}

mikroC PRO IDE

  • osa.c dosyasını “Project/Add File To Project…” adımını kullanarak projenize ekleyiniz.
  • Include yolunu “Project/Edit Search Paths…” menüsünden ulaşın. Diyalog penceresinde iki kısayol belirleme seçeneği bulunmaktadır: Source Files ve Header Files. Bize “Header files” kısmı gereklidir. “Yeşil renkli artı” ikonuna basıp, include kısayolunu ekleyiniz.
  • Görevler (task) içerisinde kullanılacak fonksiyonlara linker bilgileri tanıtılmaldır:
#pragma funcall main Task_Buttons
// Linkera bu fonksiyonun indirek çağrılacağı
// belirtiliyor

void Task_Buttons (void)
{
...
}

AVR Studio ve WinAVR

  • osa.c dosyasını “Workspace” penceresinden (AVR GCC) “Source Files” dosyasını bulun “Add Existing Source File(s)…” ile projenize ekleyiniz.
  • include-kısayolu “Project/Configuration options” altındaki “Include Directories” de tanımlanmalıdır.

IAR

  • osa.c dosyasını “Project/Add files…” ile ekleyiniz.
  • include-kısayolu “Project/Options”, “C/C++ compiler” kategorisinin altındaki “preprocessor” alanından “Additional include directories” ten ekleyiniz.
  • Daha sonra “Optimization” kısmındaki “Cross call” ‘un onayını kaldırınız.

IAR ve STM8

  • Tüm ayarlamalardan önce projenize “osa\port\stm8\osa_stm_iar.s” dosyasını ekleyiniz.

STVD ve STM8

  • osa.c dosyasını projenize eklemek için Workspace ekranına sağ tıklayın ve “Source” folder and select “Add Files To Folder…” kısmını seçiniz.
  • include-kısayolu “Project/Options”, “C/C++ compiler” kategorisinin altındaki “preprocessor” alanından “Additional include directories” ten ekleyiniz.

Raisonance ve STM8

  • osa.c dosyasını eklemek için “Project/Add Item…” menüsüne geliniz.
  • include-kısayolunu eklemek için “Project/Properties”, “Application Optios” klasöründen, “Directories” altkalsörüne geliniz.

Görev Düzenleyici (Scheduler)

OS_Run() sonsuz bir döngü içeren ve görev düzenleyiciyi (scheduler) çağıran bir servistir. Bu servis main() fonksiyonunun sonunda çağrılmalıdır. Bu servis ayrıca tüm kontrolü OSA kernel’e devretmektedir. Görev düzenleyici (scheduler) tüm görevleri (task) işler ve yüksek öncelikli hazır görevleri (task) bekler. Bu tür bir görev (task), olayı (event) bulduğunda ise görev düzenleyici (scheduler) bunu işleme alır.

OS_Run() bir makrodur. Bu makro global etiketler içerir; bu yüzden bu servis program içerisinde sadece bir kez kullanılabilir.

Sonuç olarak programınızın örnek görüntüsü aşağıdaki gibi olacaktır:

void main (void)
{
    OS_Init();
    OS_Task_Create(...);
    OS_Task_Create(...);
    // İhtiyacınız olan tüm görevleri (task) oluşturunuz
    // ...

    OS_Run();
}

Görev düzenleyici (scheduler) öncelikle tüm aktif görevleri (task) tarar (bu görevler OS_Task_Create ile yaratılmışlardır) ve işletilmeye hazır olan tüm görevleri (task) bulur. Daha sonra görev düzenleyici (scheduler) hazır görevlerin (task) önceliklerini karşılaştırır ve bunlardan önceliği en büyük olana kontrolü verir. Burada sadece bir istisna vardır: bir görev (task) kritik bölümde (critical sections) tanımlanmışsa sadece bu görev (task) kontrolü alabilir; diğer görevler (task) bu durumda görev düzenleyici (scheduler) tarafından atlanır.

Eğer görevler (task) taranırken iş düzenleyici önceliği 0 yani en yüksek görevi (task) bulursa, görev düzenleyici (scheduler) aramayı durdurur ve kontrolü bu göreve (task) aktarır. Bu görev düzenleyicinin (scheduler) hızını arttırır.

Olaylar ve Öncelikler (Events and Priority)

Görev Durumları

Görevleri (task) senkronize etmek için sistem olayları (event) kullanır. Örneğin; iki aktif görevimiz (task) olsun (bunlar OS_Task_Create ile yaratılmış olsunlar): bir tanesi sıcaklık ölçsün ve diğeri de bu değeri ekrana bassın. İkinci görev (task) bir ölçüm değeri yoksa ekrana bir şey basamayacaktır. Bu durumda birinci görev (task) ölçümü yaparken, ikinci görev (task) bekleyecektir. Sıcaklık ölçümünden sonra (diğer bir deyişle, olay (event) gerçekleştiğinde), ikinci görev (task) işlemeye hazır olur. Daha sonra da ikinci görev (task) işleme alınır.

Bu yüzden tüm görevler (task) beş farklı duruma sahip olabilirler:

aktif değil (not active) görev (task) oluşturulmamış ya da silinmiş
beklemede (waiting) görev (task) bir olay gerçekleşmesini bekliyor
hazır (ready) istenilen olay gerçekleşmiş fakat görev (task) kontrolü eline almamış
çalışıyor (running) görev (task) işletiliyor
duraklamış (paused) görev (task) duraklatılmış. Hâlâ aktif fakat kontrolü eline alamamış

Görevin (task) kontrolü ele alabilmesi için iki koşulu yerine getirmesi gerekir:

  1. Görevin (task) beklediği olay (event) gerçekleşmelidir (görev hazır (ready) durumuna geçmelidir);
  2. Görevin (task) önceliği diğer hazır görevlerden (task) büyük olmalıdır.

Olaylar

OSA da olaylar (event) aşağıdaki şekilde ayrılırlar:

  1. semafor (binary veya counting);
  2. message (bir mesaj gövdesi veya basit bir bayt mesaj göstericisi );
  3. bayrak kombinasyonları;
  4. timeout (zaman aşımı);
  5. herhangi boolean tanımlaması.

Yukarıdaki ilk 4 tip, kendi bölümlerinde açıklanacaklardır. 5. tip opsiyonel ve görevlerin (task) bazı sistem dışı beklemeleri kabul etmesini sağlar. Örneğin;

// TMR1'in taşması bekleiyor
OS_Wait(TMR1IF);            
or
OS_Wait_TO(ReadADC(0)
>  128);  
// Giriş geriliminin Vdd/2'den büyük olması bekleniyor

Bu iki servis sistem servisleri kısmında açıklanmıştır.

Öncelik

Tüm görevler (task) 0’dan (en yüksek) 7’ye (en düşük) kadar değişik önceliklere sahiptir.

Üç adet öncelik seviyesi vardır:

  • disabled priorities (öncelikler deaktif) – tüm işaretlenmiş öncelikler reddedilecektir. Bu en hızlı ve kompakt moddur: fakat bu yüksek öncelikli önemli görevleri önceliksiz kılar.
  • normal priorities (normal öncelik sırası) – her görev (task) kendi önceliğine sahiptir. Eğer birden fazla hazır (ready) görev (task) varsa, önceliği yüksek görev (task) kontrolü ele alır. Eğer bir kaç hazır (ready) görev (task) aynı önceliğe sahipse, bunlar round-robin modunda çalıştırılırlar. Bu modun iki dezavantajı vardır:
    1. Eğer sürekli hazır görev (task) yüksek öncelikliğe sahipse, hiç bir düşük öncelikli görev (task) kontrolü eline alamaz;
    2. Eğer iki ya da daha fazka görev (task) aynı önceliğe sahipse ve her ikisi de aynı olayı (event) bekliyorlarsa, sadece bir tanesi kontrolü ele alacaktır;
  • extended priorities (geliştirilmiş öncelikler) (YENİ) – her görev (task) önceliklerine göre kontrolü eline alacaktır. Örneğin, elimizde iki tane, öncelikleri sırasıyla 3 ve 4 olan görev (task) bulunsun. Bir tanesi %55-60 ile kontrülü ele alırken (önceliği 4 olan) diğeri %40-45 ile kontrolü ele alacaktır. Bu modun avantajı tüm görevlerin (task) kontrolü mutlaka ele alacağını garanti etmesidir. Fakat bu modda sistem her görev (task) için RAM’de 2 ayrı byte bölgesine ihtiyaç duyar.

Görev düzenleyiciler (scheduler) hakkında daha fazla bilgi için Hız Karakteristiği bölümünü okuyunuz.

Öncelik modları bir kez osacfg.h içerisinde OS_PRIORITY_LEVEL ile tanımlanırlar:

#define OS_PRIORITY_LEVEL    OS_PRIORITY_DISABLE    // Öncelikle deaktif
#define OS_PRIORITY_LEVEL    OS_PRIORITY_NORMAL     // Normal öncelik sıralaması açık
#define OS_PRIORITY_LEVEL    OS_PRIORITY_EXTENDED   // Geliştirilmiş öncelik sırası açık

Öncelik sıralaması varsayılan olarak OS_PRIORITY_NORMAL ayarlanmıştır.

Öncelik Çekişmesi (Priority Competition)

Bazı durumlarda farklı görevler (task) aynı olayı (event), örneğin bazı iç kaynakları (UART, ADC, SPI) ya da bazı dış kaynakları (EEPROM, LCD vb) bekleyebilirler. Peki sistem bu şekilde nasıl davranır?

Olay (event) gerçekleştikten sonra, bu olayı (event) bekleyen tüm görevler (task) hazır (ready) konumu alırlar. Kernel daha sonra en yüksek öncelikli görevi (task) bulur ve bunu işletir. Bu görev (event) işletildikten sonra, bu olay (event) temizlenir (örneğin tüm görevler semaforu bekler ve olayın (task) işletilmesi bunu resetler) ve tüm görevler (task) tekrar bekleme (waiting) moduna geçerler.

Extended priorities (geliştirilmiş öncelikler) modunda çalışmada ise, hazır fakat daha yüksek önceliğe sahip görev (task), olayı (event) resetlediği için kontrolü eline alamamış görevlerin (task) önceliği arttırılacaktır. Böylelikle düşük öncelikli görevlere (task) bir dahaki çevrimde kontrolü ele alma şansı tanınır.

TEŞEKKÜRLER

  • ‘Bug’ları bulan ve düzelten herkese teşekkürler;
  • Projede aktif rol alan, sabır ve tahammül gösteren Vadim Frank ve D. Ivanov‘a teşekkürler.
  • İngilizce dokümantasyondaki bir çok hatamı düzelten Roger Burrows teşekkürler.
  • Ayrıca Alex B. ‘ye dokümantasyon ve bunların siteye yerleştirmesi için teşekkürler.