第一部分、关于PWM的IP核的储备知识
1、什么是IP核
2、为什么要自己写IP核
3、PWM_IP核的写法
第二部分、新建Quartus II工程
1、注意
第三部分、添加自己的IP核
1、添加自己IP核的详细步骤
第四部分、修改别人的软核
1、调用自己的IP核详细步骤
第五部分、编写Quartus中的verilog代码
1、代码
2、注意
第六部分、编写ecplise里面的C代码
1、代码的功能阐述
2、代码
第七部分、总结
1、效果展示
2、感想
3、完整资料
IP核(Intellectual Property core),就是知识产权核或知识产权模块的意思。同时IP又分为软IP、固IP和硬IP。我们这里面主要做的软IP,软IP是用Verilog/VHDL等硬件描述语言描述的功能块,但是并不涉及用什么具体电路元件实现这些功能。
我猜铁子们的Quartus II都是破解版,破解版它已经破解了很多Altera的IP核(这就是为什么正版软件这么贵),但是这些IP核有时候不能满足我们的设计需求,比如我想驱动LCD屏,那我就得自己写一个LCD的IP核。
所以学会自己写IP核就特别重要,但是这个需要你学到一定的高度之后你才具备这个本领,博主现在也还是个辣鸡,你让我写,我也不会。但是这里我想教的是,别人把IP核写好了,你怎么把他导入到你的系统中去。
PWM_IP核是别人用verilog语言写的,这个需要一定的水平,反正我还不会,我这里的“pwmip2020.v”文件是我嫖来的。如图为PWM_IP核的部分verilog代码的截图
这里我还是复制小梅哥的LCD9341的初始工程到自己建立的文件夹中去,上一篇《【NiosII学习】第六篇、从零搭建属于自己的SOPC系统》已经教你们如何搭建自己的SOPC系统了,但是我怕有些读者没成功,所以这一我还是到别人工程上面改,这里不会的去看《【NiosII学习】第一篇、如何烧录NiosII工程:https://blog.csdn.net/Learning1232/article/details/110225728》
如果你和我FPGA型号不一样,那就复制你的SOPC工程文件到文件夹中,和前面一样,因为其他的步骤大致都和我的一样,没有区别。
第一步、复制小梅哥的LCD9341的初始工程,到自己建立的文件夹中,然后打开工程
第一步、打开Platform Designer,打开添加IP核的对话框
第二步、定义你IP核的名称,翻译这些英文,你就知道填啥了
第三步、添加pwmip2020.v文件(注意:这个文件要放到你的工程文件夹中的IP文件中,在这个文件夹中新建一个PWM文件夹,然后将“pwmip2020.v”文件放进去,如图我放的位置),然后再分析这个文件,步骤如图。
第四步、分析过后会报这些错误和警告,但是不要慌。点击close,关闭弹窗,点击NEXT
第五步、点击NEXT,第四个参数配置窗口不用管。再点击NEXT,打开第五个参数配置窗口
第六步、将第五个参数配置窗口拉到最大,鼠标左键单击CPU_Addr [2] 如图,并将Signal Type:选为adress。其他参数默认。
第七步、同理鼠标左键单击CPU_CS如图,并将Signal Type:选为chipselect(片选信号,chipselect表示高电平有效,chipselect_n表示低电平有效)
注意:这里为什么选高电平有效,这和你的“pwmip2020.v”这个文件的写法有关。如果你想搞的很清楚可以私聊我,如果人多我就出一期教程讲解,主要是说起来太麻烦,教程字太多,我自己都懒得看。
第八步、剩下的几个同理,鼠标左键单击,然后并将Signal Type:选为下面表格中的。
名称 |
Signal Type: |
|
CPU_Addr |
对应 |
adress |
CPU_CS |
对应 |
chipselect |
CPU_RD |
对应 |
read |
CPU_RD_DATA |
对应 |
readdata |
CPU_WR |
对应 |
write |
CPU_WR_DATA |
对应 |
writedata |
第九步、注意:PWM_Out不能像上面几个一样操作了,首先在左边点击《add interface》,然后选中Conduit。
选中Conduit后
接下来,在下面添加信号,鼠标右键选中PWM_Out,然后将它拉到Conduit_end下面
第十步、同理上面的步骤,新建一个Reset Input
和上面一样,将rst拉下来,并且将Signal Type:选为reset。
第十一步、接着你会看到一条错误“Interface must have an associated reset”
解决办法,按照图中的文字操作
第十二步、回过头看第二个参数窗口,你就会看到生成了这么一个东西,就证明你做对了。
第十三步,点击Finish,选择YES,Save
第十四步,查看你创建的IP核,(如果你的软件没有自动生成,那你就按照右图的办法操作,我没有试过),接下来就是调用了呗。
第一步、这个就和前面的IP核调用方法一样,这里没有参数配置,直接Finish
第二步、唯一要注意的就是这里要双击,把端口导出来。
第三步、生成自己的软核,再等待片刻。注意:生成好了之后记得将新生成的端口复制,这里容易忘。
module AC620_GHRD(
input wire clk, // clk.clk
input wire reset_n, // reset.reset_n
output wire lcd_rst, // lcd_rst.export
output wire lcd_rd_n, // lcd_rd.export
output wire lcd_bl, // lcd_bl.export
output wire lcd_wr_n, // lcd_wr.export
output wire lcd_rs, // lcd_rs.export
output wire lcd_cs_n, // lcd_cs.export
inout wire [15:0] lcd_data, // lcd_db.export
output wire sdram_clk, // sdram_clk.clk
output wire [11:0] sdram_addr, // sdram.addr
output wire [1:0] sdram_ba, // .ba
output wire sdram_cas_n, // .cas_n
output wire sdram_cke, // .cke
output wire sdram_cs_n, // .cs_n
inout wire [15:0] sdram_dq, // .dq
output wire [1:0] sdram_dqm, // .dqm
output wire sdram_ras_n, // .ras_n
output wire sdram_we_n, // .we_n
input wire uart_0_rxd, // uart_0.rxd
output wire uart_0_txd, // .txd
output wire epcs_dclk, // epcs.dclk
output wire epcs_sce, // .sce
output wire epcs_sdo, // .sdo
input wire epcs_data0, // .data0
//对新的端口进行定义
output wire pwm_out
);
mysystem u0 (
.clk_clk (clk), // clk.clk
.reset_reset_n (reset_n), // reset.reset_n
.uart_0_rxd (uart_0_rxd), // uart_0.rxd
.uart_0_txd (uart_0_txd), // .txd
.epcs_dclk (epcs_dclk), // epcs.dclk
.epcs_sce (epcs_sce), // .sce
.epcs_sdo (epcs_sdo), // .sdo
.epcs_data0 (epcs_data0), //
.lcd_rst_export (lcd_rst), // lcd_rst.export
.lcd_bl_export (lcd_bl), // lcd_bl.export
.lcd_wr_n (lcd_wr_n), // lcd.wr_n
.lcd_rd_n (lcd_rd_n), // .rd_n
.lcd_data (lcd_data), // .data
.lcd_rs (lcd_rs), // .rs
.lcd_cs_n (lcd_cs_n), //
.sdram_clk_clk (sdram_clk), // sdram_clk.clk
.altpll_0_phasedone_conduit_export (), // altpll_0_phasedone_conduit.export
.altpll_0_locked_conduit_export (), // altpll_0_locked_conduit.export
.altpll_0_areset_conduit_export (), // altpll_0_areset_conduit.export
.sdram_addr (sdram_addr), // sdram.addr
.sdram_ba (sdram_ba), // .ba
.sdram_cas_n (sdram_cas_n), // .cas_n
.sdram_cke (sdram_cke), // .cke
.sdram_cs_n (sdram_cs_n), // .cs_n
.sdram_dq (sdram_dq), // .dq
.sdram_dqm (sdram_dqm), // .dqm
.sdram_ras_n (sdram_ras_n), // .ras_n
.sdram_we_n (sdram_we_n), // .we_n
//PWM端口
.pwm_writeresponsevalid_n (pwm_out) // pwm.writeresponsevalid_n
);
endmodule
第一步、粘贴复制过来的代码,然后定义变量。
第二步、分配引脚,我这里直接把这个引脚分配给我FPGA上面的一个LED灯,如果你有示波器,你可以分配给一个裸露的管脚,没有的话就LED,观察LED灯的呼吸,来判断PWM是否正常。
一直改变占空比,然后你可以看到你的LED处于呼吸灯状态。
/*
* main.c
*
* Created on: 2020年12月14日
* Author: dpt
*/
#include
#include
#include
#include //printf的头文件
#include "altera_avalon_pio_regs.h"
#include "system.h"
#include "alt_types.h"
#include "sys/alt_irq.h"
#define clk100m 100000000
int main()
{
int freq=1000;
float duty=0.5;
alt_u32 n_high;
alt_u32 n_low;
printf("Hellow PWM IP LED!");
while(1)
{
if(duty<1)
duty =duty+0.1;
if(duty>=1)
duty=0.1;
n_high=(alt_u32)((clk100m/freq)*duty);
n_low=(alt_u32)((clk100m/freq)*(1-duty));
IOWR_32DIRECT(PWM_0_BASE, 0*4, n_high);
IOWR_32DIRECT(PWM_0_BASE, 1*4, n_low);
IOWR_32DIRECT(PWM_0_BASE, 2*4, 1);
usleep(400000);
}
return 0;
}
已经拍成视频放在群文件中,可以去下载查看。你也可以先点击这个链接直接观看效果(https://live.csdn.net/v/120677),这里放张图片。
其实我这里只教了你怎么导入IP核文件,然后怎么调用,这其实不难,只要你按部就班的来就不会出错。最难的就是“pwmip2020.v”这个文件的编写,博主以后会研究这个,争取出一期自己写IP核的教程,可能会很慢,因为我还是一名大三的学生,学校也很普通(我很骄傲来到自己的学校)况且我认为我自己不是一个很聪明的人,所以大家坚持和我一起学,难没关系,多花时间就可以。
最后希望有问题的铁子加下面这个群,群文件里面有所有的资料,有问题也可以直接提出来,当然也可以私聊我。
欢乐的白嫖时光从来不会缺席!(完整工程、演示视频、参考资料下载链接:https://download.csdn.net/download/Learning1232/13688871)。