• 实习项目1-串口IP升级调试


    设计目标:设计一个串口IP,要求1:输入时钟频率任意,如0-400M时钟频率;要求2:波特率超过常见的115200,要求达到4M.

    设计核心思路:波特率计算公式,divp10x = (10 * fsysclk) / (16 * baud),divp10x 是10倍分频系数,当给定一个参考时钟和波特率,那么分频系数就定了,这里16指16倍波特率时钟采样。

    为何进行16倍过采样,防止误采样数据,即一般采样时钟频率大于波特率时钟频率的16倍,数据一般不出错。本次为了便于在实际中应用,采用8倍采样,故采样时钟仅为16倍的一半。波特率4M,本次的采样时钟仅需64M,此时分频系数为2.

    做设计的思路:一:先搭建仿真环境,即能够测试串口IP,同时仿真包含顶层模块,主机的串口发送(调用串口IP),从机的串口发送和接收,SDRAM存储器给串口IP的相应寄存器地址和读写命令。看出仿真模块是重要的,并且模块众多和功能全面。二:仿真测试串口IP能够实现的功能和各模块的驱动逻辑。即波特率能支持到几兆,并且数据不出错。例如,刚开始测量常见波特率9600,115200等都能达到,后面上网一查才知道波特率和波特率参考时钟有对应关系,必须符合才能正确发送。还发现了高波特率低误差的实现,需要的条件,根据波特率计算公式,串口系数必须大于2等要求。第三步,在仿真测得相应参数,时钟 频率和波特率值后,下载程序到开发板验证,分别是发送端和接受端波特率都能达到4M,或者连接逻辑分析仪,设置触发条件和观察对应的数据波形。

    核心代码:

    module baudset(
    rst,
    sysclk,
    rxclk
    );

    input rst ;
    input sysclk;
    output rxclk ;

    reg rxclk;

    parameter fsysclk = 64_000_000;
    parameter baud = 115_200;
    parameter divp10x = (10 * fsysclk) / (16 * baud);
    parameter divp1x = fixv(divp10x);
    parameter N = wordsize(divp1x);
    parameter divp = fixv2(divp1x);
    parameter low = 1'b0;
    parameter hi = 1'b1;

    reg [N-1:0] cnt1 = {N{1'b0}};
    // reg [3:0] cnt2 = 4'd0;

    //------------function-----------//
    function [31:0]fixv;
    input [31:0]value10x;
    fixv = value10x % 10 < 5 ? value10x / 10 : (value10x / 10) + 1;
    endfunction

    function [N-1:0]fixv2;
    input [31:0]value;
    fixv2 = value;
    endfunction

    function [5:0]wordsize;
    input [31:0]value;
    begin
    wordsize = 1'b1;
    while((32'b1 << (wordsize - 1'b1)) < value) wordsize = wordsize + 1'b1;
    end
    endfunction
    //---------------------------------//

    always @(posedge sysclk or negedge rst)
    begin
    if(rst == low)
    begin
    cnt1 <= {N{1'b0}};
    rxclk <= hi;
    end
    else if(cnt1 == (divp >> 1'b1))
    begin
    cnt1 <= cnt1 + 1'b1;
    rxclk <= low;
    end
    else if(cnt1 == (divp - 1'b1))
    begin
    cnt1 <= {N{1'b0}};
    rxclk <= hi;
    end
    else
    begin
    cnt1 <= cnt1 + 1'b1;
    end
    end

    /*
    assign txclk = cnt2[3];

    always @(posedge rxclk or negedge rst) begin
    if(rst == low) begin
    cnt2 <= 4'd0;
    end
    else begin
    cnt2 <= cnt2 + 1'b1;
    end
    end
    */
    endmodule

    问题及解决办法:

    问题一:仿真测得波特率达到4M的参考时钟且数据正确接收时,下载到开发板出错:

    方法是,首先得看看硬件支不支持,原来是开发板的串口模块不支持,RS232只能到115200,然后查阅资料直到USB转串口芯片CH340能够到2M,用网络调试助手测试还是发现出错,但仿真没有问题,原来多种方法测试,由于软件的问题,那就换成官方CH340的软件串口助手,发现波特率能够到达2M。启示:用一个电子器件时或学一样东西,用官方芯片的驱动和软件,才是最正确的。要到4M,又得换一个更强的硬件芯片,即USB2XX,一个串口转芯片,能到4M,并且看了这个芯片的手册和装了它的软件。再烧写程序到开发板验证,果然可以到4M,后面就是发现对应的时钟频率为200M,得用锁相环产生这个频率。

    问题二:16倍波特率采样,波特率达到4M对应的时钟频率太高,得降一半才行。

    仔细分析了一下,主要是这个波特率计算公式:divp10x = (10 * fsysclk) / (16 * baud);即参考时钟至少是波特率的16倍,那要波特率不变,降低参考时钟频率,只需将16倍改成8倍采样即可。首先就得找出实现16倍样的逻辑。看了模块的代码,波特率产生模块,产生了一个16倍波特率分频时钟Clk16X,传递给其他模块作为时钟信号。主要是在四个模块中用到:sram_slave(其实可忽略,没用到),Rxcver(做了很多模块的驱动时钟,)Txmitt(核心应用模块)baudset(波特率产生模块)。要看懂16倍波特率采样逻辑,那就得看懂baudset和Txmitt的代码。

    问题三;怎么看懂源码?

    步骤一:先画出这个模块的框图(区别输入输出),看看输出怎么被驱动,能大概找到输入与输出的逻辑。步骤二:关键一步,仿真。通过仿真看看数据流动,输入输出信号的关系。(很重要,自己理解往往不准确,波形很直观准确反映驱动条件和执行逻辑)。步骤三(学习的心态),在看懂别人的思路后,自己动手写,不断调试直到实现功能。

    问题四:从机串口接收和发送模块的数据错误为为8'b8.正确该为8'6c

    解决过程:

    刚开始完全乱猜,就胡乱修改代码,以为是波特率问题或者divclk_en该延迟一个时钟周期,即主观臆断瞎蒙。改来改去发现还是错的。

    后面觉得这种做法是错误的,又不是写作文或做梦,全凭自己胡乱想,正确的做法,该是看看世界是怎样的,自己怎么想不重要。即该认真看波形,数据出错,那就看看到底是哪个代码驱动条件导致它错的。即根据现象找到原因,逻辑分析,依据客观世界去活,而不是自己的主观世界。我就一级级找,根据驱动逻辑分析,直到Txmitt模块,TxCNT_R模块和uart_rxs模块的cnt_bit信号,两个模块的计数器信号没有对齐延迟了7个周期。(找到出错的地方)

    3.11日,第二天,我又继续分析,,发现这两个计数信号的计数加一规律不一样,TxCNT_R一个是16个时钟周期。uart_rxs模块的cntbit信号是12个时钟。原来是这样的,那改成一样的加一规律即可。然后我再分析他们加一的驱动条件是啥,再次改成都是同样的驱动条件即可。

     待发送的数据是8‘h6c,可以从波形看出,接受模块的发送线tx,发送的数据是从低位开始,直到最高位,故发送线是0011_0110.从波形看出,8位数据位计数器cnt_bit与发送线对应的数据相合,而且数据也是待发送的8‘h6c。

    通过这次调试程序,最大感悟是:以分析现象明确原因,找出逻辑关系为原则(仿真,追根溯源,不断由输出到驱动条件一级级分析)。而不是自己猜想和胡乱改的。

    参考博客:

    长弓的坚持----为什么UART串口通信要16倍过采样数据

    https://blog.csdn.net/wordwarwordwar/article/details/80178708?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163028678816780264043616%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=163028678816780264043616&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v2~rank_v29-1-80178708.pc_v2_rank_blog_default&utm_term=%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%B2%E5%8F%A3%E8%A6%8116%E5%80%8D%E8%BF%87%E9%87%87%E6%A0%B7&spm=1018.2226.3001.4450

  • 相关阅读:
    实现基于C++的动态事件机制(转)
    D3D HLSL 一段代码注释
    directx加载ms3d动画模型
    几种空间分割算法研究之bsp
    IxEngine开发笔记
    使用UVAtlas技术管理贴图
    八叉树
    c#调用C++写的dll导出类,包含继承,重载等详细介绍(转载)
    给自己毕业前的一点任务
    大小端问题
  • 原文地址:https://www.cnblogs.com/Xwangzi66/p/14540421.html
Copyright © 2020-2023  润新知