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

2021年2月19日


◆dsPIC33FJ128MC802でPMPのDMA転送を使ってみます。
最新追記)
aitendoのLCDを使ったDMA転送は

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

参考

前回の「UARTのDMA転送」

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

PMPの設定

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

DMAの設定

 今回はチャンネル0を使用します。

 転送用バッファを用意します。

unsigned int tex_buf[1]__attribute__((space(dma)));

 動作モードビットMODE<1:0>の設定

DMA0CONbits.MODE = 0b01;

 割り込み要求レジスタIRQSELの設定

DMA0REQbits.IRQSEL = 0b0101101;

 DMA転送の割り込み要求先のperipheralを選択します。

 "0101101″の場合:PMPマスターデータ転送

 転送方向ビットDIRの設定

DMA0CONbits.DIR = 1;

 "0″の場合:RAM←Peripheralに転送されます。

 "1″の場合:RAM→Peripheralに転送されます。

 PMPマスターデータのDMA転送になるので"1″に設定します。

転送カウントレジスタの設定

 DMA0CNT = 0;

 1byte転送するので0にしました。

Peripheralアドレスの指示

 DMA0PAD = (volatile unsigned int)&PMDIN1;

DMA転送開始アドレスの指示

 DMA0STA = __builtin_dmaoffset(tex_buf);

 DMA設定の詳細はこちらから。

DMA転送仕様

 ・DMA転送:0.5秒毎に文字列をLCDにPMPで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転送される。

ソース

//=========================================================
//  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)
//========================================================================
//=================================================================================

回路図

c2ae3f36.png

よろしければバナーをクリックお願いします!