2722|1

80

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

安路SparkRoad串口转localbus实现指令控制 [复制链接]

 

Local Bus总线上的数据读写分为同步模式和异步模式。在同步模式下,需要一个外部时钟信号供接收端和发送端共用,利用时钟信号的上升沿对数据进行采样,SDRAM、SSRAM等高速信号使用同步模式;异步传输模式下,不使用时钟信号对数据进行采样(芯片内部还是需要有系统参考时钟来产生时序的),而是利用片选信号CS、写使能信号WE和读使能信号OE对数据进行采样,使用异步模式的器件有FLASH等。

我们使用串口转localbus是接口,实现各芯片的访问,扩展性强。

  • //localbus
  • output reg cpu_cs_n ,
  • output reg cpu_wr_n ,
  • output reg cpu_rd_n ,
  • output reg [12:0] cpu_addr ,
  • output reg [15:0] cpu_datain,
  • input [15:0] cpu_dataout,

上面是我们常用的localbus接口,通过cs片选,选择不同的module,实现不同的功能

 

由于串口收发都是8位,采用接受四个字节,组成32bit的数据,高16位数据,低16位最高位读写标志位,接着就是2bit功能状态位,最后就是13bit的地址位

大致的串口转locabus协议就是这样,开始写代码

另外UART与locabus跨时钟的处理,采用握手

  • `timescale 1ns / 1ps
  • module uart_localbus(
  • input clk ,
  • input rst_n ,
  • //localbus
  • output reg [31:0] cpu_cs_n ,
  • output reg cpu_wr_n ,
  • output reg cpu_rd_n ,
  • output reg [12:0] cpu_addr ,
  • output reg [15:0] cpu_datain,
  • input [15:0] cpu_dataout,
  • //UART STREAM
  • input [7:0] uart_recv ,
  • input uart_recv_vld ,
  • output reg [7:0] uart_send ,
  • output reg uart_send_vld ,
  • input uart_ready
  • );
  • //localparam
  • //reg define
  • reg [2:0] recv_vld_dly ;
  • reg [1:0] rx_cnt ;
  • reg [1:0] tx_cnt ;
  • reg [2:0] cpu_rd_dly ;
  • reg [2:0] uart_ready_dly ;
  • reg [15:0] send_reg ;
  • reg [7:0] recv_data ;
  • reg wr_flag ;
  • reg [1:0] uart_code ;
  • reg [12:0] uart_addr ;
  • reg [15:0] uart_data ;
  • reg cs_ctrl ;
  • reg [1:0] recv_done_dly;
  • reg tx_flag ;
  • //wire define
  • wire recv_vld_rising;
  • wire recv_done ;
  • wire cpu_rd_rising ;
  • wire uart_ready_rising;
  • wire recv_done_rising;
  • assign recv_vld_rising = recv_vld_dly[2:1] == 2'b01 ? 1'b1 : 1'b0;
  • assign recv_done = (rx_cnt == 2'b11)&&(recv_vld_rising == 1'b1) ? 1'b1 : 1'b0 ;
  • assign cpu_rd_rising = cpu_rd_dly[2:1] == 2'b01 ? 1'b1 : 1'b0 ;
  • assign uart_ready_rising = uart_ready_dly[1:0] == 2'b01 ? 1'b1 : 1'b0;
  • assign recv_done_rising = recv_done_dly[1:0] == 2'b01 ? 1'b1 : 1'b0 ;
  • //接收同步打拍
  • always@(posedge clk)
  • begin
  • recv_vld_dly[2:0] <= {recv_vld_dly[1:0],uart_recv_vld};
  • cpu_rd_dly[2:0] <= {cpu_rd_dly[1:0],cpu_rd_n} ;
  • uart_ready_dly[1:0] <= {uart_ready_dly[1:0],uart_ready} ;
  • recv_done_dly[1:0] <= {recv_done_dly[0],recv_done} ;
  • end
  • always@(posedge clk or negedge rst_n)
  • begin
  • if(rst_n == 1'b0)
  • recv_data <= 8'h00;
  • else if(recv_vld_dly[0] == 1'b1)
  • recv_data <= uart_recv ;
  • else;
  • end
  • //recv data num
  • always@(posedge clk or negedge rst_n)
  • begin
  • if(rst_n == 1'b0)
  • rx_cnt <= 2'b00;
  • else if(recv_vld_rising)
  • rx_cnt <= rx_cnt + 1'b1 ;
  • end
  • //接收4个字节数据处理
  • always@(posedge clk or negedge rst_n)
  • begin
  • if(rst_n == 1'b0)
  • begin
  • wr_flag <= 1'b0 ;
  • uart_code <= 2'b00 ;
  • uart_addr <= 13'd0 ;
  • uart_data <= 16'h00;
  • end
  • else if(recv_vld_rising)
  • begin
  • case(rx_cnt)
  • 2'b00 : begin
  • uart_addr[7:0] <= recv_data[7:0] ;
  • end
  • 2'b01 : begin
  • wr_flag <= recv_data[7] ;
  • uart_code <= recv_data[6:5] ;
  • uart_addr[12:8] <= recv_data[4:0] ;
  • end
  • 2'b10 : begin
  • uart_data[7:0] <= recv_data[7:0] ;
  • end
  • 2'b11 : begin
  • uart_data[15:8] <= recv_data[7:0] ;
  • end
  • default: ;
  • endcase
  • end
  • else ;
  • end
  • //cpu_cs_n
  • always@(posedge clk or negedge rst_n)
  • begin
  • if(rst_n == 1'b0)
  • cs_ctrl <= 1'b1;
  • else if(recv_done_rising)
  • cs_ctrl <= 1'b0 ;
  • else
  • cs_ctrl <= 1'b1 ;
  • end
  • //cpu_wr_n
  • always@(posedge clk or negedge rst_n)
  • begin
  • if(rst_n == 1'b0)
  • cpu_wr_n <= 1'b1;
  • else if((recv_done_rising)&&(wr_flag == 1'b0))
  • cpu_wr_n <= 1'b0 ;
  • else
  • cpu_wr_n <= 1'b1 ;
  • end
  • //cpu_rd_n
  • always@(posedge clk or negedge rst_n)
  • begin
  • if(rst_n == 1'b0)
  • cpu_rd_n <= 1'b1;
  • else if(recv_done_rising&&(wr_flag == 1'b1))
  • cpu_rd_n <= 1'b0 ;
  • else
  • cpu_rd_n <= 1'b1 ;
  • end
  • //返回的数据处理
  • always@(posedge clk or negedge rst_n)
  • begin
  • if(rst_n == 1'b0)
  • send_reg <= 16'h0000;
  • else if(cpu_rd_dly[0] == 1'b0)
  • send_reg <= cpu_dataout ;
  • end
  • always@(posedge clk)
  • begin
  • cpu_addr <= uart_addr ;
  • cpu_datain <= uart_data ;
  • // uart_send_vld <= cpu_rd_rising == 1'b1 ? 1'b1 : 1'b0 ;
  • end
  • always@(posedge clk or negedge rst_n)
  • begin
  • if(rst_n == 1'b0)
  • begin
  • uart_send <= 8'h00;
  • uart_send_vld <= 1'b0;
  • tx_flag <= 1'b0 ;
  • end
  • else if((cpu_rd_rising == 1'b1)&&(uart_ready == 1'b1)&&(!tx_flag))
  • begin
  • uart_send[7:0] <= send_reg[7:0] ;
  • uart_send_vld <= 1'b1 ;
  • tx_flag <= 1'b1 ;
  • end
  • else if(tx_flag&&(uart_ready_rising == 1'b1))
  • begin
  • uart_send[7:0] <= send_reg[15:8] ;
  • uart_send_vld <= 1'b1 ;
  • tx_flag <= 1'b0 ;
  • end
  • else
  • uart_send_vld <= 1'b0 ;
  • end
  • always@(*)
  • begin
  • case(cpu_addr[12:8])
  • 5'd0 : cpu_cs_n = {31'hffffffff,cs_ctrl } ;
  • 5'd1 : cpu_cs_n = {30'hffffffff,cs_ctrl, 1'h1} ;
  • 5'd2 : cpu_cs_n = {29'hffffffff,cs_ctrl, 2'h3} ;
  • 5'd3 : cpu_cs_n = {28'hffffffff,cs_ctrl, 3'h7} ;
  • 5'd4 : cpu_cs_n = {27'hfffffff ,cs_ctrl, 4'hf} ;
  • 5'd5 : cpu_cs_n = {26'hfffffff ,cs_ctrl, 5'h1f} ;
  • 5'd6 : cpu_cs_n = {25'hfffffff ,cs_ctrl, 6'h3f} ;
  • 5'd7 : cpu_cs_n = {24'hfffffff ,cs_ctrl, 7'h7f} ;
  • 5'd8 : cpu_cs_n = {23'hffffff ,cs_ctrl, 8'hff} ;
  • 5'd9 : cpu_cs_n = {22'hffffff ,cs_ctrl, 9'h1ff} ;
  • 5'd10 : cpu_cs_n = {21'hffffff ,cs_ctrl,10'h3ff} ;
  • 5'd11 : cpu_cs_n = {20'hffffff ,cs_ctrl,11'h7ff} ;
  • 5'd12 : cpu_cs_n = {19'hfffff ,cs_ctrl,12'h1fff} ;
  • 5'd13 : cpu_cs_n = {18'hfffff ,cs_ctrl,13'h3fff} ;
  • 5'd14 : cpu_cs_n = {17'hfffff ,cs_ctrl,14'h7fff} ;
  • 5'd15 : cpu_cs_n = {16'hfffff ,cs_ctrl,15'hffff} ;
  • 5'd16 : cpu_cs_n = {15'hffff ,cs_ctrl,16'h1ffff} ;
  • 5'd17 : cpu_cs_n = {14'hffff ,cs_ctrl,17'h3ffff} ;
  • 5'd18 : cpu_cs_n = {13'hffff ,cs_ctrl,18'h7ffff} ;
  • 5'd19 : cpu_cs_n = {12'hffff ,cs_ctrl,19'hfffff} ;
  • 5'd20 : cpu_cs_n = {11'hfff ,cs_ctrl,20'h1fffff} ;
  • 5'd21 : cpu_cs_n = {10'hfff ,cs_ctrl,21'h3fffff} ;
  • 5'd22 : cpu_cs_n = { 9'hfff ,cs_ctrl,22'h7fffff} ;
  • 5'd23 : cpu_cs_n = { 8'hfff ,cs_ctrl,23'hffffff} ;
  • 5'd24 : cpu_cs_n = { 7'hff ,cs_ctrl,24'h1ffffff} ;
  • 5'd25 : cpu_cs_n = { 6'hff ,cs_ctrl,25'h3ffffff} ;
  • 5'd26 : cpu_cs_n = { 5'hff ,cs_ctrl,26'h7ffffff} ;
  • 5'd27 : cpu_cs_n = { 4'hff ,cs_ctrl,27'hfffffff} ;
  • 5'd28 : cpu_cs_n = { 3'hf ,cs_ctrl,28'h1fffffff} ;
  • 5'd29 : cpu_cs_n = { 2'hf ,cs_ctrl,29'h3fffffff} ;
  • 5'd30 : cpu_cs_n = { 1'hf ,cs_ctrl,30'h7fffffff} ;
  • 5'd31 : cpu_cs_n = { cs_ctrl,31'hffffffff} ;
  • default : ;
  • endcase
  • end
  • endmodule

激励代码如下

  • module uart_localbus_tb();
  • `define PERIOD 10
  • reg clk ;
  • reg rst_n ;
  • //localbus
  • wire [31:0] cpu_cs_n ;
  • wire cpu_wr_n ;
  • wire cpu_rd_n ;
  • wire [12:0] cpu_addr ;
  • wire [15:0] cpu_datain ;
  • reg [15:0] cpu_dataout;
  • //UART STREAM
  • reg [7:0] uart_recv ;
  • reg uart_recv_vld ;
  • wire [7:0] uart_send ;
  • wire uart_send_vld ;
  • reg uart_ready ;
  • wire cs ;
  • assign cs =((&cpu_cs_n) == 1'b0);
  • uart_localbus u_uart_localbus(
  • .clk ( clk ),
  • .rst_n ( rst_n ),
  • .cpu_cs_n ( cpu_cs_n ),
  • .cpu_wr_n ( cpu_wr_n ),
  • .cpu_rd_n ( cpu_rd_n ),
  • .cpu_addr ( cpu_addr ),
  • .cpu_datain ( cpu_datain ),
  • .cpu_dataout ( cpu_dataout ),
  • .uart_recv ( uart_recv ),
  • .uart_recv_vld ( uart_recv_vld ),
  • .uart_send ( uart_send ),
  • .uart_send_vld ( uart_send_vld ),
  • .uart_ready ( uart_ready )
  • );
  • loc_led u_loc_led(
  • .clk (CLK_24M ),
  • .rst (~rst_n ),
  • .cpu_cs_n ( cpu_cs_n[0] ),
  • .cpu_wr_n ( cpu_wr_n ),
  • .cpu_rd_n ( cpu_rd_n ),
  • .cpu_addr ( cpu_addr[7:0] ),
  • .cpu_datain ( cpu_datain ),
  • .cpu_dataout ( led_dataout ),
  • .led (led )
  • );
  • initial
  • begin
  • clk = 1'b0 ;
  • rst_n = 1'b0 ;
  • cpu_dataout = 16'h1234;
  • uart_recv = 8'b0;
  • uart_recv_vld = 1'b0;
  • uart_ready = 1'b1;
  • $monitor($time,,"cpu_cs_n = %h,cpu_wr_n = %h,cpu_rd_n = %b,cpu_addr = %h,cpu_datain = %h",cpu_cs_n,cpu_wr_n,cpu_rd_n,cpu_addr,cpu_datain);
  • #100
  • rst_n = 1'b1;
  • repeat(20)@(posedge clk);
  • uart_send_data(32'hd5a50401);
  • repeat(20)@(posedge clk);
  • uart_send_data(32'h12340300);
  • repeat(20)@(posedge clk);
  • uart_send_data(32'h56788114);
  • end
  • always #(`PERIOD) clk <= ~clk ;
  • reg [3:0] ready_cnt ;
  • always@(posedge clk)
  • ready_cnt <= uart_ready == 1'b0 ? ready_cnt + 1'b1 : 1'b0 ;
  • always@(posedge clk)
  • begin
  • if(cs&&(!cpu_rd_n))
  • begin
  • uart_ready <= 1'b0 ;
  • end
  • else if(ready_cnt == 4'd10)
  • begin
  • uart_ready <= 1'b1 ;
  • end
  • end
  • task uart_send_data;
  • input [31:0] dat;
  • begin
  • #200 uart_recv = dat[7:0];
  • #200 uart_recv_vld = 1'b1;
  • #200 uart_recv_vld = 1'b0;
  • #1000 uart_recv = dat[15:8];
  • #100 uart_recv_vld = 1'b1;
  • #100 uart_recv_vld = 1'b0;
  • #1000 uart_recv = dat[23:16];
  • #100 uart_recv_vld = 1'b1;
  • #100 uart_recv_vld = 1'b0;
  • #1000 uart_recv = dat[31:24];
  • #100 uart_recv_vld = 1'b1;
  • #100 uart_recv_vld = 1'b0;
  • end
  • endtask
  • endmodule

 

功能仿真的波形就不放了,感兴趣的自己可以跑。

编译把代码烧录到单板,

下面看下jtag仿真抓取得波形

这是通过串口下发4字节数据给FPGA.

 

通过抓取的波形读写功能都基本功能实现了,UART读写控制LED功能正常。

串口转localbus可以继续优化下,后续功能扩展位VGA显示屏。

 

 

 

最新回复

加油加油,虽然看不懂,还是支持你!  详情 回复 发表于 2022-5-21 20:04
点赞 关注
 
 

回复
举报

7258

帖子

11

TA的资源

版主

沙发
 
加油加油,虽然看不懂,还是支持你!
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条
直播报名最后1周:艾迈斯欧司朗 OSP 开放协议,从氛围灯动态照明到传感器交互融合
直播时间:4月22日(周二)10:00
直播奖励:京东卡、蓝牙温湿度计、定制水杯

查看 »

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网 4

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表