安路SparkRoad串口转localbus实现指令控制
<p>Local Bus总线上的数据读写分为同步模式和异步模式。在同步模式下,需要一个外部时钟信号供接收端和发送端共用,利用时钟信号的上升沿对数据进行采样,SDRAM、SSRAM等高速信号使用同步模式;异步传输模式下,不使用时钟信号对数据进行采样(芯片内部还是需要有系统参考时钟来产生时序的),而是利用片选信号CS、写使能信号WE和读使能信号OE对数据进行采样,使用异步模式的器件有FLASH等。</p><p>我们使用串口转localbus是接口,实现各芯片的访问,扩展性强。</p>
<pre>
<code>//localbus
outputreg cpu_cs_n,
outputreg cpu_wr_n,
outputreg cpu_rd_n,
outputreg cpu_addr,
outputreg cpu_datain,
input cpu_dataout,</code></pre>
<p>上面是我们常用的localbus接口,通过cs片选,选择不同的module,实现不同的功能</p>
<p> </p>
<p>由于串口收发都是8位,采用接受四个字节,组成32bit的数据,高16位数据,低16位最高位读写标志位,接着就是2bit功能状态位,最后就是13bit的地址位</p>
<p>大致的串口转locabus协议就是这样,开始写代码</p>
<p>另外UART与locabus跨时钟的处理,采用握手</p>
<pre>
<code>`timescale 1ns / 1ps
module uart_localbus(
input clk ,
input rst_n ,
//localbus
outputreg cpu_cs_n,
outputreg cpu_wr_n,
outputreg cpu_rd_n,
outputreg cpu_addr,
outputreg cpu_datain,
input cpu_dataout,
//UART STREAM
input uart_recv,
input uart_recv_vld ,
outputreguart_send,
outputreg uart_send_vld ,
input uart_ready
);
//localparam
//reg define
reg recv_vld_dly ;
reg rx_cnt ;
reg tx_cnt ;
reg cpu_rd_dly ;
reg uart_ready_dly ;
reg send_reg ;
reg recv_data ;
reg wr_flag ;
reg uart_code ;
reg uart_addr ;
reg uart_data ;
reg cs_ctrl ;
reg 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'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'b01 ? 1'b1 : 1'b0;
assign uart_ready_rising =uart_ready_dly == 2'b01 ? 1'b1 : 1'b0;
assign recv_done_rising = recv_done_dly == 2'b01 ? 1'b1 : 1'b0 ;
//接收同步打拍
always@(posedge clk)
begin
recv_vld_dly<={recv_vld_dly,uart_recv_vld};
cpu_rd_dly <={cpu_rd_dly,cpu_rd_n} ;
uart_ready_dly<={uart_ready_dly,uart_ready} ;
recv_done_dly <={recv_done_dly,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 == 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 <=recv_data ;
end
2'b01 : begin
wr_flag <=recv_data ;
uart_code <=recv_data ;
uart_addr <=recv_data ;
end
2'b10 : begin
uart_data <=recv_data ;
end
2'b11 : begin
uart_data <=recv_data ;
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 == 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<=send_reg ;
uart_send_vld<= 1'b1 ;
tx_flag <= 1'b1 ;
end
else if(tx_flag&&(uart_ready_rising == 1'b1))
begin
uart_send<=send_reg ;
uart_send_vld <= 1'b1 ;
tx_flag <= 1'b0 ;
end
else
uart_send_vld<=1'b0 ;
end
always@(*)
begin
case(cpu_addr)
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</code></pre>
<p>激励代码如下</p>
<pre>
<code>module uart_localbus_tb();
`definePERIOD10
reg clk ;
reg rst_n ;
//localbus
wire cpu_cs_n ;
wire cpu_wr_n ;
wire cpu_rd_n ;
wire cpu_addr ;
wire cpu_datain ;
reg cpu_dataout;
//UART STREAM
reg uart_recv ;
reg uart_recv_vld ;
wireuart_send ;
wire uart_send_vld ;
reg uart_ready ;
wirecs ;
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 ),
.cpu_wr_n ( cpu_wr_n ),
.cpu_rd_n ( cpu_rd_n ),
.cpu_addr ( cpu_addr ),
.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 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 dat;
begin
#200uart_recv = dat;
#200uart_recv_vld = 1'b1;
#200uart_recv_vld = 1'b0;
#1000 uart_recv = dat;
#100uart_recv_vld = 1'b1;
#100uart_recv_vld = 1'b0;
#1000 uart_recv = dat;
#100uart_recv_vld = 1'b1;
#100uart_recv_vld = 1'b0;
#1000 uart_recv = dat;
#100uart_recv_vld = 1'b1;
#100uart_recv_vld = 1'b0;
end
endtask
endmodule
</code></pre>
<p> </p>
<p>功能仿真的波形就不放了,感兴趣的自己可以跑。</p>
<p>编译把代码烧录到单板,</p>
<p>下面看下jtag仿真抓取得波形</p>
<p></p>
<p>这是通过串口下发4字节数据给FPGA.</p>
<p> </p>
<p></p>
<p></p>
<p>通过抓取的波形读写功能都基本功能实现了,UART读写控制LED功能正常。</p>
<p></p>
<p>串口转localbus可以继续优化下,后续功能扩展位VGA显示屏。</p>
<p> </p>
<p> </p>
<p> </p>
加油加油,虽然看不懂,还是支持你!
页:
[1]