作者:京微雅格产品市场经理 倘余清
EMIF总线概述
外部存储器总线(EMIF, External Memory Interface)总线是京微雅格(CME)的8051硬核与FPGA之间的并行8位总线接口,主要的信号有6个,分别为:
memaddr[22:0]:23位地址总线,对应8M地址空间;
memdatao[7:0]:8位数据输出总线;
memdatai[7:0]:8位数据输入总线;
memrd:总线读信号;
memwr:总线写信号;
memack:总线应答信号;
与EMIF操作时序有关的8051的内部寄存器为CKCON寄存器,一般8051的初始化程序需要在主函数的初始化更改该寄存器的初始化值,以实现最快的总线访问效率。
EMIF总线相关的MCU寄存器:CKCON
CKCON主要作用是设置存储器地址总线memaddr[22:0]和读写memwr/ memerd信号的宽度,已实现对不同外设时序的操作,若宽度仍不够,也可以通过memack实现硬件延时,理论上可以实现任意宽度的地址总线地址和读写信号。
CKCON寄存器的默认值为:0x71
通过设置CKCON的第4-6位,可以改变CPU的运行效率,最小值是001,不可设置为000;当设置为111,运行的效率最慢;所以推荐客户在CPU开始运行就改变4-6位的值为001,以使CPU运行的效率最快。
通过设置CKCON的第0-2位,可以改变EMIF总线的memrd,memwr,memaddr的宽度,最小值是000,对应memrd,memwr,memaddr的宽度为1个时钟周期;当设置为111时,对应memrd,memwr,memaddr的宽度为8个时钟周期;所以推荐客户在CPU开始运行就改变4-6位的值为000,以使EMIF总线访问的效率最快。
所以推荐用户在8051主程序程序一开始就改变CKCON的值为0x10。
基于Data Banking的总线地址扩展规则:
CME的8051处理器为冯诺依曼结构,即程序总线和数据总线统一编址。EMIF地址总线的地址位为23位,对应8M Bytes的地址空间。8051是通过Data Banking的方式实现地址总线的扩展。8051每个bank的地址空间为32K Bytes,共有256个bank。地址空间的分布如下图所示,这里仅对外部数据存储空间做介绍:
与外部数据存储空间有关的寄存器为:
D_PAGESEL(默认初始值为0x01,即指向Bank 1地址空间)
因为D_PAGESEL为8位寄存器,所以刚好对应256个bank。D_PAGESEL的值对应地址总线上的memaddr[22:15]的值,即地址总线的高8位地址总线。注意:D_PAGESEL的值不可为0,因为当为0时,将会与Common Bank的地址空间重叠(0-7FFFF)。
逻辑地址空间与物理地址空间的对应关系
逻辑地址空间(Logical Address): CME 8051每个bank的低16位逻辑地址的空间范围为0x8000-0xFFFF,该值和C编译器里面的地址定义相同。
物理地址(Physical Address):也叫实际地址或绝对地址,是出现在CPU外部地址总线上的寻址物理内存的地址信号,是地址变换的最终结果。
逻辑地址空间:
memaddr[22:0]
高位 低位
22 15 14 0
memaddr[22:15]:该物理地址段的值由D_PAGESEL寄存器的值决定,范围为1-255,默认初始化值为0x01;
memaddr[14:0]:该物理地址段由C编译器里面的变量分配的地址决定,注意:需拿C编译器里面定义的地址(0x8000-0xFFFF)减去偏移地址0x8000,即0x8000对应的物理地址实际是0x0000,0xFFFF对应的物理地址为0x7FFF。
Keil C51编译器支持的外部变量定义方法:
代码片段1:
unsigned char xdata PORTA _at_ 0x9000;//对应低16位物理地址:0x1000
unsigned char xdata DDRA _at_ 0x9001;//对应低16位物理地址:0x1001
unsigned char xdata PORTB _at_ 0xa000;//对应低16位物理地址:0x2000
unsigned char xdata DDRB _at_ 0xa001;//对应低16位物理地址:0x2001
或者如下定义:
代码片段2:
#define PORTA XBYTE[0x9000]
EMIF总线时序
EMIF总线同步写时序:
CKCON[2:0] = 000,图中mempsrd, mempswr为MCU内部信号,用户不用考虑,memack恒为1:
EMIF总线同步读时序:
CKCON[2:0] = 000,图中mempsrd, mempswr为MCU内部信号,用户不用考虑,memack恒为1:
EMIF编程示例
FPGA主要代码片段,EMIF总线同步读写:
//8051
MyMcu u_MyMcu
(
.clkcpu (clk_sys), //8051
.resetn (rst_ncfg_n),
.swd (1’b0),
.port0i (),
.port1i (),
.port2i (),
.port3i (),
.port0o (),
.port1o (),
.port2o (),
.port3o (port3o),
.memaddr (memaddr),
.memdatao (memdatao),
.memdatai (memdatai),
.memack (1’b1),
.memwr (memwr),
.memrd (memrd)
);
always @(posedge clk_sys or negedge rst_ncfg_n)
begin
if(~rst_ncfg_n)
test_cs _d1 <= 1’b0;
else
test_cs _d1 <= gpio_cs;
end
assign memdatai = test_cs_d1 ? sta_rdata : 8’h00;
assign test_cs =( memaddr [22:15] == 8’h04 && memaddr [14:12] == 3’h01) ? 1’b1 : 1’b0;
always @(posedge clk_sys or negedge rst_ncfg_n)
begin
if(~rst_ncfg_n)
begin
test_reg0 <=8’h00;
test_reg1 <= 8’h00;
test_reg2 <= 8’h00;
end
else
begin
if(test_cs)begin
case(memaddr[7:0])
8’h00:begin
if(memwr)
test0_reg <= memdatao;
if(memrd)
sta_rdata <= test0_reg;
end
8’h01:begin
if(memwr)
test1_reg <= memdatao;
if(memrd)
sta_rdata <= test1_reg;
end
8’h02:begin
if(memwr)
test2_reg <= memdatao;
if(memrd)
sta_rdata <= test2_reg;
end
default:
endcase
end
end
end
Keil C51主要程序片段:
UINT8 xdata test[2] _at_ 0x9000;
void main(void)
{
Unsigned char tmp;
CKCON = 0x10;
D_PAGESEL = 0x4;//设置bank寄存器,memaddr[22:15]=0x04
test[0] = 0x00;//对test0_reg写操作,test[0]物理地址:0x021000
test[1] = 0x01;//对test1_reg写操作,test[1]物理地址:0x021001
test[2] = 0x02;//对test2_reg写操作,test[2]物理地址:0x021002
D_PAGESEL = 0x1;//更改回默认值,已实现对外部RAM的操作!
while(1)
{
D_PAGESEL = 0x4;
tmp = test[1];//对test1_reg读操作
if(tmp == 0x01){
D_PAGESEL = 0x1;
P0 =0x0f;
delay(1000);
}
}
}
|