APB简介及verilog代码示例
学习APB及verilog实现
APB的全称为Advanced Peripheral Bus,即先进外设接口,该总线主要用于和低速以及低功耗的外设通信,该总线中唯一的主设备为APB Bridge,而其它的外设均为从设备。其中,APB Bridge可以锁存总线所有的地址、数据和控制信号,并通过二级译码来产生APB从设备选择信号,通常APB Bridge本身挂在AHB等高速总线上,用于“桥接”低速的APB总线。
APB规定所有的信号必须在时钟上升沿触发时进行传递
APB总线最大支持32bit的数据位宽,拥有两个独立的数据通道,分别为读通道和写通道。由于APB的两个通道没有独立的握手信号,因此两个通道不会被同时使用。
1、APB信号定义如下:
大体可以分为以下三组:
- 系统信号:PCLK(系统时钟)、PRESETn(系统复位,低有效);
- master信号:PADDR(地址信号,确定读写的地址)、PSELx(片选信号,拉出来接给搭载APB总线的slave,选中slave时,PSELx信号拉高)、PNEABLE(使能信号,在PSELx拉高一个周期后,必定拉高)、PWRITE(写使能信号,PWRITE为高时写有效,为低时读有效)、PWDATA(写数据);
- slave信号:PREADY(ready为高时,代表着一次APB数据传输的结束)、PRDATA(读数据)、PSLVERR(错误数据,由slave发出,具体逻辑由slave内部决定,当slave发现内部逻辑出现故障,譬如状态机状态出错、计数器数字异常等,slave都可以使用内部逻辑把该信号拉高,使得master接收到PSLVERR为高时,哪怕ready拉高表示APB结束了,也可以使master放弃该次传输或做出其他应对策略)。
2、APB写传输
如文档所示,APB的写分为两种情况:①没有等待状态的写;②有等待状态的写。
- 没有等待状态的写
对于APB协议来说,最快的写入或者读出一个数据的周期是两周期,先给地址,再写数据;或者先给地址,再读数据。APB 协议文档中,将上述这种传输方式分为两个阶段(phase),给地址的阶段称为Set up phase;紧接着下一周期PENABLE信号拉高,标志着进入写/读数据的阶段,该阶段称为Access phase。
一次没有等待状态的写传输如上图所示,计划写数据时,第一周期PSEL拉高,表示选中某个slave,同时给出地址信息Addr1和写入数据信息Data1,紧接着下一周期,PENABLE信号拉高,PREADY信号也拉高,这时数据写入完成。
- 有等待状态的写
在文档中,对有等待周期的APB写传输描述如上,即:
第一个周期的setup phase和write with no wait没有区别,psel拉高,penable为低;第二周期,penable拉高之后,进入access phase,进入access phase之后,penable不会拉低,直到pready为高标志着一次传输结束时,penable才会随着pready一起拉低。
3、APB读传输
APB的读传输也分为两种情况:①没有等待状态的读;②有等待状态的读。
- 没有等待状态的读
一次没有等待状态的读传输如上图所示,读状态和写状态不同,写数据时PWRITE=1,读数据时应该令PWRITE=0计划读数据时,第一周期PSEL拉高,表示选中某个slave,同时给出地址信息Addr1,紧接着下一周期,PENABLE信号拉高,PREADY信号也拉高,这时数据被读出,master接受到读出数据PRDATA。
- 有等待状态的读
在文档中,对有等待周期的APB读传输描述如上,即:第一个周期的setup phase和read with no wait没有区别,psel拉高,penable为低;第二周期,penable拉高之后,进入access phase,进入access phase之后,penable不会拉低,直到pready为高,这时数据被读出,master接受到读出数据PRDATA,标志着一次传输结束,penable才会随着pready一起拉低。
4、示例代码:
module apbMBFM #(
parameter ADDR_BITS = 24,
parameter DATA_BITS = 32
) (
output reg apb_psel ,
output reg apb_pwrite ,
output reg apb_penable ,
output reg[ADDR_BITS-1:0] apb_paddr ,
output reg[DATA_BITS-1:0] apb_pwdata ,
input wire[DATA_BITS-1:0] apb_prdata ,
input wire apb_pready ,
input wire apb_pslverr ,
input wire clk ,
input wire rst_n
);
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0) begin
apb_psel <= 1'h0;
apb_pwrite <= 1'h0;
apb_penable <= 1'h0;
apb_paddr <= 24'h0;
apb_pwdata <= 32'h0;
end
end
task apb_write;
input [ADDR_BITS-1:0] addr;
input [DATA_BITS-1:0] wdata;
begin
@(posedge clk); //align clock delay
apb_penable = 1'h0;
apb_psel = 1'h1;
apb_pwrite = 1'h1;
apb_paddr = addr;
apb_pwdata = wdata;
@(posedge clk);
apb_penable = 1'h1;
@(posedge clk);
while (!apb_pready) begin
@(posedge clk);
end
apb_pwrite = 1'h0;
apb_psel = 1'h0;
apb_penable = 1'h0;
apb_paddr = 24'h0;
apb_pwdata = 32'h0;
//$display("task apb_write addr=%0h, wdata=%0h\n", addr, wdata);
end
endtask
task apb_read;
input [ADDR_BITS-1:0] addr;
output [DATA_BITS-1:0] rdata;
begin
@(posedge clk); //align clock delay
apb_penable = 1'h0;
apb_psel = 1'h1;
apb_pwrite = 1'h0;
apb_paddr = addr;
@(posedge clk);
apb_penable = 1'h1;
@(posedge clk);
while (!apb_pready) begin
@(posedge clk);
end
rdata = apb_prdata;
apb_psel = 1'h0;
apb_penable = 1'h0;
apb_paddr = 24'h0;
//$display("task pb_read addr=%0h, rdata=%0h\n", addr, rdata);
end
endtask
5、波形图:
更多推荐
所有评论(0)