2567|1

81

帖子

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
点赞 关注
 
 

回复
举报

7044

帖子

11

TA的资源

版主

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

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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

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

北京市海淀区中关村大街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
快速回复 返回顶部 返回列表