Percobaan Penjadwal Periodik FreeRTOS Dengan 2 Task

Berikut ini percobaan 2 task periodik pada FreeRTOS

Spesifikasi

Task1:

  • Waktu eksekusi 4 detik
  • Perioda 10 detik (10,8 detik terukur)

Task2:

  • Waktu eksekusi 1 detik
  • Perioda 2 detik

Perangkat Lunak

// 1 task periodik dengan FreeRTOS Arduino Nano (ATmega328)
// template umum FreeRTOS di Arduino Nano  https://github.com/feilipu/Arduino_FreeRTOS_Library/blob/master/examples/AnalogRead_DigitalRead/AnalogRead_DigitalRead.ino
// contoh pemakaian vTaskDelayUntil dan xTaskGetTickCount dari https://github.com/feilipu/avrfreertos/blob/master/MegaBlink/main.c

#include "Arduino_FreeRTOS.h"
#include <semphr.h>

#define LED1  2
#define LED2  3
#define LED3  4
#define LED4  5

static void TaskBlinkLED1(void *pvParameters);
static void TaskBlinkLED2(void *pvParameters);

// task handle diperlukan jika ingin mengakses parameter suatu task. optional
TaskHandle_t xHandle1 = NULL;

void TaskDummy(int LED_A, int LED_B, long int counter) {
  long int i;
  for (i = 0; i < counter; i++) {
    cli();
    digitalWrite(LED_A, LOW);
    digitalWrite(LED_B, HIGH);
    sei();
    asm("nop");
    cli();
    digitalWrite(LED_A, HIGH);
    digitalWrite(LED_B, LOW);
    sei();
    asm("nop");
  }
  digitalWrite(LED_A, LOW);  // matikan semua LED
  digitalWrite(LED_B, LOW);
}

void setup() {
  Serial.begin(115200);
  Serial.println("Start");
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(LED4, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);

  xTaskCreate(
    TaskBlinkLED1
    ,  "Task1"  // A name just for humans
    ,  100  // This stack size can be checked & adjusted by reading the Stack Highwater
    ,  NULL
    ,  2  // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
    ,  &xHandle1 );
xTaskCreate(
    TaskBlinkLED2
    ,  "Task2"  // A name just for humans
    ,  100  // This stack size can be checked & adjusted by reading the Stack Highwater
    ,  NULL
    ,  3  // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
    ,  &xHandle1 );    
}

void loop() {
}

static void TaskBlinkLED1(void *pvParameters) // Main Red LED Flash
{
  TickType_t xLastWakeTime;
  /* The xLastWakeTime variable needs to be initialised with the current tick
    count.  Note that this is the only time we access this variable.  From this
    point on xLastWakeTime is managed automatically by the vTaskDelayUntil()
    API function. */
  xLastWakeTime = xTaskGetTickCount();
  while (1)
  {
    Serial.println(millis());
    Serial.println(xLastWakeTime); // cetak last wake time, untuk debugging. hanya untuk slow system

    TaskDummy(LED1, LED2, 10000L / 0.172 * 4 ); // 4 detik waktu eksekusi
    vTaskDelayUntil( &xLastWakeTime, ( 10000L / portTICK_PERIOD_MS ) ); // 10 detik perioda

  }
}

static void TaskBlinkLED2(void *pvParameters) // Main Red LED Flash
{
  TickType_t xLastWakeTime;
  /* The xLastWakeTime variable needs to be initialised with the current tick
    count.  Note that this is the only time we access this variable.  From this
    point on xLastWakeTime is managed automatically by the vTaskDelayUntil()
    API function. */
  xLastWakeTime = xTaskGetTickCount();
  while (1)
  {
    Serial.println(millis());
    Serial.println(xLastWakeTime); // cetak last wake time, untuk debugging. hanya untuk slow system

    TaskDummy(LED3, LED4, 10000L / 0.172 ); // 1 detik waktu eksekusi
    vTaskDelayUntil( &xLastWakeTime, ( 2000L / portTICK_PERIOD_MS ) ); // 2 detik perioda

  }
}

 

Pengukuran

Berikut ini adalah tampilan kedua buah task di layar osiloskop.

Sinyal warna kuning adalah Task 1

Sinyal warna biru adalah Task 2.

 

Pengukuran pewaktuan dengan osiloskop
Pengukuran pewaktuan dengan osiloskop

Referensi

Percobaan Penjadwal Periodik Dengan FreeRTOS pada Arduino Nano

Pada percobaan ini dilakukan penjadwalan untuk sebuah task periodik pada sistem operasi FreeRTOS. Mikroprosesor yang dipakai adalah Arduino Nano (ATmega328).

Pengukuran akan dilakukan dengan video dengan kecepatan 25 frame per detik, sehingga pemilihan waktu eksekusi dan periode tidak boleh terlalu kecil. Untuk percobaan dipilih waktu eksekusi 4 detik, dengan perioda task adalah 10 detik.

Task 4 detik dibuat menggunakan TaskDummy yang sudah dibuat di percobaan sebelumnya. Pemilihan waktu 4 detik dapat dilakukan dengan menggunakan parameter fungsi yang sesuai.

Perangkat Keras

Perangkat keras yang digunakan adalah Arduino Nano dengan 2 buah LED terhubung ke pin 2 dan pin 3.

Implementasi Program

Berikut ini source code percobaan tersebut.

// 1 task periodik dengan FreeRTOS Arduino Nano (ATmega328)
// template umum FreeRTOS di Arduino Nano  https://github.com/feilipu/Arduino_FreeRTOS_Library/blob/master/examples/AnalogRead_DigitalRead/AnalogRead_DigitalRead.ino
// contoh pemakaian vTaskDelayUntil dan xTaskGetTickCount dari https://github.com/feilipu/avrfreertos/blob/master/MegaBlink/main.c

#include "Arduino_FreeRTOS.h"
#include <semphr.h>

#define LED1  2
#define LED2  3

static void TaskBlinkLED1(void *pvParameters);

// task handle diperlukan jika ingin mengakses parameter suatu task. optional
TaskHandle_t xHandle1 = NULL;

void TaskDummy(int LED_A, int LED_B, long int counter) {
  long int i;
  for (i = 0; i < counter; i++) {
    cli();
    digitalWrite(LED_A, LOW);
    digitalWrite(LED_B, HIGH);
    sei();
    asm("nop");
    cli();
    digitalWrite(LED_A, HIGH);
    digitalWrite(LED_B, LOW);
    sei();
    asm("nop");
  }
  digitalWrite(LED_A, LOW);  // matikan semua LED
  digitalWrite(LED_B, LOW);
}

void setup() {
  Serial.begin(115200);
  Serial.println("Start");
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);

  xTaskCreate(
    TaskBlinkLED1
    ,  "TaskBlinkLED1"  // A name just for humans
    ,  100  // This stack size can be checked & adjusted by reading the Stack Highwater
    ,  NULL
    ,  2  // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
    ,  &xHandle1 );
}

void loop() {
}

static void TaskBlinkLED1(void *pvParameters) // Main Red LED Flash
{
  TickType_t xLastWakeTime;
  /* The xLastWakeTime variable needs to be initialised with the current tick
    count.  Note that this is the only time we access this variable.  From this
    point on xLastWakeTime is managed automatically by the vTaskDelayUntil()
    API function. */
  xLastWakeTime = xTaskGetTickCount();
  while (1)
  {
    Serial.println(millis());
    Serial.println(xLastWakeTime); // cetak last wake time, untuk debugging. hanya untuk slow system

    TaskDummy(LED1, LED2, 10000L / 0.172 * 4 ); // 4 detik waktu eksekusi
    vTaskDelayUntil( &xLastWakeTime, ( 10000L / portTICK_PERIOD_MS ) ); // 10 detik perioda

  }
}

Pengukuran Dengan Video

Pengukuran dilakukan dengan merekam kedipan LED selama kurang lebih 30 detik. Kecepatan frame video yang dihasilkan adalah 25 frame per detik.

Berikut ini rekaman video lampu kedip yang dihasilkan.

Analisis frame per frame dilakukan dengan menggunakan aplikasi DaVinci Resolve 16.

Tampilan DaVinci Resolve 16
Tampilan DaVinci Resolve 16

Video dapat ditampilkan dengan mode “Media”,  “Cut” maupun “Timeline”. DaVinci Resolve secara default menampilkan waktu dalam format HH:MM:SS, namun tampilan ini dapat diubah menjadi tampilan nomor frame untuk memudahkan analisis.

Berikut ini hasil analisis video LED tersebut:

Transisi Frame
OFF -> ON 161
ON -> OFF 262
OFF->ON 432
ON->OFF 534
OFF->ON 704
ON->OFF 805
OFF->ON 975

Analisis durasi waktu eksekusi

  • 262-161 = 101 frame = 4,04 detik
  • 534-432=102 frame =  4,08 detik
  • 805-704 = 101 frame = 4,04 detik.

Analisis Perioda Task

  • 432-161= 271 frame = 10.85 detik
  • 534-262= 272 frame = 10.88 detik
  • 704-432= 272 frame= 10.88 detik
  • 805-534= 271 frame = 10.85 detik
  • 975-704= 271 frame= 10.85 detik

Durasi atau waktu eksekusi adalah 4,04 detik ~ 4,08 detik

Periode Task yang terukur adalah antara 10.85 detik sampai 10.88 detik.

Pengukuran Dengan Osiloskop

Sebagai perbandingan juga dilakukan pengukuran tegangan pada LED dengan osiloskop. Berikut ini rekaman video pengukuran dengan osiloskop

Berikut ini pengukuran perioda task dengan menggunakan fitur cursor  pada osiloskop.

Pengukuran perioda task pada FreeRTOS
Pengukuran perioda task

Dari hasil pengukuran perioda didapatkan angka 10,80 detik. Hasil ini cukup  sesuai dengan analisis frame video.

Berikut ini pengukuran durasi task.

Pengukuran durasi task pada FreeRTOS
Pengukuran durasi task

Didapatkan hasil angka durasi task adalah 4,1 detik, cukup mendekati angka 4,08 detik dari hasil analisis frame.

Analisis

Dari hasil perhitungan di atas, dapat didapatkan bahwa

  • durasi eksekusi dari TaskDummy sudah cukup mendekati hasil yang diinginkan
  • durasi perioda task berbeda cukup jauh , sekitar 8%

Dari hasil studi literatur didapatkan bahwa Timer Tick pada library FreeRTOS di Arduino Nano yang dipakai menggunakan osilator pada WDT (Watch Dog Timer). Osilator WDT ini menurut literatur datasheet tidak menggunakan kristal, dan periodanya tergantung dengan temperatur ruangan. Jadi perbedaan periode dari seharusnya 10 detik menjadi 10.8 detik dapat dijelaskan.

Referensi

Task Dummy Untuk FreeRTOS

Pada percobaan FreeRTOS dengan penjadwal periodik, diperlukan suatu task (pekerjaan) dengan waktu eksekusi yang diketahui.

Berikut ini sifat-sifat yang diperlukan dari task tersebut:

  • waktu eksekusi diketahui
  • waktu eksekusi dapat diubah-ubah dengan mengubah parameternya
  • status task dapat dimonitor dari luar mikroprosesor
  • status yang perlu diketahui: RUNNING, READY, BLOCKING, STOP.

Solusi

  • Task berupa iterasi yang jumlah iterasi dapat diubah-ubah dengan parameter.
  • Pengaruh parameter terhadap waktu eksekusi diukur. Pengukuran terbaik dengan menggunakan alat ukur eksternal seperti osiloskop. Jika tidak ada osiloskop, alternatifnya menggunakan fungsi millis() pada Arduino.
  • Task Dummy melakukan aktivitas membuat 2 buah LED berkedip secara komplementer. Jika kedua lampu nampak menyala, artinya task dalam keadaan RUNNING. Jika salah satu saja yang menyala, artinya task sedang berhenti, artinya dalam keadaan READY atau BLOCKING. Jika kedua lampu mati, artinya task sedang tidak aktif.

Berikut ini kode fungsi Task Dummy pada Arduino.

 

void TaskDummy(int LED_A, int LED_B, long int counter) {
  long int i;
  for (i = 0; i < counter; i++) {
    cli();
    digitalWrite(LED_A, LOW);
    digitalWrite(LED_B, HIGH);
    sei();
    asm("nop");
    cli();
    digitalWrite(LED_A, HIGH);
    digitalWrite(LED_B, LOW);
    sei();
    asm("nop");
  }
  digitalWrite(LED_A, LOW);  // matikan semua LED
  digitalWrite(LED_B, LOW);
}

DigitalWrite menyalakan dan mematikan LED A dan LED B. LED yang dipakai sebagai output dapat diatur melalui parameter fungsi. cli() fungsinya untuk disable interrupt, agar perubahan LED_A dan LED_B terjadi secara serentak. sei() fungsinya untuk mengaktifkan kembali interupsi. Instruksi assembly “nop” dipakai untuk menambah waktu iterasi.

Berikut ini program lengkapnya

// Contoh TaskDummy
// dengan output ke osiloskop juga
#define LED1 2
#define LED2 3
#define LED3 4
#define LED4 5

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(115200);
}

void TaskDummy(int LED_A, int LED_B, long int counter) {
  long int i;
  for (i = 0; i < counter; i++) {
    cli();
    digitalWrite(LED_A, LOW);
    digitalWrite(LED_B, HIGH);
    sei();
    asm("nop");
    cli();
    digitalWrite(LED_A, HIGH);
    digitalWrite(LED_B, LOW);
    sei();
    asm("nop");
  }
  digitalWrite(LED_A, LOW);  // matikan semua LED
  digitalWrite(LED_B, LOW);
}

// the loop function runs over and over again forever
void loop() {
  unsigned long waktu_awal;
  unsigned long waktu_akhir;
  waktu_awal = millis();
  TaskDummy(LED1, LED2, 10000L);
  waktu_akhir = millis();
  Serial.print("waktu: ");
  Serial.println(waktu_akhir - waktu_awal);
  digitalWrite(LED_BUILTIN, HIGH);
  TaskDummy(LED1, LED2, 10000L);
  digitalWrite(LED_BUILTIN, LOW);
}

Durasi TaskDummy dalam milisekon dapat diamati di port serial. Berikut ini tampilan port serial.

Dari tampilan tersebut dapat diketahui bahwa waktu eksekusi task dummy adalah 173 ms.

Berikut ini foto pengukuran dengan osiloskop. Dari gambar nampak waktu yang diperlukan untuk task dummy adalah 172 ms

Berikut ini foto percobaan.

Osiloskop yang dipakai

Referensi