Neden her zaman DMA'yı STM32'de UART ile kesintiler lehine kullanmıyorsunuz? [kapalı]


9

Geçen ay UART'ın (MIDI için) STM (STM32F103C8T6) ile kesintileri kullanarak çok fazla başarı elde etmeden çok zaman harcadım.

Ancak, bu akşam DMA kullanarak oldukça hızlı çalıştı.

DMA'yı okuduğum kadarıyla daha hızlı ve CPU'yu rahatlattığından, neden her zaman DMA'yı kesintiler lehine kullanmıyorsunuz? Özellikle STM32'de oldukça bazı sorunlar var gibi görünüyor.

STM32CubeMx / HAL kullanıyorum.


2
Neden olmasın? Bu ya bir görüş meselesi, hangi teknik nedenin mümkün olduğunu tahmin etmek isteyen ya da aynı şekilde çok geniş ve dolayısıyla buraya ait bir soru değil. Rastgele bir örnek vermek gerekirse, DMA verileri talep etmede daha fazla gecikme anlamına gelir, özellikle de birden fazla karakter toplamasına izin vermedikçe gerçek bir fayda elde edemezsiniz. Genellikle bu iyi olabilir, bazen olmayabilir.
Chris Stratton

6
Çalışmaya ara vermek haftalar sürüyorsa, bunun nedeni göreve yanlış bir şekilde yaklaşmanızdır; DMA'nın çalışması daha uzun sürebilir - aslında daha karmaşık bir görevdir, bu nedenle daha basit olandan daha karmaşık bir görevin görünür kolaylığı, muhtemelen mekanizmanın kendisine değil, her biriyle rehberlik etmek için kullandığınız kaynaklara gelir.
Chris Stratton

5
Dma'nın cpu'yu serbest bıraktığını asla varsaymayın, bazen evet, cpu devam eder, bazen hiçbir işlemci dma motoru için veriyolunu tutmak için dondurulur. Bunu bir kol uygulaması ile yapmak önemsiz, bu yüzden sadece tüm kolların bu şekilde olduğunu ve tüm x86'ların bu şekilde veya her neyse, o kadar basit olmadığını, her zaman sistem tasarımını incelemeniz ve belki de biraz hacklemeniz gerektiğini söyleyemeyiz. Sahip olduğunuz çip, kol çekirdeğini çok iyi serbest bırakabilir, bu sadece dma hakkında bir yorumdur. Sorunuza gelince, devam edemezsiniz mantıklı değil ve sadece anket yapamıyorsanız dma + int muhtemelen tam çözümdür.
old_timer

5
Kesintiler STM32F seri portunda oldukça önemsizdir. Neden bazılarınızın yanlış yaptığınızı tespit etmeye çalışabilmemiz için neden kodunuzla bir soru yayınlamıyorsunuz? Altta yatan sorunun ne olduğunu anlamadan çalışana kadar kodu kesmek asla iyi bir fikir değildir.
Jon

7
Benim (öyle değil) alçakgönüllü görüşüme göre, bu korkunç, şişkin Küp'ü kullanmanın aşağı taraflarından biridir. Yazılımı sıfırdan yazın, tam olarak UART'ın nasıl çalıştığını öğreneceksiniz (çünkü yapmanız gerekir), çevre birimini çok daha iyi anlayacaksınız ve uzun vadede size çok zaman kazandıracak.
DiBosco

Yanıtlar:


24

DMA CPU'yu rahatlatır ve böylece aynı çekirdek üzerinde çalışan diğer kesintiye dayalı uygulamaların gecikmesini azaltabilirken, bununla ilişkili maliyetler vardır:

  • Yalnızca sınırlı sayıda DMA kanalı vardır ve bu kanalların farklı çevre birimleriyle nasıl etkileşime girebileceği konusunda sınırlamalar vardır. Aynı kanaldaki başka bir çevre birimi DMA kullanımı için daha uygun olabilir.

    Örneğin, her 5 ms'de bir toplu I2C aktarımınız varsa, bu DMA için UART2'ye gelen bir hata ayıklama komutundan daha iyi bir aday gibi görünüyor.

  • DMA'yı kurmak ve sürdürmek kendi başına bir maliyettir . (Normal olarak, DMA'nın ayarlanması, bellek yönetimi, daha fazla çevre birimi, DMA kullanarak kendi kendine kesintiler ve DMA dışında ilk birkaç karakteri ayrıştırma olasılığınız nedeniyle, karakter başına kesintiye dayalı aktarım ayarlamaktan daha karmaşık olarak kabul edilir. her neyse, aşağıya bakın.)

  • DMA ek güç kullanabilir , çünkü saatin çekilmesi gereken çekirdeğin başka bir alanıdır. Diğer yandan, çekirdek destekliyorsa, DMA aktarımı devam ederken CPU'yu askıya alabilirsiniz.

  • DMA, çalışmak için bellek arabellekleri gerektirir (çevre biriminden çevre birimine DMA yapmıyorsanız), bu nedenle onunla ilişkili bir miktar bellek maliyeti vardır.

    (Bellek maliyeti olabilir Çerezsiz kesmelerini kullanırken de orada, ancak iletiler hemen kesme içine yorumlanır eğer o da beni çok daha küçük veya hiç yok olabilir.)

  • DMA bir gecikme oluşturur çünkü CPU yalnızca aktarım tamamlandığında / yarı tamamlandığında bildirim alır (diğer yanıtlara bakın).

  • Bir halka arabelleğine / aralığından veri aktarımı hariç, ne kadar veri alacağınızı / göndereceğinizi önceden bilmeniz gerekir .

    • Bu, karakter başına kesmeler kullanarak bir iletinin ilk karakterlerini işlemek gerektiği anlamına gelebilir: örneğin, bir XBee ile arayüz kurarken, önce paket türünü ve boyutunu okur ve ardından tahsis edilen ara belleğe bir DMA aktarımını tetiklersiniz.

    • Diğer protokoller için, yalnızca mesaj sonu sınırlayıcıları kullanıyorlarsa, bu hiç mümkün olmayabilir: örneğin, '\n'sınırlayıcı olarak kullanılan metin tabanlı protokoller . (DMA çevre birimi bir karakterle eşleşmeyi desteklemedikçe.)

Gördüğünüz gibi, burada dikkate alınması gereken çok sayıda ödünleşim var. Bazıları donanım sınırlamalarıyla (kanal sayısı, diğer çevre birimleriyle çakışmalar, karakterlerle eşleştirme) ilgilidir, bazıları kullanılan protokole (sınırlayıcılar, bilinen uzunluk, bellek arabellekleri) dayanır.

Bazı anekdot kanıtları eklemek için, tüm bu değiş tokuşlarla çok farklı protokollere sahip birçok farklı çevre birimi kullanan bir hobi projesinde karşılaştım. Çoğunlukla "ne kadar veri aktarıyorum ve ne sıklıkta yapacağım?" Sorusuna dayanarak bazı ödünleşmeler yapıldı. Bu temelde basit kesintiye dayalı aktarımın CPU üzerindeki etkisi hakkında kabaca bir tahmin verir. Böylece, aynı DMA kanalını kullanan birkaç saniyede bir UART aktarımı üzerinden her 5 ms'de bir I2C aktarımına öncelik verdim. Diğer UART aktarımı daha sık ve daha fazla veri ile gerçekleşirken, daha nadiren gerçekleşen başka bir I2C aktarımına göre öncelik kazanmıştır. Hepsi değiş tokuş.

Tabii ki, DMA kullanmanın da avantajları var, ancak istediğiniz şey bu değil.


Ayrıntılı cevabınız için teşekkürler. MIDI en kritik kısmı olacak, bu yüzden DMA bunun için uygun olduğunu düşünüyorum (hız düşük olmasına rağmen: 31250 baud). Yeterli DMA kanalım var, daha sonra 4 USART kullanırken başka bir STM32 kullanacağım. CPU'yu askıya almam gerekmiyor, çünkü 5V USB gücüne sahip olacak ve mesajlar arasında işlem yapmam gerekiyor (ana döngüdeki mesajları işlemek için). 256 bayt okuma ve 256 bayt iletim tamponu var. Gerekirse daha sonra artırabilirim. STM32f103c8t6'nın 20 KB RAM'i var, kullanacağım STM'nin 192 KB'si var.
Michel Keijzers

Ve bana nasıl gelişeceğime dair çok iyi bir fikir verdin. Şimdiye kadar her zaman 1 bayt okudum ve tam (MIDI) bir mesaj alındığında sürekli kontrol ediyorum. Ama ilk baytı okuyabilirim ve buna bağlı olarak çoğunlukla boyut bilinir ve geri kalanını isteyebilir. Bu bana başka bir küçük tampon maliyeti ama sorun değil.
Michel Keijzers

DMA ile tek bayt okumak çok verimsizdir. Daha düşük gecikme ve daha yüksek verimlilik için, boyutu bilinceye kadar karakter başına kesmeler kullanmak ve daha sonra DMA'ya geçmek uygun olacaktır.
Jonas Schäfer

Kesmeler (DMA olmadan) kullanarak çok fazla sorun yaşadım, 1 bayt DMA almak kullanacağımı düşünüyorum ve bundan sonra kaç bayt beklediğimi ve daha fazla almak için bir DMA isteği yapacağımı biliyorum.
Michel Keijzers

6
Bu muhtemelen bir hatadır - basit kesme kodunuzu DMA olmadan düzeltmelisiniz .
Chris Stratton

10

DMA kullanmak genellikle her karakterde bir kesinti yapmamanız, daha ziyade yalnızca bir karakter tamponu alındıktan (veya iletildikten) sonra kesinti yaptığınız anlamına gelir. Bu, bu karakterlerin işlenme gecikmesini artırır - ilk karakter, arabellekteki son karakter alınana kadar işlenmez.

Bu gecikme, özellikle MIDI gibi gecikmeye duyarlı bir uygulamada, burada birkaç msn ve canlı performanslar için ciddi oynanabilirlik sorunları ekleyebileceğiniz kötü bir şey olabilir.


Yaptığım şey bir seferde 1 bayt (yani 1 baytlık 'DMA' tamponu) almak ve bu baytın her DMA geri çağrısından sonra, elle işlediğim bir halka tamponunda saklamak için. Ana döngümde tam MIDI mesajlarını kontrol edip işlemeyi planlıyorum.
Michel Keijzers

3
DMA genellikle birden çok bayt almak için kullanılır ve yalnızca hepsi alındığında kesilir. Zaman sadece bir byte sonra kesintiye normaldir değil bunun için DMA kullanarak ekstra komplikasyonu ne anlamı var: DMA kullanarak bu beni meraklandırıyor yüzden?
Steve Melnikoff

5
@MichelKeijzers Öyleyse yaptığınız şey, kesinti odaklı uygulamalarda yaptığınızla hemen hemen aynı. Bu nedenle, bu durumda DMA kullanmanın bir faydası yoktur ve orijinal sorununuz muhtemelen DMA tarafından değil, (ISR, kurulum) kodunuzu yeniden yazmanızla çözülür.
JimmyB

@JimmyB ... teşekkürler ... ancak aşağıdaki Jonas cevabı nedeniyle, mesaj uzun olduğu için bu baytın okunması için bir iyileştirme yapacağım. Bunu ilk baytı aldıktan sonra biliyorum (çoğu durumda). Kesintiler üzerinde DMA kullanmak daha fazla fayda sağlayacaktır.
Michel Keijzers

8

DMA kesintilerin yerini tutmaz - genellikle birlikte kullanılırlar! Örneğin, bir UART üzerinden veri göndermek için DMA kullanıyorsanız, gönderme işleminin ne zaman tamamlandığını bildirmek için yine de bir kesintiye ihtiyacınız vardır.


Gerçekten de, belki sadece STM32'de (saf DMA olmayan) kesme mekanizması, doğrudan DMA'ya kıyasla biraz sakar.
Michel Keijzers

2
@duskwuff Pek değil; DMA'nın ne zaman yapıldığını görmek için anket yapabilirsiniz ve bunu yapmak isteyebilirsiniz, çünkü DMA kullanmanın temel nedenlerinden biri, programınız alınan program üzerinde hareket edebileceği bir duruma gelene kadar seri bağlantı noktasıyla uğraşmak zorunda kalmamaktır. veri. Veya giden DMA için, gönderme arabelleğine daha fazlasını eklemenin mümkün olup olmadığını görmek için yalnızca anket yapabilirsiniz.
Chris Stratton

1
@MichelKeijzers: Belirli bir çipi IDK yapın, ancak genellikle DMA'ya alternatif tam anlamıyla kesintiye uğramaz, programlanmış-IO (bir G / Ç kaydından veri okumak / yazmak için CPU talimatlarını kullandığınız yerde). Bir kesme işleyicisinde, tipik olarak bir okuma yaparsınız ve belki de ilk karakteri okurken bir karakterin gelmesi durumunda, özellikle de başka bir kesmeyi tetiklemezse, başka bir okuma yaparsınız. Veya böyle bir tampon varsa dahili bir tampon boşalana kadar okuyun. Açıkçası PIO için daha fazla kesintiye ihtiyacınız var ve bunları farklı şekilde ayarlamanız gerekiyor.
Peter Cordes

@ChrisStratton İyi bir nokta ... Şimdiye kadar iletimin mümkün olup olmadığını kontrol etmedim, sadece bir şey iletiyorum, iyi olup olmadığını kontrol etmiyorum. Muhtemelen değilse, daha sonra tekrar denerim.
Michel Keijzers

@PeterCordes Görünüşe göre STM32'nin DMA için yeterli kesintileri var ve her seferinde sadece 1 bayt okuyorum. En basit STM32 (F103c8t6) bile yeterli DMA bağlantı noktasına / kesintisine sahiptir.
Michel Keijzers

5

DMA kullanımı, UART çevresel kullanımının diğer tüm düşüncelerinin ötesinde bazı ilginç sorular ve zorluklar getirir. Size birkaç örnek vereceğim: uC'nizin diğer cihazlarla bir RS485 (veya her neyse) veriyolunda oturduğunu varsayın. Otobüste birçok mesaj var, bazıları uC'niz için tasarlanmış, bazıları değil. Ek olarak, bu veri yolu komşularının hepsinin farklı bir veri protokolü konuştuğunu varsayalım, bu da mesaj uzunluklarının farklı olduğunu gösterir.

Yalnızca DMA kullanılırken ortaya çıkan bazı sorular:

  • ne zaman araya gireceğim?
    • DMA'lar yalnızca önceden belirlenmiş miktarda veri aktardıklarında kesmeyi sever.
    • DMA kesintisini tetiklemek için asla yeterli veri almazsanız ne yaparsınız?
  • DMA kesintiye uğradığında yalnızca kısmi bir mesaj alırsanız ne olur?
  • RX tamponlarınız neye benziyor? Bunlar doğrusal mı dairesel mi?
    • DMA, yalnızca adres sınırına uyması, ancak dairesel tampon sistemindeki diğer işaretleyicileri aşmakta herhangi bir sorun yaşamaması anlamında olağandışı dairesel bir tampon katılımcı olabilir.

Her neyse, sadece düşünce için yiyecek.


Bu düşünceler için teşekkürler. Şu anda her zaman 1 bayt alıyorum ve bir halka arabelleğinde saklıyorum, çünkü mesajlarım (MIDI) farklı uzunluklara sahip olabilir ve bir sonraki adımda ne yapacağımı bilmiyorum. Ana döngümde, bunları işlemek için tam mesajlar olup olmadığını kontrol ediyorum (ve tamamlandıysa, halka arabelleğinden kaldırırım). Bu yüzden her zaman yeterli veri alacağım (baytları kaçırmazsam, bunu kontrol etmem gerekir). RX arabelleğim sadece 1 bayt, ancak bir halka / dairesel arabelleğe kopyalarım. Dolu olup olmadığını kontrol etmedim (eklemeniz gerekir).
Michel Keijzers

Hey, endişelenme. Eminim başvurunuz iyi programlanmış olacaktır. Diğerlerinin de belirttiği gibi, DMA harika, ama özgür değil hepsi. Kullanmadan uzaklaşabiliyorsanız mevcut olmayan sisteme ekstra hususlar getirir.
pgvoorhees

Umarım, hala bir acemiyim.
Michel Keijzers

3

Alma tarafında (hatırladığım gibi) DMA, bir karakter eşleşmesinde veya terminal sayımında sona erer. Bazı protokoller ve birçok etkileşimli uygulama bu modele kolayca uymaz ve her şeyi karakter karakter ele almanız gerekir. DMA teknikleri, iletişim bağlantısının güvenilir olmadığı durumlarda da kırılgan olabilir, akışta tek bir karakteri kaybetmek DMA durum makinenizi kolayca bozabilir.


Gerçekten bayt bayt alıyorum ve daha sonra işlemek için manuel olarak bir halka arabelleğe kopyalıyorum.
Michel Keijzers

1

Şu anda birkaç projede STM32CubeMx / HAL kullandım ve ürettiği UART taşıma yazılımının alma tarafında kesin eksiklikler olduğunu gördüm.

İletimde normalde bir veri bloğu veya metin satırı göndermek istersiniz. Bu durumda, veri aktarımının ne kadar sürdüğünü önceden biliyorsunuz ve bu nedenle DMA'yı kullanmak bariz bir çözümdür. Aktarım tamamlandıktan sonra bir kesinti elde edersiniz ve ana kodunuza iletimin tamamlandığını belirtmek için UART TX tam geri arama işlevini kullanabilir ve başka bir veri bloğu gönderebilirsiniz.

Veri alımı söz konusu olduğunda, ST tarafından sağlanan işlevlerin tümü, gönderen cihazın göndermeye başlamadan önce size kaç karakter vereceğini bildiğinizi varsayar. Normalde bu bilinmemektedir. Kesme işlevi, alınan verileri arabelleğe yerleştirir ve yalnızca önceden tanımlanmış sayıda karakter alındığında kullanılabilir veriler olduğunu gösterir. Sıralı tek karakter aktarımlarını ayarlayarak veri almak için DMA veya kesinti işlevini kullanmaya çalışırsanız, bunların her birinin kurulum süresi, en yavaş veri hızlarından (yapacağınız baud hızı) başka bir şeyde karakterleri kaybedeceğiniz anlamına gelir. Verileri kaybetmeye başlamak işlemcinizin saat hızına bağlı olacaktır) ve işlemciyi aşırı yükleyecek ve diğer işlemler için talimat döngüsü bırakmayacaktır.

Bunu elde etmek için, verileri küçük bir yerel dairesel tamponda saklayan ve alınan verilerin hazır olduğunu belirtmek için ana kod (RTOS sayma semaforu) tarafından okunan bir sayıyı ayarlayan kendi kesme işleyici fonksiyonumu yazdım. Ana kod daha sonra boş zamanlarında bu arabellekten veri toplayabilir, veri toplanmadan önce yerel ara belleğin taşmaması koşuluyla verilerin toplanmasında bir miktar gecikme olup olmadığı önemli değildir.


Ben de aynısını yapıyorum (sanırım). Bir seferde 1 bayt okudum ve döngüsel bir tamponda saklıyorum ve ana döngüde tam mesajlar için kontrol etmek istiyorum. Gerçi biraz geliştirilebilir.
Michel Keijzers

Her seferinde DMA kurulumunun işlemcimi / eksik karakterleri 31.250 baud'da aşırı yükleyeceği sorunuyla karşılaşabilir miyim?
Michel Keijzers

1
DMA'yı aynı anda birkaç karakter aktarmak üzere ayarladığınız sürece bundan daha fazla sorun olmayacaktır. 115200 ve daha üstü çalışan 4 UART'ım ve sorunsuz DMA kullanan I2C'im var. UART iletimlerinin tümü ~ 20 bayt veya daha uzundur. Sorun UART (80MHz, 9600baud'da L4 işlemci) almak için DMA kullanmaktı.
uɐɪ

Şu anda bir seferde 1 bayta ayarladım, ancak geliştirebilirim (ilk bayt yaparak ve daha fazla bayt gerektiğini kontrol etmekten daha fazla).
Michel Keijzers
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.