Kategori arşivi: Referans

Avokado Yetiştirmek

Umay’a faydalı olduğunu düşündüğümüz için eve epey avokado alıyoruz. Adını insan taşağından alan bu meyvenin içinden çıkan ilginç çekirdek, suda bir müddet bekleyince altından sıçan kuyruğuna benzer bir kök çıkarıyor. Bunu, çekirdeğin üst tarafından çıkan bir sürgün takip ediyor. Ve elinizde iri yeşil yapraklı, şirin bir avokado fidesi oluyor.

Bu iş bizim merakımızı çekti.  Meyvesi olur mu ümidi bir yana, yeşil iri yapraklarıyla güzel bir fide. Bir çok salon bitkisinden daha iç açıcı bir görüntüsü var.

Üstelik, çekirdekleri yeşertme prosedürü oldukça kolay:

İşe, 1,5 lt’lik pet şişeleri ortasından keserek başlıyoruz.

Sonra çekirdeğin gövdesine  orta-üst tarafından 3 tane kürdan saplıyoruz.

Bunu içine su doldurduğumuz kafası kesilmiş pet şişeye üstten bırakıyoruz. Maksat çekirdeğin tamamının suya gömülmemesidir. Aslında sadece çekirdeğin kıçının suya değmesi yeterli sanırım ama ben su seviyesini daima biraz daha fazla tutuyorum çünkü bu arkadaşlar kaloriferin üstündeler ve su seviyesi çabuk düşüyor.

Çekirdek önce çatlıyor, sonra alttan üstten kök ve filiz çıkmaya başlıyor. Çekirdeğin canlanmasının belli bir süresi olduğunu sanmıyorum. Dormansi dedikleri şey bu mudur, bilemiyorum.

Birkaç yaprak çıkıp yapraklar iyice biçimleninceye kadar uyanmış çekirdeği suda bekletmeye devam ediyoruz. Aşağıda hala suda yaşayan, toprağa kavuşacağı zamanı bekleyen bir arkadaşı görüyorsunuz:

Avokadolarda bazen tek çekirdekten çift gövde çıkıyor. Ben ikisini de bırakıyorum. Yapraklar belirginleşince ve de işim gücüm müsait olunca çekirdeği saksıya alıyorum:

Sonrasında avokadolar saksıda bir süre büyüyorlar:

Sonrası.. Sonrası da var tabi.. Ekleyeceğim.

Function Pointers in C

Fonksiyon işaretçisi, bir fonksiyonu bildirim referansını kullanarak çağırabilmemizi sağlar. Yani, bir fonksiyonu parametrik olarak çalıştırma imkanımız olur.

void (* func_name) ( ) = function_name;

Bunun bendeki en sık kullanma amacı Fonksiyon Listesi hazırlamak:


 int funcA(void);
 int funcB(void);
 int funcC(void);
 int funcD(void);
 int funcE(void);
 int funcF(void);

 int (* functionList[]) () = 
 {
  funcA, funcB, funcC, funcD, funcE, funcF 
 };

 // bu bildirimin cümle içinde kullanımı şöyle:
 ret_val = functionList[list_index]();

Her ne kadar bir kaynak dosyası içinde kullanılacak bir fonksiyon için deklarasyon yazmak zorunda olmasak da, fonksiyon listesi hazırlarken deklarasyon yazmalıyız. Deklarasyon bize yürütme kısmından önce o fonksiyona dair işaretçiyi kullanma şansı verir. Bu şekilde liste bildirimi yaparken liste elemanlarını sabit olarak kullanabiliriz.

UDP Load Data

Bu soket görevi, belirtilen konumdan itibaren, belirtilen miktarda veriyi W5500 üstündeki ilgili soketin (socket-0) TX buffer’ına yazar.


 

W5500’deki bir soketin TX buffer’ına yazma işlemleri şöyle olmalı:

  1. Buffer’da yeterince yer olup olmadığını Sn_TX_FSR okuması yapıp öğrenmek.
  2. Sn_TX_RD okuması yapıp, yazma işlemine başlayacağımız konumu öğrenmek.
  3. Veriyi buradan itibaren TX buffer’a aktarmak.
  4. Sn_TX_WR içeriğini yazdığımız byte sayısı kadar artırmak.

W5500_TX_bufferSEND komutu verildiğinde W5500, Sn_TX_RD‘den Sn_TX_WR‘ye doğru TX buffer’ındaki verileri sırayla gönderir. İşlem tamamlandığında Sn_TX_RD = Sn_TX_WR olacaktır. O yüzden, yeni bir veri yüklemesi yaptıktan sonra, Sn_TX_WR içeriğini Sn_TX_RD’den gidecek veri miktarı kadar öteye alıyorum.

Bu işaretçilerin tümü 16 bitlik işaretsiz sayılardır. W5500 0xFFFF -> 0x0000 başa sarmasını önemsemiyor. Bu durumda biz de önemsemiyoruz. Paketimiz yüklenirken bu başa sarma olsa bile bu gönderme işlemini etkilemeyecek. Ki bu başa sarma da zaten eninde sonunda olacak..

Ben ayrıca, 1. adımda söz ettiğim Free Size Register’ını da okumuyorum. Çünkü benim uygulamalarda hem yollanan veri boyları küçük, hem de uygulamalarım veri yollama işlemini senkronize olarak kullanıyorlar.

Burada not etmek istediğim son şey, veri YÜKLEME işlemi ile GÖNDER komutunun farklı şeyler olduğuna dikkat etmeniz. Birden çok kez veri yüklemesi yapıp, hepsini tek seferde yollamak istemeniz çok muhtemel.. İşlemci üstünde integral bir çıkış paketi oluşturma zorunluluğunu ortadan kaldırmak için böyle yaptım. Yani, gidecek verinin tam gideceği paket yapısı ile bir yerde üretilmiş olmasına gerek yok. İstediğiniz datayı bir yerden, sonrakini bir başka yerden W5500’e yükleyip, asıl paketi TX Buffer üzerinde oluşturabilirsiniz. Toplamda 16kB TX buffer’ımız var ne de olsa!

W5500 Interrupt Logic

W5500’den durum sinyali almanın bir yolu çipin /EC_INT pinini okumaktır. Benim uygulama periyodik SPI okuması yerine bu pinin durumunu izleyerek soketlere dair durum güncellemelerinden haberdar olur.
Her kesme kaynağının bir de mask biti var. Mask biti 1 yapılmadıkça o kaynak bir sonraki kademeye kesme iletmez.
W5500’den PC’ye bağlantı veren /EC_INT girişinin etkin olmasını sağlayan iki kaynak var:
* Çip kesmeleri : IR register’ındaki bir bitin aktif olması ile oluşur.
Benim uygulamada çip kesmelerini kullanmıyorum.
* Soket kesmeleri: SIR register’ındaki bir bitin aktif olması ile oluşur. 8 soket kesmesi register’ına (Sn_IR) ait kesme kaynaklarından birinin aktif olması SIR üzerindeki o sokete ait bitin aktif olmasını sağlar.

w5500_interrupt_logic

Benim uygulama, bir soket açıldığında o sokete ait TIMEOUT, RECEIVE ve DISCON kesmelerini otomatik olarak yetkilendirir. Ayrıca, açılan soketin Sn_IMR maske bitini de etkinleştirir. Kullanıcının bu kesmelerin devreye alınması üzerinde bir denetimi yoktur.
Yani, EC_INT pininin aktif olması bize açık soketlerden birinde zaman aşımı, veri alma ya da bağlantının sonlandırıldığı bilgilerini verir.

W5500’ün kesme pininin izlenmesi işini W5500_SPI_Thread( ) halleder. Bu thread aynı zamanda, kesme algılar algılamaz SIR register içeriğini de okur.

W5500_SPI_Thread( ) kesme durumu algıladığında işlemesi gereken bir komut yoksa derhal SIR okuma işlemine atlar.
Bu işlem esnasında; hEC.status = 200 olur.
İşlem tamamlandığında; hEC.interrupt_flag = 255 yapılarak üst thread uyarılır.
hEC.socket_interrupt içeriğine de SIR değeri yüklenmiş olunur.

W5500_SPI_Thread( )

Bu thread W5500 Ethernet Controller çipini bir üst düzey (soket işlemlerinin yapıldığı ECThread() katmanı) koddan yalıtır.
SPI okuma / yazma işlemleri, kesme yanıtlanması ve çipin donanımsal resetlenmesi görevleri bu katmanda halledilir.

w5500_SPI_Thread

Sürekli olarak /EC_INT pininin durumunu okur.
hEC.command komutunu bekler.

EC_INT = 0 durumu algılanırsa;
SIR (Socket Interrupt) register içeriğini alanına kopyalar,
hEC.socket_interrupt <– SIR (Socket Interrupt) okuması yapar.
İşlem esnasında: hEC.status = 200
hEC.interrupt_flag = 255 yapar
hEC.interrupt içeriği sıfırlanmadan bir daha EC_INT pini okuması yapılmaz.

hEC.command = 1000 yapılmışsa:
hEC’de belirtilen parametrelerle SPI okuması yapılır.
İşlem esnasında : hEC.status = 10

hEC.command = 2000 yapılmışsa:
hEC’de belirtilen parametrelerle SPI yazması yapılır.
İşlem esnasında : hEC.status = 20;

hEC.command = 3000 yapılmışsa:
W5500 resetlenir.
İşlem esnasında : hEC.status = 30;

Üstteki ECThread() ile iletişim ECHANDLE değişkeni üzerinden sağlanır:

typedef struct
{
   unsigned int 	command;		// yazma veya okuma komutu (>0 ise yazma yapma)
   WORD                 offset_address;		// erişilecek register adresi
   unsigned char        control_phase;		// blok ve okuma/yazma komutu
   unsigned char        *rampos;		// RAM tarafı hedef/kaynak adresi
   unsigned char        bytecount;		// erişilecek byte sayısı
   unsigned char        status;                 // EC durumu / işlemi gösteren bayrak
   unsigned char        interrupt_flag;         // kesme algılama durum göstergesi (yazılımla sıfırlanmalı)
   unsigned char        socket_interrupt;       // Kesme kaynağının hangi soket olduğunu gösteren SIR reg. içeriği
} ECHANDLE;
  ECHANDLE    hEC;             // W5500_SPI_Thread 'in çalışmasını ayarlayan değişken

Controller Configuration

Şu veri tipi, cihaz sıfırlandıktan sonra common register block’taki temel W5500 ayarlarının yapılması için gerekli bilgileri saklar:

typedef struct
{
    unsigned char       gateway_IP[4];      
    unsigned char       subnet_mask[4];
    unsigned char       MAC[6];
    unsigned char       device_IP[4];
    WORD                retry_period;   // Little-endian olarak yeniden deneme periyot süresi
} ECCONFIG;

w5500.c içindeki cEC değişkeni reset sonrası, çipin kullanacağı konfigürasyon değerlerini içeriyor olmalıdır:

ECCONFIG    cEC;       // ec configuration: (reset sonrası yüklenir)

NOT: retry_time hariç tüm değişkenler BIG ENDIAN olarak saklanıyor olmalı!