suxilong 发表于 2013-4-29 13:51:01

FPGA 串口接收超大数据问题

请问有没有人试过 用FPGA做 串口接受几百 Kbytes 数据的啊?
最近做了个串口郁闷死了!
波特率设置19200, 系统时钟125MHZ

接收数据只接一帧,几百个字节都没有问题, 连续起来接收的时候 中间就老是 时不时有丢帧现象!间隔100ms 都有问题

wang110 发表于 2013-4-30 16:48:35

用FIFO过度,木有问题

suxilong 发表于 2013-5-1 17:03:45

wang110 发表于 2013-4-30 16:48 static/image/common/back.gif
用FIFO过度,木有问题

现在是我的主频时钟跑了125Mhz接到中间就有那么几帧出错!!FIFO 我是用了!

NJ8888 发表于 2013-5-1 17:09:32

不应当的,相对FGPA工作速度,串口即使115200都是非常慢的

suxilong 发表于 2013-5-1 20:15:10

NJ8888 发表于 2013-5-1 17:09 static/image/common/back.gif
不应当的,相对FGPA工作速度,串口即使115200都是非常慢的

我知道115200对于FPGA 来说,对接收到的数据进行解析的时间是绰绰有余的!

问题是 现在接收的时候总是发送中间有那么几帧数据接错!
我的串口模块是模仿特权同学写的那个,全局时钟用125mhz,通过判断下降沿,来决定串口是否开始接收数据!
现在怀疑中间如果有个大于8ns毛刺 那么整个串口模块就误认为数据来了,于是导致错误!

NJ8888 发表于 2013-5-1 20:55:18

suxilong 发表于 2013-5-1 20:15 static/image/common/back.gif
我知道115200对于FPGA 来说,对接收到的数据进行解析的时间是绰绰有余的!

问题是 现在接收的时候总是发 ...

不能这样的,应当按波特率的8 16或近似(当你无法严格按波特倍乘时)的速率做采样时钟,然后8中取中间3 16取中间7要求多数作为数据电平,125M的时钟非常不合适

suxilong 发表于 2013-5-2 12:25:36

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结束

波特倍乘? 何解?

lfeng105 发表于 2013-5-2 14:21:56

altera FPGA IP串口使用中断模式,结果发送数据和接收数据老丢数,请问一下遇到过没?

suxilong 发表于 2013-5-2 15:35:23

lfeng105 发表于 2013-5-2 14:21 static/image/common/back.gif
altera FPGA IP串口使用中断模式,结果发送数据和接收数据老丢数,请问一下遇到过没? ...

哇!! 你用IP核啊!!! 我是模仿特权同学代码改的! 不一样 !所以我也不清楚IP核的丢数是否和我一样!


但个人感觉一个好的串口 接收发送 程序必须经得住以下几个考验
1。单个字节 一次性接收或发送不出错
2。单个字节 间隔接收或发送   不出错
3。单帧数据 一次性连续接收或发送几百 bytes不出错
4。多帧数据 (每帧几百bytes)间隔接收或发送   不出错

只可惜现在前三个考验都经过了,就是第四个 没能完成,一个多星期了 郁闷无助。。。。。

denike 发表于 2013-5-2 16:31:44

我的跑2.25Mbps都没问题啊,可能是你串口代码问题

suxilong 发表于 2013-5-2 19:50:58

denike 发表于 2013-5-2 16:31 static/image/common/back.gif
我的跑2.25Mbps都没问题啊,可能是你串口代码问题

求指教!我用的 是特权同学的代码!

tennokoe 发表于 2013-5-2 21:30:43

我的项目里用了9个串口,115200,8,1。
8路同时接收都没问题,MB+uarilite,SP6的芯片。

suxilong 发表于 2013-5-2 22:04:16

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:31:58

本帖最后由 tennokoe 于 2013-5-2 22:36 编辑

给一个基于FSL总线的串口IP,直接看串口部分的实现你就明白了。

如果撸主的串口是用软核+IP实现的,那么很可能是软件代码的问题。
贴出来看看。

suxilong 发表于 2013-5-3 10:54:59

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采样在中间点 )


这样的话, 误差是否就不会累积 呢?

denike 发表于 2013-5-4 10:34:06

看看人家的波特率产生
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;

denike 发表于 2013-5-4 10:35:36

// 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

denike 发表于 2013-5-4 10:36:05

这个发送部分 你参考下

lfeng105 发表于 2013-5-4 20:43:20

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[] 内容

suxilong 发表于 2013-5-4 22:35:24

denike 发表于 2013-5-4 10:34 static/image/common/back.gif
看看人家的波特率产生
parameter ClkFrequency = 36000000;        // 25MHz
parameter Baud = 57600;


谢谢! 这段代码 与FPGA4fun 上面的差不多!

只是首先我现在用的VHDL,VHDL 里面移位还不是很懂,

其次verilog 好久没用 虽然大概清楚思路,但是最让我不解的还是为什么一定要这样来做计数! 直接用主频除以波特率 得到一个数取整不就可以了吗?
这样每次rs232 ——rx电平跳变就矫正一次, 这样不是很精确吗?

jm2011 发表于 2013-5-6 13:21:05

避免毛刺可以在6,7,8的时候采样三次,然后依据两次为高取1,两次为低取0;好像这个论坛上有代码和文档的;
另外,你是采用中断的方式还是轮询的方式来进行数据传输的;可以在上位机加延时看看是什么效果;

NJ8888 发表于 2013-5-6 21:56:19

楼主真是执着到固执,你的方法对付毛刺没招

suxilong 发表于 2013-5-8 23:07:26

denike 发表于 2013-5-4 10:34 static/image/common/back.gif
看看人家的波特率产生
parameter ClkFrequency = 36000000;        // 25MHz
parameter Baud = 57600;


类似这种移位,在VHDL 里面如何实现得了呢?

suxilong 发表于 2013-5-8 23:10:35

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
后来看了他后面的链接 才发现自己原来一直误解了~~~

suxilong 发表于 2013-5-9 10:54:36

denike 发表于 2013-5-4 10:36 static/image/common/back.gif
这个发送部分 你参考下

请问你这个部分的代码 有没有testbech 啊?

fpga4fun 上面的rs232例子大家用的人很多,但实际代码很多都不是很明了, 我想跑一下仿真看看 信号的变化是怎样的, 但是老是跑不出波形 不知哪里出错~~~

suxilong 发表于 2013-5-9 11:01:48

NJ8888 发表于 2013-5-6 21:56 static/image/common/back.gif
楼主真是执着到固执,你的方法对付毛刺没招

NJ ,这是fpga4fun上面rs232的例子 用这个testbech总是跑不出 波形能否指点一下

denike 发表于 2013-5-9 11:14:29

我的就是fpga4fun的例子啊 很好用啊 修改一下可以跑1Mbps以上了

suxilong 发表于 2013-5-9 14:02:24

denike 发表于 2013-5-9 11:14 static/image/common/back.gif
我的就是fpga4fun的例子啊 很好用啊 修改一下可以跑1Mbps以上了

判断下降沿的 那部分我看不懂

我想跑一下rtl仿真 看看是怎么个原理但是 跑不起来

深海烟花 发表于 2013-5-9 22:52:32

我和楼主一样,用的的是特权同学的代码,也参考了fpga4fun的代码,应该没什么问题...

suxilong 发表于 2013-5-9 23:15:28

深海烟花 发表于 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};

skyxjh 发表于 2013-6-20 00:11:35

用我的UART代码,保证没问题。

wenxin0000 发表于 2013-11-22 15:22:12

不错 学习了

wangjun403 发表于 2013-11-22 16:06:26

代码本身有bug,可能是数据接收完成时的设置flag有问题

我曾经写过一个uart,就是这种问题

用modelsim弄大量的数据进行功能仿真也许就可以看得出来了
这种出错条件应该很固定

zhumingxing6 发表于 2014-3-19 14:17:43

请问楼主最后怎么解决的?谢谢

FighterSun 发表于 2014-3-19 14:32:09

有没有作IO毛刺过滤

武文奇 发表于 2014-3-21 11:44:30

串口收发问题以后看看,mark

xd785 发表于 2014-8-28 14:43:57

收藏了慢慢看最近也被这个串口搞的头大

yanmylbh 发表于 2014-9-6 09:54:01

000000000000000000000000000000000000000000000000

xh2008email 发表于 2014-12-24 20:20:13

感谢大家,项目上正要用类似的接口。

sunboyyb 发表于 2018-9-29 14:41:51

使用特权同学源码测试串口收发,发现发送字节数大于3个时在刚上电第一次发送,固定第二个字节会丢失

zya2008 发表于 2018-9-29 22:38:26

低级错误

xz9406 发表于 2018-9-30 10:09:54

其实同步采样,用16倍时钟,每个字节都重新调整同步,没有累积误差是又简单又稳定的做法。

wowangru 发表于 2018-11-12 17:57:16

一定要多倍过采样!!!!!!!

wowangru 发表于 2018-11-16 13:46:18

用fifo  放m4k里面
页: [1]
查看完整版本: FPGA 串口接收超大数据问题