UART üzerinden çift taraflı haberleşme

theroot

Kayıtlı Üye
Birbirine UART ile bağlı iki PIC çıft taraflı haberleşmesi gerekiyor.Haberleşmenin şekli genel olarak soru sorma, cevap alma şeklinde.Ama her iki PIC de her an soru sorabilir hatta aynı anda soru sorabilirler. Diyelim A soru sordu, B'den cevap bekliyor ama cevap yerine B'den de soru geldi. Haberleşme arap saçına dönecek.mesajların net bir yapısı yok,terminal komutları gibi düşünülebilir.Örnek:

Kod:
SORU:
netif get_settings

CEVAP:
{
   "role": "master",
   "ipaddr": "10.0.0.1"
   "version":
   {
      "major": 1,
      "minor": 1,
      "build": 0
   }
}
Sağlıklı bir haberleşme için önerisi olan var mı? Devre tasarlanırken hardware flow control sinyallerini de tanımladık yani RTS/CTS çarpraz olarak karşılıklı bağlı. Hardware flow control kullanmak bir çözüm olur mu? Ser port üzerinde yürüyen SLIP gibi protokollere baktım çok karmaşık geldi.Şimdi farkediyorum,tek bir UART yerine her iki haberleşme yönü için ayrı UART kullanmalıydık. A dan B ye UART1, B den A ya UART2. Kullanılabilecek UART da vardı.
 

taydin

Timur Aydın
Yönetici
Yani aslında PIC'lerden birisi, diğer PIC'e bir nevi terminali açıyor ve komut satırından komut giriyor. Cevap da bir JSON yapısı olarak geri döniyor.

RTS/CTS bence senin istediğini sağlamaz. O tip akış kontrolleri daha çok, alıcı ve verici arasında performans farkı varsa, hızlı tarafı yavaşlatmak için kullanılıyor. Ama senin yapıda böyle bir sorun olmaz. PIC'ler UART'a gelen datayı anında alır. Senin sorun, paketleri komut, cevap, A ve B diye kategorilere ayırmak. Komutun kendisine bakarak ayıramıyoruz, cevaba bakarak da ayıramıyoruz.

Ben olsam, verileri paketler haline getirip, etiketleyerek gönderirdim. Alan taraf, gelen paketleri toparlayacak, etikete göre de paketin türünü bilecek. Bu yapıda, her iki taraf aynı anda veri gönderse de sorun çıkmaz, çünkü her veri etiketli ve ne olduğu belli.

Dediğin gibi iki PIC arasında iki UART kullansaydın işi çok temiz bir şekilde bitirecektin. hiçbirşey birbirine karışmayacaktı.
 

theroot

Kayıtlı Üye
Evet A komut gönderdikten sonra B'den cevap beklerken B yeni bir komut gönderdiğinde o yeni gelen mesajın komut mu yoksa cevap mı olduğunu ayırt etmek gerekiyor. Dediğiniz gibi sabit boyutlu frame'ler halinde gönderilebilir ama bu oldukça karmaşıklaştırıyor. Peki RTS/CTS sinyallerine klasik flow control yerine bir işaret olarak kullansam? A ve B komut gönderdiği zaman RTS'yi set eder, cevap gönderirken set etmez.

Cevap JSON şeklinde görünüyor ama başka formatlar da olabilir. ASCII karakter dizisi şeklinde açık format. 50 Kbyte gibi bir limit belirledim hem komut hem cevap için.
 

kesmez

Kayıtlı Üye
A elemanını master yapın ve b yi devamlı kontrol etsin. b ancak a dan uyarı alınca aktif olsun.
 

taydin

Timur Aydın
Yönetici
O şekilde karşılıklı sinyalleşmede "race condition" denen zamanlama problemleri ortaya çıkar. Onu doğru bir şekilde çalışır hale getirmek çok zor. Mesela şu durumu düşünelim: A "şu anda mesal almaya hazırım" dedi. Ama bir süre mesaj gelmedi, ve A'nın da B'ye şimdi mesaj göndermesi lazım. A "artık hazır değilim" dedi ve kendi mesajını gönderdi. Ama bundan 1 mikrosaniye önce B "hazırım" durumunu gördü ve o da mesaj gönderdi. Bu durumda A ve B aynı anda mesaj göndermiş olur, ki bu istenmeyen durum.

Ama mesaj etiketlemesi kullanılırsa, hiçbir sinyalleşmeye gerek yok. İki taraf da maksimum hızda, ve istediği anda mesaj gönderebilir.
 

taydin

Timur Aydın
Yönetici
RTS/CTS sinyallerinin geleneksel olarak kullanım mantığı da şu şekilde: İki tarafta da gelen verilerin saklandığı buffer'lar var. Diyeli A, B'ye harıl harıl mesaj gönderiyor. B de buffer'ı dolmaya yakın olunca RTS/CTS sinyallerini kullanarak A'ya "dur!" diyor. A da duruyor. Sonra B'nin buffer'ı boşalıyor ve B "devam et!" diyor. Burada herhangi bir race condition durumu yok.

Ama buradaki uygulamada interaktif bir haberleşme var, soru cevap şeklinde. Neyin soru, neyi cevap olduğu bilinmeli. Hatta birden fazla soru peş peşe sorulduğunda hangi cevabın hangi soruya ait olduğu da bilinmeli.
 

theroot

Kayıtlı Üye
Bir seçenek de A'nın B'ye saniyede bir soru sorması. Böylece B'nin bir mesajı varsa o anda verebilir. Ama saniyede bir sürekli trafik yaratan bir durum. İşlemci de çok yüksek performanslı değil o yüzdn sanırım mesaj etiketlemesi yapacağım.
 
Son düzenleme:

theroot

Kayıtlı Üye
A elemanını master yapın ve b yi devamlı kontrol etsin. b ancak a dan uyarı alınca aktif olsun.
Bunun biraz farklı bir varyasyonu olabilir belki. Kural koyacağız, her zaman A komut gönderecek, B her zaman komuta cevap gönderecek. B hiçbir zaman kendiliğinden komut göndermeyecek.

Eğer B'nin A'ye diyeceği birşey varsa, RTS/CTS pinini set edecek. A da bunu görecek ve B'ye "ne var?" diye soracak. B'de cevabında ne diyecekse demiş olacak.
 

theroot

Kayıtlı Üye
Mesaj sınırlarında kesin senkronizasyon için BREAK sinyali göndermek üzerinde duruyorum. Kullanılan PIC'in kılavuzlarına bakınca, UART registerlerinde hem BREAK gönderme hem de alıcı tarafında break algılama bitleri var. Bu metot konusunda yorumunuzu alabilir miyim?
 

taydin

Timur Aydın
Yönetici
Evet break sinyali de kullanılabilir. Ama paket etiketlemesinin gene yapılması lazım, çünkü gelen mesaj komut mu yoksa senin gönderdiğin komuta cevap mı bilmen gerekiyor. Break sinyalini kullanmanın en büyük avantajı, belli bir data byte'a bağımlı olmaması. Break kullanarak UART üzerinden her türlü veriyi gönderebilirsin. Ama break olmasaydı, belli bir byte değerini (mesela 00H) senkronizasyon anlamında kullanman gerekirdi ve artık bu veriyi başka işler için kullanamazdın.
 

theroot

Kayıtlı Üye
Kodu 0 byte'ını senkronizasyon byte olarak kullarak yaptım. Her veri paketinın yapısı şu şekilde:

1 byte SYNC (00H)
4 byte uzunluk (little endian)
n byte data paketi

Kodu kütüphane olarak gerçekleştirdim. Bir FSM ile alınan bu paketler parse ediliyor ve bir callback ile uygulamaya bildiriliyor. 4 Mbaud hız ile kullanıyorum ve hiç veri kaybı olmadan çalışıyor.
 

taydin

Timur Aydın
Yönetici
Eline sağlık. Aslında reset sinyalini kullanmamanın sana şöyle bir avantajı olacak: Eğer aynı kodu linux altında kullanman gerekirse, aynı şekilde çalışacak. Reset sinyali ile linux'ta yapmak için çok yüksek ihtimalle device driver yazman gerekir, standart termios ile yapamazsın. Bazı hack'ler var milletin önerdiği, ama hepsinde sorunlar var.
 
Üst