做我的世界缩略图的网站,wordpress文章统计,有没有教做零食的网站,东莞长安网站开发公司本文档介绍了AG32开发中#xff0c;MCU与CPLD交互的具体方式以及例子。如需了解AG32更多资料可发邮件#xff1a;salesagm-micro.com
一、MCU和CPLD直接交互
cpld工程创建及编译的操作流程#xff0c;参考文档《AG32下fpga和cpld的使用入门》 在工程中#xff0c;用户逻辑… 本文档介绍了AG32开发中MCU与CPLD交互的具体方式以及例子。如需了解AG32更多资料可发邮件salesagm-micro.com
一、MCU和CPLD直接交互
cpld工程创建及编译的操作流程参考文档《AG32下fpga和cpld的使用入门》 在工程中用户逻辑部分编写是从analog_ip.v的接口下开始的。
mcu和cpld之间的交互可以分为
1. mcu传递信号给cpld如mcu的gpio传递高低信号到cpld
2. cpld传递信号给mcu如对mcu产生中断信号
3. mcu读写数据到cpld
4. 不建议cpld做为主设备对mcu写。
也就是说在mcu和cpld交互中cpld更像一个外设。
其中前两种较为简单。后两种要使用AHB总线来操作。
下边针对四种情况分别说明
1. mcu传递信号给cpld
这种使用较简单。步骤如下
在ve中定义信号
GPIO4_1 iocvt_chn:OUTPUT
表示用mcu的gpiogpio4_1来输入信号到cpld。
然后prepare LOGIC工程后可以看到analog_ip.v接口中的信号
input iocvt_chn_out_data,
input iocvt_chn_out_en,
这里的iocvt_chn_out_data就是对接到mcu的gpio4_1的信号。
当控制mcu的gpio4_1高低切换时cpld中的iocvt_chn_out_data会对应来变化。
具体样例可以参考网盘“logic样例3.mcu信号到cpld到pin”的样例该样例中展示了mcu控制cpld继续控制led的过程。
除了gpio信号输出到cpld其他比如pwm输出信号等都可以输入到cpld。
2. cpld传递信号给mcu
这种方式和1相近只不过是反向。
可以在mcu中定义gpio4_2为输入并使能中断则cpld中设置信号高低时将触发 mcu的中断。
在VE中定义信号
GPIO4_2 iocvt_chn:INPUT
表示用mcu的gpiogpio4_2信号来源于cpld的iocvt_chn。
然后prepare LOGIC工程后可以看到analog_ip.v接口中的信号
output iocvt_chn_in_data,
这里的iocvt_chn_in_data就是对接到mcu的gpio4_2的信号。
当cpld中控制iocvt_chn_in_data信号高低时mcu中的gpio4_2对应变化。
这里不再举例。
3. mcu读写数据到cpld
在地址设计中cpld的地址区间是0x60000000 ~ 0x7FFFFFFF
当mcu对这个区间内的地址访问时相当于访问了cpld的“寄存器”。
mcu是全局寻址对这个空间的访问和对ram0x20000000起空间的访问是一样的方式在C代码中可以这样写
读cpldint cpRdReg *((int *)0x60000000);
写cpld*((int *)0x60000004) cpWtReg;
Mcu端读写cpld较为简单直接通过上述语句就可以了。
当mcu读写动作发生时cpld端是如何反应的
当上述mcu读写动作发生时AHB总线会把动作拆解为读写信号传递到analog_ip.v的接口用户cpld程序需要响应该信号。
以下以写动作 *((int *)0x60000004) cpWtReg 为例描述cpld端会发生的事情。
回顾下analog_ip.v中的接口部分 其中slave_ahb_开头的一组信号是cpld作为主端时用的暂时不用理会。
Mem_ahb_开头的一组信号是cpld作为从端使用的。
当mcu有读写操作时mem_ahb_这组信号将发生变化。
这部分是遵循标准的AHB总线协议的。如果对AHB总线印象不深请自行百度。
可参考的讲解
https://blog.csdn.net/weixin_46022434/article/details/104987905
几个信号的概述更详细的讲解请自行百度
Ahb_htrans: 当前传输类型00: IDLE、01: BUSY、10: NONSEQ、11: SEQ
Ahb_readymcu读时要mcu要准备好cpld才会写
Ahb_hwrite: 要读还是要写1为写0为读
Ahb_haddr[32]: 要操作的地址
Ahb_hsizetransfer的大小以字节为单位
Ahb_hburst批量传输
Ahb_hwdata[32]写的数据32位
Ahb_hreadyout输出信号mcu写时cpld是否准备好
Ahb_hresp输出信号响应信号OK、retry、error、split
Ahb_hrdata[32]读的数据32位
根据AHB时序在一次传输中cpldslave端会先拿到addr地址读或写的标记然后交互ready信号后开始数据传输。
大致如下图无等待类型的图 比如mcu要读0x60000004的寄存器
mcu端直接C语言这样调用int cpRdReg *((int *)0x60000004);
cpld端可以根据以上信号做如下处理
----------------------------------------------
//mcu的读操作响应
//mcu端用C语言int value *((int *)0x60000004);
reg [31:0] hrdata_reg; //定义32位的hrdata_reg
always (posedge sys_clock) begin //clk上升沿触发
if (mem_ahb_htrans 2b10 //NONSEQ状态第一次传输 mem_ahb_hready //master已ready可以给数据线写入了 !mem_ahb_hwrite //读0 读1 写 mem_ahb_haddr[23:0] h04) //读地址为0x60000004cpld用相对偏移
begin
hrdata_reg hwdata_reg; //把另一准备好的数据给到hrdata_reg
end
end
assign mem_ahb_hrdata hrdata_reg;//绑定hrdata_reg到读的数据线上
-----------------------------------------------
以上代码加入到analog_ip.v的module下就可以完成cpld对mcu读动作的响应。
比如mcu要写0x60000000的寄存器
mcu端直接C语言这样调用*((int *)0x60000000) value;
cpld端可以根据以上信号做如下处理
----------------------------------------------
//mcu的写操作响应
//mcu端用C语言*((int *)0x60000000) value;
reg [31:0] hwdata_reg; //定义32位的hwdata_reg
always (posedge sys_clock) begin //clk上升沿触发
if (mem_ahb_htrans 2b00 //IDLE状态 mem_ahb_hreadyout //cpld已ready状态ahb上数据可以写过来 mem_ahb_hwrite //写0 读1 写 mem_ahb_haddr[23:0] h00) //写地址为0x60000000cpld用相对偏移
begin
hwdata_reg mem_ahb_hwdata; //把收到的数据给到hwdata_reg
end
end
//这个过程是把mcu写进来的数据收到hwdata_reg中
-----------------------------------------------
这部分的实例代码请参考网盘上cpld样例工程《5.mcu读写cpld寄存器》。
注意这里展示的仅仅是基于AHB总线上的数据交互。
在实际应用中比如要实现一个串口之类的往往是慢速设备这些是要挂载到apb上的。慢速设备要经过ahb到apb的bridge才能最终使用。请继续往下看。
二、mcu通过ahb转apb后的数据交互
上节讲述了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] ‘h04) //读地址为0x60000004cpld内部用相对偏移
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] ‘h00) //写地址为0x60000000cpld内部用相对偏移
begin
awdata_reg apb_pwdata; //把收到的数据给到hwdata_reg
end
end
//这个过程是把mcu写进来的数据收到hwdata_reg中
-----------------------------------------------
这个功能实现后其实是个简单的“空外设”。可以用它做为实现复杂功能外设的基础。
这部分的实例代码请参考网盘上cpld样例工程《5.mcu读写cpld寄存器》。
样例展示到这里mcu和cpld的交互上交互信号、跟ahb交互数据、跟apb交互数据基本的交互通路已经建立。
接下来用户根据自己的需求在cpld中交互到数据后编写自己需要的功能即可。
三、DMA在CPLD中的使用
cpld中实现DMA的逻辑
1. MCU为mastercpld为slavemcu对cpld的交互方式为存取寄存器的方式
2. mcu中配置好DMA读取cpld中准备好的数据
3. cpld中准备好数据后触发dma信号dma自动搬运到mcu指定的ram
4. 搬运一次后dma给cpld一个clear信号完成一次dma搬运
5. 等到cpld中再次准备好数据将再次触发dma信号重复3和4
对于cpld来说mcu来读取数据和dma来读取数据是一致的。
dma来读取时只是每次读完后会多给cpld一个clear信号。
更多细节请参考网盘上《7.cpld中配合实现mcu的dma读取》部分的样例。
在这个样例中展示了两部分代码
1. mcu中配置dma读取为了测试mcu会在另一地址给cpld写数据
2. cpld中会对mcu写进来的数据缓存缓存后触发dma的信号让dma来读取数据。而dma从cpld里读取数据后会给cpld一个clear信号标志一次dma交互完成。