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.
工程师您们好:
最近在使用UPP实现DSP与FPGA的数据传输,使用CACHE,在这里有两个问题请教您们一下,配图如下:
1、UPP接收完毕后需要进行一个CacheWB((unsigned int)upp_buffer_a, sizeof(upp_buffer_a));这个操作的主要目的是什么?为什么要这样呢?
2、在UPP进行DMA发送之前为什么也需要CacheWB((unsigned int)upp_buffer_b, sizeof(upp_buffer_b));操作呢?
您好:
谢谢您的回复,那也就是说接收的时候不需要回写操作对吧?那我程序里面接收的时候就不需要CACHEWB操作了。
麻烦再提几个问题:
1、我是将L1与L2及DDR全部配置成了CACHE,在UPP进行接收操作中为什么只是对L2进行CACHE invalid?,发送的回写也是争对L2的,为什么没有对 L1操作呢?当CPU在CACHE UPP地址数据时有没有可能在L1就命中呢?比如CPU在读的时候如果在L1就命中的话,即使对L2进行了CACHE invalid,那数据不是也会出错?这里我没有弄明白,请帮忙解答一下。
2、对TMS320C6748 L2进行cache invalid和write bake操作时是按照线(块)操作的,L2的最小块大小是多少啊?我没有找到相关的说明,是128Byte吗?
3、TMS320C6748的以太网也是用DMA搬移数据的?如果使用了CACHE,那是不是在读数据的时候也需要invalid呢?在发送的时候也需要write bake呢?
麻烦帮忙解答一下,谢谢!
好好学习 说:那也就是说接收的时候不需要回写操作对吧?那我程序里面接收的时候就不需要CACHEWB操作了。
回写是指将Cache中的数据写回到物理内存,是否要回写,取决于这个地址的数据是否还要,确切来说是是否要被DMA送出去。
#1. C674x的核,L1与L2是自动同步的,所以只需要对L2操作就可以了。
#2. 按Cache line size对齐: 128byte
#3. 是的。理解发Cache的工作原理就知道什么时候要做什么操作了。
细节建议阅读文档sprufk5a.
您好:
再追问一个问题,L2的cache line zize是128字节的话,那我在定义UPP的接收与发送数组时是不是说数组的首地址最好是128字节对齐呢?数组的长度也最好是128字节的整倍数对吗?这样在cache的时候就能够保证完全只对我所要操作部分地址的数据进行cache操作,而不会影响到其它数据。这样理解对吗?
可以,比如定义数组时按128byte对齐这样会比较好,但长度我觉得还是按应用怎样方便,就怎么定义吧,如果不是整数倍,无非操作时多操作几个无关的数。当然如果长度对应用无所谓,那么按128byte 的整数倍定义就更好了。
Tony Tang您好:
如果CACHE的时候CACHE到其它参数了,会不会有这种情况存在:
比如,当CPU在往一个cache地址进行写操作时,按理说会去同时更改物理内存地址(比如是A地址)的值,但是,如果当只写到cache还没来得及更改物理内存地址(A地址)时产生了中断,中断里面由于进行了读操作而进行了cache inv ,cache inv 恰恰又刚好把刚刚还没来得及写到物理内存地址的地址参数也进行了inv,当CPU下次再读取A地址的参数就会从主存读取(上次CPU对A地址的写操作还没来得及写到主存里去),这样数据不就出错了吗?有这种情况存在吗?
好好学习 说:中断里面由于进行了读操作而进行了cache inv
这个操作也是针对A地址吗?如果是,那么A地址的值你到底是要CPU更改后的,还是要EDMA更新过的?
Cache操作的问题,一定是存在第三者(比如EDMA)对同一地址操作时才要考虑的问题,如果只有CPU访问,不存在CACHE的问题。
Tony Tang您好:
中断里操作不是争对A地址的,比如B地址和A地址在CACHE里的同一个line里面,当CPU将A地址的值写进了cache,而还没来得及更新A地址的物理内存,此时进入中断后由于中断里面只是想把B地址进行cache inv,又由于A/B是在同一个line里面,因此cache inv B时实际上也把A地址进行了cache inv,那么当cpu下次再读取A地址的参数时不就会从A地址的物理内存读取,又由于刚刚A地址的参数还没来得及更新至物理内存,此时从物理内存读取不就出错了吗?
嗯,如果存在这种情况A就会从物理内存读出老的值。这么看来你已经对Cache的机制了解很清楚了:)
除了对齐处理,还可以在关键代码前后加上关,开中断的操作来避免这种情况。
Tony Tang您好:
所以我在想把定义的数组长度也按照128字节的整数倍定义,这样避免cache inv其它地址数据;谢谢您的耐心回复,我也是个初学者,以后有其它问题还需要多多请教您,十分感谢,谢谢。
Tony Tang 您好:
我使用的是TMS320C6748,我现在将L2的一半128K配置为CACHE(后28K),另一半为普通RAM(前128K),L1D及L1P全部配置成CACHE,DDR也全部配置成CACHE,我将部分代码程序放在L2的RAM中(前128K中),为什么程序就不运行了呢?放在DDR就可以?这是为什么呢?
首先这样配置没问题。至于为什么不运行,看一下,是怎么样个不运行:
#1. 程序能下载,运行到main吗?应该可以吧,那么也不能说是不运行不是。
#2. 跟踪代码,看是运行到哪出问题了,是在配置Cache后程序跑飞了吗?那么确认L2Cache的配置正确吗?不会配置成256K都是Cache了吧,如果是正确的,那么cmd文件修改了吗?检查一下map文件,看有没有部分代码或数据分配到了后128K呢?
好像是第一个图的第二句代码有点问题,CacheEnable这个函数还是后面宏定义有点问题,导致Cache的配置不对。
你可以看一下L2CFG(0x01840000)的最低3位值是不是3,如果不是则说明这个函数把Cache配置错了。改成直接写寄存器配置吧。
还是参考文档sprufk5a
Tony Tang您好:
你说的对,是CacheEnable函数的问题,L2cache配置错了!呵呵
还有,请问您们有没有UPP 16位发送与接收的相关示例程序啊?有的话能否给一份呢?谢谢!
这个真没有,因为我没有条件测试这种接口,就算做了也不知道对不对。
附件BSL里有相关例程。
Tony Tang您好:
不好意思打扰了,有一个问题我没有想明白:UPP中将接收数组upp_buffer_a[128]和发送数组upp_buffer_b[128]定义在L2前128K的普通RAM中,其余全部配置为CACHE,为什么UPP接收的数据就不正确呢?只需要将这两个数组(upp_buffer_a[128]、upp_buffer_b[128])定义在DDR中就完全正确了,这是为什么呢?没有搞明白!
Tony Tang您好:
配成128字节没有改善,现在是程序只要启动UPP发送,发送一段时间(随机),后程序就跑飞了,不启动UPP发送就不会,UPP使用了CACHE操作,不太清楚问题在哪里!您能给我一个您的邮箱吗?我将UPP部分代码发您邮箱麻烦帮我查看一下可以吗?
这个问题好像纠结好久了。感觉走的方向有点不对了。
现在到底是uPP的使用问题,还是Cache问题,还是程序本身问题,需要分开来考虑,感觉总是在怀疑uPP有什么问题。
uPP就是一个接口,用的是自已的DMA,就算是不对,至多是不搬数据,不产生中断等等这类的接口问题,而跟程序跑飞,结果对不对不应该有关系。
如果怀疑uPP有问题,那么做个简单的程序只跟FPGA之间做uPP的数据传输,验证对uPP接口的使用以及理解对不对。
至于Cache的原理你也了解了,就算操作不对,也只对数据有影响,以及对数据结果有影响,也不会影响到指令,跟跑飞也不会有关系。
我现在有点怀疑是系统不稳定了,比如DDR内存不稳定之类的。如果程序不大,先把程序放到片上内存,数据放到DDR,看会不会跑飞。
总的流程好像是在GPIO中断服务程序里发送uPP。
关GPIO中断没多大必要,反正进了中断后,就算有新中断也进不来了。
这段代码存在的问题是可能会导致发送的数据不对,至于为什么会导致跑飞,就要看程序背后的逻辑到底如何了。
在这个for循环里,先对buffer赋值,再判断upp是否空闲,其实这里的判断就是应该判断pend位吗?为什么判断的是ACT位?Cache维护,配置并启动uPP DMA,回到for 循环的开始对同一个buffer赋值,这里前面的uPP才刚开始启动,并不是传输完了,这样会导致传输的可能是会第二次更新的值,记得你前面很久的贴子说过值不对吧,说怎么操作Cache都还是不对,那问题就是在这里。
另外这个interrupt ISR是根据starterware里的例子来的吗?因为没看到回关键字interrupt。
结论,如果不是程序背后的逻辑导致跑飞,这段代码本身是不会导致跑飞的。
另外,加大堆栈(如果不够大)
Tony Tang 您好:
是判断的pend位,那函数里返回值是经过右移了1位返回的,关键字interrupt是有的,这个函数是中断函数调用的函数,堆栈是0x1000;不过有一点奇怪,当启动DMA传输后立即去判断pend位,发现pend位一直都为“0”,即
CacheWB ((unsigned int)upp_buffer_b, sizeof(upp_buffer_b));
uPPDMATransfer(SOC_UPP_0_REGS, uPP_DMA_CHQ, &transposeParB);
DMA_PEND = uPPDMAStatus_PEND(SOC_UPP_0_REGS, uPP_DMA_CHQ);
while((DMA_PEND & 0x00000001) != 0x00000000)
{
DMA_PEND = uPPDMAStatus_PEND(SOC_UPP_0_REGS, uPP_DMA_CHQ);
}
也就是说上面的while从来都没有进去过,当执行完uPPDMATransfer函数后开始判断pend位,pend始终都是“0”,还没发现为“1”的时候
这是函数调用,在退出前有堆栈的恢复操作,会占用一些时间,后面读pend又是一个函数调用,在开始部分又会有压栈动作,同样会占用时间,所以读pend位为0就不奇怪了,因为这个pend只是代码DMA启动了,新的参数可以写了,而不是DMA传完了。好好学习 说:uPPDMATransfer(SOC_UPP_0_REGS, uPP_DMA_CHQ, &transposeParB);
你可以试试不用函数调用方式,而是直接写寄存器的方式配置uPP DMA,再判断pend位状态,估计就能读到为1的时候了。
所以如果要提高代码效率,尽量减少函数调用,尤其对于一些简单的函数采用inline的方式,从而减少压栈,弹栈的时间消耗。
第一个问题好解释:因为只有两次,第一次uPP还是空闲的,所以在写完参数后就直接启动了,所以可以接着写第二个参数,如果还有第三次,那么就会要等到第一个执行完,第二个开始被执行,才可以写入第三个参数,在第二个与第三个之间一定能等到pend位的。
第二个问题,没看到程序全貌,比如说程序进来就到了default,然后break出来到if,err=0,不就直接往下执行了吗,就不知道后面是退出,还是有别的代码了,如果直接退出了,下次程序调用又进来到default~~~
前面提到的加大stack试了吗?
Tony Tang您好:
有个LWIP的问题请教一下,我现在想在c6748这边做一个服务器,当PC(客户端)机下发指令后服务器需要连续传输最多几十兆的数据给客户端。请问一下,LWIP服务器这边怎样实现连续发送几十兆的数据给客户端呢?
我使用类似于下面的连续调用tcp_write函数和tcp_output函数好像一次性最多只能发送几十K的数据,多的数据发送不了;
for(i=0;i<32;i++)
{
/*
需要发送的数据
*/
tcp_write(...);
tcp_output(...);
加点延时;
}