在搞启用fifo和BDMA的UART时,确实走了不少弯路。昨天一下午的时间我都在用轮询法检测DMA的运行情况,加上BDMA配置上犯了这样那样的错误,昨天一直都在报RUNOVER。总算在昨晚熄灯的最后时刻,停止了溢出,可接包总是丢失。对于这种最稳定的模式,这种现象是不该出现的。
考虑来考虑去,原来是我犯了低级错误。轮询怎么能用在DMA模式呢?而且我保接包数量放在普通函数中计算,通过轮询BDCON的SET位。结果可想而知。本身BDMA的数据传输就不经过CPU,而执行计数函数前又要执行其他函数或中断函数,漏查是在所难免的。好在今天觉悟了。换成中断。
void Uart_BDMAInit(void)
{
BDMApt=(char*)RAM_ADDRESS;
//*BDMApt=0;
//pool=BDMApt;
//rBDICNT0=0x0<<20;
//BDMApt=SaveBDMA;
//Savept=(Savept)|(0x0c200000)|(0x9<<27)|(0x2<<29);
rBDCON0=0x0;
rBDISRC0=0x31d00024;
rBDIDES0=(0xc200000)|(0x9<<28);
rBDICNT0=(0x8<<28)|(0xe<<20)|(0x4<<24)|(0x10);
rBDICNT0|=1<<20;
rBDCON0|=0x0;
}
///
void __irq Uart_BDMA(void)
{
rI_ISPC=BIT_BDMA0;
//printf("UART ERROR/n");
//Uart_BackSend();
e++;
}
注释我就不加了,相信都能看得懂。
结果,很OK。做了多次测试丢包数量0。另外,我的发送启用了FIFO但用的是轮询模式(前面我提过,这种模式很山寨的,慢,而且不稳,不过我这是低速场合,还好没有写溢出(丢包)的问题)。对于FIFO触发这里再多说几句,发送BDMA设的是下线,即发送过程中要保证发送FIFO不空,而接受FIFO设的上限触发,即接受过程要保证不出现RUNOVER。发送BDMA无需自动重装。因为,对于发送我们往往知道数据包大小,若不考虑总线占用问题可一次搞定所有数据。而接收时BDMA同样前提是,前提你申请的缓冲区足够大(同样是在不考虑总线占用的情况)。若为配置自动重装且BDMA计数器设为16时,每次DMA操作后移动16字节数据到设定地缓冲区(这往往在BDMA中断中完成,另外这里所说的缓冲区需要另开辟,而非BDMA目的地址,这样便有了释放总线的时间,总线不会被一直在占用)。若发非连续数据可不设自动重装,因为接收FIFO(或接收缓冲区)不触发DMA,这时是不占用总线的。连续数据需要考虑总线的占用问题(这是可以设自动重装,并需另开辟缓存区)。
如果一次发送数据不足以触发BDMA,我们就需要设一个接收超时中断,而发送则不需要设置,发送只要给数据就发出去了,不存在在FIFO中暂存的情况。超时中断函数中我们需要做以下几点,回写服务位,读接收FIFO中暂存的数据(一定要考虑这种不溢出的情况,否则就会丢包)。如读出后,后续数据满足触发条件。则后续数据直接通过BDMA存放在我们申请的缓存中。
void __irq Uart_TimeOut(void)
{
char TimeOutData=0;
rI_ISPC=BIT_UERR01;
TimeOutData=rUFSTAT0&0x000f;
for(;TimeOutData>0;TimeOutData--)
{
ot[TimeOutData]=rURXH0;
}
}
这样就完成了UART+BDMA+FIFO模式下定的数据接收。
DIY