Yüksek Hızlı Veri aktarımında Algoritma İhtiyacı.

Mucit23

Yeni Üye
Katılım
7 Ekim 2022
Mesajlar
35
Selamlar

Yazılımla uğraşan arkadaşlara bir sorum olacak.

Bir sistem geliştiriyorum. Değişken periyotlarla gelen ADC verisini Kayıp olmadan STM32'de USB CDC üzerinden PC ye göndermem gerekiyor. Veri gelme sıklığı Min 50ms Max 1ms.

50ms aralıklarla gelen veriyi kayıpsız olarak göndermek kolay. Ama 1ms aralıklara gelen veriyi tampon bellek olmadan bufferlamadan göndermek çok zor. Ben bunun için ilk başta 100 elemandan oluşan bir buffer belirledim. Her 100ms de bir Gelen veriyi biriktirip paket olarak gönderiyordum. 1ms de bir gelen veri için 100ms boyunca gelen örnekleri toplayınca zaten 100 elemanlı buffer dolmuş oluyor. Bunu çapraz bir tampon bellek ile gönderiyorum. Eğer 50ms aralıklarla yeni veri geliyorsa teorik olarak 100ms'de en fazla 2 adet ADC datası gönderirim. Gönderdiğim verinin 2 olduğunu bildiğim için burada da sorun yok. Paket başunda gelen örnek sayısınıda gönderiyorum.

Bu yöntemi pek verimli çalıştıramadım. Daha oturaklı bir sistem kurmam gerekiyor kafam durdu.

Temel ihtiyaçlarım şunlar.
  1. Gelen ADC hızından bağımsız olarak Gecikme yaşanmaması için 100ms aralıklarla veri göndermem gerek.
  2. ADC den okuduğum verilerin kayıpsız bir şekilde göndermem gerekiyor.
  3. 100mS aralıklarla Seri port üzerinden yada USB CDC ile gönderirken verinin kayıpsız bir şekilde gönderilmesi gerekiyor.
Gelen verileri c# üzerinde serialport nesnesi ile alıyorum. Paket uzunluğum sabit olduğu için serialPort1.Read(RxBuffer, 0, ReadLenght); gibi bir komut ile veriyi alıyorum. Ama veri aktarımında bu yöntem de aklıma yatmıyor. Burada sanki arada veri kaybı olduğunu hissediyorum.

Sorularım şunlar.

C# da PC ye veri aktarırken veri boyutunun sabit olduğunu düşünürsek en sağlıklı veri aktarım yöntemi hangisidir? Yada serialport sınıfını daha sağlıklı bir şekilde kullanmanın yolu varmıdır?

Ek olarak USB CDC de veri aktarım hızı baudrateden bağımsız olarak 1Mbitlerin üstünde. Dolayısıyla belki Seri porttan 1ms aralıklarla veri göndermem de sorun olmayacak ama PC tarafında sürekli serialportDataRecieved olayı tetiklendiği için program kasılacak. Bunu istemiyorum. Burada nasıl bir algoritma nasıl bir yapı kurmam gerektiği hakkında önerilere ihtiyacım var.

Donanım ile PC arasında yüksek hızlı veri transferinde kullanılan algoritmaları öğrenmek istiyorum.
 
Windows programının "kasılması", thread kullanımını anlamamak veya başaramamak nedeniyle olur. USB, Seri port cdc, hid fark etmez. Thread içinde biriken veriyi incitmeden dışarıya almak mümkündür. Aslında veri "kayıpsız" olarak Windows sürücülerine ulaşır. Orada bir yerde depolanır. Windows içinde zaten buffer vardır. Mesela 1sn boyunca okuma yapılamamışsa işte o zaman kopma olur. Büyük bir buffer mümkün.

USB yüksek hızlı transfer için Bulk yöntemi iyi. CDC de bulk transfer kullanır. Kayıpsız gönderir. isochronous transfer, daha yüksek hızları destekler. Ses gibi kopmanın önemsiz olduğu işlerde tercih edilir. Mutabakat garantili transfer isochronous için iddia edilemez.

Büyük ihtimalle başarılı işlem için özel DLL gerekir. Aslında DLL, veriyi Windows tan alarak sizin programa iletecek. İçinde thread çalışacak. C# kullanan geliştirici bu derin işlerle meşgul olmak istemeyebilir. DLL iyidir.

Stm32 USB scope projesi varsa, büyük ihtimalle istediğiniz işi yapıyor demektir
 
Son düzenleme:
USB "bulk endpoint" kullanarak çok yüksek transfer hızları elde edilebilir. Ama senin sorun yüksek bant genişliğinden ziyade çok düşük tepki süresi diye anlıyorum. Bir windows makinada da bu konuda yapılacak şeyler kısıtlıdır. Kötü bir driver yüklenmiştir, işlemciyi meşgul eder ve USB portları yeterince hızlı servis edilemez windows tarafından ...
 
Aslında Çapraz bufferleme ile güzel bir alogirtma kurmuşum fakat transfer aşamasında problem yaşıyorum. Bu yüzden Veri bufferleme algoritmamı bozmadan Veriyi gönderirken string olarak göndermeye karar verdim. Bu şekilde PC ye gönderdiğim Veriyi herhangi bir terminal yazılımı ile görselleştirip sorunu anlamaya çalışacağım.
 
Bant genişliği anlamında bakarsak, seri port modunda bile rahatlıkla 1 Mbps bant genişliği elde edilebilir. Windows'da bunu denemişliğim var. Linux'ta ise 4 Mbps elde ediyordum. Hiçbir protokol, hand shake vs de kullanmadan. Buradaki kullanım senaryosu debug logging idi. Yani program çalışıyor ve o anda neler yaptığını seri port üzerinden bildiriyor.

1764144336503.png


Şöyle bir test düzeneği kurabilirsin: Firmware'den, sürekli artan 0x00 ... 0xFF byte'lar gönder. PC'den de sürekli okuma yap ve gelen byte'ların ardışık olduğunu kontrol et. Bu döngü eğer saatlerce hatasız çalışırsa, artık sorun kalmamış demektir.
 
Bellek erişimi ile ilgili bir problemim var.

ADC Kesmesi içerisinde aşağıdaki yapı ile double buffer yöntemi ile verileri alıyorum.

Kod:
        if(ADC_Buffer_Index<100)
        {
            if(ADC_Buffer_State==0)
            {
                TxBuffer1[ADC_Buffer_Index]=ADC_Converted_Value;
            }
            else
            {
                TxBuffer2[ADC_Buffer_Index]=ADC_Converted_Value;
            }
            ADC_Buffer_Index++;
        }

Daha Sonra 100'er ms aralıklara buffer'daki verileri başka bir tampon belleğe aktarıyorum.

Kod:
  if(ADC_Buffer_State==0)
            {
                memcpy(TempBuffer,TxBuffer2,100);
                DataSize=ADC_Buffer_Index;
                ADC_Buffer_State=1;
            }
            else
            {
                memcpy(TempBuffer,TxBuffer1,100);
                DataSize=ADC_Buffer_Index;              
                ADC_Buffer_State=0;
            }
ADC_Buffer_Index=0;

Daha sonra TempBuffer'da ki veriyi bazı işlemlerden sonra USB den gönderiyorum. Şöyle bir sorun var. ADC kesme süresi eğer 5ms'nin üstünde ise sorun yok. Ama ADC kesme süresi 2mS'nin altına inerse bu sefer veriler bozulmaya başlıyor. Sanırım ADC 2 ms de bir belleğe ulaşıp buffer'daki veriyi değiştirmeye çalışıyor. O sıra 100ms aralıklarla bende belleğe ulaşıp veriyi kopyalamaya çalışınca çakışma yaşanıyor. Bunu nasıl önlerim?
 
Son düzenleme:
dma kullan adc okumaların otomatik şekilde bir buffera yazılsın. ister circular istersen linear buffer belli bir indexe geldiğinde kopyalama işlemini yaparsın. 100 byte veri kopyalama bir arm işlemci için çok çok hızlıdır. 1us bile sürmemesi lazım.

 
Kesme kodudan taşmaya karşı bir koruma yok. ADC_Buffer_Index değeri 100'e ulaştığı anda ADC_Buffer_State değiştirilmesi lazım. Bu değişikliği yapınca da aynı anda USB kütüphanesine bir önceki buffer'i vermen lazım. TempBuffer'a kopyalamaya gerek yok.
 
DMA Kullanamıyorum. ADC Her bir veri aktarımında Step motora bir puls üretiyorum. Step motorun hareketi ile ADC data aktarımını senkron bir şekilde yapmam gerekiyor. ADC Örnekleme hızı değişiyor. Sorunun buffer tanımlarıyla alakalı olduğunu farkettim. Bu şekilde çözdüm gibi sorunu.

Veriyi String'e çevirmek gerekiyordu. Uart'dan gelen verileri görselleştirmesem sorunu anlamam zor olurdu. Şuanda 1300byte civarı bir veri gönderiyorum tek seferde. Bu veriyi paketleyip göndermemde 750us civarı sürüyor. USB CDC çok hızlı gerçekten.
 

Forum istatistikleri

Konular
8,590
Mesajlar
140,522
Üyeler
3,413
Son üye
Berkesaman

Son kaynaklar

Son profil mesajları

Abdullah karaoglan falcon_browning Abdullah karaoglan wrote on falcon_browning's profile.
selamın aleyküm ses sistemindeki cızırtıyı hallettınızmi
"Araştırma, ne yaptığını bilmediğinde yaptığın şeydir." - Wernher von Braun
“Kendi yolunu çizen kişi, kimsenin izinden gitmez.” – Nietzsche
Kim İslâm’da güzel bir çığır açarsa (güzel bir alışkanlık başlatırsa), onun sevabı ve kendisinden sonra ona uyanların sevapları, onların sevaplarından hiçbir şey eksilmeksizin ona da yazılır.
erdemtr55 taydin erdemtr55 wrote on taydin's profile.
Merhaba Taydin bey,
Gruba spms serisi yapıcak mısınız?
ben 3 sargılı toroid ile 2 adet flyback sürücek bir devre yapmayı düşünüyorum.size soracak sorularım vardı?
Back
Top