您的位置: OpenADSP社区论坛 -> Blackfin专区 -> 新手上路 -> [求助]53x_AUDIO_PCM中关于中断,DMA传输和... 
本帖共有816个阅读者
发表帖子 发表投票 回复主题
[求助]53x_AUDIO_PCM中关于中断,DMA传输和缓冲的关系
qianchang(论坛新手)
qianchang
头衔:社区公民
帮派:无帮无派
帖数:7
金钱:166
积分:10
注册时间:2015/7/2
楼主信息 | 留言 | Email | 主页 | 编辑 | 管理 | 离线
[求助]53x_AUDIO_PCM中关于中断,DMA传输和缓冲的关系
大神好。
先附上修改后的AUDIO_PCM的部分main code 和中断程序。
main code:
************************************
//Read the First audio files to SDRAM
     printf("initialization is ok!\n");
    fp1 = fopen("../3.wav", "rb");
    printf("open signal file1!\n");
    printf("read signal data1!\n");
    fread(buffer1, 1, 1024*1024*5, fp1);
    fclose(fp1);
    
    Init_Interrupts();    
    Init_Sport0_TX();            
    Init_DMA4_Sport0_TX();            
    Enable_DMA4_Sport0_TX();
    
    /* Playback the first file*/
    ptr = buffer1;
      
    
    do
    {
      
        while(current_play_buffer > 15)
        {
            ;
        }
        //
        ((audio_list_t *)sport_input_ptr)->des.SAL = (unsigned long)ptr;
        ((audio_list_t *)sport_input_ptr)->des.SAH = ((unsigned long)ptr)>>16;
        ((audio_list_t *)sport_input_ptr)->des.CFG = 0x7900 | WDSIZE_16|DMAEN|DI_EN;
        ((audio_list_t *)sport_input_ptr)->des.XCNT = 1024*16;
        ((audio_list_t *)sport_input_ptr)->des.XMOD = 2;
        ((audio_list_t *)sport_input_ptr)->flag = 1;
        sport_input_ptr = ((audio_list_t *)sport_input_ptr)->next;
        current_play_buffer ++;
        //
        ptr += 1024*16*2;
        
        // Re-Play cycle
    //    if (ptr==buffer1+1024*1024*5)
    //       ptr = buffer1;
    
    }while(ptr<=buffer1+1024*1024*5+1024*16*30);
    
    Stop_DMA4_Sport0_TX();}
*********************************************
SPORT0_TX_ISR
*********************************************
int mute_flag = 0;
//transfer interrupt
EX_INTERRUPT_HANDLER(Sport0_TX_ISR)
{

    *pDMA4_IRQ_STATUS = 0x0001;

    if(current_play_buffer == 0)
    {
        if(mute_flag==1)
            printf("mute\n");
        if(*pDMA4_NEXT_DESC_PTR == &des1)
        {
            des1.SAL = mute_des.SAL;
            des1.SAH = mute_des.SAH;
            des1.CFG = mute_des.CFG;
            des1.XCNT = mute_des.XCNT;
            des1.XMOD = mute_des.XMOD;
            
        }else
        {
            des2.SAL = mute_des.SAL;
            des2.SAH = mute_des.SAH;
            des2.CFG = mute_des.CFG;
            des2.XCNT = mute_des.XCNT;
            des2.XMOD = mute_des.XMOD;
        }    
    }else
    {
        mute_flag = 1;
        if(*pDMA4_NEXT_DESC_PTR == &des1)
        {
            des1.SAL = ((audio_list_t *)sport_output_ptr)->des.SAL;
            des1.SAH = ((audio_list_t *)sport_output_ptr)->des.SAH;
            des1.CFG = ((audio_list_t *)sport_output_ptr)->des.CFG;
            des1.XCNT = ((audio_list_t *)sport_output_ptr)->des.XCNT;
            des1.XMOD = ((audio_list_t *)sport_output_ptr)->des.XMOD;
            ((audio_list_t *)sport_output_ptr)->flag = 0;
        }else
        {
            des2.SAL = ((audio_list_t *)sport_output_ptr)->des.SAL;
            des2.SAH = ((audio_list_t *)sport_output_ptr)->des.SAH;
            des2.CFG = ((audio_list_t *)sport_output_ptr)->des.CFG;
            des2.XCNT = ((audio_list_t *)sport_output_ptr)->des.XCNT;
            des2.XMOD = ((audio_list_t *)sport_output_ptr)->des.XMOD;
            ((audio_list_t *)sport_output_ptr)->flag = 0;
        }
        current_play_buffer --;
        sport_output_ptr = ((audio_list_t *)sport_output_ptr)->next;
    }    
}
******************************************************
current_play_buffer 是一个缓冲针。但缓冲针大于15就进入一个while的无限循环。看起来,这个循环里面没有任何操作,可是如果删除这个循环就无法播放音频,这个地方很难理解

主函数的do..while循环里面是current_play_buffer的累加,相当于把音频数据不断的缓冲到sport_output的链表中。
中断程序的前半段是当current_play_buffer为0时,进行静音操作。把两个descritpor都设置为静音。后半段是进行音频读取操作,每操作一次,把current_play_buffer减1.

为了更好的理解,中断,DMA传输以及缓冲之间的关系,尝试单步调试。出现了几种情况:
1. 当调试到ptr=buffer1,就进入中断程序,因为没有进入do...while,所以current_play_buffer为0,中断就不停的进行静音操作,然后没完没了。然后程序无法进入do..while,所以没有声音播放出来可以理解,因为根本没有把SDRAM的数据传输到sport_output链表中。
2. 当直接运行程序,听到声音播放的时候,暂停。然后进行单步调试。程序停在中断程序的发送部分,也可以看到current_play_buffer里面有数值,表示有缓冲数据。单步运行会把current_play_buffer最后置为0,再次进入中断的静音,然后程序开始无限循环静音。
3. 设置一个breakpoint在do..while里面的current_play_buffer的自加位置,然后运行程序。程序停在这个位置之后,单步运行,立马进入中断的静音模式。然后没有音频播放输出。

综上所述,无法理解的地方是:
1. while(current_play_buffer>15)中的15跟sport_output 20个链表之间有个什么关系。
2. 为什么移出while(current_play_buffer>15),无法播放声音。可是这个while里面没有进行任何操作啊。
3. 本以为程序是先是中断静音,然后进入缓冲,缓冲了20个链表之后,开始进入中断的DMA传输。可发现不对。好像主程序的缓冲和中断里面的DMA传输是同时进行的。也就是说,主程序不断的在进行current_play_buffer累加,同时,中断传送也在不断的触发,因为传送一个就触发一个中断,然后current_play_buffer减1. 为什么单步运行无法看到这个过程呢?而且既然是同时在运行,其实current_play_buffer存在与否都对运行应该没什么影响,可是为什么去掉了current_play_buffer就无法工作了?

希望大神能尽快解答,详细解答。
对这个audio_PCM的理解已经到了最关键的一步。多谢大神的鼎立相助。


这家伙很懒,什么也没有留下!
等级:论坛新手 参考IP地址:*.*.*.*
2015/7/19 10:09:38
尊贵身份标志
andy(论坛版主)
andy
头衔:社区公民
帮派:无帮无派
帖数:2287
金钱:11132
积分:2263
注册时间:2011/6/8
1信息 | 留言 | Email | 主页 | 编辑 | 管理 | 离线
15设置的为最大缓冲帧,超过了就要等DMA那端消耗这个缓冲,一但删除可能会造成缓冲帧溢出。
while(current_play_buffer > 15)  就是当缓冲过多时,让代码停止缓冲,在这里等一等。

单步运行时,有一些DMA机制是无法正常触发的,比如中断不能在单步下触发,DMA传输有时会传输错误,所以导致代码工作异常。
如果想看哪些参数,可以用串口把参数实时发送出来,在超级终端上看。



这家伙很懒,什么也没有留下!
等级:论坛版主 参考IP地址:*.*.*.*
2015/7/26 17:00:39
qianchang(论坛新手)
qianchang
头衔:社区公民
帮派:无帮无派
帖数:7
金钱:166
积分:10
注册时间:2015/7/2
2信息 | 留言 | Email | 主页 | 编辑 | 管理 | 离线
Andy,多谢你的解释。

刚开始读取数据是以Unsigned char的类型存到了buffer里面。当修改成char的类型,也能正常运行。
但是,当修改成short类型,音频播放出来就断断续续的了。

这个问题应该如何定位?

这家伙很懒,什么也没有留下!
等级:论坛新手 参考IP地址:*.*.*.*
2015/7/27 3:06:20
尊贵身份标志
andy(论坛版主)
andy
头衔:社区公民
帮派:无帮无派
帖数:2287
金钱:11132
积分:2263
注册时间:2011/6/8
3信息 | 留言 | Email | 主页 | 编辑 | 管理 | 离线
你在内存中看看数据存储,是否数据不连续,比如short数据的高8位为0导致数据不连续。

这家伙很懒,什么也没有留下!
等级:论坛版主 参考IP地址:*.*.*.*
2015/8/2 23:30:54
Powered by OpenADSP Copyright © 2010 www.Openadsp.com. All rights reserved.159131 Call, 1 Queries, Processed in 0.031250 second(s),