OMAPL138学习---arm_call_dsp分析-

第一次用ARM DSP双核的板子(OMAPL138),对arm call dsp比较陌生,唯有官方源码,手上没有太多资料,只有从源码出发解读arm call dsp 流程。

  ARM源文件

-arm_main.c :主要的ARM应用程序源代码。这些代码设置DSPLINK和CMEM,下载DSP应用程序,并通过MSGQ管理与DSP的通信。

-arm_interface.c/h:处理DSPLIB特殊函数数据的ARM应用程序源代码。这些代码处理从输入文件得到的输入数据,保存输出数据到输出文件,并且当处理过程结束时释放CMEM的缓存。

-arm_parse.c/h:处理文本文件的解析的ARM应用程序源代码。

-common_interface.h:ARM和DSP应用程序共同的头文件,包括通用的自定义类型和枚举类型。

-arm_makefile:GNU 为ARM应用程序生成的makefile文件,其中BIN:=call_dsplib定义了生成的ARM 应用程序文件名为call_dsplib.

 DSP源文件

-dsp_main.c:DSP应用程序的主要源代码,包括对DSP/BIOS的静态设置结构体和动态TSK生成代码。

-dsp_interface.c/h:DSP应用程序源代码,包括DSPLINK和MSGQ的代码以及翻译DSPLIB函数调用ARM的请求。

-common_interface.h

-dsplib_server.cmd:包括手动添加到生成TCF连接器命令文件。

-dsplib_server.tcf: DSP/BIOS的文本配置文件(TCF)。定义了DSP程序的配置(存储段等)。

-dsp_makefile:GUN为ARM应用程序生成的makefile文件,其中PROJNAME:=dsplib_server定义了DSP工程名,BIN:=$(PROJNAME).out定义了生成的DSP程序文件名为dsplib_server.out。



ARM应用程序源代码 arm_main.c

 if (CMEM_init() == -1)
        {
            printf("Failed to initialize CMEM.\n");
            return -1;
        }
 初始化CMEM(一套管理一块或多块连续物理内存的API以及函数库)
实现代码在 cmem.c中:
int CMEM_init(void)
{
    int flags;
    unsigned int version;

    __D("init: entered - ref_count %d, cmem_fd %d\n", ref_count, cmem_fd);

    if (cmem_fd >= 0) {
        ref_count++;
        __D("init: /dev/cmem already opened, incremented ref_count %d\n",
            ref_count);
        return 0;
    }

    cmem_fd = open("/dev/cmem", O_RDWR);

    if (cmem_fd == -1) {
        __E("init: Failed to open /dev/cmem: '%s'\n", strerror(errno));
        return -1;
    }

    ref_count++;

    __D("init: successfully opened /dev/cmem, matching driver version...\n");

    version = CMEM_getVersion();
    if ((version & 0xffff0000) != (CMEM_VERSION & 0xffff0000)) {
        __E("init: major version mismatch between interface and driver.\n");
        __E("    needs driver version %#x, got %#x\n", CMEM_VERSION, version);
        CMEM_exit();
        return -1;
    }
    else if ((version & 0x0000ffff) < (CMEM_VERSION & 0x0000ffff)) {
        __E("init: minor version mismatch between interface and driver.\n");
        __E("    needs driver minor version %#x or greater.\n"
            "    got minor version %#x (full version %#x)\n",
            CMEM_VERSION & 0x0000ffff, version & 0x0000ffff, version);
        CMEM_exit();
        return -1;
    }

    __D("init: ... match good (%#x)\n", version);

    flags = fcntl(cmem_fd, F_GETFD);
    if (flags != -1) {
        fcntl(cmem_fd, F_SETFD, flags | FD_CLOEXEC);
    }
    else {
        __E("init: fcntl(F_GETFD) failed: '%s'\n", strerror(errno));
    }

    __D("init: exiting, returning success\n");

    return 0;
}

②确定DSPLIB函数索引

 index = get_fxnIndex(argv[1]);
        if (index < 0)
        {
            printf("Function name \"%s\" not recognized.  Function names are case sensitive.\n", argv[1]);
            return -1;
        } 
③为DSP从输入文件读取参数和准备信息
 parseStatus = parse_params(index, argv[2], &paramsARM, &paramsDSP);
        if (parseStatus < 0)
        {
            printf("Parameter parse failed in file %s.\n", argv[2]);
            return -1;
        } 
④初始化DSPLINK
if (LINKCFG_config.dspConfigs[Processor_ID]->dspObject->doDspCtrl == DSP_BootMode_NoBoot)
    {
        // strDspAddr(c_int00 address) and .args address are not required for
        // noboot mode. DSPLINK_shmBaseAddress address is not required to pass
        // because it is statically defined in linker command file of dsp side.
        //
        strDspAddr = "0x0";
        strShmAddr = "0x0";
        strArgsAddr = "0x0";
        call_dsplib_dspAddr = strtoll(strDspAddr, NULL, 16);
        call_dsplib_shmAddr = strtoll(strDspAddr, NULL, 16);
        call_dsplib_argsAddr = strtoll(strDspAddr, NULL, 16);
    }
    
    printf("Initializing DSPLINK...\n");

⑤开通消息队列
status = call_dsplib_init();
    if (DSP_FAILED(status)) { LOCAL_dsplinkFail("call_dsplib_init() failed.  Status = 0x%X\n", status); }
    
        #ifdef DDSP_DEBUG
        // debug: allow JTAG connection to DSP before message is sent
        printf("DSPLIB server loaded and running.  Press Enter to continue.");
        getchar();
        #endif
    
    printf("Calling DSPLIB function...\n");
static int call_dsplib_init(void)
{
    MSGQ_LocateAttrs syncLocateAttrs;
    Uint32 numArgs = 1;
    Char8* args[1] = { "123" }; // contents not used
    NOLOADER_ImageInfo imageInfo;
    DSP_STATUS status = DSP_SOK;
    
    // open DSPLINK
    status = PROC_setup(NULL);
    if (DSP_FAILED(status)) { LOCAL_dsplinkFail("PROC_setup() failed.  Status = 0x%X\n", status); }
    
    status = PROC_attach(Processor_ID, NULL);
    if (DSP_FAILED(status)) { LOCAL_dsplinkFail("PROC_attach() failed.  Status = 0x%X\n", status); }

    // create POOL and incoming MSGQ
    status = POOL_open(POOL_makePoolId(Processor_ID, Sample_POOL_ID), &SamplePoolAttrs);
    if (DSP_FAILED(status)) { LOCAL_dsplinkFail("POOL_open() failed.  Status = 0x%X\n", status); }
    
    status = MSGQ_open("dsplib_dsp2arm", &dsp2arm_msgq, NULL);
    if (DSP_FAILED(status)) { LOCAL_dsplinkFail("MSGQ_open() failed.  Status = 0x%X\n", status); }
    
    // set MSGQ error handler
    status = MSGQ_setErrorHandler(dsp2arm_msgq, POOL_makePoolId(Processor_ID, Sample_POOL_ID));
    if (DSP_FAILED(status)) { LOCAL_dsplinkFail("MSGQ_setErrorHandler() failed.  Status = 0x%X\n", status); }
    
    // load and execute DSP code
    if (LINKCFG_config.dspConfigs[Processor_ID]->dspObject->doDspCtrl ==  DSP_BootMode_NoBoot)
    {
        imageInfo.dspRunAddr = call_dsplib_dspAddr;
        imageInfo.shmBaseAddr = call_dsplib_shmAddr;
        imageInfo.argsAddr = call_dsplib_argsAddr;
        imageInfo.argsSize = 50;
        status = PROC_load(Processor_ID, (Char8 *) &imageInfo, numArgs, args);
    }
    else
    {
        status = PROC_load(Processor_ID, "./dsplib_server.out", numArgs, args);
    }
    if (DSP_FAILED(status)) { LOCAL_dsplinkFail("PROC_load() failed.  Status = 0x%X\n", status); }
    
    status = PROC_start(Processor_ID);
    if (DSP_FAILED(status)) { LOCAL_dsplinkFail("PROC_start() failed.  Status = 0x%X\n", status); }
    
    // Open the remote transport
    mqtAttrs.poolId = POOL_makePoolId(Processor_ID, Sample_POOL_ID);
    status = MSGQ_transportOpen(Processor_ID, &mqtAttrs);
    if (DSP_FAILED(status)) { LOCAL_dsplinkFail("MSGQ_transportOpen() failed.  Status = 0x%X\n", status); }
    
    // Locate the DSP's message queue
    // At this point the DSP must open a message queue named "DSPMSGQ"
    syncLocateAttrs.timeout = WAIT_FOREVER;
    status = DSP_ENOTFOUND;

    while ((status == DSP_ENOTFOUND) || (status == DSP_ENOTREADY))
    {
        status = MSGQ_locate("dsplib_arm2dsp", &arm2dsp_msgq, &syncLocateAttrs);
        if ((status == DSP_ENOTFOUND) || (status == DSP_ENOTREADY))
            usleep(100000);
        else if (DSP_FAILED(status)) { LOCAL_dsplinkFail("MSGQ_locate() failed.  Status = 0x%X\n", status); }
    }
    
    return status;
}
其中:
  ❶PROC_setup() 采用ARM 端应用程序载入DSP程序到DSP中运行的方法启动DSP,由于PROC组件被用物模拟DSP,首先要针对PROC进行创建和初始化。
❷PROC_attach(processorId,NULL) 在DSP端运行之前,需要建立与GPP端通信的DSP的关联,其中指定的processorId为与之通信的DSP的编号,防止ARM与多DSP通信时造成连接混乱。
❸POOL_open(POOL _makePoolId(processorId,POOL_ID),&SamplePoolAttrs),打开共享内存池,内存缓冲区同样需要一个ID来进行不同的分工,SamplePoolAttrs用来指定缓冲区大小,buffer个数等属性。
❹MSGQ_open(SampleGppMsgqName,&SampleGppMsgq,NULL) 在进行MSGQ通信之前的一个前提是处理器双方都需要各自打开一个消息队列,每个消息队列拥有各自的name,只有当连接方提出的name与消息队列的name相吻合的时候,消息队列才得到建立。利用此API打开消息队列,SampleGppMsgqName 指代的是GPP 端消息队列的name。
❺PROC_load(processorId,(Char8 *)&imageInfo,numArgs,args) 将编译好的DSP程序载入DSP中,相关参数为DSP的编号、DSP可运行程序名字、参数的个数和运行参数。
❻PROC_start(processorId) 开始运行编号为processorId 的DSP。
❼MSGQ_locate(dspMsgqName,&SampleDspMsgq,&syncLocateAttrs)等待需要建立的消息队列打开,由于通信时需要将一条消息队列的两个端口都关联到指定的处理器,只有name为dspMsgqName的消息队列一边已经打开后,才能连接指定要连接的消息队列,该消息队列才真正建立起来,半进行通信。该接口函数与MSGQ_open相呼应。syncLocateAttrs为指定等待的相关属性,如指定该属性为syncLocateAttrs.timeout=WAIT_FOREVER时,程序一旦运行到此函数处,如果另一方处理器还没有MSGQ_open的name为dspMsgqName的消息队列,便会阻塞在此处,直到打开为止。到这里GPP端的消息队列已经完成设置,等待DSP端消息队列的建立。


学习双核通信组件DSPLINK

猜你喜欢

转载自blog.csdn.net/zxycele/article/details/19969375