0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PIC32MX370F512F 64pin (4.1) SPI通信 with DMA

Last updated at Posted at 2024-10-25

DMAを使用して、SPI通信をハード制御で出力。

IMG_5024.JPG

SPI16ビットIOエキスパンダーMCP23S17の通信をDMAを介して、通信させます。わずか送信4バイトですが、DMA使用時のコードがわかりやすいので、ひな型としてコードを載せておきます。
TFT液晶128×160の画面を、DMAを使って高速描画できたので、このひな形で行けるはずです。
DMAを使用しないSPI通信の記事は、PIC32MX370F512F 64pin (4) SPI通信で書いてありますので、まずDMAを使用しない場合で通信ができてから、DMAを使ってください。

pin割り付け表.png

DMAをSPI送信に使うための初期化

DMA初期化
uint8_t txDATA1[10];//SPI送信バッファ
void DMA2Init(void)
{
    IEC2bits.DMA2IE = 0;   // 設定のためDMA2を一時停止させる
   
    DCH2CON = 0;
    DCH2ECON = 0;
    DCH2INT = 0;

    DCH2CONbits.CHPRI = 3;              // DMAチャネルの優先度(3)
    DCH2ECONbits.CHSIRQ = _TIMER_2_IRQ;   // DMAを開始する割り込み番号
    DCH2ECONbits.SIRQEN = 1;            // 割り込みによる転送を有効にする
    DCH2INTbits.CHBCIE = 1;             // DMA割り込みを有効にする
   
    DCH2SSA = KVA_TO_PA(&txDATA1);
    DCH2SSIZ = 4;//転送元全サイズ(byte)
    DCH2DSA = KVA_TO_PA(&SPI2BUF);
    DCH2DSIZ = 1;//転送先大きさ(byte)
    DCH2CSIZ = 1;//転送単位(byte)
    
    IFS2bits.DMA2IF = 0;   // 割り込みフラグのクリア
    IPC11bits.DMA2IP = 5;  // 割り込み優先度1:Lowest 7:Highest
    IPC11bits.DMA2IS = 3;  // 副割り込み優先度
    IEC2bits.DMA2IE = 1;   // DMA2割り込みを有効にする
    DCH2CONbits.CHEN = 1;               // DMA1を使用する
    DMACONbits.ON = 1;     // DMAモジュールを有効にする
}

DMA転送トリガーにTimer2の割り込みを使用します。
転送の開始は、

DMA転送開始
    SPI2_Start();
    T2CONbits.ON=1;

CSピンをLowにしてSPI通信を開始。Timer2をカウント開始させると、Timer2の割り込みがかかるたびに、
DMAのソースエリアから、ディスティネーションに1バイトずつ転送されます。

DCH2SSAで、転送元ソースをtxDATA1の配列先頭アドレスを指定。
DCH2DSAで、転送先ディスティネーションアドレスとしてSPI2BUFを指定。

転送元サイズ、転送先サイズ、転送単位を設定。

これで、DMAの初期化は完了です。

DMAモジュールの割り込み関数。

DMA割込み関数
void __ISR(_DMA2_VECTOR, IPL5AUTO) ISR_Dma2(void)
{     
    IFS2bits.DMA2IF = 0;        // DMA1割り込みフラグのクリア
    if(DCH2INTbits.CHBCIF == 1)
    {
        LATBbits.LATB1=~LATBbits.LATB1;//LED
        SPI2_Stop();//CS is High
        T2CONbits.ON=0;//Timer2 interrupt stoped.
        DCH2SSA = KVA_TO_PA(&txDATA1);
        DCH2CONbits.CHEN = 1;   // DMA1を有効にする
        
        DCH2INTbits.CHBCIF = 0; // ブロック終了割り込みフラグのクリア
        
        DCH2ECONbits.SIRQEN = 1;
    }
    
}

指定したソースエリアのサイズ分の送信が完了し、
DMA転送が終了すると、上記割込み関数が実行されます。

今回は、4バイト送信の完了で、この割り込みが発生します。

CHBCIFビットは、転送ブロックの転送完了割込みのフラグです。
ブロック転送(4byte)が完了した状態です。

SPIのCSピンをHighにもどして、SPI通信を終了させます。

Timer2をOFFにして、転送割込みトリガを止めています。

ソースアドレスにtxDATA1を再設定します。

これで、再度Timer2を稼働させるまで、DMA転送は停止状態になります。

main.c

main.c
....<>
void main(void) 
{
    uint8_t val,length,val1;
    uint8_t txt[10];
    unsigned int counter=0x0000;
    uint32_t address;
    unsigned int tmp_CP0_Status; // Temporary register for CP0 reg storing 
    
    //oscillator init---------------------------------
    SYSKEY = 0x0;           // ensure OSCCON is locked
    SYSKEY = 0xAA996655;    // Write Key1 to SYSKEY
    SYSKEY = 0x556699AA;    // Write Key2 to SYSKEY
    //PLL Output Divisor bits
    OSCCONbits.PLLODIV=0b000;   //000 = PLL output divided by 1
    //PeripheralBusClock diviser.
    OSCCONbits.PBDIV=0b00;  //SYSCLK divided by1
    SYSKEY = 0x0;           // ensure OSCCON is locked
    
    //port init---------------------------------------
    portInit();
    
    //peripheral initializing-------------------------
    timer1Init();
    timer2Init();
    I2C1_Init();
    LCD_Init(LcdDeviceAdd);
    I2C1BRG=0x003D;//600khz Fp=80Mhz
    LCD_Printf(LcdDeviceAdd,"PIC32MX",7,0x80);
    usartInit();
    __delay_ms(10);//これを入れないとazが出力されない。
    putchar('a');putchar('z');putchar('\r');
    DMA2Init();
    Spi2Init();
    
    MCP23S17Init(MCP23S17_deviceAdd1);
    //MCP23Sdebug(MCP23S17_deviceAdd1);
    //interrupt initializing-------------------------
    printf("\nPIC32MX370F512HT\n");
    
    //割り込み関連
    address=_CP0_GET_EBASE();//例外ベクタアドレス
    printf("EBASE=%lx\n",address);
    INTCONbits.MVEC=1;
    tmp_CP0_Status=_CP0_GET_STATUS();
    tmp_CP0_Status|=0x00000001;//CP0.STATUS.IE=1で割り込み許可
    _CP0_SET_STATUS(tmp_CP0_Status);
    // __builtin_enable_interrupts();
   
    val1=0x01;
    while(1)
    {
        if(rxU1.completed)
        {
            rxU1.completed=false;
            printf("%s\r",rxU1.buf);            
            rxU1.length=0;
            IEC1bits.U1RXIE=1;
        }
        
        if(tm1.fg)
        {
            tm1.fg=false;
            
            LATBbits.LATB0=~LATBbits.LATB0;
            I2C1_b1Write(0x4A,val);//PCF8574

            //DMA ソース転送元データの書き込み
            //MCP23S17は、シーケンシャル書き込み
            txDATA1[0]=MCP23S17_deviceAdd1;
            txDATA1[1]=0x14;
            txDATA1[2]=val1;
            txDATA1[3]=val1++;
            
            SPI2_Start();//SPI通信スタート
            T2CONbits.ON=1;//DMA転送開始
            
            if(val==0x55)
                val=0xAA;
            else
                val=0x55;
            length=sprintf(txt,"%8ld",counter++);
            LCD_Printf(LcdDeviceAdd,txt,length,0xC0);
            
            
            IEC0bits.T1IE=1;
        }
    }
    
    
    return;
}

Peripheral.c
//Fpb=80Mhz 0.025us * 2 * 10 = 0.5us
void timer2Init(void)
{
    T2CON=0x00;
    TMR2=0x00;
    PR2=0x000A;
    T2CONbits.T32=0;//16bitsTimer
    T2CONbits.TCKPS=0b001;//1:2 prescale 
    T2CONbits.TCS=0;//internal peripheral clock
    IFS0bits.T2IF=0;
    IPC2bits.T2IP=1;
    IPC2bits.T2IS=0;
    IEC0bits.T2IE=0;
    T2CONbits.ON=0;
}


uint8_t txDATA1[10];
void DMA2Init(void)
{
    IEC2bits.DMA2IE = 0;   // 設定のためDMA2を一時停止させる
   
    DCH2CON = 0;
    DCH2ECON = 0;
    DCH2INT = 0;

    DCH2CONbits.CHPRI = 3;              // DMAチャネルの優先度(3)
    DCH2ECONbits.CHSIRQ = _TIMER_2_IRQ;   // DMAを開始する割り込み番号
    DCH2ECONbits.SIRQEN = 1;            // 割り込みによる転送を有効にする
    DCH2INTbits.CHBCIE = 1;             // DMA割り込みを有効にする
   
    DCH2SSA = KVA_TO_PA(&txDATA1);
    DCH2SSIZ = 4;
    DCH2DSA = KVA_TO_PA(&SPI2BUF);
    DCH2DSIZ = 1;
    DCH2CSIZ = 1;
    
    IFS2bits.DMA2IF = 0;   // 割り込みフラグのクリア
    IPC11bits.DMA2IP = 5;  // 割り込み優先度1:Lowest 7:Highest
    IPC11bits.DMA2IS = 3;  // 副割り込み優先度
    IEC2bits.DMA2IE = 1;   // DMA2割り込みを有効にする
    DCH2CONbits.CHEN = 1;               // DMA1を使用する
    DMACONbits.ON = 1;     // DMAモジュールを有効にする
    
}
interrupt.c
void __ISR(_DMA2_VECTOR, IPL5AUTO) ISR_Dma2(void)
{     
    IFS2bits.DMA2IF = 0;        // DMA1割り込みフラグのクリア
    if(DCH2INTbits.CHBCIF == 1)
    {
        LATBbits.LATB1=~LATBbits.LATB1;//LED
        SPI2_Stop();//CS is High
        T2CONbits.ON=0;//Timer2 interrupt stoped.
        DCH2SSA = KVA_TO_PA(&txDATA1);
        DCH2CONbits.CHEN = 1;   // DMA1を有効にする
        
        DCH2INTbits.CHBCIF = 0; // ブロック終了割り込みフラグのクリア
        
        DCH2ECONbits.SIRQEN = 1;
    }
    
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?