AX7A200教程(5): 基于DDR3的串口发送和接收(一次突发)(一)

本章节主要使用ddr3做为缓存,串口接收的数据通过ddr缓存后通过发送模块发送出去。整体的功能框图所下图所示

写通道

串口接收到8位数据后,将4个8位数据合并为一个32位数据写入到写fifo,当写入8个32位数据后,也就是一共256位宽数据,这时会发出一个突发写使能信号wr_len_en,将256位数据写入到ddr3中存储(rd_data_count = 9'd1表示写fifo已经写入一个256位宽数据

    //突发写使能
    always@(posedge ui_clk or negedge i_rst_n)begin
            if(!i_rst_n)
                wr_len_en    <=  1'd0;    
            else if(ddr_wr_end)
                wr_len_en    <=  1'd0;    
            else if(rd_len_en)
                wr_len_en    <=  1'd0;    
            else if(wr_len_done)
                wr_len_en    <=  1'd0;                             
            else if(rd_data_count >= 9'd1)
                wr_len_en    <=  1'd1;                        
    end

读通道

当写fifo写入256数据后,并且突发写完成(wr_len_done为突发写完成信号),这时会产生一个突发读使能信号rd_len_en,将ddr3中的256位宽数据读出写入到读fifo中

    always@(posedge ui_clk or negedge i_rst_n)begin
            if(!i_rst_n)
                wr_len_done_r   <=  1'b0;
            else 
                wr_len_done_r   <=  wr_len_done;
    end                    
    
    //突发读使能
    always@(posedge ui_clk or negedge i_rst_n)begin
            if(!i_rst_n)
                rd_len_en    <=  1'd0;
            else if(ddr_rd_end)
                rd_len_en    <=  1'd0;            
            else if(wr_len_en)
                rd_len_en    <=  1'd0;     
            else if(rd_len_done)
                rd_len_en    <=  1'd0;                 
            else if(wr_len_done_r)
                rd_len_en    <=  1'd1;                     
    end 

当tx_data_convert模块检测读fifo的read_fifo_empty为0时,也就是读fifo有数据时,会产生一个read_en读使能信号,读出读fifo的数据,每次都是读一个32位数据read_dout

always@(posedge i_clk or negedge i_rst_n)begin
        if(!i_rst_n)
            read_data   <=  32'd0;
        else if(count == 4 )
            read_data   <=  32'd0;    
        else if(read_en)
            read_data   <=  read_dout;
        else
            read_data   <=  read_data;    
end
always@(posedge i_clk or negedge i_rst_n)begin
        if(!i_rst_n)begin
            read_en  <=  1'd0;
            read_en_flag  <=  1'd0;
            end
        else if(count == 4 )begin
            read_en  <=  1'd0;
            read_en_flag  <=  1'd0;
            end    
        else if(read_en_flag)
            read_en  <=  1'd0;    
        else if(!read_fifo_empty)begin 
            read_en  <=  1'd1;
            read_en_flag  <=  1'd1;
            end
        else
            read_en  <=  1'd0;        
end

最后tx_data_conver模块会将读出32位数据转换为4个8位数据,并且通过uart_tx发送出去

always@(posedge i_clk or negedge i_rst_n)begin
        if(!i_rst_n)
            tx_data  <=  8'd0;
        else case(count)
            0: tx_data  <=  read_data[31:24];
            1: tx_data  <=  read_data[23:16];
            2: tx_data  <=  read_data[15:8];
            3: tx_data  <=  read_data[7:0];
            default:tx_data <= tx_data;
            endcase
end
uart_tx uart_tx_inst(
    . sclk      (clk_50M),
    . s_rst_n   (rst_n),
    // UART Interface
    . rs232_tx  (rs232_tx),
    . tx_flag   (tx_flag),
    . tx_done   (tx_done),
    // others
    . tx_trig   (tx_trig),//tx_trig
    . tx_data   (tx_data)//tx_data
    
    )

将开发板上电,连接串口

因ddr3突发一次是256位宽,也就是32个8位数据,所以一次发32个8位数据开发板接收后才会将接收到的数据发送出来。

串口未发送任何数据

串口发送32个8位数据,可以看到发送的和接收的数据是一致的

点重复发送,看下效果,发送和接收的数据一致并且数量一样

重复发送后,可以看到,当数据接收到2048就停止了

为什么接收到2048就停止了,打开程序发现我们设置ddr最大的读写地址为512,每次都是突发8个32位256位宽数据,设置为512表示一共计数512个32位宽的数据,换算一下就是2048个8位数据刚好和接收停止的一致

所以我们这里需要对ddr的读写地址进行清零,才能再次接收,这里使用ddr读写完成信号ddr_wr_end和ddr_rd_end产生vin_vs和vout_vs信号,发出wr_reset和rd_reset对地址进行清零

always@(posedge ui_clk or negedge rst_n)begin
        if(!rst_n)
            wr_load_r   <=  1'd0;
        else 
            wr_load_r   <=  {wr_load_r[14:0],vin_vs};
end 

always @(posedge ui_clk or negedge rst_n) begin
         if(!rst_n)
             wr_page    <=  3'd0;
         //else if(wr_load_r[0] && !wr_load_r[14])
             //wr_page    <=  wr_page + 1'b1;
end
      
always@(posedge ui_clk or negedge rst_n)begin
        if(!rst_n)
            wr_reset   <=  1'd0;
        else if(wr_load_r[0] && !wr_load_r[14])
            wr_reset   <=  1'd1;
        else if(app_addr_wr == 0 && !(wr_load_r[0] && !wr_load_r[14]))    
            wr_reset   <=  1'd0;
end
always@(posedge ui_clk or negedge rst_n)begin
        if(!rst_n)
            rd_load_r   <=  1'd0;
        else 
            rd_load_r   <=  {rd_load_r[14:0],vout_vs};
end

always @(posedge ui_clk or negedge rst_n) begin
         if(!rst_n)
             rd_page    <=  3'd0;
         //else if(rd_load_r[0] && !rd_load_r[14])
             //rd_page    <=  wr_page - 1'b1;
end 
       
always@(posedge ui_clk or negedge rst_n)begin
        if(!rst_n)
            rd_reset   <=  1'd0;
        else if(rd_load_r[0] && !rd_load_r[14])
            rd_reset   <=  1'd1;
        else if(app_addr_rd == 0 && !(rd_load_r[0] && !rd_load_r[14]))    
            rd_reset   <=  1'd0;
end 

重新编译工程,将程序下载开发板,重复发送,可以看到发送和接收都是一致的

整个工程文件较多,所以不贴代码了

ddr3的简单用法就写到这里,如果有不懂的可以直接下载工程进行仿真测试

链接:https://pan.baidu.com/s/1TOrTU7i1RpgEXw-igxiL1A

提取码:2x12

ddr读写需要大家理解读写突发的基本概念,如果基本的读写突发能够理解,基本这个工程也能完全的看懂,这个uart工程每次只进行一次突发传输,所以还是比较好理解的

从评论可以看到64个32位宽数据和128个32位宽数据出现问题,通过仿真发现如果设置为64个32位数据也就是两个突发长度确实会出现问题

2次突发更改的地方

仿真到1个突发长度

rd_data_count计数器确实是1

第二个突发长度

rd_data_count计数器还是1,并不是我们期望的2,所以无法产生突发写命令

从官方的fifo仿真波形来,前面三次写的数据都会出现rd_data_count计数器保持为1的情况

直到第四fifo读写数据才开始是正常的计数相加

将上面总结一下,按照两次突发,可以看出fifo计数rd_data_count前三次都是值为1保持不变,只在第四次开始正常的相加,也就是第四次才能产生一个rd_data_count等于2,并且产生一次写突发,既然四次才能产生一次写突发并且同时产生读突发,那么我们直接一次写入四个突发长度,也就是4个256位数据,一共128个8位数据,因四个突发长度只能产生一次写突发,所以只能打印出前面2个突发长度的数据

从上图可以看出发送了4个突发长度数据,按照程序来看确实打印了64个8位数据,也就是一次2个突发长度的数据,还有第二次的2个突发长度数据没有出来,也就是41~80这部分数据没有出来,因fifo后面的数据突发都是正常的,所以我们再发送一次2个突发长度数据,将41~80这部分数据给挤出来,为了区别,这次发送的2个突发长度都是设置为一样的数据

按照程序成功的将第二次的fifo里面的数据挤出来了,正常打印了41~80的数据,我们再次发送2个突发长度的数据将将这次发送相同的01数据都给打印出来

从上面可以看出来数据是连续的并且是完整的,对于ddr这个fifo虽然前面几次突发有这样的问题,但整体的数据完整性是没有问题,再发送依然是将上次的挤出来了

那有没有办法可以解决这样的两次突发都正常,可以使用写fifo中的wr_data_count做为计数

下面的截图执行了两次突发,可以看到每次突发都是wr_data_count都是0~8,可以每次等于8就计数器加一,执行两次突发会出现两个8也就相当于计数为2,可以直接触发突发写,这样可以避免出现rd_data_count前面三次突发出现一直保持为1的情况,当然如果是摄像头类的大量数据还是建议使用rd_data_count这种方式,这种方法大家可以尝试一下

因2次突发读写和4次突发读写是一样的,所以这里不再继续测试4次突发读写,大家有兴趣可以尝试一下

因有人在下面评论串口接收后,发送会不会速度跟不上,所以将工程又改了一下

突发长度不变

突发写使能不变

    //突发写使能
    always@(posedge ui_clk or negedge i_rst_n)begin
            if(!i_rst_n)
                wr_len_en    <=  1'd0;    
            else if(ddr_wr_end)
                wr_len_en    <=  1'd0;    
            else if(rd_len_en)
                wr_len_en    <=  1'd0;    
            else if(wr_len_done)
                wr_len_en    <=  1'd0;                             
            else if(rd_data_count >= 9'd1)
                wr_len_en    <=  1'd1;                        
    end  

突发读变为突发写结束后,才开始进行突发读并且通过串口打印输出,也就是接收完成所有数据后,再通过串口打印输出。其中ddr_wr_end为ddr写完成信号,ddr的最大地址设置为256,说明一共传输256个32位数据,也就是1024个8位就会拉高ddr_wr_end信号,并且会触发ddr读突发,将写入到ddr里面的数据通过串口都打印出来

    //突发读使能
    always@(posedge ui_clk or negedge i_rst_n)begin
            if(!i_rst_n)
                rd_len_en    <=  1'd0;
            else if(ddr_rd_end)
                rd_len_en    <=  1'd0;            
            else if(wr_len_en)
                rd_len_en    <=  1'd0;     
            else if(rd_len_done)
                rd_len_en    <=  1'd0;                 
            else if(ddr_wr_end && wr_data_count <= 9'd1)
                rd_len_en    <=  1'd1;                     
    end   

串口准备1024个8位数据

发送数据,发送和接收都是正常的,并且数据量是一样的

从ila可以看到,wr_len_en为写突发最后一次突发传输,传输完成后立马产生ddr_wr_en写完成信号,并且产生了突发读使能rd_len_en一共进行了8次突发读

同样再次测试也可以抓到最后一次突发读rd_len_en,并且产生ddr_rd_end结束信号

工程链接:https://pan.baidu.com/s/1PWE1cw9OlI9Zgvz-kj6MDw

提取码:czez

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 48
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 48
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值