第一部分、按键的储备知识
1、读写数据寄存器
2、读写方向寄存器
3、读写中断屏蔽寄存器
4、读写边沿捕捉寄存器
第二部分、新建Quartus II工程
第三部分、修改别人的软核
1、添加PIO核之LED
2、添加PIO核之按键Key
第四部分、编写Quartus中的verilog代码
1、verilog代码:
第五部分、编写Ecplise里面的C代码
1、注意
2、c代码
第六部分、总结
1、效果演示
2、闲话
3、完整资料
IORD_ALTERA_AVALON_PIO_DATA(base);//base:是你设置引脚对应的地址,在sysm.h文件中找。
IOWR_ALTERA_AVALON_PIO_DATA(base, data);//base:是你设置引脚对应的地址,在sysm.h文件中找。data:是你想要写入的数据。
用法:
例如在按键中:
K = IORD_ALTERA_AVALON_PIO_DATA(base);
K = 0则证明按键被按下,K = 1 证明按键没有被按下。
IORD_ALTERA_AVALON_PIO_DIRECTION (base);
IOWR_ALTERA_AVALON_PIO_DIRECTION(base, data);
IORD_ALTERA_AVALON_PIO_IRQ_MASK(base);
IOWR_ALTERA_AVALON_PIO_IRQ_MASK(base, data);
IORD_ALTERA_AVALON_PIO_ EDGE_CAP (base);
IOWR_ALTERA_AVALON_PIO_ EDGE_CAP (base, data);
第一步、还是复制小梅哥的LCD9341的初始工程,到自己建立的文件夹中,省略很多步骤,前面几篇说过了。
注意:如果你和我FPGA型号不一样,那就复制你的SOPC工程文件到文件夹中,和前面一样,因为其他的步骤大致都和我的一样,没有区别。
第一步、添加软核需要的东西,这里不从头开始搭建,我们先学会在别人的工程上更改。
注意:我这还是以小梅哥的LCD驱动程序代码作为自己的基础,你FPGA型号如果和我不一样,那你选择一个你FPGA自带的资料中找一个类似SOPC工程,然后照着我下面的步骤一起操作
第二步、搜索PIO,双击添加PIO,然后进行相关的配置,如图
第三步、配置LED对应的PIO,AC620一共有四个LED灯,所以Width应该是4位,Direction方向应该是output输出。初始的复位值可以设置位(0x。。。。0)让四个LED处于亮状态。(我的FPGA上LED3,2,1,0分别对应A3,A4,B3,A2 )
注意:你如果是别的FPGA,那你注意你FPGA上LED的个数。
第四步、进行连线,连线按照下面的错误提示来一步一步的连,基本上没有问题
第五步、首先给pio_0重新命名为pio_led,便于识别。然后再自动分配地址,操作如图中
第六步、双击导出端口(看他的英文指导,你也知道怎么操作)
第七步、当你的操作步骤都是正确的时候,就会出现让人舒服的绿色信息,就像我字体的颜色
第一步、同理前面的步骤,再添加一个PIO核来对应按键Key。并添加PIO的中断程序,但是在配置方面要注意,这里配置为下降沿的方式触发,如图中的配置。
第二步、又重复第五个步骤,注意命名为pio_key,唯一多出的步骤就是连上中断线
第三步、按照上述的配置,又出现让人爽快的绿色信息
第四步、上述操作过后,接下来生成自己的软核,然后等待漫长的3-5分钟。
第五步、生成完成后,先别急着退出,将要导出的端口复制,这里你的名字可能和我的不一样,没关系,只要是你添加的PIO端口就可以,我这里是图中红色方框。
第一步、将你刚刚复制的代码复制到V文件中的u0中(目的是为了例化),然后定义你端口变量的名称和输出类型,再进行预编译。
注意:我感觉我在这里没有说明白,因为你要一点点Verilog语法的基本知识,这里你才容易明白。如果没明白,你看一下我的代码的备注,就算你FPGA型号不同,你也可以看一下,很容易懂得。
第二步、预编译完成后,再分配引脚,分配完引脚后再进行全编译。
module AC620_GHRD(
//按键输入
input wire pio_key,
/*需要添加的代码,我的FPGA是4个LED,所以这里是四位,类型是输出的*/
output wire [3:0] pio_led,/*这里名字,和下面括号中的要保持一致*/
/*需要添加的代码,我的FPGA是4个LED,所以这里是四位,类型是输出的*/
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
);
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
/*这里是你刚刚复制的代码*/
/*这个是我导出的端口,复制到这里来*/
.pio_led_export (pio_led), // pio_led.export
/*这个是我导出的端口,复制到这里来*/
.pio_key_export (pio_key) // pio_irq.export
//按键输入
);
endmodule
这里我省略如何新建Ecplise中的工程,不会的话看前面的笔记(https://blog.csdn.net/Learning1232/article/details/110225728)。
第一步、新建新的工程,一般是Blank Project,这些都不难,主要出错误的就是代码。所以直接附上代码
#include
#include
#include "altera_avalon_pio_regs.h"//PIO读写头文件
#include "priv/alt_legacy_irq.h" //注册中断函数的地方
#include "unistd.h" //延时函数的头文件
#include "alt_types.h"
void Irq_key();
alt_u8 x=0;
int main()
{
//中断使能寄存器,置 1 时中断使能有效,否则无效,我们把它置 1,使中断使能有效;
IOWR_ALTERA_AVALON_PIO_IRQ_MASK(PIO_KEY_BASE,1);//使能中断KEY_INTERRUPT_MASK 是 PIO 的
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(PIO_KEY_BASE,1);//清中断边沿捕获寄存器
alt_irq_register(PIO_KEY_IRQ,NULL,Irq_key);//注册中断
IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE,15);
while(1)
{
usleep(1000000);
printf("%d\n",x);//打印进入中断次数x的值
}
}
void Irq_key()
{
x++;//每次进入一次中断x就增加一次
if(x == 1)
{
IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE,0);//进入中断,LED灯亮
}
else if(x == 2)
{
x=0;
IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE,15);//再次进入中断,LED灭
}
//清除中断标志位,使得下次仍然可以产生中断
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(PIO_KEY_BASE,1);//清中断边沿捕获寄存器
}
第二步、程序烧进去没有反应,我遇到了这种情况,心态一般,有一点点裂开。所以FPGA开发,你有一半的时间和软件做斗争
第三步、如果发现程序一直死在中断中,那么有可能是标黄的地方出错了alt_irq_register(PIO_KEY_IRQ,NULL,Irq_key);//注册中断
已经拍成视频发放在文件夹中,你也可以先点击这个链接直接观看(https://live.csdn.net/v/120094),其功能就是按下按键进入中断开灯,在按一下进入中断,关灯。注意:这里按键效果不好,为什么嘞?因为没有进行按键消抖,FPGA的按键硬件消抖有点麻烦,你先去百度吧,百度经验解释了。。。。。以后有时间我在写一篇关于硬件消抖。
说实话有些知识我说的也不是很清楚,你去要课下去补充一下,因为这也是我给自己做的学习笔记,所以希望读者多多包容。
希望读者克服一下,如果你实在不懂,还是那句话扫码加群,然后加我QQ单独联系我或者直接私信我。只要我不在上课,我就可以手把手帮你解决问题。
“马老师,发生甚么事了?”
我把这篇文章涉及到的所有的资料(完整工程、演示视频、参考资料下载链接:https://download.csdn.net/download/Learning1232/13673152)都会放在这个文件夹里面,文件夹你可以扫码进群下载,或者关注我,直接下载,粉丝福利(哈哈)!!!