Bu derste yüksek hızda kare dalga işaretinin nasıl üretilebileceği anlatılmıştır
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şlemcisiremoteproc1
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ı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.
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.
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.
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.
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.
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.
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ı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.
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