31684


SPIマスタ等の自分からクロックを出力する通信の場合は、何バイト受信するかを自分で把握できているのでDMAを仕掛けるのは簡単ですが、UARTの場合、非同期でいつ来るかわからないデータを待ち受けてるのが普通だと思います。

いつ受信するかわからない。何バイト受信するかわからない、という状況なので、指定回数受信したらDMA割込み、というシンプルな使い方ができず、実装をどうすればいいのか悩んでいます。

パッと思いついたのは、下記で示しているように、贅沢にもバッファを3本用意して、周期的にDMAバッファを切り替えるという方法です。

[code]

    for (;;)
    {
        メインループ処理;
    
        if (前回の処理から適当な期間が経過した)
        {
            int count; // DMAカウンタ
            int prev;
            UART割込み無効;
                count = getDMACount();
                prev = index;
                index ^= 1;   // DMAバッファインデックスの切替
                // この区間で他の割込み処理が入るとオーバーランが発生しそうなので全割込み禁
                // 止にしておいた方がよい？
                setDMABuffer(duble_buffer[index]);
            UART割込み有効;
    
            if (count > 0)
            {
                // ダブルバッファとは別に用意したメインのバッファの末尾にコピーする。
                memcpy(main_buffer + last, duble_buffer[prev], count);
                last += count;
            }
        }
    }
    
[/code]

こういう処理ってほとんどやることは決まっていると思うので、定石みたいな実装があると思うのですが、何か実装の参考になる文献や入手可能なソースコードはないでしょうか。Linuxカーネルのソースもちょっと覗いてみましたが、該当しそうな部分が見つけれらませんでした。


CC BY-SA 3.0
2017-01-06T17:03:28.947
31679
2017-03-03T14:55:36.350
17238
question
c++ c
UARTの受信DMA処理の定石


以下オイラの私見です。期待している回答とは異なるかもしれません。

オイラは２０年以上マイコンプログラムを書いている身ですが、シリアル通信の受信側で DMA を使ったことは数えるほどしかないです。

他機器や同一機器内別マイコンとの通信をする機会はよくありますが、原理的に「通信はエラーがありうるもの」です (エラー発生確率は ppm オーダーだったり
ppb オーダーだったりしますが) 可能性は低くても対処しないわけにはいかないので、エラー発生時に「途中でやめるには別手続きが必要な DMA
」は使い勝手が悪いのです。

USB の Isochronous 通信など  
\- Transaction のエラー検出・訂正はハードウエア側が勝手にやってくれる  
\- Transaction 成功時には事前に決めたバイト数が必ず得られる  
\- Transaction 失敗時にマイコンソフトが何かする必要が一切ない  
ような案件以外では DMA 使ったことないです。

定石があるとしたら、すでに質問中に書かれている通り、  
\- 定期的に、事前に決めた固定バイト長の通信がある場合に、限定的に DMA を使う  
くらいでしょうか？  
それ以外では（特に受信側で） UART 関連で DMA を使うことはまず _ない_ です。

「使わないのが定石」なのだと、オイラ個人的には思います。


CC BY-SA 3.0
2017-01-06T23:24:43.860
31684
2017-01-06T23:24:43.860
8589
31679
answer


DMAって、バス接続されたCPUとRAMと周辺回路ブロックがある場合に、周辺回路ブロック内のSRAMからRAMへCPUを介さずに転送する仕組みだと理解していますが、質問者の想定と合っているでしょうか？

その前提に立てば、C言語で書いたバッファ(配列)はRAM上にあるわけなので、そのバッファに代入するということはCPUを介して周辺回路ブロック内のSRAMからRAMに転送しているわけで、DMAで高速化すべき部分は既に(遅い処理を使って)終わらせてしまっているのではないでしょうか？

16ビット程度のマイコンのUART回路ブロック内のSRAMって高々1キャラクタ(1～2バイト)分しか無いと思いますので、わざわざDMA使っても知れてるのではないかというのが私見です。

ただもっと高性能なマイコンだと回路ブロック内のSRAMが巨大でそのうち何バイトまで溜まったらDMAに連鎖するとかいったレジスタ設定を持つものもありますが、CPU側から見ると、受信したはずのデータがCPUから見える(RAMに転送される)まで不定期に遅延が発生するといった現象にもなり、結局、DMAを使わないか1バイトでも受信したらDMAを発動させるみたいな変な使い方にもなります。

なおLinuxのユーザランドでの定石としては、openで取得したファイルディスクリプタをselectとかepollとかで登録して、マイコンで言うUART受信割り込みのような使い方をします。その辺はソケット通信をしているサーバプログラム(webサーバとか)のソースやHowTo本を見るとよく見かけます。


CC BY-SA 3.0
2017-01-08T02:59:57.200
31702
2017-01-08T02:59:57.200
20139
31679
answer


PCの事は良くわかってない組込み屋です。  
部分的な回答ですみません。  
UART割込み無効;〜UART割込み有効;の間は全割り込み禁止ではなくて、  
割り込みコントローラをいじって割り込み優先度を調整する方が定石的に感じます。  
同じように、UARTの受信を妨害してしまう割り込み禁止区間をできるだけ削って、  
割り込み優先度を調整して対処してはどうでしょうか？


CC BY-SA 3.0
2017-03-03T14:55:36.350
33076
2017-03-03T14:55:36.350
20904
31679
answer