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.

dsp dma中断方式学数据到内存DDR2,有错误

Other Parts Discussed in Thread: SYSBIOS

TI专家,你好,

我的设计是:从dsp upp_A口读入48kB数据,采用dma方式传到内存(0xc200-000,共20块,每块4kB)。

dsp从upp_A口,dma每完成一次(每读到4KB数据),将产生一次中断,共应产生12次中断。

问题是:

1、开始数据有丢。

2、中断次数不足12次。

我每次在设置好内存后、设置dma传输前,有加Cache_inv(),在读内存数据前加Cache_wb(),错误没有变化。

加的头文件是:#include<ti/sysbios/hal/Cache.h>

请帮忙分析问题所在。

谢谢!

  • jack zhao3 说:
    我每次在设置好内存后、设置dma传输前,有加Cache_inv(),在读内存数据前加Cache_wb(),错误没有变化。

    置dma传输前,有加Cache_inv()。这一步要不要无所谓。

    在读内存数据前加Cache_wb(),这一步明显错误了,write back是将Cache的内容写回物理地址,岂不是把DMA更新后的数据用Cache里的老数据覆盖了,要做也是Cache_inv()。

    jack zhao3 说:

    1、开始数据有丢。

    2、中断次数不足12次。

    你做的是接收,那么要确保在upp DMA配置完成后,外部才开始发start信号启动uPP DMA的接收。

  • Tony 你好,

    也就是在“在读内存数据前加Cache_inv()”,就可以。

    我试过,问题依旧。

    upp DMA配置完成以后,才开始传输数据的。

  • 你这中断数都不对,跟Cache本来就无关。先把中断数搞对了,数据再不对的话再来查是不是Cache的问题。

  • 你好,Tony,

           1、丢终端问题解决了,是程序含延时造成的。

           2、我在读内存数据前加入以下语句,问题依旧。

    Cache_inv(node,sizeof(DataNode),Cache_Type_L2,true);
    Cache_inv(data,SR_BUFFER_SIZE,Cache_Type_L2,true);
    Cache_wait();

  • 你好,Tony,

    现在情况如下。

    每次接收完UPP的数据后,dsp共享内存里数据如下:

    [INFO |print_nodes@main.c,61] nodes:0,681,35b60,40000100,b5880100
    [INFO |print_nodes@main.c,61] nodes:1,81,493e0,40001180,b5881180
    [INFO |print_nodes@main.c,61] nodes:2,181,493e0,40002200,b5882200
    [INFO |print_nodes@main.c,61] nodes:3,281,493e0,40003280,b5883280
    [INFO |print_nodes@main.c,61] nodes:4,381,493e0,40004300,b5884300
    [INFO |print_nodes@main.c,61] nodes:5,481,493e0,40005380,b5885380
    [INFO |print_nodes@main.c,61] nodes:6,581,493e0,40006400,b5886400
    [INFO |print_nodes@main.c,61] nodes:7,681,493e0,40007480,b5887480
    [INFO |print_nodes@main.c,61] nodes:8,781,493e0,40008500,b5888500
    [INFO |print_nodes@main.c,61] nodes:9,881,493e0,40009580,b5889580
    [INFO |print_nodes@main.c,61] nodes:10,981,493e0,4000a600,b588a600
    [INFO |print_nodes@main.c,61] nodes:11,a81,493e0,4000b680,b588b680
    [INFO |print_nodes@main.c,61] nodes:12,b81,493e0,4000c700,b588c700
    [INFO |print_nodes@main.c,61] nodes:13,81,35b60,4000d780,b588d780
    [INFO |print_nodes@main.c,61] nodes:14,781,3e8,4000e800,b588e800
    [INFO |print_nodes@main.c,61] nodes:15,181,35b60,4000f880,b588f880
    [INFO |print_nodes@main.c,61] nodes:16,281,35b60,40010900,b5890900
    [INFO |print_nodes@main.c,61] nodes:17,381,35b60,40011980,b5891980
    [INFO |print_nodes@main.c,61] nodes:18,481,35b60,40012a00,b5892a00
    [INFO |print_nodes@main.c,61] nodes:19,581,35b60,40013a80,b5893a80

    493e0是这次的采样速率

    但dsp变量里数据,我是从共享内存中读出的,与它不同:

    [INFO |client_handler_do@client_handler.c,91] dd:0,681,35b60,40000100,b5880100
    [INFO |client_handler_do@client_handler.c,91] dd:1,81,493e0,40001180,b5881180
    [INFO |client_handler_do@client_handler.c,91] dd:2,881,35b60,40002200,b5882200
    [INFO |client_handler_do@client_handler.c,91] dd:3,981,35b60,40003280,b5883280
    [INFO |client_handler_do@client_handler.c,91] dd:4,a81,35b60,40004300,b5884300
    [INFO |client_handler_do@client_handler.c,91] dd:5,b81,35b60,40005380,b5885380
    [INFO |client_handler_do@client_handler.c,91] dd:6,581,33450,40006400,b5886400
    [INFO |client_handler_do@client_handler.c,91] dd:7,681,33450,40007480,b5887480
    [INFO |client_handler_do@client_handler.c,91] dd:8,781,33450,40008500,b5888500
    [INFO |client_handler_do@client_handler.c,91] dd:9,881,33450,40009580,b5889580
    [INFO |client_handler_do@client_handler.c,91] dd:10,981,33450,4000a600,b588a600
    [INFO |client_handler_do@client_handler.c,91] dd:11,a81,33450,4000b680,b588b680
    [INFO |client_handler_do@client_handler.c,91] dd:12,b81,33450,4000c700,b588c700

    它们前两行数据相同。

  • dsp变量里数据,我是从共享内存中读出的数据,是dsp共享内存里上一次存进的数据。

    似乎dsp读共享内存比dma快一点。

  • 从dsp upp_A口读入48kB数据,采用dma方式传到内存(0xc200-000,共20块,每块4kB)。

    我想请教upp数据到共享内存,dma方式,数据是直接到内存,还是先到cache?

  • 从dsp upp_A口读入48kB数据,采用dma方式传到共享内存(0xc200-000,共20块,每块4kB)。

    dsp从upp_A口,dma每完成一次(每读到8KB数据),将产生一次中断,共应产生6次中断。

    共享内存里数据 变量内存数据比较,请见附件。

  • 哇,一下这么多问题,我一个一个来尝试回答吧。

    jack zhao3 说:
           1、丢终端问题解决了,是程序含延时造成的。

    是因为任务里的task_sleep吗,我觉得这里不应该用sleep,应该用sem_pend,而semphore在UPP的ISR里post,然后直接触发任务处理,不然task_sleep在那里白白等1000个tick.

    jack zhao3 说:

         2、我在读内存数据前加入以下语句,问题依旧。

    Cache_inv(node,sizeof(DataNode),Cache_Type_L2,true);
    Cache_inv(data,SR_BUFFER_SIZE,Cache_Type_L2,true);
    Cache_wait();

    这个可能与放在代码中的位置有关系,后面你的问题里好像还有更详细的描述,在后面回答吧。

  • jack zhao3 说:
    每次接收完UPP的数据后,dsp共享内存里数据如下

    这是ARM端读的吗?如果这是正确的数据,那么说明数据是正常接收了。恭喜你。

    jack zhao3 说:
    但dsp变量里数据,我是从共享内存中读出的,与它不同:

    我理解这是DSP程序读取后再打印的,与上面ARM读的有出入,那么这里应该就是DSP的Cache维护没做好了。你是在uPP接收中断后,做Cache Invalid再做读取到变量的吗?

  • 不是快慢的问题,DSP是优先从Cache读的,虽然数据从UPP到物理内存更新了,但是如果DSP在读取同一个地址前没做Cache Invalid,那么Cache里的内容可能没有被替换,那么就是上一次的数据。

    关于Cache的工作机制,可以网上搜一下简单说明,基本原理都是一样的。

    而DMA是不经过Cache,一定会直接更新目标地址的数据的。

  • DMA到内存不经过CPU,不经过Cache,Cache是给CPU用的,用来加快CPU与外存之间的访问效率。

  • 如果我没理解你的图中的数据想表达的意思的话,第一次内存的数据与变量的数据是一致的,第二次就有部分不一致了,是吗?

    如果是的,那么就是Cache的维护问题了,虽然你作了Cache的维护操作,但是你是在什么位置加入Cache操作的代码呢?还有uPP DMA的buffer位置是ping-pong交替的吗?前后有没有存在还没读完UPP又送新数覆盖的问题。

    Cache invalid操作是要在CPU读写前,记得千万别搞错成了Cache write back。

  • 你好,Tony,

    1、Cache Invalid位置:

    DataNode *node = (DataNode *)ListMP_getTail(server->list_free); /* get free node */
    int *data = (int *)SharedRegion_getPtr(node->SR_buffer);

    ........

    Cache_inv(node,sizeof(DataNode),Cache_Type_L2,true);

    Cache_inv(data,SR_BUFFER_SIZE,Cache_Type_L2,true);
    Cache_wait();
    da[pdd]=(unsigned int)data;
    db[pdd]=node->SR_buffer;
    dd[pdd]=*(data+2);
    dd1[pdd]=*(data+3);


  • 2、“”如果我没理解你的图中的数据想表达的意思的话,第一次内存的数据与变量的数据是一致的,第二次就有部分不一致了,是吗?“”

    应当讲,每次读到内存变量里的数据与共享内存里的数据是不一样的,是上一次共享内存里的数据。

    “”共享内存里的数据“”是arm读出来的。

    “”内存变量里的数据“”是dsp读出来的。

    3、我现在的“”Cache invalid操作“”,是加在dsp的程序里。

    4、“”uPP DMA的buffer位置“”

    应当是在共享内存(0xc200-0000)里生成的堆里,共20块,每块含对指针、数据buffer。

    arm:

    /* create data nodes */
    DataNode *nodes[SYS_CFG_LIST_NODES];
    int i;
    for (i = 0; i < SYS_CFG_LIST_NODES; i++) {
    DataNode *node = (DataNode *)Memory_alloc(heap_node, sizeof(DataNode), 0, NULL);

    UInt32* data = (UInt32 *)Memory_alloc(heap_data, SR_BUFFER_SIZE, 0, NULL);
    node->SR_buffer = SharedRegion_getSRPtr(data, SYS_CFG_SR_ID_UPP_HEAP);
    node->size = SR_BUFFER_SIZE;
    node->buffer_pitch = BUFFER_PITCH;
    node->buffer_height = BUFFER_HEIGHT;

    nodes[i] = node;
    }

  • 你好,Tony,

    1、Cache Invalid位置:

    DataNode *node = (DataNode *)ListMP_getTail(server->list_free); /* get free node */
    int *data = (int *)SharedRegion_getPtr(node->SR_buffer);

    ........

    Cache_inv(node,sizeof(DataNode),Cache_Type_L2,true);

    Cache_inv(data,SR_BUFFER_SIZE,Cache_Type_L2,true);
    Cache_wait();
    da[pdd]=(unsigned int)data;
    db[pdd]=node->SR_buffer;
    dd[pdd]=*(data+2);
    dd1[pdd]=*(data+3);

    2、“”如果我没理解你的图中的数据想表达的意思的话,第一次内存的数据与变量的数据是一致的,第二次就有部分不一致了,是吗?“”

    应当讲,每次读到内存变量里的数据与共享内存里的数据是不一样的,是上一次共享内存里的数据。

    “”共享内存里的数据“”是arm读出来的。

    “”内存变量里的数据“”是dsp读出来的。

    3、我现在的“”Cache invalid操作“”,是加在dsp的程序里。

    4、“”uPP DMA的buffer位置“”

    应当是在共享内存(0xc200-0000)里生成的堆里,共20块,每块含对指针、数据buffer。

    arm:

    /* create data nodes */
    DataNode *nodes[SYS_CFG_LIST_NODES];
    int i;
    for (i = 0; i < SYS_CFG_LIST_NODES; i++) {
    DataNode *node = (DataNode *)Memory_alloc(heap_node, sizeof(DataNode), 0, NULL);

    UInt32* data = (UInt32 *)Memory_alloc(heap_data, SR_BUFFER_SIZE, 0, NULL);
    node->SR_buffer = SharedRegion_getSRPtr(data, SYS_CFG_SR_ID_UPP_HEAP);
    node->size = SR_BUFFER_SIZE;
    node->buffer_pitch = BUFFER_PITCH;
    node->buffer_height = BUFFER_HEIGHT;

    nodes[i] = node;
    }

  • Cache_inv(data,SR_BUFFER_SIZE,Cache_Type_L2,true);

    我不知该调用的函数,其输入参数是否正确?

    这是dsp里的程序内容。


  • Cache_inv(),Cache_wait()函数是哪来的?不是BIOS的,也是不是starterware的,自己写的?对不对啊?

  • 不是自己写的。

    “”Cache_Type_L2“”是<ti/sysbios/hal/Cache.h>里定义的。

    Cache_inv(),Cache_wait()我还没查出在哪里。但<ti/sysbios/hal/Cache.h>有声明。

  • 补充一下“”uPP DMA的buffer位置“”说明:

    /* heap for malloc list node */
    IHeap_Handle heap_node = (IHeap_Handle)SharedRegion_getHeap(SYS_CFG_SR_ID_LIST_HEAP);

    /* heap for malloc buffer for upp data */
    IHeap_Handle heap_data = (IHeap_Handle)SharedRegion_getHeap(SYS_CFG_SR_ID_UPP_HEAP);

    /* create data nodes */
    DataNode *nodes[SYS_CFG_LIST_NODES];
    int i;
    for (i = 0; i < SYS_CFG_LIST_NODES; i++) {
    DataNode *node = (DataNode *)Memory_alloc(heap_node, sizeof(DataNode), 0, NULL);

    UInt32* data = (UInt32 *)Memory_alloc(heap_data, SR_BUFFER_SIZE, 0, NULL);
    node->SR_buffer = SharedRegion_getSRPtr(data, SYS_CFG_SR_ID_UPP_HEAP);
    node->size = SR_BUFFER_SIZE;
    node->buffer_pitch = BUFFER_PITCH;
    node->buffer_height = BUFFER_HEIGHT;

    nodes[i] = node;
    }

  • 我把我的设计思路再描述一下:

    1、

    从dsp upp_A口读入48kB数据,采用dma方式传到内存(0xc200-000,共20块,每块8kB)。

    dsp从upp_A口,dma每完成一次(每读到8KB数据),将产生一次中断,共应产生6次中断。

    2、程序请见附件

  • 在dsp端程序,不加下列语句,效果是一样的。好像Cache_inv()未起作用。

    Cache_inv(node,sizeof(DataNode),Cache_Type_L2,true);
    Cache_inv(data,SR_BUFFER_SIZE,Cache_Type_L2,true);

  • 回复:“Cache_inv(),Cache_wait()函数是哪来的?”“

    ”bios_6_35_04_50/packages/ti/sysbios/hal/Cache.h有声明,但原函数再哪,不清楚。

    我包含了<ti/sysbios/hal/Cache.h>

  • 回复:  "你是在uPP接收中断后,做Cache Invalid再做读取到变量的吗?"

    是的。

  • 接上面一个问题:

    /* wait */
    while (upp_dmai_int_cut < 1 && upp_error_count == 0);
    等待中断后,在往下运行。

  • 采用mcsdk开发,arm端是采用linux os,dsp采用sys/bios,它们之间采用syslink通讯。

    问题1:cache一致性

    两种方案:1、每次操作通信用共享内存时刷 cache;2、设置shared memory 的某段范围为 cache disable。

    #1. Cache同步操作函数:

    a. DSP/BIOS里提供了API。

    应当采用sysbios下api,我包含了<ti/bios_6_35_04_50/packages/ti/sysbios/hal/cache.h>,但不知原函数cache_inv在哪。能编译通过,但不起作用

    b. Starterware(http://www.ti.com/tool/starterware-dsparm)提供了API:C6748_StarterWare_1_20_03_03\system_config\c674x\cache.c

    该目录下,有一个‘intvecs.asm’,不知如何编译

    #2. 通过设置MARn寄存器可控制某段地址不被Cache,每个MAR寄存控制16MByte空间,寄存器地址参考文档108页:http://www.ti.com/litv/pdf/sprufk5a

        4.4.4 Memory Attribute Registers (MARn)

    通过HWREG(0x01848308) &= ~0x01;,也不起作用

    问题2:

    arm端是否需要设置cache_inv(),该如何设置?


  • 你好,Tony,

    该问题一直没解决,整个项目停在这。

    不知您对我提出的问题,是否有完整的了解。

  • 烦请帮忙分析一下。

  • #1. 设置为不可Cache也有问题,说明就不是Cache的问题了。

    #2. ARM端的Cache维护操作要看Linux是怎么操作的。

    前面提到DSP读到的是上一次的数据,这说不通啊,你目前DSP的软件是在等待中断状态后就读内存,那么这时读的是最新的状态,怎么会是上一次的值呢?除非谁把上一次的值写回了,而DSP的Cache没使能,那么肯定不是DSP干的,难道是ARM写回的?如果是ARM的Cache写回的,那他自己读的数据怎么又是更新后的呢。怎么都说不通。

    ARM是何时读的值?

  • dsp采用dma方式,从upp_a口得到4kB的数据后,中断程序设置“数据块准备好标志”。

    dsp查询到中断程序设置的“数据块准备好标志”,设置数据块忙,通知arm。

    arm在查询到该数据块忙后,读取该数据块。

    每块数据接收好后,dsp端读取该数据块打印。arm端读取该数据块,打印,同时,打印整个共享内存的数据。都是打印第一行16B中的几个byte。

    arm与dsp读取的数据是一样的,都是共享内存被刷新前的数据。而打印的共享内存的数据是此次更新的数据。

  • 上面描述有误。

    dsp采用dma方式,从upp_a口得到4kB的数据后,中断程序设置“数据块准备好标志”。

    dsp查询到中断程序设置的“数据块准备好标志”,设置数据块忙,通知arm。

    arm在查询到该数据块忙后,读取该数据块。

    每块数据接收好后,dsp端读取该数据块存入内存数组。arm端读取该数据块,存入内存数组。

    当12块数据都传输完成后,dsp打印内存数组。arm打印内存数组,同时,打印整个共享内存的数据。都是打印第一行16B中的几个byte。

    arm与dsp读取的数据是一样的,都是共享内存被刷新前的数据。而打印的共享内存的数据是此次更新的数据。

  • 你说的DSP采用DMA方式,指的主是uPP的DMA吧,如果是则没有必要强调了,因为这是uPP自己的DMA,它也只有这种方式接收数据。

    你的DSP的任务采用了task_sleep(1000),这个没有必要等吧,一则在读数据时本身就有while在等状态,再者前后两次uPP DMA之间是如何连贯起来的?要知道uPP是一直在连续的接收的,如果你在当前这次uPP启动后没有为下一次uPP准备好DMA参数,那么在当前这次结束后,后面的数据怎么接收?

    再者建议将任务改成semaphore或者SWI替换这个task.

    还有从你提供的程序来看,这里等的是一个局部变量,它是如何在ISR在被更改的,没想通。


    upp_error_count = 0;
    upp_dmai_int_cut = 0;

    /* fill in data */
    uPPDMATransfer(SOC_UPP_0_REGS, uPP_DMA_CHI, &server->transposeParA);

    /* wait */
    while (upp_dmai_int_cut < 1 && upp_error_count == 0);

    if (upp_error_count != 0) {
    LOG_ERROR("data mismatch in buffers");
    LOG_ERROR("upp_error_count=%d",upp_error_count);
    }

  • dsp端程序:

    1、

    extern volatile int upp_error_count;
    extern volatile int upp_dmai_int_cut;
    extern volatile int upp_dmaq_int_cut;

    ....

    static bool server_upp_data_transfer(Server *server) { 

    if(server->ad_started == false) return true;
    while (ListMP_empty(server->list_free)) /* wait */
    //Task_sleep(10000);

    DataNode *node = (DataNode *)ListMP_getTail(server->list_free); /* get free node */
    int *data = (int *)SharedRegion_getPtr(node->SR_buffer);

    server->transposeParA.WindowAddress = (unsigned int *)data; /* set taget */
    server->transposeParA.LineCount = node->buffer_height;
    server->transposeParA.ByteCount = node->buffer_pitch;
    server->transposeParA.LineOffsetAddress = node->buffer_pitch;

    upp_error_count = 0;
    upp_dmai_int_cut = 0;

    /* fill in data */
    uPPDMATransfer(SOC_UPP_0_REGS, uPP_DMA_CHI, &server->transposeParA);

    /* wait */
    while (upp_dmai_int_cut < 1 && upp_error_count == 0);

    if (upp_error_count != 0) {
    LOG_ERROR("data mismatch in buffers");
    LOG_ERROR("upp_error_count=%d",upp_error_count);
    }

    /* make data node in busy list */
    ListMP_putHead(server->list_busy, (ListMP_Elem *)node);

    return true;
    }

    2、中断程序

    volatile int upp_error_count = 0;

    volatile int upp_dmai_int_cut = 0;
    volatile int upp_dmaq_int_cut = 0;

    void uPPIsr(void)
    {
    unsigned int intr_dmai_status, intr_dmaq_status;

    // 取?? DMA ?卸?状态
    intr_dmai_status = uPPIntStatus(SOC_UPP_0_REGS, uPP_DMA_CHI);
    intr_dmaq_status = uPPIntStatus(SOC_UPP_0_REGS, uPP_DMA_CHQ);

    while(intr_dmai_status != 0 || intr_dmaq_status != 0)
    {
    if (intr_dmai_status & uPP_INT_EOL)
    {
    uPPIntClear(SOC_UPP_0_REGS, uPP_DMA_CHI, uPP_INT_EOL);
    }

    if (intr_dmai_status & uPP_INT_EOW)
    {
    uPPIntClear(SOC_UPP_0_REGS, uPP_DMA_CHI, uPP_INT_EOW);
    upp_dmai_int_cut++;
    }

    if (intr_dmai_status & uPP_INT_ERR)
    {
    uPPIntClear(SOC_UPP_0_REGS, uPP_DMA_CHI, uPP_INT_ERR);
    upp_error_count++;
    }

    if (intr_dmai_status & uPP_INT_UOR)
    {
    uPPIntClear(SOC_UPP_0_REGS, uPP_DMA_CHI, uPP_INT_UOR);
    upp_error_count++;
    }

    if (intr_dmai_status & uPP_INT_DPE)
    {
    uPPIntClear(SOC_UPP_0_REGS, uPP_DMA_CHI, uPP_INT_DPE);
    upp_error_count++;
    }

    if (intr_dmaq_status & uPP_INT_EOL)
    {
    uPPIntClear(SOC_UPP_0_REGS, uPP_DMA_CHQ, uPP_INT_EOL);
    }

    if (intr_dmaq_status & uPP_INT_EOW)
    {
    uPPIntClear(SOC_UPP_0_REGS, uPP_DMA_CHQ, uPP_INT_EOW);
    upp_dmaq_int_cut++;
    }

    if (intr_dmaq_status & uPP_INT_ERR)
    {
    uPPIntClear(SOC_UPP_0_REGS, uPP_DMA_CHQ, uPP_INT_ERR);
    upp_error_count++;
    }

    if (intr_dmaq_status & uPP_INT_UOR)
    {
    uPPIntClear(SOC_UPP_0_REGS, uPP_DMA_CHQ, uPP_INT_UOR);
    upp_error_count++;
    }

    if (intr_dmaq_status & uPP_INT_DPE)
    {
    uPPIntClear(SOC_UPP_0_REGS, uPP_DMA_CHQ, uPP_INT_DPE);
    upp_error_count++;
    }

    // uPP ?卸辖??????录?????为同一?卸?源
    // ?卸??欠?全?????楸????????
    intr_dmai_status = uPPIntStatus(SOC_UPP_0_REGS, uPP_DMA_CHI);
    intr_dmaq_status = uPPIntStatus(SOC_UPP_0_REGS, uPP_DMA_CHQ);
    }

    // 通知 CPU uPP ?卸洗????????员??????录????圆???
    uPPEndOfInt(SOC_UPP_0_REGS);
    }

  • Task_sleep(10000);我去除了。

  • //Task_sleep(10000);屏蔽掉了,没有用。

    upp_a接收完一块数据4kB,将产生一次中断,upp_dmai_int_cut加1。

    dsp查询(upp_dmai_int_cut>=1),置该共享内存数据块为busy,通知arm该共享内存数据块已有数据。然后分配新的共享内存数据块给upp。共20块共享内存数据块。

    外部给upp_a数据也是一块一块给的,每块之间有时间间隔,至少1ms。