This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Ping pong DMA using mibspi3

Other Parts Discussed in Thread: HALCOGEN

Got a RM57L Hercules launchpad connected to a Seiko/EPSON IMU M-G350 via the MIBSPI3 port.

The plan is to read 500 16bit-words at a time from the IMU using DMA.  The mibspi3 element count is 10, frame count is 50.

Mibspi3 is set up to trigger on GIOA7. This works fantastic- logic analyzer show all SPI signals as expected.

My problem is the DMA receive buffer does not get filled, and I'm confused what DMA interrupt routine should be used (dmaBTCAInterrupt or dmaGroupANotification) and how to configure it. Can not find good documentation for the libraries generated by halcogen.

How can I set up mibspi3 using DMA to fill up 2x 500 word buffers (ping pong scheme) and make it jump to an interrupt routine when each buffer is full?

(In my test code below, i'm trying to fill one buffer only)



#include "HL_sys_common.h"
/* USER CODE BEGIN (1) */
#include "HL_mibspi.h"
#include "HL_esm.h"
#include "HL_sys_core.h"
#include "HL_sys_dma.h"
#include "HL_system.h"
#include "HL_sys_vim.h"

/* example data Pattern configuration */
#define D_SIZE      500

#define DMA_CH_TX  DMA_CH15
#define DMA_CH_RX  DMA_CH14


void     mibspiEnableInternalLoopback(mibspiBASE_t *mibspi);
void     dmaConfigCtrlPacket(uint32 sadd,uint32 dadd,uint32 dsize);
void     mibspiDmaConfig(mibspiBASE_t *mibspi,uint32 channel, uint32 txchannel, uint32 rxchannel);
void     initIMU();
uint16_t  ReadWrite16(uint16_t reg);
void     testGetIMUdata();
void     Delay(uint32 w);
void     dmaInterrupt(void);
void     dmaInit();


#pragma SET_DATA_SECTION(".sharedRAM")
uint16 TXDATA[D_SIZE];         /* transmit buffer in sys ram */
uint16 RXDATA[D_SIZE]= {0};    /* receive  buffer in sys ram */
#pragma SET_DATA_SECTION()

#define BTCA_INT_CHANNEL 40


bool         dma_done = false,
            DMA_Comp_Flag=false;

g_dmaCTRL     g_dmaCTRLPKT1,
            g_dmaCTRLPKT2;    /* dma control packet configuration stack */


/* USER CODE END */

/** @fn void main(void)
*   @brief Application main function
*   @note This function is empty by default.
*
*   This function is called after startup.
*   The user can use this function to implement the application.
*/

/* USER CODE BEGIN (2) */
/* USER CODE END */

void main(void)
{
/* USER CODE BEGIN (3) */

    _enable_IRQ_interrupt_();

    mibspiInit();
    dmaEnable();
    Delay(0xFFFFFF);

    // init IMU
    initIMU();

    TXDATA[0]=FLAG;
    TXDATA[1]=TEMP_OUT;
    TXDATA[2]=XGYRO_OUT;
    TXDATA[3]=YGYRO_OUT;
    TXDATA[4]=ZGYRO_OUT;
    TXDATA[5]=XACCEL_OUT;
    TXDATA[6]=YACCEL_OUT;
    TXDATA[7]=ZACCEL_OUT;
    TXDATA[8]=DONTCARE;
    TXDATA[9]=DONTCARE;

    dmaInit();

    mibspiTransfer(mibspiREG3,0 );

   while (!mibspiIsTransferComplete(mibspiREG3, 0ul));

   while(1)
   {
       if (DMA_Comp_Flag || dma_done)
           Delay(0xFFFFF); //set breakpoint here
   }

        /* loop forever */

/* USER CODE END */
}

/* USER CODE BEGIN (4) */
/** void mibspiEnableLoopback(mibspiBASE_t *mibspi )
*
*   enabling internal loopback on mibspix
*/

void dmaInit()
{


    // DMA ch1 configuration for TX
    dmaReqAssign(DMA_CH_TX,DMA_REQ15);
    dmaEnableInterrupt(DMA_CH_TX, BTC,  DMA_INTA); /* enable interrupt for block transfer complete */
    g_dmaCTRLPKT1.SADD      = (uint32)TXDATA;    /* source address             */
    g_dmaCTRLPKT1.DADD      = (uint32)&(mibspiRAM3->tx[0].data);    /* destination  address       */
    g_dmaCTRLPKT1.CHCTRL    = 0;                 /* channel control            */
    g_dmaCTRLPKT1.FRCNT        = 50;                 /* frame count                */
    g_dmaCTRLPKT1.ELCNT     = 10;//D_SIZE;            /* element count              */
    g_dmaCTRLPKT1.ELDOFFSET = 4;                 /* element destination offset */
    g_dmaCTRLPKT1.ELSOFFSET = 0;                    /* element destination offset */
    g_dmaCTRLPKT1.FRDOFFSET = 0;                    /* frame destination offset   */
    g_dmaCTRLPKT1.FRSOFFSET = 0;                 /* frame destination offset   */
    g_dmaCTRLPKT1.PORTASGN  = PORTA_READ_PORTB_WRITE;
    g_dmaCTRLPKT1.RDSIZE    = ACCESS_16_BIT;        /* read size                  */
    g_dmaCTRLPKT1.WRSIZE    = ACCESS_16_BIT;     /* write size                 */
    g_dmaCTRLPKT1.TTYPE     = FRAME_TRANSFER ;   /* transfer type              */
    g_dmaCTRLPKT1.ADDMODERD = ADDR_INC1;         /* address mode read          */
    g_dmaCTRLPKT1.ADDMODEWR = ADDR_OFFSET;       /* address mode write         */
    g_dmaCTRLPKT1.AUTOINIT  = AUTOINIT_ON;       /* autoinit                   */
    dmaSetCtrlPacket(DMA_CH_TX,g_dmaCTRLPKT1);
    dmaSetChEnable  (DMA_CH_TX, DMA_HW);


    //DMA request for RX
    dmaReqAssign(DMA_CH_RX, DMA_REQ14);
    dmaEnableInterrupt(DMA_CH_RX, BTC,  DMA_INTA); /* enable interrupt for block transfer complete */
    g_dmaCTRLPKT2.SADD      = (uint32)&(mibspiRAM3->rx[0].data);    /* source address             */
    g_dmaCTRLPKT2.DADD      = (uint32)RXDATA;    /* destination  address       */
    g_dmaCTRLPKT2.CHCTRL    = 0;                 /* channel control            */
    g_dmaCTRLPKT2.FRCNT        = 50;                 /* frame count                */
    g_dmaCTRLPKT2.ELCNT     = 10;//D_SIZE;             /* element count              */
    g_dmaCTRLPKT2.ELDOFFSET = 0;                 /* element destination offset */
    g_dmaCTRLPKT2.ELSOFFSET = 4;                    /* element destination offset */
    g_dmaCTRLPKT2.FRDOFFSET = 0;                    /* frame destination offset   */
    g_dmaCTRLPKT2.FRSOFFSET = 0;                 /* frame destination offset   */
    g_dmaCTRLPKT2.PORTASGN  = PORTB_READ_PORTA_WRITE;
    g_dmaCTRLPKT2.RDSIZE    = ACCESS_16_BIT;        /* read size                  */
    g_dmaCTRLPKT2.WRSIZE    = ACCESS_16_BIT;     /* write size                 */
    g_dmaCTRLPKT2.TTYPE     = FRAME_TRANSFER ;   /* transfer type              */
    g_dmaCTRLPKT2.ADDMODERD = ADDR_OFFSET;         /* address mode read          */
    g_dmaCTRLPKT2.ADDMODEWR = ADDR_INC1;       /* address mode write         */
    g_dmaCTRLPKT2.AUTOINIT  = AUTOINIT_ON;       /* autoinit                   */
    dmaSetCtrlPacket(DMA_CH_RX,g_dmaCTRLPKT2);
    dmaSetChEnable(DMA_CH_RX, DMA_HW);
    /* upto 32 control packets are supported. */

    mibspiDmaConfig(mibspiREG3,0,0,1); //mibspi3[0], and mibspi3[1]
    mibspiEnableGroupNotification(mibspiREG3,0,1);

}


/** void mibspiDmaConfig(mibspiBASE_t *mibspi,uint32 channel, uint32 txchannel, uint32 rxchannel)
*
*   configuring mibspi dma with
*
*       channel   > mibspi dma channel number
*       txchannel > transmit channel dedicated for mibspi
*       rxchannel > receive  channel dedicated for mibspi
*/
void mibspiDmaConfig(mibspiBASE_t *mibspi,uint32 channel, uint32 txchannel, uint32 rxchannel)
{
    uint32 bufid  = D_SIZE - 1;
    uint32 icount = 0;

    /* setting transmit and receive channels */
    mibspi->DMACTRL[channel] |= (((rxchannel<<4)|txchannel) << 16);

    /* enabling transmit and receive dma */
    mibspi->DMACTRL[channel] |=  0x8000C000;

    /* setting Initial Count of DMA transfers and the buffer utilized for DMA transfer */
    mibspi->DMACTRL[channel] |=  (icount << 8) |(bufid<<24);

}

  • Hello:

    We have received your post and will get back to you soon.

    Regards,

    Enrique
  • Hi,

    Sorry for the delayed response.

    There are two things I noticed in the MIBSPI DMA configuration:

    • bufid is set as 499. That is an invalid configuration as the maximum value you can set as BUFID is 127. I believe you need a DMA transfer at the end of every 10 MIBSPI transfers. In that case BUFID should be set as 9.
    • One shot transfer is enabled (Bit 31 in DMACTRL register). Please disable the One-shot transfer so that the transfer size is controlled by the DMA.
       

    Hope this helps!

    Thanks and Regards,

    Veena

  • Thanks Veena.

    I set D_SIZE=10. Do you have any suggestions how to set up the dmaCTRL to fill 500bytes, then jump to dmaBTCAInterrupt() ?

    Elementcount=10, framecount=50 still doesnt trigger interrupt.

    The TX channel sends the same 10bytes over and over. Should it be set to mode ADDR_FIXED?

        g_dmaCTRLPKT1.SADD      = (uint32)TXDATA;    /* source address             */
        g_dmaCTRLPKT1.DADD      = (uint32)&(mibspiRAM3->tx[0].data);    /* destination  address       */
        g_dmaCTRLPKT1.CHCTRL    = 0;                 /* channel control            */
        g_dmaCTRLPKT1.FRCNT        = 1;           /* frame count                */
        g_dmaCTRLPKT1.ELCNT     = D_SIZE;       /* element count              */
        g_dmaCTRLPKT1.ELDOFFSET = 4;                 /* element destination offset */
        g_dmaCTRLPKT1.ELSOFFSET = 0;                    /* element destination offset */
        g_dmaCTRLPKT1.FRDOFFSET = 0;                    /* frame destination offset   */
        g_dmaCTRLPKT1.FRSOFFSET = 0;                 /* frame destination offset   */
        g_dmaCTRLPKT1.PORTASGN  = PORTA_READ_PORTB_WRITE;
        g_dmaCTRLPKT1.RDSIZE    = ACCESS_16_BIT;        /* read size                  */
        g_dmaCTRLPKT1.WRSIZE    = ACCESS_16_BIT;     /* write size                 */
        g_dmaCTRLPKT1.TTYPE     = FRAME_TRANSFER ;   /* transfer type              */
        g_dmaCTRLPKT1.ADDMODERD = ADDR_INC1;         /* address mode read          */
        g_dmaCTRLPKT1.ADDMODEWR = ADDR_OFFSET;       /* address mode write         */
        g_dmaCTRLPKT1.AUTOINIT  = AUTOINIT_ON;       /* autoinit                   */



        //DMA request for RX
        g_dmaCTRLPKT2.SADD      = (uint32)&(mibspiRAM3->rx[0].data);    /* source address             */
        g_dmaCTRLPKT2.DADD      = (uint32)RXDATA;    /* destination  address       */
        g_dmaCTRLPKT2.CHCTRL    = 0;                 /* channel control            */
        g_dmaCTRLPKT2.FRCNT        = 1;                 /* frame count                */
        g_dmaCTRLPKT2.ELCNT     = D_SIZE;             /* element count              */
        g_dmaCTRLPKT2.ELDOFFSET = 0;                 /* element destination offset */
        g_dmaCTRLPKT2.ELSOFFSET = 4;                    /* element destination offset */
        g_dmaCTRLPKT2.FRDOFFSET = 0;                    /* frame destination offset   */
        g_dmaCTRLPKT2.FRSOFFSET = 0;                 /* frame destination offset   */
        g_dmaCTRLPKT2.PORTASGN  = PORTB_READ_PORTA_WRITE;
        g_dmaCTRLPKT2.RDSIZE    = ACCESS_16_BIT;        /* read size                  */
        g_dmaCTRLPKT2.WRSIZE    = ACCESS_16_BIT;     /* write size                 */
        g_dmaCTRLPKT2.TTYPE     = FRAME_TRANSFER ;   /* transfer type              */
        g_dmaCTRLPKT2.ADDMODERD = ADDR_OFFSET;         /* address mode read          */
        g_dmaCTRLPKT2.ADDMODEWR = ADDR_INC1;       /* address mode write         */
        g_dmaCTRLPKT2.AUTOINIT  = AUTOINIT_ON;       /* autoinit                   */

        vimEnableInterrupt(40, SYS_IRQ);

  • Hi,

    Let me try to understand your problem better.

    Do you want to sent the entire 500 data for every rising edge of GIOA_7? Or do you want to sent 10 data each per GIO trigger?

    Thanks and Regards,

    Veena

  • I'd like to send/receive 10bytes per rising GIO_A7.
  • I got it to work. Thanks Veena.