シリアルポートDMAによるデータ送信時のデータオーバーライドの問題


STM 32などのモノリシックマシンでは、プログラムの実行効率を向上させるため、シリアルポートを使用する場合、DMA方式でデータの送受信を行うことが多く、CPUは送信キャッシュ領域にデータを置くだけで離れることができる.
ただし、シリアルポート送信では参照呼び出しが使用されるため、データをコピーするのではなく、データ転送時に送信するポインタが転送されます.このような利点は、便利で迅速であるが、同時に結果をもたらす場合、そのデータがまだ送信されていない場合、次の列のデータはその送信バッファに入れられない.そうしないと、データオーバーライドの問題が発生する.すなわち、後の列のデータは前にまだ送信されていないデータをオーバーライドする.
一般的にこのようなデータオーバーライドの問題は、2つ以上のデータが連続して送信されたときに、最初のデータがまだ送信されていないうちに、後のデータが上書きされます.
送信前に前回データの送信が完了したか否かを判断し、送信が完了しないまま待機するとCPUの効率が低下する.あるいは,シリアルポート送信関数を使用するたびに前後に遅延を使用すれば,このような問題を解決できるが,そうすればDMAを使用する意味はない.
そこで、この問題を解決するために、筆者自身はダブルバッファを構築する方法を考えて、直接コードを貼りました.
void SendData(uint8_t* pData, uint16_t dataLen)
{
    uint8_t ret = 0;
	static uint8_t num = 0;
	static uint8_t buffer1[256] = {"\r
"}; static uint8_t buffer2[256] = {0}; // DMA , , if(num == 0) { ret = DMA_USART1_Transmit(buffer1, strlen((const char*)buffer1)); if(ret == 0) { num++; memset(buffer2, 0, sizeof(buffer2)); strcat((char*)buffer2, (char*)pData); } else { strcat((char*)buffer1, (char*)pData); } } else { ret = DMA_USART1_Transmit(buffer2, strlen((const char*)buffer2)); if(ret == 0) { num--; memset(buffer1, 0, sizeof(buffer1)); strcat((char*)buffer1, (char*)pData); } else { strcat((char*)buffer2, (char*)pData); } } }

上段コードでは関数SendData()は外部呼び出しであり,パラメータは送信が必要な文字列および送信データの長さである.関数DMA_USART1_Transmit()は真の送信関数であり、この関数では送信に成功すると0が返され、現在データが送信されている場合は1が返され、他の送信エラーが返されます.
この部分コードは、送信時にbuffer 1のデータを先に送信し、buffer 1のデータを送信する際に、その後送信する必要があるデータはすべてbuffer 2に格納し、buffer 1の送信が完了するとbuffer 2のデータを送信し、このとき送信されたデータはすべてbuffer 1に格納するという考え方である.このように交互に送信する方式を採用し,二重バッファを利用すれば,単一バッファのデータオーバーライド問題を効果的に解決できる.