【dsPIC33FJ128MC802】PMP接続のDMA転送(連続転送)でaitendoの液晶を使ってみる。
◆dsPIC33FJ128MC802でaitendoの1.44インチTFT液晶ZY-FGD1442701V1-PCBをPMP接続でDMA転送してみます。
パクる気満々で色々ググってもPICマイコンでPMPのDMA転送をやられている方が
いらっしゃらないようで・・・挙句には自分のサイトが出てきてしまいました。
これはチャレンジするしかない!
以前の作成した記事PMPのDMA転送をつかってみる。と
aitendoの1.44インチ液晶TFT(ZY-FGD)をPMP接続で使ってみる!を組み合わせて
ちょっと変えれば出来ます。
その他マイクロチップ社のリファレンスマニュアルを参考にしました。
PMPの設定
PMPのリファレンスDS70299のP28の35-5にDMAサポートの記載がちょろっとあります。
割り込み要求ビット
PMMODEbits.IRQM = 0b01;
PMP書き込み後に割り込み発生をかけます。
実際にはこの機能を利用して割り込みフラグをチェックしてDMA転送完了を知ります。
ほかの機能は前回と同様なので省きます。
DMAの設定
dsPIC33Fには8チャンネルあります。
今回はチャンネル0を使用します。
DMA0CONレジスタの各ビットを設定していきます。
データ転送サイズビット
DMA0CONbits.SIZE = 1;
”0”の場合は「word転送」(2byte)
”1”の場合は「byte転送」
今回は1のbyte転送で設定します。
データ転送方向ビットDIR
DMA0CONbits.DIR = 0;
"0″の場合は「peripheralアドレスから読みだしてRAMアドレスに書き込む。」
"1″の場合は「RAMアドレスから読みだしてperipheralアドレスに書き込む。」
PMPにDMA転送なので本BITはRAM→peripheralの"1″に設定します。
データ転送割り込みビット
DMA0CONbits.HALF = 0;
"0″の場合は「全データ転送されたら割り込みが発生します。」
"1″の場合は「データの半分が転送されたら割り込み発生します。」
全部転送したら割り込みたいので"0″に設定します。
動作モードビット
DMA0CONbits.MODE = 0b01;
よくわからないので単純な転送のワンショットモードにします。
「DMA0CNT = 255」
転送したbyte数を入れます。ただし「0」は「1byte」なのでn-1で設定します。
最大で9bit=1024byte設定可能です。
RAMアドレスの設定
unsigned int tex_buf[256]attribute((space(dma)));
転送バッファーを用意します。サイズはunsigned int型です。DS70215のpage18を参照。
peripheralアドレスの設定
DMA0PAD = (volatile unsigned int)&PMDIN1;
peripheralAddressを指示します。
⑧DMA転送開始Addressを指示
DMA0STA = __builtin_dmaoffset(tex_buf);
DMA転送開始Addressを指示します。
DMA転送ルーチン
①PMADDRbits.ADDR0をセットします。
②tex_buf[]にデータを入れる。
③DMA0CONbits.CHENをセットしDMA0をENABLEにします。
④DMA0REQbits.FORCEをセットし強制転送を開始します。
⑤勝手にWRはパタパタします。
⑥ADDR0を固定すれば連続書き込みが可能!!
⑦CPUを介さないDMA転送といえど書き込み完了を待つ必要があります。
超重要:IFS0bits.DMA0IFをチェックして転送が完了したか否かを判断します。
これがわからずに1日費やしてしまいました。
PMPのDMA設定部のソース
//== DMA_PMP ======================================================== DMA0CON = 0x0000; //clear DMA0CONbits.SIZE = 1; //<14>byte_send DMA0CONbits.DIR = 1; //<13>write_mode DMA0CONbits.HALF = 0; //<12>full_block DMA0CONbits.MODE = 0b01; //<1-0>one_shot DMA0CNT = 255; //block_size_254byte DMA0REQbits.IRQSEL = 0b0101101; //PMP_peripheral DMA0PAD = (volatile unsigned int)&PMDIN1; //peripheral_address DMA0STA = __builtin_dmaoffset(tex_buf); //DMA_start_address DMA0CONbits.CHEN = 0; //dma_disable
ソース
LCDの初期化等は省きます。aitendoのままです。
ブルーバック後、任意の個所に赤ラインを描画します。
LCDに256byte連続でDMA転送してます。
//== interrupt_function_prototype ================================================ void __attribute__((interrupt,auto_psv)) _DMA0Interrupt(void); //DMA0_Interrupt //== DMA_PMP ==================================================================== unsigned int tex_buf[256]__attribute__((space(dma))); //dma_buffer unsigned char *st_pointer; //line_pointer unsigned char st_box[256]; //line_data //== main ================================================================== int main(void) { //== クロックの設定 ====================================================== //== Fcy=Fosc/2=7.37M*((PLLFBD+2)/(N2*N1))/2=39.61MHz ================ PLLFBDbits.PLLDIV = 41; //M=PLLFBD+2 CLKDIVbits.PLLPOST = 0; //N2=2 CLKDIVbits.PLLPRE = 0; //N1=2 OSCTUN = 0; //TuneFRC:7.37MHz RCONbits.SWDTEN = 0; //Disable Watch Dog while(OSCCONbits.LOCK != 1); //wait for PLL Lock //== AD切り替え ========================================================== AD1PCFGL = 0xffff; //全digital //=== TRISA =========================================================== TRISA = 0x0000; //initial_ //== TRISB ============================================================= TRISB = 0x0000; //input: //== PMP_Initialize =================================================== PMMODE = 0x0000; PMMODEbits.MODE = 0b11; //<9-8>MastarMode_1 PMMODEbits.IRQM = 0b01; //<15-14>dma_interrupt_request PMCON = 0x0000; //== port_select ==== //== R/W:PMRD/PMWR == PMCONbits.PTRDEN = 1; //<8>PMRD/PMWR_enable PMCONbits.RDSP = 1; //<0>PMRD/PMWR //== RS:PMA0 ======== PMAENbits.PTEN0 = 1; //<0>PMA0_enable //== CN_Initialize =================================================== //== DMA_PMP ======================================================== DMA0CON = 0x0000; //clear DMA0CONbits.SIZE = 1; //<14>byte_send DMA0CONbits.DIR = 1; //<13>write_mode DMA0CONbits.HALF = 0; //<12>full_block DMA0CONbits.MODE = 0b01; //<1-0>one_shot DMA0CNT = 255; //block_size_254byte DMA0REQbits.IRQSEL = 0b0101101; //PMP_peripheral DMA0PAD = (volatile unsigned int)&PMDIN1; //peripheral_address DMA0STA = __builtin_dmaoffset(tex_buf); //DMA_start_address //== 前処理 ===================================================== PMCONbits.PMPEN = 1; //<15>PMP_enable DMA0CONbits.CHEN = 0; //dma_disable zy_init(); //sb1602_init() st_pointer = &st_box[0]; //first_byte_set zy_full_set(0x00,0x1f); //blueback //== while文 =========================================================== while(1) { zy_line(st_pointer); //line_out }//while(1) }//int main(void) //== set =================================================== unsigned char st_box[256] = { 0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00, 0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00, 0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00, 0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00, 0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00, 0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00, 0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00, 0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00, 0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00, 0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00, 0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00, 0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00, 0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00, 0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00, 0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00, 0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00, 0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00, 0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00, 0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00, 0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00, 0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00, 0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00, 0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00, 0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00, 0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00,0xf8,0x00, 0xf8,0x00,0xf8,0x00,0xf8,0x00 }; //========================================================== void zy_line(unsigned char *byte) { zy_write(0,0x2a); //x_address zy_write(1,0x00); //start zy_write(1,0x02); zy_write(1,0x00); //end zy_write(1,0x81); zy_write(0,0x2b); //y_address zy_write(1,0x00); //start zy_write(1,0x0f); zy_write(1,0x00); //end zy_write(1,0x0f); zy_write(0,0x2c); //memory_write //check_pin LATAbits.LATA0 = !LATAbits.LATA0; //array_copy memcpy(tex_buf,byte,sizeof(tex_buf)); //pmp+dma_sending PMADDRbits.ADDR0 = 1; //write_mode IFS0bits.DMA0IF = 0; //flag_off //force_dma_one_times DMA0CONbits.CHEN = 1; //DMA0_enable DMA0REQbits.FORCE = 1; //One_times //dma_sending_wait while(IFS0bits.DMA0IF == 0); //send_wait //check_pin LATAbits.LATA0 = !LATAbits.LATA0; }//void zy_line() //====================================================================== //== zy_fgd Write 0:cmd/1:data ==================================================== void zy_write(unsigned flag, unsigned char data) { //command_mode if(flag == 0) {PMADDRbits.ADDR0 = 0;} //command_mode/cd_low //data_mode else{PMADDRbits.ADDR0 = 1;} //data_mode //PMP while(PMMODEbits.BUSY == 1); //PMP_OK? PMDIN1 = data; }//void zy_write(unsigned flag, unsigned char data)
オシロスコープにて確認
黄色がWRの挙動です。ピンクはRA1に接続してます。1ライン転送毎に切り替えてます。
1ライン分256byteDMA転送するのに19.34μsecかかり、(1byte転送は大体50nsecでした。)
DMA転送バッファーにコピーするのに13.12μsecかかりました。
TOTALで32.84μsecかかりました。PMP接続と比較すると2.5倍速くなりました。
実行の様子
PMP接続の時と見た目は変わりません。
回路図
PMP接続の時と見た目は変わりません。
ディスカッション
コメント一覧
まだ、コメントがありません