FPGA 串口接收超大数据问题
请问有没有人试过 用FPGA做 串口接受几百 Kbytes 数据的啊?最近做了个串口郁闷死了!
波特率设置19200, 系统时钟125MHZ
接收数据只接一帧,几百个字节都没有问题, 连续起来接收的时候 中间就老是 时不时有丢帧现象!间隔100ms 都有问题 用FIFO过度,木有问题 wang110 发表于 2013-4-30 16:48 static/image/common/back.gif
用FIFO过度,木有问题
现在是我的主频时钟跑了125Mhz接到中间就有那么几帧出错!!FIFO 我是用了! 不应当的,相对FGPA工作速度,串口即使115200都是非常慢的 NJ8888 发表于 2013-5-1 17:09 static/image/common/back.gif
不应当的,相对FGPA工作速度,串口即使115200都是非常慢的
我知道115200对于FPGA 来说,对接收到的数据进行解析的时间是绰绰有余的!
问题是 现在接收的时候总是发送中间有那么几帧数据接错!
我的串口模块是模仿特权同学写的那个,全局时钟用125mhz,通过判断下降沿,来决定串口是否开始接收数据!
现在怀疑中间如果有个大于8ns毛刺 那么整个串口模块就误认为数据来了,于是导致错误! suxilong 发表于 2013-5-1 20:15 static/image/common/back.gif
我知道115200对于FPGA 来说,对接收到的数据进行解析的时间是绰绰有余的!
问题是 现在接收的时候总是发 ...
不能这样的,应当按波特率的8 16或近似(当你无法严格按波特倍乘时)的速率做采样时钟,然后8中取中间3 16取中间7要求多数作为数据电平,125M的时钟非常不合适 NJ8888 发表于 2013-5-1 20:55 static/image/common/back.gif
不能这样的,应当按波特率的8 16或近似(当你无法严格按波特倍乘时)的速率做采样时钟,然后8中取中间3 1 ...
我的采样时钟的就是一个脉冲(宽度即为 主频时钟(8ns))!
cnt 在两种情况下会清零,
1。计数到BPS_PARA的时候 --- BPS_PARA =主频时钟(125 ) * 1000 000/波特率(115200)
2。 RS232_RX 脚下降沿来了的时候
cnt 计数器 计数到中间的时候就产生采样时钟,采样时钟的就是一个脉冲(宽度即为 主频时钟(8ns))!采样一个BIT 然后每次采样完1bit 就又用另外的计数Rx_bit_cnt计数1次 计数10次就算一个byte结束
波特倍乘? 何解? altera FPGA IP串口使用中断模式,结果发送数据和接收数据老丢数,请问一下遇到过没? lfeng105 发表于 2013-5-2 14:21 static/image/common/back.gif
altera FPGA IP串口使用中断模式,结果发送数据和接收数据老丢数,请问一下遇到过没? ...
哇!! 你用IP核啊!!! 我是模仿特权同学代码改的! 不一样 !所以我也不清楚IP核的丢数是否和我一样!
但个人感觉一个好的串口 接收发送 程序必须经得住以下几个考验
1。单个字节 一次性接收或发送不出错
2。单个字节 间隔接收或发送 不出错
3。单帧数据 一次性连续接收或发送几百 bytes不出错
4。多帧数据 (每帧几百bytes)间隔接收或发送 不出错
只可惜现在前三个考验都经过了,就是第四个 没能完成,一个多星期了 郁闷无助。。。。。 我的跑2.25Mbps都没问题啊,可能是你串口代码问题 denike 发表于 2013-5-2 16:31 static/image/common/back.gif
我的跑2.25Mbps都没问题啊,可能是你串口代码问题
求指教!我用的 是特权同学的代码! 我的项目里用了9个串口,115200,8,1。
8路同时接收都没问题,MB+uarilite,SP6的芯片。 tennokoe 发表于 2013-5-2 21:30 static/image/common/back.gif
我的项目里用了9个串口,115200,8,1。
8路同时接收都没问题,MB+uarilite,SP6的芯片。 ...
网上见到很多:
UART在发送或接收数据时,使用的时钟信号频率f是波特率(b=9 600 b/s)的16倍,由外部系统时钟进行16分频得到。UART每16个波特时钟发送或接收一个二进制位,设计中采用的晶振频率c=25 MHz,那么波特率发生器输出的时钟信号周期为: k = 25*1000 000 / 16* 96000
这个十六到底是怎么回事?
如果我用的是125MHZ用一个cnt 来计数, 计数到 BPS_PA 就清零或者检测到下降沿就清零, 数到中间 产生一个脉冲进行bit 采样!
BPS_PA = 125*1000 000/ 9600
这样可以吗?
两者有什么区别?
本帖最后由 tennokoe 于 2013-5-2 22:36 编辑
给一个基于FSL总线的串口IP,直接看串口部分的实现你就明白了。
如果撸主的串口是用软核+IP实现的,那么很可能是软件代码的问题。
贴出来看看。 tennokoe 发表于 2013-5-2 22:31 static/image/common/back.gif
给一个基于FSL总线的串口IP,直接看串口部分的实现你就明白了。
如果撸主的串口是用软核+IP实现的,那么很 ...
谢谢! 我没有用软核,我全部用硬件语言实现在!VHDL 写在, 当然一切都得感谢特权 同学.VERILOG 版本也有直接可以参照 特权同学在代码
等我把代码注释一下再贴出来请教大家, 现在没注释很乱....
其实我有一个相当困惑在问题! 为什么大家都说采样频率 最好是波特率的 8 ,或16 倍
最终无非是保证能够在BIT 中间进行采样, 那如果我 用以下在思路实现是否有问题呢
FPGA主频125MHZ ,波特率使用 115200
定义一个 CNT , 范围为 0 到 BPS_PA, BPS_PA =(125 * 1000 000 / 115200 ) -1
其次计数到1/2 BPS_PA 产生一个脉冲 进行采样一个BIT
正常情况下不停在计数, 只有在以下两种情况进行清零
1. 计数计满 BPS_PA
2. 检测到RS232_RX 接收端 有电平跳变(作用,不停在矫正计数器保证计数到1/2 BPS_PA 产生在脉冲处于 BIT采样在中间点 )
这样的话, 误差是否就不会累积 呢? 看看人家的波特率产生
parameter ClkFrequency = 36000000; // 25MHz
parameter Baud = 57600;
parameter RegisterInputData = 1; // in RegisterInputData mode, the input doesn't have to stay valid while the character is been transmitted
// Baud generator
parameter BaudGeneratorAccWidth = 16;
reg BaudGeneratorAcc;
`ifdef DEBUG
wire BaudGeneratorInc = 17'h10000;
`else
wire BaudGeneratorInc = ((Baud<<(BaudGeneratorAccWidth-8))+(ClkFrequency>>9))/(ClkFrequency>>8);
`endif
wire BaudTick = BaudGeneratorAcc;
wire TxD_busy;
always @(posedge clk) if(TxD_busy) BaudGeneratorAcc <= BaudGeneratorAcc + BaudGeneratorInc; // Transmitter state machine
reg state;
wire TxD_ready = (state==0);
assign TxD_busy = ~TxD_ready;
reg TxD_dataReg;
always @(posedge clk) if(TxD_ready & TxD_start) TxD_dataReg <= TxD_data;
wire TxD_dataD = RegisterInputData ? TxD_dataReg : TxD_data;
//The RS-232 parameters used are fixed: 8-bits data, 2 stop bits, no-parity.
always @(posedge clk)
case(state)
4'b0000: if(TxD_start) state <= 4'b0100;
//4'b0001: if(BaudTick) state <= 4'b0100;
4'b0100: if(BaudTick) state <= 4'b1000;// start
4'b1000: if(BaudTick) state <= 4'b1001;// bit 0
4'b1001: if(BaudTick) state <= 4'b1010;// bit 1
4'b1010: if(BaudTick) state <= 4'b1011;// bit 2
4'b1011: if(BaudTick) state <= 4'b1100;// bit 3
4'b1100: if(BaudTick) state <= 4'b1101;// bit 4
4'b1101: if(BaudTick) state <= 4'b1110;// bit 5
4'b1110: if(BaudTick) state <= 4'b1111;// bit 6
4'b1111: if(BaudTick) state <= 4'b0010;// bit 7
4'b0010: if(BaudTick) state <= 4'b0000;// stop1
//4'b0011: if(BaudTick) state <= 4'b0000;// stop2
default: if(BaudTick) state <= 4'b0000;
endcase
// Output mux
reg muxbit;
always @( * )
//always @( state )
case(state)
3'd0: muxbit <= TxD_dataD;
3'd1: muxbit <= TxD_dataD;
3'd2: muxbit <= TxD_dataD;
3'd3: muxbit <= TxD_dataD;
3'd4: muxbit <= TxD_dataD;
3'd5: muxbit <= TxD_dataD;
3'd6: muxbit <= TxD_dataD;
3'd7: muxbit <= TxD_dataD;
endcase
// Put together the start, data and stop bits
reg TxD;
always @(posedge clk) TxD <= (state<4) | (state & muxbit);// register the output to make it glitch free 这个发送部分 你参考下 tennokoe 发表于 2013-5-2 22:31 static/image/common/back.gif
给一个基于FSL总线的串口IP,直接看串口部分的实现你就明白了。
如果撸主的串口是用软核+IP实现的,那么很 ...
static void uart1_ISR(void)
{
if(UART1->STATUS.BITS.TRDY && UART1->CONTROL.BITS.ITRDY)
{
if (uart1.TxTail != uart1.TxHead) //如果itrdy中断已打开,判断发送缓冲区是否为空
{
UART1->TXDATA.BITS.TRANSMIT_DATA = uart1.TxBuf; //如果发送缓冲区中还有发送数据,发送一个字节数据
if (++uart1.TxTail > (TXBUFSIZE - 1)) //如果已到达数组尾部,TxTail索引值返回数组头部
uart1.TxTail = 0;
}
else //已经没有待发送数据,关闭发送中断,使能接收中断
{
UART1->CONTROL.BITS.ITRDY=0; //关发送中断
}
}
if(UART1->STATUS.BITS.RRDY)
{
if(uart1.receive_count < RXBUFSIZE)
{
uart1.receive_buffertmp = UART1->RXDATA.BITS.RECEIVE_DATA;
if(uart1.receive_buffertmp==';')
{
uart1.receive_flag = 1;
uart1.RxTail = uart1.receive_count-1;
}
}
else
{
uart1.receive_count = 0;
uart1.receive_buffertmp = UART1->RXDATA.BITS.RECEIVE_DATA;
if(uart1.receive_buffertmp==';')
{
uart1.receive_flag = 1;
uart1.RxTail = uart1.receive_count-1;
}
}
}
}
这是软核IP的接受发送中断代码,RXBUFSIZE = 1024,程序判断字尾‘;’。在主程序中循环处理uart1.receive_buffertmp[] 内容 denike 发表于 2013-5-4 10:34 static/image/common/back.gif
看看人家的波特率产生
parameter ClkFrequency = 36000000; // 25MHz
parameter Baud = 57600;
谢谢! 这段代码 与FPGA4fun 上面的差不多!
只是首先我现在用的VHDL,VHDL 里面移位还不是很懂,
其次verilog 好久没用 虽然大概清楚思路,但是最让我不解的还是为什么一定要这样来做计数! 直接用主频除以波特率 得到一个数取整不就可以了吗?
这样每次rs232 ——rx电平跳变就矫正一次, 这样不是很精确吗?
避免毛刺可以在6,7,8的时候采样三次,然后依据两次为高取1,两次为低取0;好像这个论坛上有代码和文档的;
另外,你是采用中断的方式还是轮询的方式来进行数据传输的;可以在上位机加延时看看是什么效果; 楼主真是执着到固执,你的方法对付毛刺没招 denike 发表于 2013-5-4 10:34 static/image/common/back.gif
看看人家的波特率产生
parameter ClkFrequency = 36000000; // 25MHz
parameter Baud = 57600;
类似这种移位,在VHDL 里面如何实现得了呢? NJ8888 发表于 2013-5-6 21:56 static/image/common/back.gif
楼主真是执着到固执,你的方法对付毛刺没招
谢谢NJ 不辞劳苦回复, 今天回头去看看FPGA4fun的例子,发现原来是我自己一直没有彻底理解16分频的目的
http://www.erg.abdn.ac.uk/~gorry/course/phy-pages/async.html
后来看了他后面的链接 才发现自己原来一直误解了~~~ denike 发表于 2013-5-4 10:36 static/image/common/back.gif
这个发送部分 你参考下
请问你这个部分的代码 有没有testbech 啊?
fpga4fun 上面的rs232例子大家用的人很多,但实际代码很多都不是很明了, 我想跑一下仿真看看 信号的变化是怎样的, 但是老是跑不出波形 不知哪里出错~~~ NJ8888 发表于 2013-5-6 21:56 static/image/common/back.gif
楼主真是执着到固执,你的方法对付毛刺没招
NJ ,这是fpga4fun上面rs232的例子 用这个testbech总是跑不出 波形能否指点一下
我的就是fpga4fun的例子啊 很好用啊 修改一下可以跑1Mbps以上了 denike 发表于 2013-5-9 11:14 static/image/common/back.gif
我的就是fpga4fun的例子啊 很好用啊 修改一下可以跑1Mbps以上了
判断下降沿的 那部分我看不懂
我想跑一下rtl仿真 看看是怎么个原理但是 跑不起来 我和楼主一样,用的的是特权同学的代码,也参考了fpga4fun的代码,应该没什么问题... 深海烟花 发表于 2013-5-9 22:52 static/image/common/back.gif
我和楼主一样,用的的是特权同学的代码,也参考了fpga4fun的代码,应该没什么问题... ...
fpga4fun的代码看不懂啊, 太久没动verilog~~~ 写个testbech 又仿真不出来~~~~
尤其以下两个进程
////////////////////////////
reg RxD_sync_inv;
always @(posedge clk) if(Baud8Tick) RxD_sync_inv <= {RxD_sync_inv, ~RxD};
// we invert RxD, so that the idle becomes "0", to prevent a phantom character to be received at startup
reg RxD_cnt_inv;
reg RxD_bit_inv;
always @(posedge clk)
if(Baud8Tick)
begin
if( RxD_sync_inv && RxD_cnt_inv!=2'b11) RxD_cnt_inv <= RxD_cnt_inv + 2'h1;
else
if(~RxD_sync_inv && RxD_cnt_inv!=2'b00) RxD_cnt_inv <= RxD_cnt_inv - 2'h1;
if(RxD_cnt_inv==2'b00) RxD_bit_inv <= 1'b0;
else
if(RxD_cnt_inv==2'b11) RxD_bit_inv <= 1'b1;
end
reg state;
reg bit_spacing;
// "next_bit" controls when the data sampling occurs
// depending on how noisy the RxD is, different values might work better
// with a clean connection, values from 8 to 11 work
wire next_bit = (bit_spacing==4'd10);
always @(posedge clk)
if(state==0)
bit_spacing <= 4'b0000;
else
if(Baud8Tick)
bit_spacing <= {bit_spacing + 4'b0001} | {bit_spacing, 3'b000}; 用我的UART代码,保证没问题。 不错 学习了 代码本身有bug,可能是数据接收完成时的设置flag有问题
我曾经写过一个uart,就是这种问题
用modelsim弄大量的数据进行功能仿真也许就可以看得出来了
这种出错条件应该很固定 请问楼主最后怎么解决的?谢谢 有没有作IO毛刺过滤 串口收发问题以后看看,mark 收藏了慢慢看最近也被这个串口搞的头大 000000000000000000000000000000000000000000000000 感谢大家,项目上正要用类似的接口。 使用特权同学源码测试串口收发,发现发送字节数大于3个时在刚上电第一次发送,固定第二个字节会丢失 低级错误 其实同步采样,用16倍时钟,每个字节都重新调整同步,没有累积误差是又简单又稳定的做法。 一定要多倍过采样!!!!!!! 用fifo 放m4k里面
页:
[1]