Raspberry Pi Pico Çift Çekirdek Programlama (2 Core)

Raspberry Pi Pico Çift Çekirdek Programlama (2 Core) çift çekirdek programlama

Bu yazımızda, Raspberry Pi Pico’nun her iki işlemci çekirdeğini aynı anda aktif ederek, çift çekirdek programlama yapıyoruz. İki bağımsız LED’i birbirini bloke etmeden farklı gecikme süreleriyle nasıl kontrol edeceğimizi, hem MicroPython hem de C/C++ (Arduino) ortamlarında detaylıca inceleyeceğiz. Donanım özellikleri hakkında temel bilgi edinmek için Adafruit Feather RP2040 İncelemesi yazımıza göz atabilirsiniz.

Raspberry Pi Pico, kalbinde yer alan RP2040 mikrodenetleyicisinin sunduğu çift çekirdekli (Dual ARM Cortex-M0+ @ 133 MHz) güçlü donanım mimarisi sayesinde, gerçek zamanlı gömülü sistem projelerinde gerçek paralel programlama (true multitasking) yapılmasına imkan tanır.

Klasik tek çekirdekli mikrodenetleyicilerde (örneğin standart Arduino UNO – ATmega328P), `delay()` veya benzeri bloke edici fonksiyonlar kullanıldığında tüm sistem donar ve başka bir işlem gerçekleştiremez. Paralel görevler yürütmek için milisaniye takibi (`millis()`) gibi yazılımsal yöntemler kullanılsa da, bu işlemler hala tek bir CPU üzerinde sırayla icra edilir. Raspberry Pi Pico’da ise CPU döngülerini kontrol eden bir işletim sistemi (RTOS) olmaksızın, donanımsal olarak iki ayrı bağımsız iş parçacığını (thread) sıfır gecikmeyle paralel olarak çalıştırabilirsiniz.

Çift Çekirdek Programlama için Gerekli Malzemeler

  • Raspberry Pi Pico veya Pico W geliştirme kartı
  • 2 adet Farklı Renkte LED (Örn: Kırmızı ve Yeşil)
  • 2 adet 330 Ohm Direnç (LED akım sınırlaması için)
  • Breadboard ve Jumper Bağlantı Kabloları

Devre Şeması ve Bağlantı Yapısı

Birinci LED’in anot ucunu 330 ohm direnç üzerinden Pico’nun GPIO16 pinine, ikinci LED’in anot ucunu ise yine 330 ohm direnç üzerinden GPIO15 pinine bağlayın. Her iki LED’in katot (eksi) uçlarını birleştirerek Pico’nun herhangi bir fiziksel GND pinine bağlayın.

Raspberry Pi Pico Çift Çekirdek Programlama (2 Core)
Raspberry Pi Pico Çift Çekirdek Programlama (2 Core)

Raspberry Pi Pico Çift Çekirdek Programlama (2 Core): MicroPython

Sanılanın aksine, MicroPython, RP2040 mikrodenetleyicisi üzerinde çift çekirdek desteği sunmaktadır. MicroPython çekirdeğinde yer alan `_thread` kütüphanesi, oluşturulan yeni iş parçacığını (thread) doğrudan donanımsal ikinci çekirdeğe (core1) atar. Böylece ana kodunuz varsayılan olarak core0 üzerinde çalışırken, arka plandaki fonksiyonunuz tamamen bağımsız olarak core1 üzerinde koşturulur.

Bu projede kullanılacak kodları bilgisayarınıza çekmek için Circuit Digest Pico Kod Arşivi deposunu ziyaret edebilirsiniz. Thonny IDE üzerinde çalıştıracağımız `main.py` kodunun parça parça teknik açıklaması şu şekildedir:

from machine import Pin
import utime
import _thread

Burada donanım kontrolü için `machine` kütüphanesinden `Pin` sınıfını, hassas zaman gecikmeleri için `utime` kütüphanesini ve donanımsal ikinci çekirdeği kontrol etmek amacıyla ise `_thread` (multi-threading) kütüphanesini içeri aktarıyoruz.

led1 = Pin(16, Pin.OUT)
led2 = Pin(15, Pin.OUT)
sLock = _thread.allocate_lock()

LED pinlerini çıkış olarak yapılandırdıktan sonra `_thread.allocate_lock()` metodu ile bir Semafor Kilidi (Mutex) tanımlıyoruz. Çift çekirdekli programlamada, her iki çekirdek de aynı SRAM bellek alanını paylaştığı için, aynı anda tek bir global değişkene veya donanım pinine erişmeye çalıştıklarında Yarış Durumu (Race Condition) veya bellek bozulmaları meydana gelebilir. Bu kilit mekanizması, kritik kod bloklarının (critical sections) aynı anda sadece tek bir çekirdek tarafından yürütülmesini garanti altına alır.

def CoreTask():
    while True:
        sLock.acquire() # Kritik bölge kilitlemesi
        print("İkinci çekirdeğe (Core 1) girildi")
        utime.sleep(1)
        led2.high()
        print("LED 2 AÇIK (Core 1)")
        utime.sleep(2)
        led2.low()
        print("LED 2 KAPALI (Core 1)")
        utime.sleep(1)
        print("İkinci çekirdek görevi tamamlandı")
        sLock.release() # Kilidi serbest bırak
        utime.sleep(0.5) # İşlemciyi dinlendir

# İkinci çekirdekte (Core 1) görevi başlat
_thread.start_new_thread(CoreTask, ())

`CoreTask()` adında tanımladığımız fonksiyon, `_thread.start_new_thread(CoreTask, ())` çağrısı yapıldığı an otomatik olarak core1 çekirdeğinde paralel bir sonsuz döngü olarak başlatılır. `sLock.acquire()` ile başlayan kritik bölge, işlem tamamlanıp `sLock.release()` çağrılana kadar kilitli tutulur. Bu sırada ana çekirdek (core0) kendi döngüsünü yürütmeye devam eder:

while True:
    sLock.acquire()
    print("Ana çekirdek (Core 0) aktif")
    led1.toggle()
    utime.sleep(0.15)
    print("LED 1 Durum Değiştirdi (Core 0)")
    sLock.release()
    utime.sleep(0.5)

Thonny IDE üzerinde yazdığınız bu kodu Pico’ya yüklemek için Ctrl+Shift+S tuşlarına basarak hedef sürücü olarak “Raspberry Pi Pico”yu seçin ve dosyayı mutlaka `main.py` ismiyle kaydedin. Bu sayede, bilgisayar bağlantısı kesilip Pico’ya harici bir güç verildiğinde de program otomatik olarak çift çekirdekli modda çalışmaya başlayacaktır.

Thonny Dosya Kaydetme Seçeneği
Kodun bağımsız çalışabilmesi için dosyayı Pico içine main.py olarak kaydedin

MicroPython Kodunun Tamamı

from machine import Pin
import utime
import _thread

# Donanım pin tanımlamaları
led1 = Pin(16, Pin.OUT)
led2 = Pin(15, Pin.OUT)

# Çekirdekler arası bellek koruma kilidi (Mutex)
sLock = _thread.allocate_lock()

# Donanımsal 2. Çekirdekte (Core 1) çalışacak fonksiyon
def CoreTask():
    while True:
        sLock.acquire()
        print("İkinci çekirdeğe (Core 1) girildi")
        utime.sleep(1)
        led2.high()
        print("LED 2 AÇIK (Core 1)")
        utime.sleep(2)
        led2.low()
        print("LED 2 KAPALI (Core 1)")
        utime.sleep(1)
        print("İkinci çekirdek görevi tamamlandı")
        sLock.release()
        utime.sleep(0.5)

# Core 1 üzerinde thread'i tetikleme
_thread.start_new_thread(CoreTask, ())

# Ana Çekirdekte (Core 0) çalışan ana döngü
while True:
    sLock.acquire()
    print("Ana çekirdek (Core 0) aktif")
    led1.toggle()
    utime.sleep(0.15)
    print("LED 1 Durum Değiştirdi (Core 0)")
    sLock.release()
    utime.sleep(0.5)

Arduino C/C++ ile Çok Daha Kolay Çift Çekirdek Programlama

Eğer projelerinizi Arduino IDE (C/C++) ortamında geliştiriyorsanız ve donanım paketi olarak Earle Philhower çekirdeğini kurduysanız, çift çekirdekli programlama yapmak inanılmaz derecede kolaylaşır. Hiçbir karmaşık kütüphane veya thread oluşturma komutu çağırmaksızın, sadece standart fonksiyon isimlerini kullanarak her iki çekirdeğe de doğrudan görev atayabilirsiniz:

  • Core 0 Kontrolü: Klasik `setup()` ve `loop()` fonksiyonları doğrudan ana çekirdek üzerinde koşturulur.
  • Core 1 Kontrolü: Skecinizin herhangi bir yerine ekleyeceğiniz `setup1()` ve `loop1()` fonksiyonları, derleyici tarafından otomatik olarak ayrıştırılarak doğrudan donanımsal ikinci çekirdek (core1) üzerinde paralel olarak başlatılır!
// --- ÇEKİRDEK 0 (Core 0) GÖREVLERİ ---
void setup() {
  pinMode(16, OUTPUT);
}

void loop() {
  digitalWrite(16, HIGH);
  delay(150);
  digitalWrite(16, LOW);
  delay(150);
}

// --- ÇEKİRDEK 1 (Core 1) GÖREVLERİ ---
void setup1() {
  pinMode(15, OUTPUT);
}

void loop1() {
  digitalWrite(15, HIGH);
  delay(1000);
  digitalWrite(15, LOW);
  delay(1000);
}

C/C++ derleyicisinin sunduğu bu yerleşik `setup1()` / `loop1()` yapısı, mikrodenetleyicinin tüm gücünü en yalın haliyle kullanmanızı sağlar. Çekirdekler arası veri transferi gerektiren daha profesyonel senaryolarda ise, donanımsal FIFO (First-In-First-Out) kuyruk yapısı (`multicore_fifo_push_blocking` ve `multicore_fifo_pop_blocking` fonksiyonları) kullanılarak çekirdekler arasında güvenli ve kayıpsız mesajlaşma köprüleri kurulabilir.

MicroPython `_thread` kütüphanesinin çalışma detayları ve bellek tahsis yöntemleri hakkında daha fazla bilgi almak için resmi MicroPython _thread Kütüphane Dokümantasyonunu inceleyebilir, paralel programlama becerilerinizi endüstriyel standartlara taşıyabilirsiniz.

Yorum yapma özelliği, forum tarafından gelen istek sebebiyle kapatılmıştır. Lütfen tartışmalar ve sorularınız için topluluk forumumuza katılın.