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.

在omapl138上面跑linux+sysbios时双核都使用EDMA遇到的问题

Other Parts Discussed in Thread: SYSBIOS

ARM端使用SPI flash跑的是linux的3.3内核,DSP那边跑sysbios,使用slaveloader进行引导,DSP端有mcasp和mcbsp使用EDMA,在ARM端SPI flash也是使用EDMA,当只跑ARM核时可以正常使用EDMA,可以删除、储存文件系统里面的文件,但是DSP端也跑起来的时候ARM这边同步文件之后系统就卡住了,感觉应该是EDMA这一块冲突了,之后查看了一下linux里面关于EDMA初始化的代码,里面有一个结构体是关于EDMA_CC0和EDMA_CC1的,给DSP保留了对应的channel和slot,channel这个参数是芯片维护的32个通道,slot是用户维护的128个通道;

而且手册和代码里面都注明了,可以用同一个EDMACC控制器,ARM核和DSP核使用的shadow寄存器不一样,中断向量也不一样,(错误中断虽然只有一个但是现在还不牵涉这个问题)

DSP端的EMDA配置使用startware里面的代码,进去EDMAIint函数里面,把ARM那边初始化过的全局寄存器这段都屏蔽了,只初始化DSP自己的区域部分寄存器,这样抛弃DSP的EDMA之后DSP的EDMA可以正常跑,但是ARM这边的SPI flash操作部分就卡住了;

现在只能使用中断方式进行SPI flash的读写,速度慢了很多,请问群里有没有用过这种场景的工程师或者TI的技术师傅有没有这方面的例程可以参考一下的,毕竟EDMA控制器这部分文档写的比较简单,就是寄存器的配置,没有写双核都要用时怎么分开使用的情况;

双核通讯用的是syslink

  • 我想先把EDMA的寄存器状态log下来分析一下当前对应SPI的EDMA配置是什么状态吧。

    简单的做法,在DSP端,从CCS里把EDMA的寄存器都截下来,以及对应的parameter.

  • 对于EDMA的控制器来说,双核可以单独指定EDMA_CC_INTm之外,其他的错误中断是不是只能一边用?不能两个核都用的,虽然都有向量?还是中断完成的中断都只能一边用的?ARM这边配置EDMA_CC_INT0之后,引导跑起来DSP,然后在DSP端配置了EDMA_CC_INT1之后,ARM这边就不产生了中断完成的中断了。

  • 看了一下startware里面的EDMAInit()函数,如果先跑起来Linux内核,再跑DSP,DSP调用EDMAInit();的时候就会让linux端的EDMA失效了,TI有没有提供在linux端已经跑起来EDMA的某个通道了,然后引导DSP程序时,DSP里面能初始化EDMA,但是不影响ARM端的函数接口?

  • bingliang chen 说:
    对于EDMA的控制器来说,双核可以单独指定EDMA_CC_INTm之外,其他的错误中断是不是只能一边用?不能两个核都用的,虽然都有向量?还是中断完成的中断都只能一边用的?ARM这边配置EDMA_CC_INT0之后,引导跑起来DSP,然后在DSP端配置了EDMA_CC_INT1之后,ARM这边就不产生了中断完成的中断了。

    应该说是只需要一边用错误中断,进错误中断的处理无非就是查错误源,再清错误状态。如果两边都使能了这个中断,那么中断信号产生时,一定会同时送到两边的中断控制器,也就是都要会触发ARM和DSP的中断,而进入各自的中断服务程序。

    问题是如果两边都用了这个中断,一定会有一个先查到错误状态(进中断程序的先后根据各自当前软件所处状态会有差异,比如某个核当前是中断disable的状态,那么要等到中断enable状态后才有机会响应这个中断进入ISR),清除错误状态,另一个进到中断ISR的就查不到错误状态了,则不会做处理就退出。

    这样子我觉得也不会对程序造成什么影响,只是做了不必要的一次中断进出操作。

  • bingliang chen 说:
    看了一下startware里面的EDMAInit()函数,如果先跑起来Linux内核,再跑DSP,DSP调用EDMAInit();的时候就会让linux端的EDMA失效了,TI有没有提供在linux端已经跑起来EDMA的某个通道了,然后引导DSP程序时,DSP里面能初始化EDMA,但是不影响ARM端的函数接口

    具体两边怎么搞,我一下没办法提供一个完整的方案,但是EDMA初始化部分真正必需要操作的寄存并不多。在我看来,必需要操作的global寄存器也就是region寄存DRAE,其它的可以自己的region即shadow寄存器操作。

    可以根据这个方向简化一下DSP的EDMA初始化程序,我想这样比修改linux端的要方便直观些,至少对于我来说是这样。

  • 如果真的如您所说的EDMA控制器对双核的响应都是这样子的话,那可以排除在配置不同channel通道的时候造成的影响,问题就已经缩小了,可以定位到startware里面的EDMAInit();函数把linux端使用的EDMA通道相关的配置改写了。

    Tony哥:EDMAInit()函数有两个入参,一个是CC基址,另一个是寄存器区域,DSP选1,ARM选0,函数里面还有一个区域相关的宏,也是DSP为1,ARM为0,我还进去讲与区域无关的全局重置的代码都屏蔽了,还是会导致ARM端EDMA出问题,能否提供一个新代码,在DSP端初始化的时候不会影响到ARM端的EDMA,新代码中肯定需要知道ARM端已经使用了哪些channel,这个都可以提供。

  • 我觉得有必要升级一下startware的版本,把这个EDMA控制器共用的互斥部分该加进去,我相信很多人都遇到这个问题,以前的老帖子已经有人提出这个问题了,三年了,都没有人解决。其他模块只会一个核用,不会出现这个问题
  • 如果希望软件自己知道ARM,DSP用了哪些通道,需要用codec engine framework,以及EDMA LLD驱动,大致的思路是用一个数组来配置和记录哪些通道ARM用了,哪些DSP用了。如果有兴趣可以去研究一下,有点复杂的。

    我看了一下你提到的EDMA3Init函数,里面将所有通道都在region 1(DSP)使能了。

    /* FOR TYPE EDMA*/
    /* Enable the DMA (0 - 64) channels in the DRAE and DRAEH register */

    HWREG(baseAdd + EDMA3CC_DRAE(regionId)) = EDMA3_SET_ALL_BITS;
    HWREG(baseAdd + EDMA3CC_DRAEH(regionId)) = EDMA3_SET_ALL_BITS; //这一句应该去掉,L138上没有32-63通道。

    你可以看一下DSP配置完后影响了哪些与ARM端EDMA相关的寄存器。从CCS里截个屏不就行了吧,我不觉得这有多难啊。

  • 问题就是region 1的使能跟arm端的spi 通道不相关的,arm使用的是region 0,从手册上写的来看应该不会影响到arm端,只要dsp不使用arm已经用掉的spi的通道,就不应该影响到arm端的edma,所以去不去掉这一句话不影响结果。
  • bingliang chen 说:
    我觉得有必要升级一下startware的版本,把这个EDMA控制器共用的互斥部分该加进去,我相信很多人都遇到这个问题,以前的老帖子已经有人提出这个问题了,三年了,都没有人解决。其他模块只会一个核用,不会出现这个问题

    关于这个问题我有必要说明一下:

    #1. TI有,我前面提到 的Codec engine framework.

    #2. 那解释一下#1,为什么需要在framework才能做这个事。本身两个核是独立的,各跑各的程序,从硬件上没有机制知道对方用了什么,即互斥。所以要软件实现,软件实现无非要一个告知另一个我用了哪些通道,以及我要用哪些通道。做为一个变量能让对方通过API能查询得到。那么两个核之间必然要实现一套供调用的底层API,这个说起来就这么一句话,实际上实现起来是一套复杂的软件框架,有兴趣可以了解一下codec engine。

    其实上面的实现无非是通过软件方式知道对方用了哪些通道,我不用就行了,我用没用的通道。如果软件是你自己写的,芯片资源(EDMA通道)也是由你分配的,那要不要上面这套机制又有什么关系呢?

    #3. 对于这种ARM+DSP的架构的芯片,还有一层意思,你可以把所有外设相关的操作都交给ARM,DSP只做数据运算处理,不与外设打交道,这样就不需要纠结资源分配的问题了,也可以考虑一下。

  • 请问,在Linux下如何调用EDMA LLD驱动呢?能提供简单的例程么?