DMAモジュール
パターンマッチモード・チャンネルチェインモードによる
UART RX、TX折り返し制御
(→プロジェクトファイル(Harmony Ver.2.04版 ) ダウンロード)
DMAモジュールには、チャンネルチェインモード 及びパターンマッチモードと呼ばれる制御がありますが、ここではこの2つをつかった Tera Term(UART)の送受信の例を紹介します。 ➀ チェンネルチェインモード …… DMAチェンネルの転送が終了後、自動的に別のDMAチャンネルの転送を実行する ➁ パターンマッチモード …… あらかじめ設定しておいたパターン(データ)と一致するパターンが転送データの中に現れた場合転送を終了する。 |
PCのキーボードからTera Termに文字を入力して 最後に^(キャロット)をキーインすると 入力した文字(含む^)がまとめて返信されます。
<仕様>
・PIC32MZのDMAモジュールを用いパターンマッチモード転送 及びチェンネルチェインモード転送を行う。
・Tera Term を用いて PCとPIC32MZ間のUART(U6RX、U6TX)送受信を行う。
・U6RXでレジスタU6RXREGに 受信したデータをバッファメモリに転送するチャンネルをDMAチャンネル0(DMA0)に設定する。
・バッファメモリのデータをU6TXのU6TXREGレジスタに転送するチャンネルをDMAチャンネル1(DMA1)に設定する。
・データの中に^(キャロット)があった場合は転送を終了する。
(パターンマッチモードで使用するパターンは ^(キャロット)とする)
・DMAチャンネル0の転送が終了したら DMAチャンネル1の転送が開始されるようにする。
・DMA転送されたバッファメモリの内容をキャラクタ液晶に表示する。
<外観>PIC32MZ評価ボード(→購入方法)を使った実験品の外観です。
汎用モジュール評価ボード(段積みボード)には本テーマと関係ない部品が多々実装されています。
<動作結果> (→ 動画:1080pのHD動画を見ることができます。)
RX入力データ(Hellow World !!)受信済み | 備考 |
|
➀ RX入力データ(^ :DMAパターンマッチデータ)受信前 |
➁ RX入力データ(^ :DMAパターンマッチデータ)受信後 |
|
![]() |
![]() |
キャラクタ液晶下段には、 メモリramBuf[ ]が表示されて います。 |
<解説>以下に、記載してある内容は要点だけです。 詳細はプロジェクトファイルを精読願います
(以下は、Harmony v2.04 をもとに作成しています。最新のバージョンとは異なることがあるかもしれませんので注意してください。)
■ MHC設定
■ Options
■ Pin Settings
項目 | ④ポート設定 |
MHC | ![]() |
備考 | デフォルトからの変更要領: RC2/Function: U6TX (U6のTX設定) RG9/Function: U6RX (U6のRX設定) |
■ キャラクタ液晶表示のライブラリ 1lcd_lib_XC32.h と 1lcd_lib_XC32.cを main.cと同じフォルダにコピーして、プロジェクトに追加します。
(詳細→ キャラクタ液晶表示方法 参照)
■ app.cに、青字部分を追加します。
➀インクルードファイルを追加します。stdio.hがないと、sprintf( )がコンパイラのバージョンによってコンパイルで警告となることがあります。
#include <stdio.h>
➁DMAチャンネルのハンドルを宣言します。 チャンネルDMA0からの受信元、チェンネルDMA1の送信元となるメモリramBuf[ }を宣言します。
尚、メモリの宣言ではアトリビュート修飾子__attribute__((coherent))をつかってキャッシュは使わないようにコンパイラに指示します。
SYS_DMA_CHANNEL_HANDLE channelHandle0;
SYS_DMA_CHANNEL_HANDLE channelHandle1;
unsigned char __attribute__((coherent)) ramBuf[256 + 1]; // transfer
buffer
int delay_Clock = 200000000; //システムクロック:200MHz
char __attribute__((coherent)) Buf[32];
③NOPを用いた 1μsec、1msecの遅延関数 delay_usec( )、delay_ms( )をつくります。
void delay_us(volatile unsigned int usec) //1μsec遅延
{
volatile int count;
count = (int)(delay_Clock/20000000)*usec;
……
……
④UARTの文字列送信関数をつくります。
void Write_Byte(char chr) //1バイト送信関数
{
PLIB_USART_TransmitterByteSend(USART_ID_6, chr); //送信バッファーに1バイト書込み・送信
// U6TXREG = chr; ////送信バッファーに1バイト書込み・送信
while (!PLIB_USART_TransmitterIsEmpty(USART_ID_6)); //送信バッファーが空になるまで待つ
//while(!U6STAbits.TRMT); //送信バッファーが空になるまで待つ
⑤myDMA_init( )の中でDMAに係る初期化をおこないます。
SYS_DMA_ChannelAllocate( )関数でDMAオブジェクトのハンドルを取得します。
SYS_DMA_ChannelTransferAdd( )関数でDMA転送元アドレス、転送先アドレス、転送元データサイズ、転送先データサイズ、セルサイズ(1回の転送サイズ)などを
設定します。
SYS_DMA_ChannelSetup( )関数でいろいろなモードを設定します。
例: チャンネル起動モード、パターンマッチ終了モード、チャンネルチェインモード、DMA転送開始のトリガモード など
SYS_DMA_ChannelSetupMatchAbortMode( )関数で パターンマッチの詳細について設定します。
例: パターンマッチデータ、パターンマッチデータのサイズ(1バイト or 2バイト)、2バイトのパターンマッチにおいて1バイトだけパターンマッチした場合の有効/無効処理
void myDMA_init(void)
{
//Harmony DMAライブラリ関数制御
channelHandle0 = SYS_DMA_ChannelAllocate(DMA_CHANNEL_0); //DMA0チャンネルオープン
& ハンドル取得
channelHandle1 = SYS_DMA_ChannelAllocate(DMA_CHANNEL_1); //DMA0チャンネルオープン & ハンドル取得
SYS_DMA_ChannelTransferAdd(channelHandle0, (const void *)&U6RXREG,
1, (const void *)&ramBuf , 256, 1 ); //DMA0転送諸元設定
SYS_DMA_ChannelTransferAdd(channelHandle1, (const void *)&ramBuf,
256, (const void *)&U6TXREG, 1, 1 ); //DMA1転送諸元設定
SYS_DMA_ChannelSetup(
channelHandle0,
SYS_DMA_CHANNEL_OP_MODE_MATCH_ABORT | //パターンマッチ終了モード &
SYS_DMA_CHANNEL_OP_MODE_AUTO, //チャンネル自動起動モード
DMA_TRIGGER_USART_6_RECEIVE); //トリガ: U6RX 受信完了
SYS_DMA_ChannelSetup(
channelHandle1,
SYS_DMA_CHANNEL_OP_MODE_MATCH_ABORT | //パターンマッチ終了モード &
SYS_DMA_CHANNEL_OP_MODE_CHAIN_HIGH, //チャンネルチェインモード
DMA_TRIGGER_USART_6_TRANSMIT //トリガ: U6TxのバッファーU6TXREGにデータがレジスト(登録)完了となった時
);
SYS_DMA_ChannelSetupMatchAbortMode(channelHandle0, '^', // ^(キャロット)をパターンマッチデータにセット
DMA_PATTERN_MATCH_LENGTH_1BYTE, //パターンマッチデータは1バイト
SYS_DMA_CHANNEL_IGNORE_MATCH_DISABLE,
0);
SYS_DMA_ChannelSetupMatchAbortMode(channelHandle1, '^', // ^(キャロット)をパターンマッチデータにセット
DMA_PATTERN_MATCH_LENGTH_1BYTE, //パターンマッチデータは1バイト
SYS_DMA_CHANNEL_IGNORE_MATCH_DISABLE,
0);
}
⑥void APP_Initialize ( void )関数の中でmyDMA_init( )を実行して DMA関係の初期化をおこないます。
myDMA_init();
⑦PIC起動時に キャラクタ液晶に表示する文字を設定します。
lcd_init(); // LCD初期化
lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF
lcd_clear();
lcd_cmd(0x80); //1目の先頭へ
sprintf(Buf,"DMA Match_Chain ");//
……
……
⑧キャラクタ液晶の文字表示において一部の制御文字を表示しようとすると制御が飛んでしまうので改行に係る制御文字以外はスペース文字に変換しておきます。
int i;
for(i = 0; i < 256; i++) // %c非表示文字をSpace表示化 //これを実行しないと制御が飛んでしまう。
{
if(((ramBuf[i] >= 0x00) && (ramBuf[i] <= 0x1F)) &&
(ramBuf[i] != '\r'))ramBuf[i] = ' '; //改行は除く
if(ramBuf[i] >= 0x80) ramBuf[i] = ' ';
}
⑨バッファメモリramBuf[ ]に記憶されているデータをリアルタイムで表示します。
lcd_cmd(0x80); //1目の先頭へ
sprintf(Buf,"RAM is below ");
lcd_str(Buf); //液晶表示
lcd_cmd(0xC0); //2行目の先頭へ
sprintf(Buf,"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
ramBuf[0],ramBuf[1],ramBuf[2],ramBuf[3],ramBuf[4],ramBuf[5],ramBuf[6],ramBuf[7],
ramBuf[8],ramBuf[9],ramBuf[10],ramBuf[11],ramBuf[12],ramBuf[13],ramBuf[14],ramBuf[15]);
lcd_str(Buf); // 開始メッセージ1行目表示
以下、app.c