APB简介
APB(Advanced Peripheral Bus,高级外围总线),属于AMBA家族协议其中之一,是片内总线。APB接口用在低带宽和不需要高性能的总线的外围设备上
APB只有一个Master-APB_Bridge,APB具有低功耗(低翻转率)、低成本、低复杂度、低带宽的特点,是非流水线操作,传输周期至少为2个周期(建立周期和使能周期)
APB主机传输过程中的状态转移图如下,描述了整个APB传输数据的过程:
在IDLE空闲状态时,片选信号PSEL为0
当有传输时,进入SETUP状态,此时将片选信号PSEL首先拉高,保持一个周期后,进入ACCESS状态
在SETUP状态转换到ACCESS状态时,将使能信号PENABLE拉高,在SETUP转换到ACCSEE状态时,地址(address)、读写标志(write)、写数据(write_data)必须保持稳定
ACCESS状态的跳转取决于SLAVE输出的PREADY信号:
如果PREADY为0,表示从机还没有准备好接收数据的传输,或没有准备好数据的输出,会让其保持在ACCESS状态
如果PREADY为1,表示从机已完成数据的传输,此时如果还有新的传输,则跳转到SETUP,若没有新的传输,则返回IDLE状态
APB参考代码
本文介介绍的为APB从机代码,APB_BRIDGE发送指令,通过APB从机对外设进行访问,本文访问的外设为uart,按照需求可以例化其他外设模块
- 端口定义及例化
本文例化的从机为UART,设置地址7位,数据7位,1位读写控制位,一个指令为16bit数据
module apb2uart (
input apb_clk,
input apb_prstn,
input apb_sel,
input apb_penable,
input apb_write,
input [6:0] apb_addr,
input [7:0] apb_wdata,
input rx,
output reg [7:0] apb_rdata,
output reg apb_ready,
output tx
);
reg [15] cmd_in;
reg cmd_rdy,cmd_vld,read_vld;
reg [7:0] read_data;
uart #(.BAUD_RATE(115200),
.CLK_FREQ(50)
) uart_dut0
(
.clk(apb_clk),
.rst_n(apb_prstn),
.cmd_in(cmd_in),
.cmd_vld(cmd_vld),
.rx(rx),
.cmd_rdy(cmd_rdy),
.tx(tx),
.read_vld(read_vld),
.read_data(read_data)
);
2.代码主体
//cmd_in
always@(posegde apb_clk or negegde apb_prstn)
if(!apb_prstn)
cmd_in <= 16'd0;
else if(apb_sel)
cmd_in <= {apb_write,apb_addr,apb_wdata}; //片选信号有效,主机信息整理为一次指令
else
cmd_in <= cmd_in;
//cmd_vld
always@(posegde apb_clk or negegde apb_prstn)
if(!apb_prstn)
cmd_vld <= 1'b0;
else if(apb_sel && !apb_enable) //在主机的SETUP阶段,拉高cmd_vld
cmd_vald <= 1'b1;
else
cmd_vld <= 1'b0;
//apb_ready
always@(posegde apb_clk or negegde apb_prstn)
if(!apb_prstn)
apb_rdy <= 1'b0;
else if(cmd_vld)
apb_rdy <= 1'b0;
else if(read_vld) //读完数据
apb_rdy <= 1'b1;
else if(cmd_rdy) //写完数据
apb_rdy <= 1'b1;
else
apb_rdy <= apb_rdy;
//apb_read data
always@(posegde apb_clk or negegde apb_prstn)
if(!apb_prstn)
apb_rdata <= 8'd0;
else if(read_vld)
apb_rdata <= read_data;
else
apb_rdata <= 8'd0;