C5515 DMA为什么只能进一次中断?

程序中对DMA配置如下:

dmaConfig.pingPongMode = CSL_DMA_PING_PONG_DISABLE; 
dmaConfig.autoMode = CSL_DMA_AUTORELOAD_ENABLE; //自动加载
dmaConfig.burstLen = CSL_DMA_TXBURST_1WORD;
dmaConfig.trigger = CSL_DMA_SOFTWARE_TRIGGER;//软件触发DMA传输

dmaConfig.dmaEvt = CSL_DMA_EVT_NONE;

dmaConfig.dmaInt = CSL_DMA_INTERRUPT_ENABLE; // 使能DMA中断
dmaConfig.chanDir = CSL_DMA_WRITE; // 方向为写,即发送
dmaConfig.trfType = CSL_DMA_TRANSFER_MEMORY; // 在内存之间传输
dmaConfig.dataLen = I2S_DMA_BUF_LEN*2; // 传输长度

dmaConfig.destAddr = (Uint32)dmaDstBuf;

dmaConfig.srcAddr = (Uint32)dmaSrcBuf;

在调用一次DMA_start(dmaHandle)之后,产生了一次中断,完成I2S_DMA_BUF_LEN*2字节的数据dmaSrcBuf到dmaDstBuf的传输。

由于设置了dmaConfig.autoMode = CSL_DMA_AUTORELOAD_ENABLE,DMA会继续自动完成传输。

所以,当更新dmaSrcBuf中的数据时,dmaDstBuf也会被更新。

但是,传输完成后,并没有再次产生中断,为什么?

中断函数中,已经对DMAIFR寄存器的标志位进行了清零:

ifrValue = CSL_SYSCTRL_REGS->DMAIFR;
CSL_SYSCTRL_REGS->DMAIFR |= ifrValue;

  • 请问SYNCMODE=1吗?
    The auto-initialization feature can only be used when event synchronization is used (SYNCMODE = 1 in DMACHmTCR2).
  • 回复 Shine Zhang:

    查看资料后,终于知道了,自动加载只能用在事件触发模式(dmaConfig.trigger = CSL_DMA_EVENT_TRIGGER)。软件触发模式(CSL_DMA_SOFTWARE_TRIGGER)下不支持自动加载。

    现在遇到了新问题,我用I2S的TX事件触发,为什么仍然只能进入一次中断?

    关键代码:

    CSL_Status I2sDmaInit(void)
    {
        I2S_Config hwConfig;
        CSL_DMA_Config dmaConfig;
        CSL_Status status;
    
        /* DMA engine initialization */
        /* Open the device with instance 2 (AIC3204 is connected to I2S2 on C5515 EVM) */
        hI2s = I2S_open(I2S_INSTANCE, DMA_INTERRUPT, I2S_CHAN_STEREO);
        if(NULL == hI2s)
        {
            status = CSL_ESYS_FAIL;
            return (status);
        }
        else
        {
        	LOG_printf(&trace,"I2S Module Instance opened successfully\n");
        }
    
        /* Set the value for the configure structure */
        hwConfig.dataFormat     = I2S_DATAFORMAT_LJUST;
        hwConfig.dataType       = I2S_STEREO_ENABLE;
        hwConfig.loopBackMode   = I2S_LOOPBACK_DISABLE;
        hwConfig.fsPol          = I2S_FSPOL_LOW;
        hwConfig.clkPol         = I2S_FALLING_EDGE;
        hwConfig.datadelay      = I2S_DATADELAY_ONEBIT;
        hwConfig.datapack       = I2S_DATAPACK_DISABLE;
        hwConfig.signext        = I2S_SIGNEXT_DISABLE;
        hwConfig.wordLen        = I2S_WORDLEN_16;
        hwConfig.i2sMode        = I2S_SLAVE;
        hwConfig.clkDiv         = I2S_CLKDIV2; // don't care for slave mode
        hwConfig.fsDiv          = I2S_FSDIV32; // don't care for slave mode
        hwConfig.FError         = I2S_FSERROR_DISABLE;
        hwConfig.OuError        = I2S_OUERROR_DISABLE;
    
        /* Configure hardware registers */
        status = I2S_setup(hI2s, &hwConfig);
        if(status != CSL_SOK)
        {
            return (status);
        }
        else
        {
        	LOG_printf(&trace,"I2S Module Configured successfully\n");
        }
    
        /* Configure DMA channel 0 for I2S left channel read */
        dmaConfig.pingPongMode  = CSL_DMA_PING_PONG_DISABLE;
        dmaConfig.autoMode      = CSL_DMA_AUTORELOAD_ENABLE;
        dmaConfig.burstLen      = CSL_DMA_TXBURST_1WORD;
        dmaConfig.trigger       = CSL_DMA_EVENT_TRIGGER;
    
        dmaConfig.dmaEvt        = CSL_DMA_EVT_I2S2_TX;
    
        dmaConfig.dmaInt        = CSL_DMA_INTERRUPT_ENABLE;
        dmaConfig.chanDir       = CSL_DMA_WRITE;
        dmaConfig.trfType       = CSL_DMA_TRANSFER_IO_MEMORY;
        dmaConfig.dataLen       = NUM_SAMP_PER_MS*NUM_MS_PER_FRAME*2; // two frames
    
        dmaConfig.destAddr      = (Uint32)&CSL_I2S2_REGS->I2STXLT0;
    
        dmaConfig.srcAddr       = (Uint32)i2sDmaReadBufLeft;
    
        /* Open DMA ch0 for I2S left channel read */
        dmaLeftRxHandle = DMA_open(DMA_CHAN_L, &dmaObj0,&status);//DMA_CHAN_L = 4
        if (dmaLeftRxHandle == NULL)
        {
        	LOG_printf(&trace,"DMA_open CH4 Failed \n");
            dmaLeftRxHandle = NULL;
        }
    
        /* Configure DMA channel */
        status = DMA_config(dmaLeftRxHandle, &dmaConfig);
        if (status != CSL_SOK)
        {
        	LOG_printf(&trace,"DMA_config CH4 Failed \n");
            dmaLeftRxHandle = NULL;
        }
    
    //	I2S_transEnable(hI2s, TRUE);
    
        /* Configure DMA ch1 for I2S right channel read */
        dmaConfig.pingPongMode = CSL_DMA_PING_PONG_DISABLE;
        dmaConfig.autoMode     = CSL_DMA_AUTORELOAD_ENABLE;
        dmaConfig.burstLen     = CSL_DMA_TXBURST_1WORD;
        dmaConfig.trigger      = CSL_DMA_EVENT_TRIGGER;
    
        dmaConfig.dmaEvt        = CSL_DMA_EVT_I2S2_TX;
    
        dmaConfig.dmaInt       = CSL_DMA_INTERRUPT_ENABLE;
        dmaConfig.chanDir      = CSL_DMA_WRITE;
        dmaConfig.trfType      = CSL_DMA_TRANSFER_IO_MEMORY;
        dmaConfig.dataLen      = NUM_SAMP_PER_MS*NUM_MS_PER_FRAME*2;  // two frames
    
        dmaConfig.destAddr     = (Uint32)&CSL_I2S2_REGS->I2STXRT0;
    
        dmaConfig.srcAddr      = (Uint32)i2sDmaReadBufRight;
    
        /* Open DMA ch0 for I2S right channel read */
        dmaRightRxHandle = DMA_open(DMA_CHAN_R, &dmaObj1,&status);//DMA_CHAN_R = 5
        if (dmaRightRxHandle == NULL)
        {
        	LOG_printf(&trace,"DMA_open CH1 Failed \n");
            dmaRightRxHandle = NULL;
        }
    
        /* Configure DMA channel */
        status = DMA_config(dmaRightRxHandle, &dmaConfig);
        if (status != CSL_SOK)
        {
        	LOG_printf(&trace,"DMA_config CH1 Failed \n");
            dmaRightRxHandle = NULL;
        }
    
    //	I2S_transEnable(hI2s, TRUE);
    
        /* Start left Rx DMA */
        status = DMA_start(dmaLeftRxHandle);
        if (status != CSL_SOK)
        {
        	LOG_printf(&trace,"I2S Dma Left Failed!!\n");
            return (status);
        }
    
        /* Start right Rx DMA */
        status = DMA_start(dmaRightRxHandle);
        if (status != CSL_SOK)
        {
        	LOG_printf(&trace,"I2S Dma Right Failed!!\n");
            return (status);
        }
    
        // Enable DMA interrupt
        IRQ_enable(DMA_EVENT); // 必须,否则无法进入DMA中断
    
        /* Enable I2S */
        I2S_transEnable(hI2s, TRUE);
    
        return CSL_SOK;
    }

  • 回复 Shine Zhang:

    我要实现的功能是I2S+DMA播放音频文件。
    思路是通过I2S触发DMA传输RAM数据到I2S数据寄存器,DMA使用Ping-Pong模式。

    下面是Ping-Pong模式下的ISR,还没有完成。

    // DMA ISR
    void DmaIsr(void)
    {
        int ifrValue;
        Uint32 i;
        CSL_Status 	status;
    
      	ifrValue = CSL_SYSCTRL_REGS->DMAIFR;
    	CSL_SYSCTRL_REGS->DMAIFR |= ifrValue;
    	if ((DMA_getLastTransferType (dmaLeftRxHandle, &status)) == 1)
    	{
    		// Pong传输完成,标志位1
        	for (i=0; i<I2S_DMA_BUF_LEN; i++)
            {
    //    		dmaPongSrcBuf_L[i]  = dmaPongDstBuf_L[i];
    //    		dmaPongSrcBuf_R[i]  = dmaPongDstBuf_R[i];
            }
    	}
    	else
    	{
    		// Ping传输完成,标志位0
        	for (i=0; i<I2S_DMA_BUF_LEN; i++)
            {
    //    		dmaPingSrcBuf_L[i]  = dmaPingDstBuf_L[i];
    //    		dmaPingSrcBuf_R[i]  = dmaPingDstBuf_R[i];
            }
    	}
    }

    https://e2echina.ti.com/question_answer/dsp_arm/c5000/f/48/p/73804/245753?tisearch=e2e-quicksearch&keymatch=DMA#245753

    这个帖子的答案说,“#2. 在中断ISR里要读一下DMACSR清除状态。”,是否指的是8~9行的操作?

  • 回复 Shine Zhang:

    另外,我是在DSP/BIOS下使用的上述代码,是否有什么冲突?

    DmaIsr函数已经通过.tcf文件配置为HWI_INT8的ISR。主文件完整内容见附件。

    5153.tsk.c

  • 回复 Shide Lu:

    解决方法:用CSL函数来设置DM中断函数。
    不知道为什么,通过.tcf文件配置DmaIsr函数为HWI_INT8的ISR没有用,只能进一次中断。不知道DSP/BIOS是如何管理这个中断函数的。
    所以最终还是用CSL函数IRQ_plug(DMA_EVENT, &DmaIsr);来实现中断函数的设置。此时void DmaIsr(void){}要用interrupt 修饰。