やりたいこと
PIC24FでUARTの送受信をDMA転送をします。開発環境はMPLABで、MCC (MPLAB Code Configurator) によるコード生成を用います。
MCCでUARTの設定
まず、MCCでUARTの設定します。MCCはUIがゴチャゴチャして分かりにくいツールなので、大きいモニタで作業したほうが良いです。ノートPCだとつらいです。直感的でないUIなので、使い方は「MPLAB Code Configurator v3.xx ユーザガイド」を読んで確認しましょう。
ここではUART3を用いるものとします。Easy Setupで設定します。
- Enable UART にチェック。
- Baud Rate, Parity, Data Bits, Stop Bits, Flow Controlを適宜設定します。
- Enable UART Interrupts はチェックしません。 ←ここポイント
- Redirect Printf to UART はチェックしません。
あと、ピン割り当てもMCCで別途設定します。ここでは説明を省略します。
MCCでDMAの設定
続いてDMAもMCCで設定します。ここではChannel 0を送信に、Channel 1を受信に割り当てます。こちらもEasy Setupで設定します。
- Enable DMA にチェック。
- Low Address Limit, High Address Limitは0x800, 0xFFFFのままでもOK。
Channel 0 (送信用)の設定
- Enable Channel 0 をチェック。
- Enable Reloadはチェックしない。
- Transfer Mode は One Shot を選択。 ←ここポイント
- Trigger Source は UART3 TX を選択。
- Source Address Mode は Incremented を選択。
- Destination Address Mode は Unchanged を選択。
- Source Address, Destination Address, Transfer Count はここでは0のままにしておく。
- Data Size は 8bit を選択。 ←ここポイント
Channel 1 (受信用)の設定
- Enable Channel 1 をチェック。
- Enable Reloadはチェックしない。
- Transfer Mode は One Shot を選択。 ←ここポイント
- Trigger Source は UART3 RX を選択。
- Source Address Mode は Unchanged を選択。
- Destination Address Mode は Incremented を選択。
- Source Address, Destination Address, Transfer Count はここでは0のままにしておく。
- Data Size は 8bit を選択。 ←ここポイント
設定が終われば「Generate」ボタンを押してコードを生成します。
初期化処理
UAR3とDMAの初期化は、UART3_Initialize() と DMA_Initialize() ですが、これらは SYSTEM_Initialize() の中で呼ばれます。
送信処理
ここでは特にDMA割り込みは使用せず、送信完了、送信バイト数はポーリングすることにします。
static uint16_t s_sendSize; // 送信サイズをおぼえておく // 送信開始 // data: 送信データ // size: 送信サイズ void Uart_send(uint8_t *data, uint16_t size) { s_sendSize = size; // UART送信いったん無効 U3STAbits.UTXEN = 0; // DMAチャンネルをいったん無効 DMA_ChannelDisable(DMA_CHANNEL_0); // 転送サイズ、転送元 (メモリ)、転送先 (UART)の設定 DMA_TransferCountSet(DMA_CHANNEL_0, size); DMA_SourceAddressSet(DMA_CHANNEL_0, (uint16_t)data); DMA_DestinationAddressSet(DMA_CHANNEL_0, (uint16_t)&U3TXREG); // DMAチャンネルを有効 DMA_ChannelEnable(DMA_CHANNEL_0); // UART送信を有効(送信開始) U3STAbits.UTXEN = 1; } // 送信完了したか? bool Uart_sendComplete(void) { return DMA_IsOperationDone(DMA_CHANNEL_0); } // 送信したデータサイズ uint16_t Uart_sendSize(void) { // 送信したサイズ = 送信すべきサイズ - 残りサイズ uint16_t size = s_sendSize - DMA_TransferCountGet(DMA_CHANNEL_0); return size; }
受信処理
ここでは特にDMA割り込みは使用せず、受信バイト数はポーリングすることにします。
static uint16_t s_recvSize; // 受信サイズをおぼえておく // 受信開始 // data: 受信データの格納先 // size: 受信最大サイズ void Uart_recv(uint8_t *data, uint16_t size) { s_recvSize = size; // DMAチャンネルをいったん無効 DMA_ChannelDisable(DMA_CHANNEL_1); // UART受信バッファオーバーランクリア U3STAbits.OERR = 0; // UART受信バッファ読み捨て volatile uint16_t rx = U3RXREG; rx = U3RXREG; rx = U3RXREG; rx = U3RXREG; // 転送サイズ、転送元 (UART)、転送先 (メモリ)の設定 DMA_TransferCountSet(DMA_CHANNEL_1, size); DMA_SourceAddressSet(DMA_CHANNEL_1, (uint16_t)&U3RXREG); DMA_DestinationAddressSet(DMA_CHANNEL_1, (uint16_t)data); // DMAチャンネルを有効 DMA_ChannelEnable(DMA_CHANNEL_1); } // 受信したデータサイズ uint16_t Uart_recvSize(void) { // 受信したサイズ = 受信最大サイズ - 残りサイズ uint16_t size = s_recvSize - DMA_TransferCountGet(DMA_CHANNEL_1); return size; }