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

2021年2月20日


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

参考

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

仕様

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

ワンショットモードの設定

 今回はチャンネル0を使用します。
 準備:転送用バッファを用意します。

  unsigned int rex_buf[10]__attribute__((space(dma)));

ワンショットモード

チャンネル許可ビットCHENの設定

DMA0CONbits.CHEN = 1;

“1"の場合:チャンネル0が有効になります。
“0"の場合:チャンネル0が無効になります。

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

 DMA0CONbits.MODE = 0b01;

 "01″の場合:ワンショット転送となります。
  DMA転送が終わると自動的にDMA0CONbits.CHENが0になります。
  再度DMA転送を利用したい場合は1にすると出来ます。

転送するデータのサイズビットSIZEの設定

  DMA0CONbits.SIZE = 0;

 "0″の場合:wordサイズ(2byte)
 "1″の場合:byteサイズ

転送方向ビットDIRの設定

DMA0CONbits.DIR = 0;

 "0″の場合:RAM←Peripheralに転送されます。
 "1″の場合:RAM→Peripheralに転送されます。
 UART受信のDMA転送になるので"0″に設定します。

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

 DMA0CNT = 9;

  10byte転送したいので9にします。

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

DMA0REQbits.IRQSEL = 0b0001011;

 DMA転送の割り込み要求先のperipheralを選択します。
 "00001011″の場合:UART1の受信です。

IRQSEL<6-0>peripheralfunction
0000000INT0外部割込み0
0000001IC1入力キャプチャ1
0000010OC1出力コンペア1
0000101IC2入力キャプチャ2
0000110OC2出力コンペア2
0000111TMR2タイマー2
0001000TMR3タイマー3
0001010SPI1SPI1転送完了
0001011UART1RXUART1受信
0001100UART1TXUART1送信
0001101ADC1ADC1変換終了
0011110UART2RXUART2受信
0011111UART2TXUART2送信
0100001SPI2SPI2転送完了
0100010ECAN1RXECAN受信準備OK
0101101PMPPMPマスターデータ転送
0111100DCICODEC転送完了
1000110ECAN1TXECAN送信要求
1001110DAC1(right)右データ出力
1001111DAC1(left)左データ出力

Peripheralアドレスの指示

 DMA0PAD = (volatile unsigned int)&U1RXREG;

  volatileとは・・・最適化をさせない。
  UART受信レジスタU1RXREGを指定します。

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

  DMA0STA = __builtin_dmaoffset(rex_buf);
 転送用バッファーを指定します。

割り込み受信時の処理・・・

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

ソース

リファレンスマニュアル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)
//========================================================================
//=================================================================================

回路図

PICマイコンでDMA転送によるUART受信

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