【Altera SoC体验之旅】高速数据采集之中断
[复制链接]
本帖最后由 chenzhufly 于 2015-4-17 01:26 编辑
作者:chenzhufly QQ:36886052 1、 硬件环境 硬件平台:Embest SoC --LarkBoard 软件平台:开发板-linux-3.10.31 Quartus 14.0
2、系统概述 简单点说,就是FPGA准备好数据了,现在需要通知ARM过来取数据。在传统的设计里面可以把FPGA的一个IO挂在ARM的外部中断上,准备好数据了就触发一次中断,大喊一声“HI,我来啦!准备接客”。那么在soc中怎么设计呢,如下图所示:
1) ADC采集来的数据先进FIFO缓存 2) 在FPGA内部生成IRQ逻辑,并挂在lwhps上
3、系统生成 在qsys中我们要生成如下的硬件系统,整体连接关系如下:
中断号应该是几呢?请看下面分解。
中断的参数设计如下:
地址映射关系如下:
HDL Example如下: - lark_pcie u0 (
- .memory_mem_a (<connected-to-memory_mem_a>), // memory.mem_a
- .memory_mem_ba (<connected-to-memory_mem_ba>), // .mem_ba
- .memory_mem_ck (<connected-to-memory_mem_ck>), // .mem_ck
- .memory_mem_ck_n (<connected-to-memory_mem_ck_n>), // .mem_ck_n
- .memory_mem_cke (<connected-to-memory_mem_cke>), // .mem_cke
- .memory_mem_cs_n (<connected-to-memory_mem_cs_n>), // .mem_cs_n
- .memory_mem_ras_n (<connected-to-memory_mem_ras_n>), // .mem_ras_n
- .memory_mem_cas_n (<connected-to-memory_mem_cas_n>), // .mem_cas_n
- .memory_mem_we_n (<connected-to-memory_mem_we_n>), // .mem_we_n
- .memory_mem_reset_n (<connected-to-memory_mem_reset_n>), // .mem_reset_n
- .memory_mem_dq (<connected-to-memory_mem_dq>), // .mem_dq
- .memory_mem_dqs (<connected-to-memory_mem_dqs>), // .mem_dqs
- .memory_mem_dqs_n (<connected-to-memory_mem_dqs_n>), // .mem_dqs_n
- .memory_mem_odt (<connected-to-memory_mem_odt>), // .mem_odt
- .memory_mem_dm (<connected-to-memory_mem_dm>), // .mem_dm
- .memory_oct_rzqin (<connected-to-memory_oct_rzqin>), // .oct_rzqin
- .clk_clk (<connected-to-clk_clk>), // clk.clk
- .reset_reset_n (<connected-to-reset_reset_n>), // reset.reset_n
- .hps_0_h2f_reset_reset_n (<connected-to-hps_0_h2f_reset_reset_n>), // hps_0_h2f_reset.reset_n
- .hps_0_f2h_cold_reset_req_reset_n (<connected-to-hps_0_f2h_cold_reset_req_reset_n>), // hps_0_f2h_cold_reset_req.reset_n
- .hps_0_f2h_debug_reset_req_reset_n (<connected-to-hps_0_f2h_debug_reset_req_reset_n>), // hps_0_f2h_debug_reset_req.reset_n
- .hps_0_f2h_warm_reset_req_reset_n (<connected-to-hps_0_f2h_warm_reset_req_reset_n>), // hps_0_f2h_warm_reset_req.reset_n
- .pio_led_external_connection_export (<connected-to-pio_led_external_connection_export>), // pio_led_external_connection.export
- .pio_button_external_connection_export (<connected-to-pio_button_external_connection_export>) // pio_button_external_connection.export
- );
复制代码
做到这里硬件系统就设计完成了!
4、关于中断号 从上图看到,我们的中断是挂在f2h_irq0上,实际的物理中断是多少呢,需要认真看手册了 总共fpga到arm的有64个中断源,分别分配在f2h_irq0和f2h_irq1上,所以上面的设计对应的物理中断号是77,记住了哦,下面还有用!
5、产生中断源 简单的写了一个计数器,作为中断源,如下: - module count_int (
- input clk,
- input reset,
-
- output avl_irq
- );
-
- reg [31:0] s_cnt;
- always @(posedge clk or negedge reset)
- begin
- if (!reset)
- s_cnt <= 32'd0;
- else
- s_cnt <= s_cnt + 1'b1;
- end
- assign avl_irq = s_cnt[24];
- endmodule
复制代码
把输出挂在HPS的模块上就可以 - .pio_button_external_connection_export (avl_irq)
复制代码
6、linux驱动 1)首先要告知内核,要挂在这个中断啊,dts中需要添加 - altera_pio: gpio@0xff200000{
- compatible = "altr,pio-1.0";
- reg = <0xff200010 0x10>;
- //reg = <0xff200000 0x10>;
- interrupts = <0 45 4>;
- //interrupts = <0 40 4>;
- altr,gpio-bank-width = <32>;
- altr,interrupt_type = <2>; //failing edge
- #gpio-cells = <2>;
- gpio-controller;
- //inter_gpios = < &altera_pio 0 1 >;
- #interrupt-cells = <1>;
- interrupt-controller;
- };
复制代码
注意: - reg = <0xff200010 0x10>;和上面的地址分配是对应的
- interrupts = <0 45 4>;,这个45需要加上32,那么和上面的中断号77也是对应的
2)挂载自己的驱动程序 还要告知内核,我用了它的哪个中断源,取个名字叫key_int吧 - #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/device.h>
- #include <linux/platform_device.h>
- #include <linux/leds.h>
- #include <linux/io.h>
- #include <linux/uaccess.h>
- #include <linux/semaphore.h>
- #include <linux/cdev.h>
- #include <linux/types.h>
- #include <linux/fs.h>
- #include <linux/interrupt.h>
- #include <linux/irq.h>
- #include <linux/of.h>
- #include <linux/of_gpio.h>
- #include <linux/of_device.h>
- #include <linux/gpio.h>
- int key_gpio;
- int key_irq;
- /*******************************************/
- //中断处理函数:
- static irqreturn_t key_interrupt (int irq, void *dev_id)
- {
- // printk("=============key_interrupt=============\n");
- return 0;
- }
- int button_release(struct platform_device *pdev)
- {
- return 0;
- }
- int button_probe(struct platform_device *pdev)
- {
- int result;
- struct device_node *node = pdev->dev.of_node;
- key_gpio = of_get_named_gpio(node,"inter_gpios",0);
- key_irq = __gpio_to_irq(key_gpio);
- printk("=============key_irq = %d=============\n",key_irq);
-
- result = request_irq(key_irq, key_interrupt,IRQF_TRIGGER_FALLING, "key_int", NULL);
- if(result)
- {
- printk(KERN_INFO"[FALLED: Cannot register Key Interrupt!]\n");
- }
-
- return 0;
- }
- static struct of_device_id altera_gpio_of_match[] = {
- { .compatible = "altr,key-int", },
- {},
- };
- MODULE_DEVICE_TABLE(of, altera_gpio_of_match);
- static struct platform_driver button_fops = {
- .driver = {
- .name = "key_int",
- .owner = THIS_MODULE,
- .of_match_table = of_match_ptr(altera_gpio_of_match),
- },
- .probe = button_probe,
- .remove = button_release,
- };
- // 模块加载函数
- static int __init button_init(void)
- {
- printk(KERN_ALERT "key modules is install\n");
- return platform_driver_register(&button_fops);
-
- }
- // 模块卸载函数
- static void __exit button_cleanup(void)
- {
- printk("Goodbye,chenzhufly!\n");
- platform_driver_unregister(&button_fops);
- }
- module_init(button_init);
- module_exit(button_cleanup);
- MODULE_AUTHOR("chenzhufly");
- MODULE_LICENSE("Dual BSD/GPL");
复制代码
7、测试 8、小结 1)学习的过程总是苦逼的,但结果总是异常的简单明了,纵观下来,其实所涉及的东西并不多,但如何能在一开始就融汇贯通,难度相当的大啊 2)soc中断设计比传统的arm+fpga架构要好使很多,避免很多麻烦的事情,自从调通以后,我就喜欢上了它 3)提醒一下3.10内核的linux版本,不支持arm端的IO中断,有需要的需要自己移植了,不要再在这个上面浪费时间了
|