Bu makalede, STM32F070RB-Nucleo Board üzerinde FreeRTOS’un temel kurulumu ve temel task işlemleri hakkında uygulamaya yönelik paylaşımda bulunuyorum.

RTOS , mikrodenetleyici üzerinde koşacak farklı görevleri, belirtilen önceliklere ve zamanlamalara göre bağımsız olarak gerçekleştirmeyi , görevler arasında haberleşmeyi ve görevlerin anlık olarak yönetimini sağlayan bir middleware’dir.

STM32CubeMx ile FreeRTOS gelmektedir. FreeRTOS’u kullanabilmek için STM32CubeMx üzerinden FreeRTOS’u aktif edip, ayarlarını projemizin ihtiyacına göre düzenlememiz gerekir.

Uygulamamızda FreeRTOS’un çalışmasını gözlemleyebilmek için MCU’muzun UART’ından yararlanacağız.


1) STM32CubeMx’i açarak mikrodenetleyicimizin çevresel birimlerini ihtiyaca göre düzenliyoruz.

2) Mikrodenetleyicinin clock ayarlarının yapılması gerekiyor.

3) Pinout & Configuration sekmesinden SYS‘ye girerek, TimeBase Source‘u SysTick yerine, donanımsal timer’lardan birisi olarak ayarlamak gerekiyor.(TIM1)
FreeRTOS kullanılmadığında bu zorunluluk olmuyor. FreeRTOS donanımsal bir timer’a ihtiyaç duyduğu için bu ayarı yapmak gerekiyor.

4) Pinout & Configuration sekmesinden FREERTOS‘a girilerek , Interface olarak CMSIS_V1 seçiliyor. İşletim sisteminin koşacağı tasklara önceliklendirme yapmak isteyeceğimizden dolayı USE_PREEMPTION parametresini “Enabled” olarak ayarlamalıyız.

5) FREERTOS kurulumu yapıldığında CubeMX , işletim sistemi üzerinde “defaultTask” isminde bir task oluşturur. Taskları görebilmek ve yenisini ekleyebilmek için “Tasks and Queues” sekmesine girmek gerekiyor.

Bu kısımda FreeRTOS’un çalışmasını daha iyi gözlemleyebilmek amacıyla “Add” butonuna basarak yeni bir task ekleyelim. Task ekleme işlemi yukarıdaki resimde gösterilmiştir.

6) Task ekleme işlemimizden sonra “Generate Code” işlemi yapılabilir. Projenin main.c modülünü açtığımızda “Private Variables” kısmında UART çevresel biriminin yanı sıra, CubeMX üzerinde tanımlı olan 2 taskla ilgili handle tanımlamalarını görüyoruz.

7) Tanımlama kısmından aşağıya doğru devam ettiğimizde, tasklarımızın koşulacağı thread’lerin yaratıldığı tanımlamaları görüyoruz.

Kodların açıklaması aşağıda belirtildi.

osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);

  • Thread tanımlaması yapılıyor.
  • Thread’in ilişkilendirildiği task ismi : defaultTask
  • Thread çalıştığında koşmasını istediğimiz fonksiyonun adı “StartDefaultTask”
  • Thread’in önceliklendirmesi : osPriorityNormal

defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);

  • Tanimlanan thread’in işletim sistemi üzerinde aktifleştirilmesi sağlanıyor.
  • Aktifleştirilen thread’in bilgileri defaultTaskHandler struct’ına yazılıyor.
  • defaultTaskHandler struct’ı işletim sistemi çalışırken task’ı yönetmek için kullanılabiliyor.(Bu kısma değineceğim)

8) Thread’lerin çalıştıklarında koşacakları fonksiyon isimlerini belirtmiştik. Şimdi bu fonksiyonları görelim.

  • defaultTask çalıştığında StartDefaultTask isimli fonksiyonu çağıracak.
  • Fonksiyon çalıştığında UART üzerinden “Default Task Calisti !” stringini basacaktır.
  • Task kendini 1000 ms süre ile bloklayacaktır. Task’ın bir sonraki execution işlemi 1000 ms sonra yapılabilecektir.

  • Task2 çalıştığında Task2_Init isimli fonksiyonu çağıracak.
  • Fonksiyon çalıştığında UART üzerinden “Task2 Calisti !” stringini basacaktır.
  • Task kendini 2000 ms süre ile bloklayacaktır. Task’ın bir sonraki execution işlemi 2000 ms sonra yapılabilecektir.

9) UART çıkışlarını terminal ekranından izlediğimizde :

Uygulamayı bu kısma kadar gerçekleştirerek, temel FreeRTOS kurulumu ve task execution işlemini gözlemlemiş olduk.

Şimdi devam ederek , bazı task yönetim fonksiyonlarını gözlemleyelim.

Gözlemleyebilmek için fonksiyonlarımı şu şekilde düzenledim.

İşletim sistemi çalışmaya başladığında, her 2 task da , 1 saniyelik periyotlarla UART’a kendi stringlerini basacaklardır.

Task2_Init içindeki cnt her çalıştığında 1 artacak ve 5 olduğunda, osThreadSuspend(defaultTaskHandle) işlemini yapacaktır. Bu işlem gerçeklendiğinde, defaultTask resume ettirilene kadar geçici olarak çalışmayacaktır.

    if(cnt == 5)
    {
        osThreadSuspend(defaultTaskHandle);
    }

cnt değeri 10 olduğunda , osThreadResume(defaultTaskHandle) işlemi yapılacaktır. Bu durumda , defaultTask kaldığı yerden çalışmasına devam edecektir. Fakat istenildiğinde tekrar suspend edilebilir.

    if(cnt == 10)
    {
        osThreadResume(defaultTaskHandle);
    }       

cnt değeri 20 olduğunda ise osThreadTerminate(defaultTaskHandle) işlemi yapılacaktır. Bu işlem yapıldığında defaultTask , resume ettirilemecek şekilde sonlanacaktır.

    if(cnt == 20)
    {
        osThreadTerminate(defaultTaskHandle);
    }

defaultTask’ı tekrar aktifleştirmek istersek, init işlemlerinin tekrar yapılması gerekir. cnt değeri 25 olduğunda defaultTask tekrar init ediliyor. defaultTask periyodik çalışmasına devam edecektir.

    if(cnt == 25)
    {
       osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);
       defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
    }       

Task’ların yönetimi ile ilgili cmsis_os.c modülündeki diğer fonksiyonları inceleyip , deneyebilirsiniz. Başka özellikler de mevcuttur.

Gelecek makalelerde, FreeRTOS queue ve mutex yapısı gibi diğer özelliklere değinmeyi planlıyorum.

İyi çalışmalar.

Çağatay KAYNAK
Gömülü Yazılım Mühendisi
cagataykaynak@gmail.com