PICマイコンの使い方

PICマイコンの8bitマイコンから32bitマイコンまで使いこなすぞ! 周辺機能やアセンブラ、C言語を使いこなすぞ。ARMには負けないぞ! 頼みの綱はPIC32MZだ!たのしみだなー

DMA

【PIC32MX370F512H】PMP接続のDMA転送でaitendoの1.44インチ液晶TFT(ZY-FGD)を使ってみる。その4

◆PIC32MX370F512HのPMP接続のDMA転送を使って
aitendoの1.44インチ液晶TFTに高速表示します!
SDcardに書き込まれた画像ファイルBMPを読み込んでます。
1)動画

動画はこちらから


速度はだいたい30fpsといったところです。



【dsPIC33FJ128MC802】PMP接続のDMA転送でaitendoの1.44インチ液晶TFT(ZY-FGD)を使ってみる。その3

◆dsPIC33FJ128MC802でaitendoの1.44インチTFT液晶ZY-FGD1442701V1-PCBをPMP接続でDMA転送してみます。
①gifをgomplayerで画像ファイルを抜き取り
②gimpで16bitBMPに変換
③VC++で作ったアプリケーションでBMPファイルを都合のいいように編集
④BMPヘッダをカットしてリトルエディアンをビッグエディアンに変更する。
⑤SDカードに保存しPICからMicroChipのFATシステムAN1045を使ってDMAのメモリ一杯分の1024byteをread
⑥そのまんまPMPのDMA転送する。(4行分)
だいたい12fpsぐらいでした。
動画1

動画2


動画3


動画4


スパゲティー状態:
1.44インチTFT液晶ZY-FGD1442701V1-PCB

【dsPIC33FJ128MC802】PMP接続のDMA転送(連続転送)でaitendoの液晶を使ってみる。


◆dsPIC33FJ128MC802でaitendoの1.44インチTFT液晶ZY-FGD1442701V1-PCBをPMP接続でDMA転送してみます。



1)参考
パクる気満々で色々ググってもPICマイコンでPMPのDMA転送をやられている方がいらっしゃらないようで・・・
挙句には自分のサイトが出てきてしまいました。これはチャレンジするしかない!
以前の作成した記事PMPのDMA転送をつかってみる。aitendoの1.44インチ液晶TFT(ZY-FGD)をPMP接続で使ってみる!を組み合わせてちょっと変えれば出来ます。その他マイクロチップ社のリファレンスマニュアルを参考にしました。
2)PMPの設定
PMPのリファレンスDS70299のP28の35-5にDMAサポートの記載がちょろっとあります。
PMP_DMAのサポート
①「PMMODEbits.IRQM = 0b01」にする。
重要:PMP書き込み後に割り込み発生をかけます。
実際にはこの機能を利用して割り込みフラグをチェックしてDMA転送完了を知ります。
ほかの機能は前回と同様なので省きます。
3)DMAの設定(チャンネル0を使用する。)
 ①「DMA0CONbits.SIZE = 1」
byte転送にします。(0でword転送)
 ②「DMA0CONbits.DIR = 0」
転送方向をRAM→peripheralにします。
 ③「DMA0CONbits.HALF = 0」
フルブロック転送したら割り込みにします。
 ④「DMA0CONbits.MODE = 0b01」
転送はワンショットモード。
 ⑤「DMA0CNT = 255」
転送したbyte数を入れます。ただし「0」は「1byte」なのでn-1で設定します。
最大で9bit=1024byte設定可能です。
 ⑥「unsigned int tex_buf[256]__attribute__((space(dma)));」
転送バッファーを用意します。サイズはunsigned int型です。DS70215のpage18を参照。
 ⑦「DMA0PAD = (volatile unsigned int)&PMDIN1;」
peripheralAddressを指示します。
 ⑧「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







4)メインのプログラム

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)







5)波形の確認
黄色がWRの挙動です。ピンクはRA1に接続してます。1ライン転送毎に切り替えてます。
1ライン分256byteDMA転送するのに19.34μsecかかり、(1byte転送は大体50nsecでした。)
DMA転送バッファーにコピーするのに13.12μsecかかりました。
TOTALで32.84μsecかかりました。PMP接続と比較すると2.5倍速くなりました。
1f3858c2.png

6)実行の様子(PMP接続の時と変わりません。)
aitendoの1.44インチ液晶TFT(ZY-FGD)PMP接続DMA転送1ライン出力

7)回路図(PMP接続の時と変わりません。)
28b9ed33.png


【dsPIC33FJ128MC802】PMPのDMA転送をつかってみる。


◆dsPIC33FJ128MC802でPMPのDMA転送を使ってみます。



最新追記)
aitendoのLCDを使ったDMA転送は【dsPIC33FJ128MC802】PMP接続のDMA転送(連続転送)でaitendoの液晶を使ってみる。

1)参考
前回の「UARTのDMA転送」

「PMPをつかってみる」
を組み合わせます。

さらにマイクロチップのリファレンスマニュアルの
①パラレルマスタポートPMPのリファレンスマニュアル:DS70299C
page28:「ダイレクトメモリアクセスDMAのサポート」を参照しました。(ちょっとしか書いてない・・・)
PMPusingDMA
②UARTのリファレンスマニュアル:DS70188D
③DMAのリファレンスマニュアル:DS70182Bを参考にしました。

2)仕様
・DMA転送:0.5秒毎に文字列をLCDにPMPでDMA転送します。
(変わり映えしないので)動作確認の為に、頭文字だけを毎回インクリメントさせます。

3)PMPの設定
①Master1に設定します。
PMP設定の詳細はこちらから。

4)DMAの設定
 ①チャンネル0を使用。
 ②転送用バッファを用意。
 「unsigned int tex_buf[1]__attribute__((space(dma)));」
 ③ワンショットモードを選択。
 「DMA0CONbits.MODE = 0b01;」
 ④DMA-Peripheralの選択の設定。
 「DMA0REQbits.IRQSEL = 0b0101101;」
 ⑤転送方向の設定。
 「DMA0CONbits.DIR = 1;」
 「1:RAM→Peripheral」になります。
 ⑥転送カウントレジスタの設定
 「DMA0CNT = 0;」
 1byte転送するので0にしました。
 ⑦Peripheralアドレスの指示
 「DMA0PAD = (volatile unsigned int)&PMDIN1;」
 ⑧DMA転送開始アドレスの指示
 「DMA0STA = __builtin_dmaoffset(tex_buf);」
DMA設定の詳細はこちらから。

5)DMA転送
割り込みは使わず
DMAREQレジスタのFORCEビットを1にして強制送信してます。
tex_buf[0] = data;  //send_data_set
//DMA_data_send
DMA0CONbits.CHEN = 1; //DMA0_enable
DMA0REQbits.FORCE = 1; //One_times
//ここでLCDにはセットしたdataがDMA転送される。


4)ソース

//=========================================================
// TEST
//=========================================================
//== ヘッダファイル ============================================
#include <p33fj128mc802.h>
#include <stdio.h>

//== define =============================================================
//== configuration ======================================================
_FBS(BSS_NO_FLASH //No Boot program Flash segment
& BWRP_WRPROTECT_OFF); //Boot Segment may be written
_FGS(GSS_OFF //User program memory is not code-protected
& GWRP_OFF); //User program memory is not write-protected
_FOSCSEL(FNOSC_FRCPLL //Internal Fast RC (FRC) w/ PLL
& IESO_OFF); //Start-up device with user-selected oscillator source
_FOSC(FCKSM_CSDCMD //Both Clock Switching and Fail-Safe Clock Monitor are disabled
& IOL1WAY_ON // Allow Only One Re-configuration
& OSCIOFNC_ON //OSC2 pin has digital I/O function
& POSCMD_NONE); //Primary Oscillator Disabled
_FWDT(FWDTEN_OFF); //Watchdog timer enabled/disabled by user software
_FPOR(FPWRT_PWR128 //PowerOnReset_128ms
& ALTI2C_OFF); //I2C mapped to SDA1/SCL1 pins
_FICD(JTAGEN_OFF //JTAG is Disabled
& ICS_PGD1); //Communicate on PGC1/EMUC1 and PGD1/EMUD1
//== interrupt_function_prototype ================================================
void __attribute__((interrupt,no_auto_psv)) _U1RXInterrupt(void); //UART_RX_Interrupt
void __attribute__((interrupt,auto_psv)) _DMA0Interrupt(void); //DMA0_Interrupt
//== DMA_UART ====================================================================
unsigned int tex_buf[1]__attribute__((space(dma))); //1byte
//== UART ========================================================================
char U1RXstring(void); //receive_string
void U1TXstring(char *string, unsigned char count); //tex_string
//== SD1602LCD用プロトタイプ =========================================================
void sd1602_init(void); //sd1602初期化
void sd1602_write(unsigned flag, unsigned char data); //sd1602コマンド書き込み(flag:command/data)
//== sd1602文字列書き込み(配列 + 行目 + 出力数) =======================================
void sd1602_string_write(char *data, char line, unsigned char count);

//== MyTimer =====================================================================
void delay_us(unsigned int usec); //Timer1を利用したusec関数
void delay_ms(unsigned int msec); //msec関数
//== StringBox ===================================================================
char rev_data[4]; //uart_rex
char test_box[10] = "test_mode";
//== original_struct ======================================================
struct{
unsigned pwm_out : 1;
unsigned fan : 1;
unsigned lamp : 1;
}st_flag;
//== 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:
//== i2c設定 ============================================================
//== TIMER1設定 =========================================================
T1CONbits.TON = 0; //<15>Timer1_OFF
T1CONbits.TSIDL = 1; //<13>アイドルモード:Sleep中は停止
T1CONbits.TGATE = 0; //<6>ゲート積算時間:OFF
T1CONbits.TCKPS = 0B00; //<5:4>_PS1:1
T1CONbits.TCS = 0; //<2>クロックソース:内部
IEC0bits.T1IE = 0; //割り込み拒否
IPC0bits.T1IP = 0; //優先レベル0
//== UART1設定 =========================================================
//== PMP_Initialize ===================================================
PMMODE = 0x0000;
PMMODEbits.MODE = 0b11; //<9:8>MastarMode_1
PMCON = 0x0000;
//== port_select ====
//== R/W:PMRD/PMWR ==
PMCONbits.PTRDEN = 1; //<8>PMRD/PMWR_enable
PMCONbits.RDSP = 1; //<0>PMRD/PMWR
//== E:PMENB ========
PMCONbits.PTWREN = 1; //<9>PMWR/PMENB_enable
PMCONbits.WRSP = 1; //<1>PMENB
//== RS:PMA0 ========
PMAENbits.PTEN0 = 1; //<0>PMA0_enable
//== wait ==
//PMMODEbits.WAITE = 0B01; //
PMMODEbits.WAITM = 0B0001; //byre_read:1Tcy
PMMODEbits.WAITB = 0B00; //data_hold:1Tcy
//== CN_Initialize ===================================================
//== DMA_PMP ========================================================
DMA0CON = 0x0000; //clear
DMA0CONbits.SIZE = 1; //<14>byte_send
DMA0CONbits.DIR = 1; //<13>write_mode
DMA0CONbits.MODE = 0b01; //<1-0>one_shot
DMA0CNT = 0; //1byte
DMA0REQbits.IRQSEL = 0b0101101; //PMP_peripheral
DMA0PAD = (volatile unsigned int)&PMDIN1; //peripheral_address
DMA0STA = __builtin_dmaoffset(tex_buf); //DMA_start_address
//== 前処理 ======================================================
//IPC2bits.U1RXIP = 6; //PriorityLevel_6
//IEC0bits.U1RXIE = 1; //UART_revInterrupt_enable
//DMA0CONbits.CHEN = 1; //DMA0_enable
//IEC0bits.DMA0IE = 1; //DMA0_interrupt_enable
//st_flag.pwm_out = 0; //PWM_OFF
PMCONbits.PMPEN = 1; //<15>PMP_enable
sd1602_init(); //LCD初期化
sd1602_write(0,0x80);
//== while文 ===========================================================
while(1)
{
sd1602_string_write(test_box,2,9);
sd1602_string_write(test_box,1,9);
test_box[0] = test_box[0]+1;
delay_ms(500);
}//while(1)
}//int main(void)


//== delay_us関数 =================================================================
void delay_us(unsigned int usec)
{
TMR1 = 0; //TMR1=0
T1CONbits.TON = 1; //Timer1_start
PR1 = 39; //PR1値:((目的値1usec)/(1サイクル:0.0025usec*PS)-1)=39
unsigned int i;
for(i=0; i<usec; i++)
{ //タイマーフラグ待ち
while(!IFS0bits.T1IF); //Timer1割り込みフラグチェック(IFS0bits.T1IF==0)
IFS0bits.T1IF = 0; //割り込みフラグ下ろす
}//for(i=0; i<usec; i++)
}//void delay_usec();
//== delay_ms関数 ==================================================================
void delay_ms(unsigned int msec)
{
unsigned int i;
for(i=0; i<msec; i++)
{
delay_us(1000); //call:1000usec
}//for
}//void delay_ms
//== DMA0_Interrupt =========================================================================
void __attribute__((interrupt,auto_psv)) _DMA0Interrupt(void)
{
IFS0bits.DMA0IF = 0; //Flag_OFF
//DMA0CONbits.CHEN = 1; //DMA0_reset_enable
//== DebugFlag =============================================================
}//void __attribute__((__interrupt__)) _DMA0Interrupt(void)
//== U1RXstringGet =============================================================
char U1RXstring(void)
{
unsigned char i;
for(i=0; i<4; i++) //4byteInterrupt
{
while(!U1STAbits.URXDA); //Buffer_has_data
rev_data[i] = U1RXREG; //SET_Buffer
}//for(i=0; i<count; i++)
return(*rev_data);
}//void U1string(unsigned char *tex, char count)
//== U1TXstring ==============================================================
void U1TXstring(char *string, unsigned char count)
{
unsigned char i;
for(i=0; i<count; i++)
{
while(U1STAbits.UTXBF); //Buffer_empty
U1TXREG = string[i]; //set_Buffer
}//for(i=0; i<count; i++)
}//void U1string(unsigned char *tex, char count)
//== SD1602 initialize ===================================================
void sd1602_init(void)
{
delay_ms(100); //100msec
sd1602_write(0,0x30); //command/Function_set
delay_ms(10); //4.1msec
sd1602_write(0,0x30); //command/Function_set
delay_ms(100); //100msec
sd1602_write(0,0x30); //command/Function_set
delay_ms(10);
sd1602_write(0,0x38); //command/N=1:2line
delay_ms(10);
sd1602_write(0,0x06); //command/EntryMode
delay_ms(1);
sd1602_write(0,0x01); //command/ClearDisplay
delay_ms(10);
sd1602_write(0,0x0c); //command/DisplayOn
delay_ms(1);
} //sd1602_init(void)
//== SD1602 Write ====================================================
void sd1602_write(unsigned flag, unsigned char data)
{
unsigned char sute_yomi;
//flag_check
if(flag == 0)
{PMADDRbits.ADDR0 = 0;} //command_mode
else
{PMADDRbits.ADDR0 = 1;} //data_mode
//PMP
while(PMMODEbits.BUSY == 1); //PMP_OK?
tex_buf[0] = data; //send_data_set
//DMA_data_send
DMA0CONbits.CHEN = 1; //DMA0_enable
DMA0REQbits.FORCE = 1; //One_times
//busy_check
TRISBbits.TRISB5 = 1; //PMD7_input
do{
while(PMMODEbits.BUSY == 1);
PMADDRbits.ADDR0 = 0; //RS=0_command_mode
sute_yomi = PMDIN1; //data_in
}while(PORTBbits.RB5 == 0); //PMD7_check
TRISBbits.TRISB5 = 0; //output
delay_us(40);
}//void sd1602_data_write(unsigned char data)
//== SD1602 String_Write ====================================================
void sd1602_string_write(char *data, char line, unsigned char count)
{
if(line == 1) //1行目
{sd1602_write(0,0x80);}
else if(line == 2) //2行目
{sd1602_write(0,0xC0);}
unsigned int i;
for(i=0; i<count; i++)
{
sd1602_write(1,data[i]); //data_mode_write
}//for(i=0; i<count; i++)
}//void sd1602_string_write(unsigned char *data, unsigned char count)
//========================================================================

//=================================================================================



5)回路図
c2ae3f36.png

【dsPIC33FJ128MC802】UARTのDMA転送を使ってみる。受信


◆dsPIC33FJ128MC802でUARTのDMA転送を使ってみます。



1)参考
前回のUARTの記事にDMA機能を追加します。
・UARTリファレンスマニュアル:DS70188D
・DMAリファレンスマニュアル:DS70182Bを参考にしました。

2)仕様
・送信仕様:1秒毎に’a’を送信させます。
・受信仕様:ワンショットモードで10byteDMA受信したら割り込んで最初の1byteをエコーバックさせます。

3)ワンショットモードの設定
チャンネル0を使用します。
 ・準備
 転送用バッファを用意します。
 「unsigned int rex_buf[10]__attribute__((space(dma)));」

1.ワンショットモード
 ①DMA転送許可
 「DMA0CONbits.CHEN = 1;」
 ②モードに設定
 「DMA0CONbits.MODE = 0b01;」
 DMA転送が終わると自動的にDMA0CONbits.CHENが0になります。
 再度DMA転送を利用したい場合は1にすると出来ます。
 ③転送するデータのサイズ
 「DMA0CONbits.SIZE = 0;」
 「0:word」、「1:byte」になります。
 ④転送方向の設定
 「DMA0CONbits.DIR = 0;」
 「0:RAM←Peripheral」、「1:RAM→Peripheral」になります。
 ⑤転送カウントレジスタの設定
 「DMA0CNT = 9;」
 10byte転送するので9にします。
 0で比較するから-1なのかな!?
 ⑥DMA-Peripheralの選択の設定(歯抜けなので注意)
 「DMA0REQbits.IRQSEL = 0b0001011;」
























IRQSEL<6:0>peripheralmemo
0000000INT0外部割り込み0
0000001IC1入力キャプチャ1
0000010OC1出力コンペア1
0000101IC2入力キャプチャ2
0000110OC2出力コンペア2
0000111TMR2タイマー2
0001000TMR3タイマー3
0001010SPI1SPI1転送完了
0001011U1RXUART1受信
0001100U1TXUART1送信
0001101ADC1ADC1変換完了
0010101ADC2ADC2変換完了
0011110U2RXUART2受信
0011111U2TXUART2送信
0100001SPI2SPI1転送完了
0100010ECAN1RXECAN1RXレディ
0100111ECAN2RXECAN2RXレディ
0111100DCIコーデック完了
1000110ECAN1TXECAN1TX要求
1000111ECAN2TXECAN2TX要求


 ⑦Peripheralアドレスの指示
 「DMA0PAD = (volatile unsigned int)&U1RXREG;」
 volatileとは・・・最適化をさせない。
 UART受信レジスタU1RXREGを指定します。

 ⑧DMA転送開始アドレスの指示
 「DMA0STA = __builtin_dmaoffset(rex_buf);」
 転送用バッファーを指定します。

割り込み受信時の処理・・・
割り込み時点でバッファーに文字が入ってますので取り出してください。
1byte目を読む場合・・・
 ex)data = rex_buf[0];

4)ソース
リファレンスマニュアルDS70182のpage21に記載のプログラムを参照しました。

//=========================================================
// TEST
//=========================================================
//== ヘッダファイル ============================================
#include <p33fj128mc802.h>
#include <stdio.h>

//== define ===========================================================
#define SB1602_RE LATBbits.LATB7
#define debug_pin LATBbits.LATB6
//== configuration ======================================================
_FBS(BSS_NO_FLASH //No Boot program Flash segment
& BWRP_WRPROTECT_OFF); //Boot Segment may be written
_FGS(GSS_OFF //User program memory is not code-protected
& GWRP_OFF); //User program memory is not write-protected
_FOSCSEL(FNOSC_FRCPLL //Internal Fast RC (FRC) w/ PLL
& IESO_OFF); //Start-up device with user-selected oscillator source
_FOSC(FCKSM_CSDCMD //Both Clock Switching and Fail-Safe Clock Monitor are disabled
& IOL1WAY_ON // Allow Only One Re-configuration
& OSCIOFNC_ON //OSC2 pin has digital I/O function
& POSCMD_NONE); //Primary Oscillator Disabled
_FWDT(FWDTEN_OFF); //Watchdog timer enabled/disabled by user software
_FPOR(FPWRT_PWR128 //PowerOnReset_128ms
& ALTI2C_OFF); //I2C mapped to SDA1/SCL1 pins
_FICD(JTAGEN_OFF //JTAG is Disabled
& ICS_PGD1); //Communicate on PGC1/EMUC1 and PGD1/EMUD1
//== interrupt_function_prototype ================================================
void __attribute__((interrupt,no_auto_psv)) _U1RXInterrupt(void); //UART_RX_Interrupt
void __attribute__((interrupt,auto_psv)) _DMA0Interrupt(void); //DMA0_Interrupt
//== DMA_UART ====================================================================
unsigned int rex_buf[10]__attribute__((space(dma))); //10byte
//== UART ========================================================================
char U1RXstring(void); //receive_string
void U1TXstring(char *string, unsigned char count); //tex_string
//== MyTimer =====================================================================
void delay_us(unsigned int usec); //Timer1を利用したusec関数
void delay_ms(unsigned int msec); //msec関数
//== StringBox ===================================================================

char rev_data[4]; //uart_rex
//== 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:
//== i2c設定 ============================================================
//== TIMER1設定 =========================================================
T1CONbits.TON = 0; //15_Timer1_OFF
T1CONbits.TSIDL = 1; //13_アイドルモード:Sleep中は停止
T1CONbits.TGATE = 0; //6_ゲート積算時間:OFF
T1CONbits.TCKPS = 0B00; //5-4_PS1:1
T1CONbits.TCS = 0; //2_クロックソース:内部
IEC0bits.T1IE = 0; //割り込み拒否
IPC0bits.T1IP = 0; //優先レベル0
//== UART1設定 =========================================================
//Port_set
RPINR18bits.U1RXR = 15; //RP15_U1RX
TRISBbits.TRISB15 = 1; //U1RX_input
RPOR7bits.RP14R = 3; //U1TX_RP14
U1MODE = 0x0000; //初期クリア
U1MODEbits.UARTEN = 1; //15_UART有効
U1MODEbits.RTSMD = 1; //11_単方向モード
U1MODEbits.BRGH = 0; //3_低速
U1STA = 0x0000; //初期クリア
//U1STAbits.URXISEL = 0B11; //4ByteReceive_Interrupt
U1STAbits.UTXEN = 1; //10_TX_enable
U1BRG = 257; //低速,ビットレート:9600bps U1BRG=(Fcy/(16*9600))-1
//== CN_Initialize ===================================================
//== DMA_UART ========================================================
DMA0CON = 0x0000; //clear
//DMA0CONbits.SIZE = 1; //14_byte
DMA0CONbits.MODE = 0b01; //1-0_OneShot
DMA0CNT = 9; //10byte
DMA0REQbits.IRQSEL = 0b0001011; //UART1_RX
DMA0PAD = (volatile unsigned int)&U1RXREG; //peripheral_address
DMA0STA = __builtin_dmaoffset(rex_buf); //DMA_start_address
//== 前処理 ======================================================
DMA0CONbits.CHEN = 1; //DMA0_enable
IEC0bits.DMA0IE = 1; //DMA0_interrupt_enable
//== while文 ===========================================================
while(1)
{
while(U1STAbits.UTXBF);
U1TXREG = 'a';
delay_ms(1000);
}//while(1)
}//int main(void)


//== delay_us関数 =================================================================
void delay_us(unsigned int usec)
{
TMR1 = 0; //TMR1=0
T1CONbits.TON = 1; //Timer1_start
PR1 = 39; //PR1値:((目的値1usec)/(1サイクル:0.0025usec*PS)-1)=39
unsigned int i;
for(i=0; i<usec; i++)
{ //タイマーフラグ待ち
while(!IFS0bits.T1IF); //Timer1割り込みフラグチェック(IFS0bits.T1IF==0)
IFS0bits.T1IF = 0; //割り込みフラグ下ろす
}//for(i=0; i<usec; i++)
}//void delay_usec();
//== delay_ms関数 ==================================================================
void delay_ms(unsigned int msec)
{
unsigned int i;
for(i=0; i<msec; i++)
{
delay_us(1000); //call:1000usec
}//for
}//void delay_ms
//== DMA0_Interrupt =========================================================================
void __attribute__((interrupt,auto_psv)) _DMA0Interrupt(void)
{
IFS0bits.DMA0IF = 0; //Flag_OFF
DMA0CONbits.CHEN = 1; //DMA0_reset_enable
//== DebugFlag =============================================================
while(U1STAbits.UTXBF); //Buffer_empty
U1TXREG = rex_buf[0]; //first_byte
debug_pin = !debug_pin;
}//void __attribute__((__interrupt__)) _DMA0Interrupt(void)
//== U1RXstringGet =============================================================
char U1RXstring(void)
{
unsigned char i;
for(i=0; i<4; i++) //4byteInterrupt
{
while(!U1STAbits.URXDA); //Buffer_has_data
rev_data[i] = U1RXREG; //SET_Buffer
}//for(i=0; i<count; i++)
return(*rev_data);
}//void U1string(unsigned char *tex, char count)
//== U1TXstring ==============================================================
void U1TXstring(char *string, unsigned char count)
{
unsigned char i;
for(i=0; i<count; i++)
{
while(U1STAbits.UTXBF); //Buffer_empty
U1TXREG = string[i]; //set_Buffer
}//for(i=0; i<count; i++)
}//void U1string(unsigned char *tex, char count)

//========================================================================

//=================================================================================



5)回路図
fbf03e72.png

ギャラリー
  • 【PIC24F08KL200】PIC24F08KL200でsprintfを使う
  • 【PIC24F08KL200】PIC24F08KL200でsprintfを使う
  • 【PIC24F08KL200】PIC24F08KL200でsprintfを使う
  • 【PIC24F08KL200】PIC24F08KL200でsprintfを使う
  • 【PIC24F08KL200】PIC24F08KL200でsprintfを使う
  • 【PIC24F04KA200】PIC24F04KA200ではsprintfが使えない件
  • 【PIC24F04KA200】PIC24F04KA200ではsprintfが使えない件
  • 【PIC24F04KA200】PIC24F04KA200ではsprintfが使えない件
  • 【PIC24F04KA200】PIC24F04KA200ではsprintfが使えない件
メッセージはこちちらからお願いします。

名前
メール
本文
アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

ブログパーツ
  • SEOブログパーツ
にほんブログ村 その他趣味ブログ 電子工作へ
にほんブログ村
アクセスカウンタ
アクセスランキング