APB模块设计及仿真
第一章:APB协议相关概念
1.1APB总线介绍
1APB基本介绍
APB协议,Advanced Peripheral Bus,高级外设总线。属于AMBA家族协议其中之一,AMBA(Advanced Microcontroller Bus Architecture)高级微控总线架构是由ARM公司制定的高性能片上总线协议集。AMBA包括AXI,AHB,APB三大总线。ACE(4.0) CHI(5.0),ASB被AHB淘汰。
- APB接口用在低带宽和不需要高性能总线的外围设备上。
总线:在一条通路上接多个模块,各个模块之间的传数接收都通过一条线传数,总线类似与一条高速公路;不过同一时间只允许一台主机和从机进行通讯。允许多条数据传数的方法:Bus matrix(总线矩阵) 和crossbar(交叉拓扑)。
APB在AMBA总线系统中的位置
UART和另一个芯片/模块进行TX/RX数据交换,SPI外接FLASH。这些模块都是挂在芯片外围,所以APB是高级外设总线。
AHB:High-performance ARM processor(cortex m0,1,3,4)高性能处理器;高带宽存储器;
AHB2APB Bridge:信号转接桥
AXI2AHB Bridge。协议不同却要进行传数,都需要转换桥。
Master:主机。数据传输中的发起者
Slave:从机。数据传输中的接收者。
APB Master:只有一个Master ---- Bridge桥。其余挂在APB接口上的都是他的从机(slave)。单Master多Slave系统。通过psel选择某个从机。
2APB协议实现多Slave互联架构
桥为Master,发送信号到多个Slave从机,所有从机都会收到数据信号。Decoder片选译码器,Master发出的地址信号先发到地址译码器。
Master读取Slave发送的数据,通过mux选择信号(也由Decoder产生)
1.2APB BUS接口信号(AMBA3 APB)
apb_write:1write 0read
apb_ready:Master发数时要先握手(acknowledge),确保APB总线可以传数。
其中,只有apb_rdata和apb_ready是从机slave到主机master的信号;其余都是主机到从机的信号。如果ready拉低,读写的数据都无效,如果从机发数到主机来不及,拉低ready,称为反压;
1.3APB接口时序
时钟从高电平到低电平,灰色部分表示亚稳态,瞬态,high imdedance高阻态,多比特中数据未对齐。
APB状态机
Master发出APB信号时,由状态机控制;有三个状态。IDLE——SETUP——ENABLE,初始化后有建立和保持两个状态,传数不是一个周期就能完成的。
做APB接口时,要分开Master和Slave接口。
APB两种操作:读/写。
写分为有等待和无等待两种操作;
-
无等待写操作:主机发数时候需不需要等待从机接收。由pready确定
slave在T2时刻,就能采样到地址信号PADDR,写信号PWRITE,片选信号PSEL,写数据内容PWDATA。此时由pready告诉主机是否要等待,不等待,则拉高pready,直接写数据;同时拉高penable,这信号不用看pready的值,在数据信号发出的下个周期拉高penable。发送完数据,拉低penable,状态机进入IDLE状态。paddr和pwrite和pwdata信号不用刻意拉低,以降低信号反转频率,信号反转率越高,电路功耗就越大。 -
APB无等待读操作,T1时刻后,发送PADDR,PWRITE,PSEL,PRDATA,T2时刻,Slave采集到Pready有效,把要读的数据放到PRDATA。T3时刻,Master采样到Pready高信号,此时data1读数有效。
-
有等待写操作(带反压)
等待到T5时刻,采样到PREADY信号拉高,完成写数。Slave延长了两个周期。
- APB有等待读操作
第二章 APB2UART模块设计代码实现及仿真
UART是APB的slave接口。
SBUF_REG用于接收和发数。即作为TX的寄存器,也用于RX的寄存器。作为半双工接口。
UART是个低速模块,收发都是比较慢的。
module apb_uart(
//apb interface
input pclk ,
input prst_n ,
input psel ,
input penable ,
input pwrite ,
input [ 31: 0]paddr,
input [ 31: 0]pwdata,
output reg [ 31: 0]prdata,
output pready ,
//uart interface
input rx ,
output tx
);
reg start_reg ;
reg [ 15: 0]sbuf_reg ;
reg uint_reg ;
wire apb_wr ;
wire apb_rd ;
reg [ 15: 0]cmd_in ;
reg cmd_vld ;
reg txrx_flag ;
wire [ 15: 0]read_data ;
wire read_vld ;
parameter START_REG_ADDR= 32'H0 ; //only write
parameter SBUF_REG_ADDR= 32'H4 ; // wirte/read
parameter UINT_REG_ADDR= 32'H8 ; //only read
//apb write/read enable //
assign apb_wr = psel & penable & pwrite;
assign apb_rd = psel & penable & !pwrite;
//register//
always @(posedge pclk or negedge prst_n)
begin
if(!prst_n)
start_reg <= 0;
else if(apb_wr && (paddr == START_REG_ADDR))
start_reg <= 1'b1; //pwdata=32'b1;
else
start_reg <= 0;
end
always @(posedge pclk or negedge prst_n)
begin
if(!prst_n)
sbuf_reg <= 16'b0;
else if(apb_wr && (paddr == SBUF_REG_ADDR))
sbuf_reg <= pwdata[15:0]; //tx data
else if (read_vld) begin
sbuf_reg <= {8'b0,read_data} //rx data
end
end
// cmd interface
always @(posedge pclk or negedge prst_n)
begin
if(!prst_n)
begin
cmd_in <= 16'b0;
cmd_vld <= 0;
end
else if(start_reg == 1)
begin
cmd_in <= sbuf_reg;
cmd_vld <= 1;
end
end
//interrupt register //
always @(posedge pclk or negedge prst_n)
begin
if(!prst_n) begin
uint_reg <= 0;
end
else if(cmd_vld)
uint_reg <= 0;
else if (cmd_rdy & txrx_flag) begin
uint_reg <= 1;
end
else if(apb_rd && (paddr == UINT_REG_ADDR))
uint_reg <= 0;
end
always @(posedge pclk or negedge prst_n)
begin
if(!prst_n)
txrx_flag <= 0;
else if(cmd_rdy)
txrx_flag <=1;
else if (cmd_rdy) begin
txrx_flag <= 0;
end
end
// apb buf read//
always@(*)
begin
if (apb_rd) begin
case (paddr)
SBUF_REG_ADDR : prdata = {16'b0,sbuf_reg};
UINT_REG_ADDR : prdata = {31'b0,uint_reg};
default: prdata = 32'b0;
endcase
end
end
assign pready = psel & penable;