Yüksek hızda işaret üretmek

Bu derste yüksek hızda kare dalga işaretinin nasıl üretilebileceği anlatılmıştır

Giriş

Bu derste nasıl yüksek hızda kare dalga işareti üretebileceğimizden bahsedeceğiz.

Gerçek zamanlı işlemcinin saat hızı 200 MHz. Bu saniyede 200.000.000 demek oluyor.

Bu süre 5 nano saniyeye tekabül ediyor.

Dalganın bir çevrimini 10 nano saniye alırsak bu 100 MHz sıklığında kare bir işaret üretebiliriz anlamına geliyor.

Eğer bu kadar hızlı bir işareti ölçebilecek donanımınız varsa bildirebilirsiniz.

Yüksek sıklıkta ölçümlerde, ölçüm kolu ("probe") ile gelen dişli teller yeterli olmuyor.

Bunun yerine topraklama yayı kullanılması öneriliyor.

İşaret ve toprak arası mesafeyi kısa tutmakta fayda var.

Beaglebone ile 3 tane ayrık işlemci geliyor.

Bu işlemcilere /sys/class/remoteproc dizininden erişilebilir.

  • remoteproc0 Beaglebone üzerindeki ARM Cortex-M3 işlemcisi
  • remoteproc1 Gerçek zamanlı ilk işlemci, 4a334000.pru olarak isimlendiriliyor.
  • remoteproc2 Gerçek zamanlı ikinci işlemci 4a338000.pru olarak isimlendiriliyor.

Amacımız hızlı bir kare dalga üretmek.

Konuyu daha iyi anlatabilmek için bir misal verelim.

İşletim sistemini, tek bir sütçü beygirinin çektiği, 3- 5 yolcusu olan bir at arabasına benzetebiliriz. Biri sağa çekiyor, biri sola çekiyor.

Gerçek zamanlı işlemciyi ise sadece size tahsis edilmiş bir yarış atına benzetebiliriz.

Koşuyor da koşuyor.

İşletim sistemini kullanarak örneğin Python ile aynı yazılımı geliştirdiğimizi düşünelim.

Bekleme görevini sleep komutu ile verebiliriz.

Diyelim ki Apache sunucusundan, diğer uygulamalardan istekler geldi. İşletim sistemi diğer uygulamaların taleplerine de yanıt verme durumunda kalıyor.

İşlemcinin saat işareti tüm bu uygulamalar arasında paylaşıldığı için, bizim uygulamamızın isteklerine anlık yanıt veremiyor.

Gerçek zamanlı işlemcide ise uygulamayı aygıt yazılımı olarak yazıyoruz.

Aygıt yöneticini yukledikten sonra, gerçek zamanlı işlemcinin tek görevi yazdığımız aygıt yazılımını çalıştırmak oluyor.

Devre şeması

Beaglebone beyaz

Devre şemasına baktığımızda önceki uygulamadan çok fazla fark yok.

Sadece P9 üzerindeki 31 numaralı kapı çıkış olarak belirtilmiş.

Burada kullanılan direncin en az 500 ohm olmasına dikkat ediniz.

Yaklaşık gerilimi 3.5 volt kabul edelim. 1.5 volt ışık kaynağı yüzünden gerilim düşmesi olursa geriye 2 volt kalır.

Beaglebone'un uçlarından çekilebilecek en fazla akım 4 mA'dir. $ V = I\ R $ formülünü kullanarak bir hesap yaparsak direnci 500 ohm buluruz.

Direnci 500 ohm ile 1000 ohm arasında kullanabilirsiniz.

Kaynak Tablosu

Uygulamayı yazmaya geçmeden önce bir tane aygıt yazılımı ("firmware") yazmak istediğimizi ifade etmiştik.

Bu aygıt yazılımında kaynak tablosu isminde bir yapı kullanacağız.

Bu yapı hakkında biraz temel bilgi vermek istiyorum.

Kaynak tablosu, aygıt yazılımında genel değişken olarak tanımlanan bir yapıdır.

Bu tablo, işlemci çalıştırılmadan önce, örneğin bitişik bellek tahsisi gibi ayrık işlemcinin ihtiyaç duyduğu kaynakları içerir.

Kaynak tablosu ayrık işlemcinin desteklediği özellikler hakkında bilgi de içerebilir.

Uygulamayı yazalım

Derse başlamadan önce, bir önceki dersi takip ettiğinizi ve SSH ile Beaglebone'a bağlanabildiğinizi varsayacağız.

Öncelikle tara komutunu vererek SSH ile Beaglebone'u görebildiğimizi teyit edelim.

Daha sonra bb komutunu vererek Beaglebone üzerinde oluşturduğumuz çalışmalar dizinini açalım.

#include <stdint.h>
#include <rsc_types.h>  /* kaynak tablosu için başlık */

/* Gerçek zamanlı işlemci 200 MHz saat hızına sahip */
#define SANIYEDEKI_DEVIR_SAYISI 200000000


#define P9_31 (1 << 0) /* çıkış ucu */

/* Gerçek zamanlı işlemci için kullandığımız yazmaç */
volatile register uint32_t __R30;

void main(void)
{
    while (1)
    {
        __R30 |= P9_31; /* R30 yazmacındaki ilk biti 1 yap */

        /* yarım saniye bekle */
        __delay_cycles(SANIYEDEKI_DEVIR_SAYISI / 2);

        __R30 &= ~P9_31; /* R30 yazmacındaki ilk biti 0 yap */

        /* yarım saniye bekle */
        __delay_cycles(SANIYEDEKI_DEVIR_SAYISI / 2);
    }
}

/* bahsettiğimiz kaynak tablosunu buraya ekliyoruz */
#pragma DATA_SECTION (kaynakTablosu, ".resource_table")
#pragma RETAIN (kaynakTablosu)
struct kaynakTablomuz
{
    struct resource_table temel;
    uint32_t uzaklik[1];
} kaynakTablosu = { 1, 0, 0, 0, 0 };

Yukarıdaki kütüğü c dizininde kare.c ismi ile kaydediniz.

Derleme kütüğü

Uygulamayı derlemek için gene c dizininde bir make kütüğü oluşturacağız.

KAYNAK = kare.c
DERLEYICI = clpru
BAGLAYICI = lnkpru

DERLEME_DIZINI = /usr/lib/ti/pru-software-support-package/include
BAGLAMA_DIZINI = /usr/lib/ti/pru-software-support-package/labs/lab_2

DERLEYICI_BAYRAKLARI =  --include_path=${DERLEME_DIZINI} \
    --include_path=${DERLEME_DIZINI}/am335x \


kare: ${KAYNAK}
    ${DERLEYICI} ${DERLEYICI_BAYRAKLARI} ${KAYNAK} --output_file $@.o
    ${BAGLAYICI} ${BAGLAMA_DIZINI}/AM335x_PRU.cmd $@.o -o $@
    cp kare /lib/firmware/am335x-pru0-fw

clean temizle:
    rm kare.o kare

Aşağıdaki kütüğü Makefile ismi ile aynı dizinde kaydediniz.

Derleme işlemini bazı ayarlar yaptıktan sonra yapacağız.

Yeni takma isimler ekleyelim

Tekrar bb komutunu kullanarak Beaglebone belgeler klasörüne bağlanalım.

/home/debian dizinindeki .bashrc kütüğüne aşağıdakileri ekleyiniz.

alias başla='echo start > /sys/class/remoteproc/remoteproc1/state'
alias dur='echo stop > /sys/class/remoteproc/remoteproc1/state'
aç()
{
    config-pin $1 pruout
}

Kütüğü kaydediniz. Böylece bazı ek takma isimler tanımlamış olduk.

Uygulamayı derleyip çalıştıralım

Tekrar bone komutunu kullanarak SSH ile cihaza bağlanalım.

Tanımladığımız takma isimlerin etkin olması için bir kereye mahsus aşağıdaki komutu veriniz.

source .bashrc

Çalışmalar dizinine gidelim.

cd çalışmalar/c/

Uygulamayı derlemek için

make

komutunu veriniz.

aç P9_31

Yukarıdaki komut ile P9_31 numaralı çıkışı gerçek zamanlı birim olarak kullanmak istediğimizi belirtiyoruz.

Eğer başla yazarsanız ve her şey yolunda gitti ise ışığın yanıp sönmeye başladığını görebilirsiniz.

Uygulamayı durdurmak için dur yazınız.

Ölçüm

Osiloskop ile kare dalgaya baktığımızda yatay eksende dalganın bir çevriminin 5 tane kutudan oluştuğunu görebilirsiniz.

Her kutu 200 milisaniye. Toplamda 1000 milisaniye. Yani 1 saniye.

Saniyede 1 kere anlamında dalganın sıklığı 1 Hz oluyor.

Hızı arttıralım

Hızı arttırıp 1 MHz'ye çıkarmak için aşağıdaki değişiklikleri yapabilirsiniz.

#include <stdint.h>
#include <rsc_types.h>  /* kaynak tablosu için başlık */

/* Gerçek zamanlı işlemci 200 MHz saat hızına sahip */
#define SANIYEDEKI_DEVIR_SAYISI 200000000

#define P9_31 (1 << 0) /* çıkış ucu */

/* Gerçek zamanlı işlemci için kullandığımız yazmaç */
volatile register uint32_t __R30;

void main(void)
{
    while (1)
    {
        __R30 |= P9_31; /* R30 yazmacındaki ilk biti 1 yap */

        /* yarım saniye bekle */
        __delay_cycles(SANIYEDEKI_DEVIR_SAYISI / 2000000);

        __R30 &= ~P9_31; /* R30 yazmacındaki ilk biti 0 yap */

        /* yarım saniye bekle */
        __delay_cycles(SANIYEDEKI_DEVIR_SAYISI / 2000000);
    }
}

/* bahsettiğimiz kaynak tablosunu buraya ekliyoruz */
#pragma DATA_SECTION (kaynakTablosu, ".resource_table")
#pragma RETAIN (kaynakTablosu)
struct kaynakTablomuz
{
    struct resource_table temel;
    uint32_t uzaklik[1];
} kaynakTablosu = { 1, 0, 0, 0, 0 };

Eğer burada ilgili bölümü

__delay_cycles(1);

olarak değiştirirseniz 100 MHz'ye çıkıyor olmanız lazım.

Benim kullandığım Hantek osiloskop'ta 1 MHz'de bile işaretlerde bozulma oluyor.

Ölçüm

Burada da dalganın toplam çevrim süresi 1000 nano saniye.

Sıklığını bulmak için bu hesap sayfasından faydalanabiliriz.

Burada T ile gösterilen çevrim süresine 1000 ns girerseniz, f ile gösterilen sıklığın 1 MHz olduğunu görebilirsiniz.

Uygulamayı derlemek için make komutunu veriniz.

Aygıt yazılımını yüklemek için 'başla' komutunu verebilirsiniz.

Yorumlar

yorum yaz

Yorum yaz

Henüz yorum yok.