AG32 mcu通过ahb转apb方式操作cpld外设
上节讲述了mcu和cpld之间交互数据的实现方式。
但数据是在ahb层面的响应,慢速设备不能直接使用。慢速设备需要ahb转为apb后,使用apb的信号来交互。这种情况,转变为mcu和apb 之间的交互。
mcu和apb之间的交互,相比mcu和aph之间的交互,多了一层ahb到apb的转换。 这个转换是借助于“桥”ahb2apb.v模块来实现的(在example/analog下找该.v文件)。
该模块:输入是ahb的一组信号,输出是apb的一组信号。使用如下图:
如果实现mcu和apb的交互,则需要操作的是转换后的这组apb信号。
关于apb总线的使用,更多信息请自行百度。这里只是简述下apb信号列表(与ahb略有不同):
- apb_psel:片选
- apb_penable:表示传输进入第二周期(准备好了读/写)
- apb_pwrite:传输方向(1-写;0-读)
- apb_paddr[32]:地址总线,要操作的地址
- apb_pwdata[32]:写的数据,32位
- apb_prdata[32]:读的数据,32位
以下展示在apb下如何实现跟mcu的交互,仍以ahb的两个寄存器为例。
1. 首先需要增加ahb转apb的信号关联;
如上图。
Ahb2apb模块会把ahb信号转换为apb信号。接下来操作apb信号即可。
2. 在转换后的apb信号中,实现写和读的操作。
mcu读操作时:
比如,mcu要读0x60000004的寄存器:
mcu端直接C语言这样调用:int cpRdReg = *((int *)0x60000004);
cpld端,可以根据以上信号做如下处理:
----------------------------------------------
//mcu的读操作响应
//mcu端用C语言:int value = *((int *)0x60000004);
reg [31:0] ardata_reg; //定义32位的hrdata_reg
always @(posedge apb_clock) begin //clk上升沿触发
if (!apb_pwrite && //读 (0 读,1 写)
apb_penable && //是否准备好
apb_paddr[11:0] == ADDR_READ) //读地址为0x60000004(cpld内部用相对偏移)。
begin
ardata_reg <= awdata_reg; //把另一准备好的数据给到hrdata_reg
end
end
assign apb_prdata = ardata_reg; //绑定hrdata_reg到读的数据线上-----------------------------------------------
mcu写操作时:
比如,mcu要写0x60000000的寄存器:
mcu端直接C语言这样调用:*((int *)0x60000000) = value;
cpld端,可以根据以上信号做如下处理:
----------------------------------------------
//mcu的写操作响应
//mcu端用C语言:*((int *)0x60000000) = value;
reg [31:0] awdata_reg; //定义32位的hwdata_reg
always @(posedge apb_clock) begin //clk上升沿触发
if (apb_pwrite && //写 (0 读,1 写)
apb_penable && //是否准备好
apb_paddr[11:0] == ADDR_WRITE)//写地址为0x60000000(cpld内部用相对偏移)。
begin
TestLedCtrl <= !TestLedCtrl; //led灯切换,表示有写操作触发
awdata_reg <= apb_pwdata; //把收到的数据给到hwdata_reg
end
end
//这个过程,是把mcu写进来的数据收到hwdata_reg中-----------------------------------------------
这个功能实现后,其实是个简单的“空外设”。可以用它做为实现复杂功能外设的基础。
这部分的实例代码,请参考网盘上获取:
链接:百度网盘 请输入提取码 里边的 \cpld-fpga文档\logic样例\5.mcu读写cpld寄存器
.
样例展示到这里,mcu和cpld的交互上:交互信号、跟ahb交互数据、跟apb交互数据,基本的交互通路已经建立。
接下来,用户根据自己的需求,在cpld中交互到数据后,编写自己需要的功能即可。