YS電子工作ラボ

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転送されたバッファメモリの内容をキャラクタ液晶に表示する。
 


<回路図> (→PDFファイル



<外観>PIC32MZ評価ボード(→購入方法)を使った実験品の外観です。
     汎用モジュール評価ボード(段積みボード)には本テーマと関係ない部品が多々実装されています。



<動作結果> (→ 動画:1080pのHD動画を見ることができます。)

 RX入力データ(Hellow World !!)受信済み  備考 
                    

 RX入力データ(^ :DMAパターンマッチデータ)受信前 
 ➁
 RX入力データ(^ :DMAパターンマッチデータ)受信後  
キャラクタ液晶下段には、
メモリramBuf[ ]が表示されて
います。





<解説>以下に、記載してある内容は要点だけです。 詳細はプロジェクトファイルを精読願います
      (以下は、Harmony v2.04 をもとに作成しています。最新のバージョンとは異なることがあるかもしれませんので注意してください。)

■ MHC設定
  Options 

項目  ①Config設定
Device & Project Configuration
  > PIC32MZ2048 Device Configuration 
②USART設定
Harmony Framework Configuration > Drivers
 > USART
③DMA設定
Harmony Framework Configuration >
 System Services > DMA
MHC 
備考 デフォルトからの変更要領:
 FPLLIDIV: DIV3
 FPLLICLK: PLL_POSC
 POSCMOD: EC

システムクロック周波数: 200MHz
外部
 主発振器: 24MHz
 副発振器: 32.768KHz

#pragma config FNOSC = SPLL
#pragma config POSCMOD = EC
#pragma config FPLLIDIV = DIV_3
#pragma config FPLLICLK = PLL_POSC
#pragma config FPLLMULT = MUL_50
#pragma config FPLLODIV = DIV_2 
デフォルトからの変更要領:
 □Use USART Driver? チェックを入れる
 USART Module ID: USART_ID_6
デフォルトからの変更要領:
 □Use DMA System Service?チェックをいれる
 Number of DMA channel instances: 2
 DMA CHANNEL0/Interrupt priority
            :INTPRIORITY_LEVEL5
 DMA CHANNEL1/Interrupt priority
            :INTPRIORITY_LEVEL2


  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