Zybo ile Ultrasonik Sensör Uygulaması (Distance Measurement by Ultrasonic Sensor with Zybo)

42
KOCAELİ ÜNİVERSİTESİ ELEKTRONİK VE HABERLEŞME MÜHENDİSLİĞİ BÖLÜMÜ ZYBO İLE ULTRASONİK SENSÖR UYGULAMASI 6.DÖNEM PROJESİ Yrd. Doç. Dr. Anıl Çelebi MELEK SÖNMEZ 130207075

Transcript of Zybo ile Ultrasonik Sensör Uygulaması (Distance Measurement by Ultrasonic Sensor with Zybo)

KOCAELİ ÜNİVERSİTESİ

ELEKTRONİK VE HABERLEŞME MÜHENDİSLİĞİ

BÖLÜMÜ

ZYBO İLE ULTRASONİK SENSÖR UYGULAMASI

6.DÖNEM PROJESİ

Yrd. Doç. Dr. Anıl Çelebi

MELEK SÖNMEZ

130207075

ÖZET

Ultrasonik sensörler araç park sensörleri, otomatik kapı sensörleri, hırsız algılama

sensörleri olarak günlük hayatta yaygın olarak kullanılır. Endüstriyel uygulamalarda

ultrasonik sensörler, sıvı seviyesi algılanmasında, akışkanlık algılamada, ahşap, kâğıt,

cam, şişe vb. fabrikalarda ürün algılamada ve daha birçok uygulamada kullanılırlar.

FPGAler ise sayısal işaret işleme, radar haberleşme sistemi, uzay, savunma sistemleri,

medikal resimleme, robotik, ses tanıma, şifreleme ve kod çözme gibi birçok alanda

kullanılmaktadır. İlerleyen teknoloji ve paralel işlem yapabilme yeteneğine duyulan

ihtiyacın artması ile FPGAler günlük hayata daha fazla adapte olmaktadır.

Bu projede, HC-SR04 ultrasonik sensörü ZYBO FPGA kartın ARM-Cortex-A9

işlemcisi ile programlanarak mesafe ölçümü uygulaması gerçeklenmiştir.

1. ZYBO İLE GÖMÜLÜ SİSTEMLER

1.1 VİVADO, BLOK TASARIM OLUŞTURMA

1.1.1. ÖRNEK TASARIM

Örnek bir tasarım olarak Zybo kart üzerinde bulunan switchlerin değerlerini yine Zybo

kart üzerinde bulunan ledlere yazdırma uygulaması anlatılacaktır.

Vivado 2015.4 programı çalıştırılır. Şekil 1.1 ekranında görülen create new project

seçeneği seçilir. Açılan pencerede next butonuna tıklanıp Şekil 1.2’deki yeni pencerede

projenin adı yazılır ve next butonuna basılır.

Şekil 1.1 Şekil 1.2

Yeni pencere Şekil 1.3’te RTL project seçeneği seçilip next butonuna tıklanır ve

eklenecek kaynak dosya varsa bu aşamadan sonra projeye eklenir. Eğer eklenecek

kaynak dosya, benzetim dosyası, xdc dosyası veya ip dosyası yoksa açılan yeni

pencerelerde 4 kere next butonuna tıklanır. Uygulamanın yapılacağı kartın seçileceği

ekrandan (Şekil 1.4) Zybo kart seçilir ve önce next sonra finish butonlarına tıklanarak

proje oluşturulur.

Şekil 1.3 Şekil 1.4

Burada önemli bir nokta, Zybo kartın dosyaları Vivado programı yüklenirken otomatik

olarak bilgisayara gelmez. Zybo.zip dosyası Xilinx’in sitesinden indirilerek bilgisayarda

C:\Xilinx\Vivado\2016.1\data\boards\board_parts adresine eklenir.

Blok tasarım oluşturmak için sol tarafta bulunan flow navigator panelinden ip integrator

menüsünden create block design seçilir(Şekil 1.5), açılır pencerede tasarımın adı yazılır

ve ok butonuna basılır(Şekil 1.6).

Şekil 1.5 Şekil 1.6

Diagram kenar çubuğu altında bulunan simgesine tıklanarak ip kataloğu açılır (Şekil

1.7.a) ve ZYNQ7 Processing System (Şekil 1.7.b) tasarıma eklenir. Diagram kenar

çubuğunun üst kısmında çıkan run block automation seçeneğine tıklanır (Şekil 1.8).

Şekil 1.7.a Şekil 1.7.b Şekil 1.8

Açılan pencerede ok butonuna tıklanır (Şekil 1.9) ve işlemci blok tasarımda Şekil

1.10’da gösterilen halini alır.

Şekil 1.9 Şekil 1.10

ZYNQ ip bloğuna çift tıklanarak ip ayarları istenilene göre düzenlenir (Şekil 1.11).

Şekil 1.11

Açılan pencerede peripheral i/o pins sekmesine tıklanarak (Şekil 1.12) tasarımda

kullanılacak olan giriş/çıkış portları aktif veya pasif edilir. Bu aşamada genellikle

UART1 portu pasif edilmez, çünkü Zybo kart ile bilgisayar arasında haberleşme bu port

ile yapılır.

Şekil 1.12

Yine aynı pencerede clock configuration sekmesinden tasarımda kaç tane clock

kullanılacağı ve bunların hızları ayarlayanabilir (Şekil 1.13).

Şekil 1.13

Tasarımda kesme uygulaması kullanılacaksa işlemcinin kesme özelliği re-customize ip

penceresindeki interrupts sekmesinden kullanılacak olan kesmeye uygun kesme

seçeneği aktifleştirilerek tasarım kesme uygulamasına uygun hale getirilir (Şekil 1.14).

Bu örnekte kesme uygulaması kullanılmayacağı kesme portları pasif bırakılır.

Şekil 1.14

İşlemcinin ip ayarları yapılandırıldıktan sonra Zybo kart üzerindeki led ve switchleri

tasarıma ekleyebilmek için ip kataloğundan axi gpio eklenir (Şekil 1.15). Ip tasarıma

eklendikten sonra oluşan (Şekil 1.16) run connection automation seçeneğine tıklanır.

Şekil 1.15 Şekil 1.16

Açılan pencerede tüm seçenekler işaretlenip GPIO seçeneğinde istenilen ip

seçilir(switchler için sws_4bits, ledler için leds_4bits) (Şekil 1.17) ve ok butonuna

basılarak ip ayarları tamamlanmış olur.

Şekil 1.17

Tasarım tamamlandığında blok şema Şekil 1.18’deki gibi olur.

Şekil 1.18

Tasarım bittikten sonra butonuna tıklanarak tasarımda bir hata olup olmadığı

kontrol edilir (Şekil 1.19).

Şekil 1.19

Oluşturulan tasarımın sentezlenebilmesi ve SDK’ya ve oradan da karta aktarılabilmesi

için sources bölmesinde design_1.bd (Şekil 1.20) isimli blok tasarıma fare ile sağ

tıklanıp (Şekil 1.21) önce generate output products seçilir daha sonra create hdl wrapper

seçilir ve tasarım sentezlenmeye hazır hale gelmiş olur.

Şekil 1.20 Şekil 1.21

Bu işlemler de tamamlandıktan sonra flow navigator panelinden run synthesis

seçeneğine tıklanır ve böylece sentezleme başlamış olur. Sentez bittikten sonra açılan

pencerede (Şekil 1.22) open synthesized design seçeneği işaretlenip ok butonuna

basılarak sentezlenmiş tasarım açılır.

Şekil 1.22

Sentezlenmiş tasarımın görüntüsü (pin atamaları, kart üzerinde pinlerin yerleşimi) Şekil

1.23’teki gibi olur. Tasarımın sentezlenmesi sonucunda kartta kullanılan bölgeleri

görmek için device sekmesi açılır.

Şekil 1.23

Şekil 1.24’te tasarımda kullanılan portların hangi pinlere atandıkları, çalışacakları

gerilim değerleri vb. özellikler gösterilmektedir. Bu örnek tasarımda port olarak sadece

gpio kullanıldığı için pin atamaları, gerilim değerleri bu pinlerin diğer özellikleri seçili

olarak sentezlenmiştir.

Şekil 1.24

Daha sonra yine flow navigator panelinden generate bitstream seçeneğine tıklanarak

SDK’ya geçirilmek üzere tasarım için bitstream oluşturulur.

Bitstream oluşturulduktan sonra file menüsündeki export hardware seçeneği ile (Şekil

1.25.a) tasarım SDK’ya aktarılmış olur (Şekil 1.25.b). Daha sonra yine file menüsünden

launch SDK seçeneği ile (Şekil 1.26) SDK programına geçilir.

Şekil 1.25.a Şekil 1.25.b Şekil 1.26

SDK programı açıldığında Şekil 1.27’deki gibi gözükür.

Şekil 1.27

File menüsünden new→application project seçilir (Şekil 1.28).

Şekil 1.28

Açılan pencerede proje adı girilip next butonuna basılır (Şekil 1.29.a), empty

application seçeneği işaretlenip finish butonuna tıklanır (Şekil 1.29.b).

Şekil 1.29.a Şekil 1.29.b

Bu işlemden sonra C/C++ dosyalarının ekleneceği “proje_adi” isimli bir klasör ve

“proje_adi_bsp” isimli başka bir klasör projeye eklenir (Şekil 1.30.a). “proje_adi” isimli

klasöre sağ tıklanıp import seçilir (Şekil 1.30.b). Açılan pencerede general→file system

seçilir (Şekil 1.30.c).

Şekil 1.30.a Şekil 1.30.b Şekil 1.30.c

Açılan yeni pencerede browse butonuyla eklenecek kaynak dosyanın klasörü seçilip

tamam butonuna tıklanır (Şekil 1.30.d). Ve Şekil 1.30.e’ de görülen ekranda eklenmek

istenen kaynak dosya/lar seçilip finish butonuna tıklanır.

Şekil 1.30.d Şekil 1.30.e

Aşağıda bu uygulama için yazılmış C kodu görülmektedir. Kodun içeriği ile ilgili

detaylar SDK kısmında detaylıca açıklanmıştır.

#include "xparameters.h"

#include "xgpio.h"

int main (void)

{

XGpio dip, led;

int i, dip_check;

xil_printf("-- Start of the Program --\r\n");

XGpio_Initialize(&dip, 0);

XGpio_SetDataDirection(&dip, 1, 0xffffffff);

XGpio_Initialize(&led, 1);

XGpio_SetDataDirection(&led, 1, 0x00000000);

while (1)

{

dip_check = XGpio_DiscreteRead(&dip, 1);

xil_printf("DIP Switch Status %x\r\n", dip_check);

XGpio_DiscreteWrite(&led, 1, dip_check);

for (i=0; i<9999999; i++);

}

}

Bu adımdan sonra projeyi karta yükleyip uygulamayı gerçekleyebilmek için (Şekil 1.31)

window→show view→other→terminal→terminal seçilip ok butonuna tıklanır (Şekil

1.32).

Şekil 1.31 Şekil 1.32

Usb-uart bağlantı kablosu ile kart bilgisayara bağlanır, Zybo kart güç düğmesinden

açılır. Ekranın sağ alt kısmında açılan terminal bölmesinde simgesine tıklanır (Şekil

1.33.a). Açılan terminal settings penceresinde connection type→serial, baud

rate→115200 seçilir (Şekil 1.33.c / Şekil 1.33.d). Port seçeneğini ayarlarken hangi

COM bağlantı portunun kullanıldığı aygıt yöneticisinde bağlantı noktalarına bakılarak

öğrenilebilir (Şekil 1.33.b).

Şekil 1.33.a Şekil 1.33.b

Şekil 1.33.c Şekil 1.33.d

Terminal bağlantısı yapıldıktan sonra imgesine tıklanır ve açılan pencerede program

butonuna tıklanarak FPGA programlanır (Şekil 1.34).

Şekil 1.34

Projenin uygulamasını kartta gerçekleyebilmek için “proje_adi” isimli klasöre sağ

tıklanıp run as→launch on hardware(GDB) seçilir (Şekil 1.35).

Şekil 1.35

Örnek uygulamanın çıktıları aşağıdaki görsellerde verilmiştir.

Şekil 1.36.a Şekil 1.36.b

Şekil 1.36.c Şekil 1.36.d

1.1.2. IP TASARIMI

Vivado 2015.4 programı çalıştırılır. Manage ip seçeneği tıklanır (Şekil 1.37) ve new ip

location seçilir.

Şekil 1.37

Açılan pencerede next butonuna tıklanıp ip tasarımının kaydedileceği dosya adresi

yazılıp finish butonuna tıklanır. Daha sonra tools→create and package ip seçilir (Şekil

1.38).

Şekil 1.38

Açılan pencerede next butonuna tıklanır, daha sonra create axi4 peripheral seçeneği

seçilip next butonuna tıklanır (Şekil 1.39).

Şekil 1.39

Sonraki pencerede ip tasarımının adı yazılıp next butonuna tıklanır (Şekil 1.40). Daha

sonra next ve finish butonlarına tıklanarak ip projesi oluşturulmuş olur.

Şekil 1.40

Bu işlemlerin sonunda Vivado yeni bir proje penceresi açar. Ip tasarımının verilog hdl

dilinde kodları bu pencerede yazılıp ip tasarımı paketlenir.

Kaynaklar bölmesinde myip_v1_0 kaynak dosyasına çift tıklanarak dosya açılır.

Şekil 1.41

Dosyanın 7.satırına giriş/çıkış portlarının parametreleri yazılır (Şekil 1.42).

// Users to add parameters here

parameter width = 8,

// User parameters ends

Şekil 1.42

Aynı dosyanın 18.satırında, ip tasarımında giriş/çıkış hangi portlar kullanılacaksa, port

tanımlaması yapılır (Şekil 1.43).

// Users to add ports here

input [width-1 : 0] giris,

output [width-1 : 0] cikis,

// User ports ends

Şekil 1.43

48.satırda tanımlanan parametreler, 52.satırda portlar alt fonksiyona bağlamak üzere

yazılır. Kaynaklar bölmesinde myip_v1_0_S00_AXI_inst isimli dosyaya çift tıklanıp

dosya açılır. Diğer dosyada 7. ve 18.satırlar için yapılan işlemler bu dosyada da yapılır.

Dosyanın 400.satırına inilir ve ip tasarımının fonksiyonelliği buraya yazılır. Daha sonra

flow navigator bölmesinden tasarım sentezlenir. Sentez tamamlandıktan sonra package

ip sekmesine gelinir compability seçeneğinde ikonuna tıklanıp add family explicitly

seçilip ZYNQ seçeneği seçilir ve ok butonuna tıklanarak ip tasarımı ZYNQ

mimarisinde de kullanılabilir hale gelmiş olur. File groups seçeneğinde merge file

groups yazısına tıklanır. Customization parameters sekmesinde hidden parameters

genişletip parametreye sağ tıklanıp import ip parameters seçilir ve ok butonuna

tıklanarak kullanıcı parametreleri de diğer parametrelere eklenmiş olur. Sekmelerde hata

yoksa (Şekil 1.44) re-view and package ip sekmesinde re-package ip butonuna

tıklanarak ip tasarımı paketlenmiş olur.

Şekil 1.44

1.1.3. OLUŞTURULAN IP TASARIMININ PROJEYE EKLENMESİ

butonuna tıklanarak proje ayarları açılır. Açılan pencerede ip sekmesi seçilir ve

simgesine tıklanarak eklenmek istenen ip projesinden ip_repo klasörü seçilip projeye

eklenir. Klasör eklendikten sonra açılan pencerede ok butonuna basılır ve proje ayarları

penceresinde apply butonuna basılarak ip tasarımı projeye eklenmiş olur.

Şekil 1.45 Şekil 1.46

1.2 SDK, C DİLİNDE PROGRAMLAMA

1.2.1 KÜTÜPHANELER

Sıkça kullanılan kütüphaneler ve işlevleri aşağıda listelenmiştir:

xparameters.h İşlemci ile ilgili paramatrelerin bulunduğu kütüphanedir.

xgpio.h Gpio ip’lerinin kodlanması için gerekli kütüphanedir.

xil_printf.h Terminale karakter dizisi veya bir değer bastırmak için kullanılan

xil_printf fonksiyonunun kütüphanesidir.

xtmrctr.h Axi timerın fonksiyonelliğini sağlayan kütüphanedir.

xscugic.h Kesme uygulaması için gerekli kütüphanedir.

xscutimer.h SCU(snoop control unit) timerın fonksiyonelliğini sağlayan

kütüphanedir.

1.2.2 KODA TİMERI DAHİL ETME

Axi timer aşağıda belirtilen fonksiyonlar ile aşağıda verilen kodlarda gösterildiği gibi

koda dahil edilir.

1. XTmrCtr_Initialize()

2. XTmrCtr_SetResetValue()

3. XTmrCtr_SetOptions()

4. XTmrCtr_SetHandler() //kesme uygulaması için kullanılır.

//----------------------------------------------------

// SETUP THE TIMER

//----------------------------------------------------

status = XTmrCtr_Initialize(&TMRInst0, TMR_0_DEVICE_ID);

if(status != XST_SUCCESS)

return XST_FAILURE;

XTmrCtr_SetHandler(&TMRInst0, TMR_Intr_Handler, &TMRInst0);

XTmrCtr_SetResetValue(&TMRInst0, 0, TMR_LOAD_0);

XTmrCtr_SetOptions(&TMRInst0, 0, XTC_INT_MODE_OPTION |

XTC_AUTO_RELOAD_OPTION);

XTmrCtr_Start(&TMRInst0, 0);

//----------------------------------------------------

// SETUP THE COUNTER TIMER

//----------------------------------------------------

status = XTmrCtr_Initialize(&TMRInst1, TMR_1_DEVICE_ID);

if(status != XST_SUCCESS)

return XST_FAILURE;

XTmrCtr_SetResetValue(&TMRInst1, 1, TMR_LOAD_1);

XTmrCtr_SetOptions(&TMRInst1, 1, XTC_DOWN_COUNT_OPTION |

XTC_AUTO_RELOAD_OPTION);

1.2.3 KESME UYGULAMASI

Kartın kesme uygulamalarına hazır hale gelmesi için port aktifleştirme işlemi Vivado

tarafında, kod fonksiyonelliği SDK tarafında yapılır. Kesme uygulaması konu başlığı

altında gpio(buton) kesmesinin ve timer kesmesinin kod fonksiyonelliği anlatılmaktadır.

BUTON KESMESİ [1]

Kesme uygulamasına başlamadan önce,

#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID

#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID

#define GPIO_INTERRUPT_ID XPS_GPIO_INT_ID

static XScuGic Intc; // Interrupt Controller Driver

static XGpioPs Gpio; //GPIO Device

tanımlamaları yapılır.

xil_exception.h ve xsucig.h kütüphaneleri koda eklenir. Kesme uygulamasını kesme

kontrolörüne (GIC) bağlamak ve kesme izinlerini vermek için,

//GIC config

XScuGic_Config *IntcConfig;

Xil_ExceptionInit();

//initialize the GIC

IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);

XScuGic_CfgInitialize(GicInstancePtr, IntcConfig,

IntcConfig->CpuBaseAddress);

//connect to the hardware

Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(

Xil_ExceptionHandler)XScuGic_InterruptHandler,

GicInstancePtr);

yazılır.

xgpiops.h kütüphanesi eklenir ve,

void XGpioPs_IntrEnable(XGpioPs *InstancePtr, u8 Bank, u32 Mask);

void XGpioPs_IntrEnablePin(XGpioPs *InstancePtr, int Pin);

fonksiyonları tanımlanır.

Kesme servis rutininin sağlanabilmesi için,

XGpioPs_SetCallbackHandler(Gpio, (void *)Gpio, IntrHandler);

fonksiyonu tanımlanır.

Butona her basıldığında gerçekleştirilmek istenen fonksiyonellik,

static void IntrHandler(void *CallBackRef, int

Bank, u32 Status)

{

int delay;

XGpioPs *Gpioint = (XGpioPs *)

CallBackRef;

XGpioPs_IntrClearPin(Gpioint, pbsw);

printf(“****button pressed****\n\r”);

toggle = !toggle;

XGpioPs_WritePin(Gpioint, ledpin, toggle);

for( delay = 0; delay < LED_DELAY; delay++)

//wait

{}

}

kesme koduna gömülerek gerçekleştirilebilir.

TİMER KESMESİ [2]

Timer kütüphanesi koda dahil edilir (bu kesme örneğinde scutimer kullanılmıştır).

Timera yükleme değeri,

#define TIMER_LOAD_VALUE 0xFFFFFFFF

satırı ile tanımlanır.

Aşağıda verilen kod parçası yazılarak timer tanımlanır.

//timer initialisation

TMRConfigPtr = XScuTimer_LookupConfig

(TIMER_DEVICE_ID);

XScuTimer_CfgInitialize(&Timer,

TMRConfigPtr,TMRConfigPtr->BaseAddr);

//load the timer

XScuTimer_LoadTimer(&Timer, TIMER_LOAD_VALUE);

Timer kesmesini aktifleştirip GIC’e bağlamak için,

//set up the timer interrupt

XScuGic_Connect(GicInstancePtr, TimerIntrId,

(Xil_ExceptionHandler)TimerIntrHandler,

(void *)TimerInstancePtr);

//enable the interrupt for the Timer at GIC

XScuGic_Enable(GicInstancePtr, TimerIntrId);

//enable interrupt on the timer

XScuTimer_EnableInterrupt(TimerInstancePtr);

yazılır. Timer kesmesi ile gerçekleştirilmek istenen fonksiyonellik,

static void TimerIntrHandler(void *CallBackRef)

{

XScuTimer *TimerInstancePtr =

(XScuTimer *) CallBackRef;

XScuTimer_ClearInterruptStatus(TimerInstancePtr);

printf(“****Timer Event!!!!!!!!!!!!!****\n\r”);

kesme koduna gömülerek gerçekleştirilebilir.

1.3 BİR IP TASARIMINI PROGRAMDA KULLANMA

Ip tasarımları SDK tarafında,

IP_ADI_mWriteReg(BaseAdress, RegOffset)

IP_ADI_mReadReg(BaseAdress, RegOffset) fonksiyonları ile kullanılır.

Kullanılmak istenen ip nin adresine verilog programında adress editor

bölmesinden bakılıp (Şekil 1.47) kodda uygun fonksiyonlarda BaseAdress yazan

yerlere yazılır.

Şekil 1.47

2. HC-SR04, ULTRASONİK SENSÖR

2.1 ÇALIŞMA PRENSİBİ

Trigger(tetikleme) pininden en az 10us lik 5V pulse görderildiğinde sensör ultrasonik

verici (Tx) den 40KHz de 8 adet pulse gönderir ve ECHO pinini “H” ye çeker.

Gönderilen bu dalgalar Ultrasonik alıcı (Rx) sensöre ulaştığında ECHO pini “L”‘ye

düşürür. Ölçüm yaparken ECHO pinin “H” de kaldığı süre ölçülerek sesin havada

yayılma hızına göre hesap yapılarak mesafe bulunur. [3]

Şekil 2.1

2.2 IP TASARIMI

Ultrasonik sensörün ip tasarımında echo giriş, trigger çıkış olarak tanımlanır (Şekil 2.2).

Echo ve trigger portlarının birbirlerinin değerlerini etkilememesi için ikisi için de ayrı

birer register kullanılır. Bu projede kullanılan ip tasarımında slv_reg0 trigger portu için,

slv_reg1 echo portu için kullanılmıştır. Echo giriş pininin değerini okuyabilmek için ip

kodunda slv_reg1 yerine echo portu yazılır (Şekil 2.3).

// Users to add ports here

input echo,

output trigger,

// User ports ends

Şekil 2.2

assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid;

always @(*)

begin

// Address decoding for reading registers

case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )

2'h0 : reg_data_out <= slv_reg0;

2'h1 : reg_data_out <= echo;

2'h2 : reg_data_out <= slv_reg2;

2'h3 : reg_data_out <= slv_reg3;

default : reg_data_out <= 0;

endcase

end

Şekil 2.3

Trigger portuna SDK tarafında slv_reg0’a 1 değeri yazıldığında 1, 0 yazıldığında 0

değerlerinin yazılabilmesi fonksiyonelliğini sağlayacak kod parçası Şekil 2.5’te

verilmiştir. Şekil 2.4’te trigger fonksiyonelliğini sağlayan sonic fonksiyonun ip

tasarımında nasıl çağrıldığı gösterilmektedir.

// Add user logic here

sonic sonic(S_AXI_ACLK, S_AXI_ARESETN, axi_awaddr, slv_reg_wren,

slv_reg0, trigger);

// User logic ends

Şekil 2.4

module sonic(input S_AXI_ACLK,

input S_AXI_ARESETN,

input [3:0] axi_awaddr,

input slv_reg_wren,

input [31:0] slv_reg0,

output reg trigger);

always @(posedge S_AXI_ACLK )

begin

if ( S_AXI_ARESETN == 1'b0 )

trigger = 1'b0; //trigger

else if(slv_reg_wren && (axi_awaddr == 4'h0))

begin

if(slv_reg0 == 32'h1)

begin

trigger = 1'b1;

end

else if(slv_reg0 == 32'h0)

begin

trigger = 1'b0;

end

end

end

endmodule

Şekil 2.5

Şekil 2.6’da sonic fonksiyonunun RTL şeması, Şekil 2.7’de sonic fonksiyonunun

benzetim çıktısı verilmiştir.

Şekil 2.6

Şekil 2.7

Şekil 2.8’de ip tasarımının paket görüntüsü verilmiştir.

Şekil 2.8

2.3 C DİLİNDE FONKSİYONELLİK

HC-SR04 ultrasonik sensör işlevini ses dalgası yayarak gerçekleştirir. Sesin havada

yayılma hızı 340m/sn’dir. O halde 1us de ne kadar yol kat edeceği hesaplanırsa;

mesafe=340000mm/1000000us olur. Sinyal karşısındaki engele ulaşıp dönene kadar iki

birim zaman geçtiği için formül 2’ye bölünür. Mesafe(mm)=(süre(us)*34)/200 olarak

bulunur. Mesafe(cm)=(süre(us)*0.017) olur.

Bu formülün C dilinde fonksiyonelliği Şekil 2.9‘da verilmiştir.

int read_distance_sensor_cm()

{

int echo, echo_pulse_duration, i, j, k, toplam = 0;

for(i=0; i<=63; i++){

SONIC_mWriteReg(0x43C00000, 0, BIT0);

for(j=0 ; j<=20; j++); //20us delay for trigger pulse

SONIC_mWriteReg(0x43C00000, 0, 0);

echo = SONIC_mReadReg(0x43C00000, 4);

while ((echo & BIT0) == 0)

echo = SONIC_mReadReg(0x43C00000, 4);

XTmrCtr_Reset(&TMRInst1, 1); XTmrCtr_Start(&TMRInst1, 1);

echo = SONIC_mReadReg(0x43C00000, 4);

while ((echo & BIT0) == 1)

echo = SONIC_mReadReg(0x43C00000, 4);

XTmrCtr_Stop(&TMRInst1, 1);

echo_pulse_duration = XTmrCtr_ReadReg(0x42810000, 1, 8);

toplam = toplam+(int)(0.017*(TMR_LOAD_1-echo_pulse_duration ));

for(k=0; k<=49999; k++); }

return (toplam>>7);

}

Şekil 2.9

3. SSD

3.1 ÇALIŞMA PRENSİBİ

Digilent’in pmod SSD modülü ortak katot yapısıma sahiptir. Yani pinden 1 değeri

gönderildiğinde ilgili pinin ledi yanar. Pmod SSD modülü ile ilgili devre şeması ve pin

atamaları aşağıda verilmiştir.

Şekil 3.1.a Şekil 3.1.b

Şekil 3.1.c

3.2 IP TASARIMI

SSD ip tasarımında 8 bit ssd çıkış portu tanımlanır (Şekil 3.2).

// Users to add ports here

output wire [7:0] SSD,

// User ports ends

Şekil 3.2

Ip nin registerlarında bir oynama yapılmaz, ssd fonksiyonunda iki gösterge arasında

geçişi zamanlamak için 20 bitlik bir counter ve ssd lere hangi değerlerin atanacağının

belirlemek için 7 bitlik data0_ssd_data ve data1_ssd_data reg tipinde tanımlanır (Şekil

3.3).

reg [19:0] counter; //Counter for 20ms delay

reg [6:0] data0_ssd_data;

reg [6:0] data1_ssd_data;

Şekil 3.3

SDK tarafından yazılan değere göre ssd lere hangi değerlerin yazılacağı

fonksiyonelliğini sağlayan kod parçası aşağıda verilmiştir.

always @(posedge S_AXI_ACLK) begin

if (S_AXI_ARESETN == 1'b0) begin

SSD <= 8'd0;

counter <= 20'd0;

end else if(slv_reg_wren && (axi_awaddr == 3'h0))

begin

case(slv_reg0[3:0])

//A high on the anode will lit the related segment on the PMOD SSD

//module

//The order of the bits from MSB to LSB are G F E D C B A

// GFEDCBA

4'h0: data0_ssd_data <= 7'b0111111;

4'h1: data0_ssd_data <= 7'b0000110;

4'h2: data0_ssd_data <= 7'b1011011;

4'h3: data0_ssd_data <= 7'b1001111;

4'h4: data0_ssd_data <= 7'b1100110;

4'h5: data0_ssd_data <= 7'b1101101;

4'h6: data0_ssd_data <= 7'b1111101;

4'h7: data0_ssd_data <= 7'b0000111;

4'h8: data0_ssd_data <= 7'b1111111;

4'h9: data0_ssd_data <= 7'b1101111;

4'hA: data0_ssd_data <= 7'b1110111;

4'hB: data0_ssd_data <= 7'b1111100;

4'hC: data0_ssd_data <= 7'b0111001;

4'hD: data0_ssd_data <= 7'b1011110;

4'hE: data0_ssd_data <= 7'b1111001;

4'hF: data0_ssd_data <= 7'b1110001;

default: data0_ssd_data <= 7'b0000000;

endcase

case(slv_reg0[7:4])

//A high on the anode will lit the related segment on the PMOD SSD

//module

//The order of the bits from MSB to LSB are G F E D C B A

// GFEDCBA

4'h0: data1_ssd_data <= 7'b0111111;

4'h1: data1_ssd_data <= 7'b0000110;

4'h2: data1_ssd_data <= 7'b1011011;

4'h3: data1_ssd_data <= 7'b1001111;

4'h4: data1_ssd_data <= 7'b1100110;

4'h5: data1_ssd_data <= 7'b1101101;

4'h6: data1_ssd_data <= 7'b1111101;

4'h7: data1_ssd_data <= 7'b0000111;

4'h8: data1_ssd_data <= 7'b1111111;

4'h9: data1_ssd_data <= 7'b1101111;

4'hA: data1_ssd_data <= 7'b1110111;

4'hB: data1_ssd_data <= 7'b1111100;

4'hC: data1_ssd_data <= 7'b0111001;

4'hD: data1_ssd_data <= 7'b1011110;

4'hE: data1_ssd_data <= 7'b1111001;

4'hF: data1_ssd_data <= 7'b1110001;

default: data1_ssd_data <= 7'b0000000;

endcase

Şekil 3.4’te ssd ler arasında geçişi zamanlayan counter değişkeninin fonksiyonelliğini

sağlayan kod parçası verilmiştir.

if(counter == {20{1'b1}}) begin

counter <= 20'd0;

end else begin

counter <= counter + 1'b1;

end

if(!counter[9]) begin

SSD <= {1'b0,data0_ssd_data};

end else begin

SSD <= {1'b1,data1_ssd_data};

end

end

end

endmodule

Şekil 3.4

Şekil 3.5’te ip tasarımının paket görüntüsü verilmiştir.

Şekil 3.5

3.3 C DİLİNDE FONKSİYONELLİK

SSD ip tasarımının fonksiyonelliği Şekil 3.6’da verilen C kodu ile gerçeklenebilir.

#include "xparameters.h"

#include "xgpio.h"

#include "ssd_ip.h"

int main (void)

{

XGpio push;

int i, SSD, SSDReg;

xil_printf("-- Start of the Program --\r\n");

XGpio_Initialize(&push, 0x41200000);

XGpio_SetDataDirection(&push, 1, 0xFFFFFFFF);

while (1)

{

SSD = XGpio_DiscreteRead(&push,1);

xil_printf("Zybo DIP Switch Status %x\r\n", push);

SSD_IP_mWriteReg(0x43C00000, 0, SSD);

SSDReg = SSD_IP_mReadReg(0x43C00000, 0);

xil_printf("PMOD SSD Status %x\r\n", SSDReg);

for (i=0; i<99999999; i++);

}

}

Şekil 3.6

4. UYGULAMA

4.1 VİVADO, BLOK TASARIM

Bu projenin blok tasarımında,

ZYNQ işlemci sistemi

Buton gpio ip modülü

Led gpio ip modülü

Axi timer (periyot için)

Axi timer (mesafe hesaplanırken gerekli olan sayıcı için)

Sonic ip modülü

SSD ip modülü

Concat modülü (birden fazla kesmeyi işlemciye sürebilmek için) kullanılmıştır.

Şekil 4.1 Blok tasarım

4.2 SDK, C DİLİNDE PROGRAMLAMA

Aşağıdaki şekillerde biri periyot timerı diğeri sayıcı olarak kullanılan 2 timer ile

kodlanmış, her buton kesmesi ile ilgili ledi yakıp mesafe değerini ssd modülüne

yazdıran ve mesafeyi hesaplayan fonksiyonu içeren C kodu verilmiştir.

#include "xparameters.h"

#include "xgpio.h"

#include "xtmrctr.h"

#include "xscugic.h"

#include "xil_exception.h"

#include "xil_printf.h"

#include "sonic.h"

#include "ssd_ip.h"

// Parameter definitions

#define INTC_DEVICE_ID XPAR_PS7_SCUGIC_0_DEVICE_ID

#define TMR_0_DEVICE_ID 0

#define TMR_1_DEVICE_ID 1

#define BTNS_DEVICE_ID XPAR_AXI_GPIO_0_DEVICE_ID

#define LEDS_DEVICE_ID XPAR_AXI_GPIO_1_DEVICE_ID

#define INTC_GPIO_INTERRUPT_ID

XPAR_FABRIC_AXI_GPIO_0_IP2INTC_IRPT_INTR

#define INTC_TMR_INTERRUPT_ID XPAR_FABRIC_AXI_TIMER_0_INTERRUPT_INTR

#define BTN_INT XGPIO_IR_CH1_MASK

#define TMR_LOAD_1 50000

#define TMR_LOAD_0 0xF8000000

#define BIT0 0x01

XGpio LEDInst, BTNInst;

XScuGic INTCInst;

XTmrCtr TMRInst0;

XTmrCtr TMRInst1;

static int ssd_value;

static int btn_value;

static int mesafe;

int i;

//----------------------------------------------------

// PROTOTYPE FUNCTIONS

//----------------------------------------------------

static void BTN_Intr_Handler(void *InstancePtr);

static void TMR_Intr_Handler(void *InstancePtr);

static int InterruptSystemSetup(XScuGic *XScuGicInstancePtr);

static int IntcInitFunction(u16 DeviceId, XTmrCtr *TmrInstancePtr,

XGpio

*GpioInstancePtr);

static int read_distance_sensor_cm();

void BTN_Intr_Handler(void *InstancePtr)

{

// Disable GPIO interrupts

XGpio_InterruptDisable(&BTNInst, BTN_INT);

// Ignore additional button presses

if ((XGpio_InterruptGetStatus(&BTNInst) & BTN_INT) !=BTN_INT) {

return;

}

btn_value = XGpio_DiscreteRead(&BTNInst, 1);

XGpio_DiscreteWrite(&LEDInst, 1, btn_value);

SSD_IP_mWriteReg(0x43C10000, 0, mesafe);

ssd_value = SSD_IP_mReadReg(0x43C10000, 0);

xil_printf("SSD = %x\r\n",ssd_value);

(void) XGpio_InterruptClear(&BTNInst, BTN_INT);

// Enable GPIO interrupts

XGpio_InterruptEnable(&BTNInst, BTN_INT);

}

void TMR_Intr_Handler(void *InstancePtr)

{

if (XTmrCtr_IsExpired(&TMRInst0, 0)){

XTmrCtr_Stop(&TMRInst0, 0);

XTmrCtr_Reset(&TMRInst0, 0);

XTmrCtr_Start(&TMRInst0, 0); }

}

int main (void)

{

int status;

// Initialise LEDs

status = XGpio_Initialize(&LEDInst, LEDS_DEVICE_ID);

if(status != XST_SUCCESS) return XST_FAILURE;

// Initialize Push Buttons

status = XGpio_Initialize(&BTNInst, BTNS_DEVICE_ID);

if(status != XST_SUCCESS) return XST_FAILURE;

// Set LEDs direction to outputs

XGpio_SetDataDirection(&LEDInst, 1, 0x00);

// Set all buttons direction to inputs

XGpio_SetDataDirection(&BTNInst, 1, 0xFF);

//----------------------------------------------------

// SETUP THE TIMER

//----------------------------------------------------

status = XTmrCtr_Initialize(&TMRInst0, TMR_0_DEVICE_ID);

if(status != XST_SUCCESS)

return XST_FAILURE;

XTmrCtr_SetHandler(&TMRInst0, TMR_Intr_Handler, &TMRInst0);

XTmrCtr_SetResetValue(&TMRInst0, 0, TMR_LOAD_0);

XTmrCtr_SetOptions(&TMRInst0, 0, XTC_INT_MODE_OPTION |

XTC_AUTO_RELOAD_OPTION);

//----------------------------------------------------

// SETUP THE COUNTER TIMER

//----------------------------------------------------

status = XTmrCtr_Initialize(&TMRInst1, TMR_1_DEVICE_ID);

if(status != XST_SUCCESS)

return XST_FAILURE;

XTmrCtr_SetResetValue(&TMRInst1, 1, TMR_LOAD_1);

XTmrCtr_SetOptions(&TMRInst1, 1, XTC_DOWN_COUNT_OPTION |

XTC_AUTO_RELOAD_OPTION);

// Initialize interrupt controller

status = IntcInitFunction(INTC_DEVICE_ID, &TMRInst0, &BTNInst);

if(status != XST_SUCCESS) return XST_FAILURE;

XTmrCtr_Start(&TMRInst0, 0);

xil_printf("-- Start of the Program --\r\n");

while(1){

mesafe = read_distance_sensor_cm();

xil_printf("mesafe(cm) = %x \r\n", mesafe);}

return 0;

}

//sensor fonksiyonu

int read_distance_sensor_cm()

{

int echo, echo_pulse_duration, i, j, k, toplam = 0;

for(i=0; i<=63; i++){

SONIC_mWriteReg(0x43C00000, 0, BIT0);

for(j=0 ; j<=20; j++); //20us delay for trigger pulse

SONIC_mWriteReg(0x43C00000, 0, 0);

echo = SONIC_mReadReg(0x43C00000, 4);

while ((echo & BIT0) == 0)

echo = SONIC_mReadReg(0x43C00000, 4);

XTmrCtr_Reset(&TMRInst1, 1); XTmrCtr_Start(&TMRInst1, 1);

echo = SONIC_mReadReg(0x43C00000, 4);

while ((echo & BIT0) == 1)

echo = SONIC_mReadReg(0x43C00000, 4);

XTmrCtr_Stop(&TMRInst1, 1);

echo_pulse_duration = XTmrCtr_ReadReg(0x42810000, 1, 8);

toplam = toplam+(int)(0.017*(TMR_LOAD_1-echo_pulse_duration ));

for(k=0; k<=49999; k++); }

return (toplam>>7);

}

int IntcInitFunction(u16 DeviceId, XTmrCtr *TmrInstancePtr,

XGpio *GpioInstancePtr)

{

XScuGic_Config *IntcConfig;

int status;

// Interrupt controller initialization

IntcConfig = XScuGic_LookupConfig(DeviceId);

status = XScuGic_CfgInitialize(&INTCInst, IntcConfig,

IntcConfig->CpuBaseAddress);

if(status != XST_SUCCESS) return XST_FAILURE;

// Call to interrupt setup

status = InterruptSystemSetup(&INTCInst);

if(status != XST_SUCCESS) return XST_FAILURE;

// Connect GPIO interrupt to handler

status = XScuGic_Connect(&INTCInst, INTC_GPIO_INTERRUPT_ID,

(Xil_ExceptionHandler) BTN_Intr_Handler,

(void *)GpioInstancePtr);

if(status != XST_SUCCESS) return XST_FAILURE;

// Connect timer interrupt to handler

status = XScuGic_Connect(&INTCInst, INTC_TMR_INTERRUPT_ID,

(Xil_ExceptionHandler)TMR_Intr_Handler,

(void *)TmrInstancePtr);

if(status != XST_SUCCESS) return XST_FAILURE;

// Enable GPIO interrupts interrupt

XGpio_InterruptEnable(GpioInstancePtr, 1);

XGpio_InterruptGlobalEnable(GpioInstancePtr);

// Enable GPIO and timer interrupts in the controller

XScuGic_Enable(&INTCInst, INTC_GPIO_INTERRUPT_ID);

XScuGic_Enable(&INTCInst, INTC_TMR_INTERRUPT_ID);

return XST_SUCCESS;

}

int InterruptSystemSetup(XScuGic *XScuGicInstancePtr)

{

// Enable interrupt

XGpio_InterruptEnable(&BTNInst, BTN_INT);

XGpio_InterruptGlobalEnable(&BTNInst);

Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,

(Xil_ExceptionHandler) XScuGic_InterruptHandler,

XScuGicInstancePtr);

Xil_ExceptionEnable();

return XST_SUCCESS;

}

4.3 UYGULAMA ÇIKTILARI

Bu projenin uygulama çıktıları aşağıdaki görsellerde verilmiştir.

Şekil 4.2 Şekil 4.3

Şekil 4.4 Şekil 4.5

Şekil 4.6 Şekil 4.7

5. KAYNAKÇA

[1] , [2] How to Use Interrupts on the Zynq SoC, Adam P. Taylor

[3] https://elektrokod.wordpress.com/2014/01/17/ultrasonik-mesafe-sensoru-uygulamasi