搜索
bottom↓
回复: 0

【正点原子FPGA连载】第六章定时器中断实验--摘自【正点原子】达芬奇之Microblaze 开发指南

[复制链接]

出0入234汤圆

发表于 2020-10-13 10:24:59 | 显示全部楼层 |阅读模式
本帖最后由 正点原子 于 2020-10-16 16:43 编辑

1)实验平台:正点原子达芬奇FPGA开发板
2)购买链接:https://detail.tmall.com/item.htm?id=624335496505
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/fpga/zdyz_dafenqi.html
4) 正点原子官方B站:https://space.bilibili.com/394620890
5)对正点原子FPGA感兴趣的同学可以加群讨论:876744900 点击加入: QQ群头像.png                                                                                                                            
6)关注正点原子公众号,获取最新资料


100846rel79a9p4uelap24.jpg

100846f1ce1fg14zbg0va4.png


第六章定时器中断实验


前面已经介绍过利用AXI Uartlite中断通信的方法,本章实验将介绍另一个重要的IP核AXI Timer。AXI Timer具有AXI总线接口,能够产生不同时间周期和占空比的时钟、脉冲产生电路、产生与时间有关的中断和用于电机控制的脉宽调制信号。本章实验我们将介绍AXI Timer中断信号的使用。
本章包括以下几个部分:
66.1 简介
6.2实验任务
6.3硬件设计
6.4程序设计
6.5下载验证
6.1
简介
AXI Timer IP核提供了一个AXI4 Lite接口用于与处理器通信;它内部有两个可编程的定时器,具有中断、事件生成和事件捕获功能,用户可根据自身需求选择8、16、32位定时器的计数宽度;通过对两个定时器联合操作,可以输出一个脉宽调制信号,我们可以通过该信号控制一些外设,如LED等;我们也可以对两个32位宽的定时器进行级联操作,生成一个64位宽的定时器;在软件调试期间冻结停止计数器的输入。
下图是AXI Timer IP核的结构框图:
阿莫论坛发帖达芬奇专用1423.png

图 6.1.1 AXI Timer IP核的结构框图

下面我们将介绍下各个模块的功能:
AXI4-Lite Interface(AXI4-Lite接口):该AXI4-lite接口模块被设计成AXI4-lite从接口,用于访问内存映射的定时器寄存器,我们也可以通过该接口对各个寄存器模块进行配置。
Timer Registers(定时器寄存器):该模块是一组32位寄存器。这组寄存器包含加载寄存器(Load Register)、定时器/计数器寄存器和控制/状态寄存器(Control/Status Registers)。加载寄存器保存用于事件生成的计数器的初始值或捕获值。控制/状态寄存器包含定时器模块的控制位和状态位。
32-bit Counters(32位寄存器):定时器/计数器模块有两个32位计数器,每个计数器可设置为递增或递减计数,并可从加载寄存器中加载一个值。
Interrupt Control(中断控制):中断控制模块根据操作模式生成单个中断。
Pulse Width Modulation (PWM,脉宽调制):PWM模块能够产生具有指定频率和占空比的脉冲信号PWM0。它使用Timer0作为PWM0周期,Timer1作为PWM0输出宽度。
6.2实验任务
本章的实验任务是通过定时器产生中断,控制LED灯闪烁。
6.3硬件设计
从实验任务我们可以画出如下的系统框图:
阿莫论坛发帖达芬奇专用11055.png

图 6.3.1 系统框图

本次实验,AXI Timer产生中断,MicroBlaze处理器通过中断控制器的中断请求信号控制LED闪烁,AXI UART打印处理器发送的信息。
本次的硬件设计我们在《Hello World》实验的基础上进行,我们打开《Hello World》实验中的Vivado工程“hello world”,打开后在菜单栏中依次点击“File->Project->Save As...”,将工程名改为“axi_timer_intr”,工程路径保持不变。
在Flow Navigator中,点击IP INTEGRATOR下的“Open Block Design”,在Diagram界面添加一个AXI GPIO IP核,并将其位宽设置为4;一个AXI INTC IP核;然后添加AXI Timer IP核,如图 6.3.2所示:
阿莫论坛发帖达芬奇专用11495.png

图 6.3.2 添加AXI Timer

双击打开AXI Timer,进入配置页面,由于我们本次实验只是用定时器中断功能,因此不需要对Capture(捕获)、Generate(生成)进行配置,我们直接点击“OK”,图 6.3.3是AXI Timer配置界面。
阿莫论坛发帖达芬奇专用11693.png

图 6.3.3 AXI Timer配置界面

这里我们简单介绍下该界面中个选项的作用。
Enable 64-bit mode(使能64位模式):选择该选项后AXI Timer的两个32定时器会被级联成一个64位寄存器,选用该模式后,Enable Timer2选项会被禁用。一般情况下我们都是使用32位模式就可以了,只有在需要的寄存器超过了32位才用该模式。
Width of the Timer/Counter(定时器/计数器位宽)(bits):根据用户需求选择8、16、32位计数位宽。
Active state of Capture Trigger(捕获触发器的活动状态):该选项可以设置捕获活动高信号还是活动低信号。
Active state of Generate Out signal(生成输出信号的活动状态):此选项可以设置生成的信号是高还是低。
Enable Timer2(使能定时器2):该选项可以打开定时器2,定时器2的捕获和生成两处的配置方法与定时器1相同,但可以独立配置。
接下来点击“Run Connection Automation”按钮,在弹出的页面选中所有信号,点击“OK”,完成连线,如图 6.3.4所示:
阿莫论坛发帖达芬奇专用12281.png

图 6.3.4 自动连线

连线完成后可以点击“Regenerate Layout”按钮重新布局,以便观察布局布线,然后将gpio_rtl_0改为“LED”。
将AXI Timer的interrupt接口与AXI Interrupt Controller的intr[0:0]接口连接,将AXI Interrupt Controller的interrupt接口与MicroBlaze的INTERRUPT接口连接,如图 6.3.5所示:
阿莫论坛发帖达芬奇专用12566.png

图 6.3.5 连接中断信号

最后整体的布局如图 6.3.6所示:
阿莫论坛发帖达芬奇专用12669.png

图 6.3.6 最终布局视图

到这里我们的Block Design就设计完成了,在Diagram窗口空白处右击,然后选择“Validate Design”验证设计。验证完成后弹出对话框提示“Validation Successful”表明设计无误,点击“OK”确认。最后按快捷键“Ctrl+S”保存设计。
接下来在Source窗口中右键点击Block Design设计文件“system.bd”,然后依次执行“Generate Output Products”和“Create HDL Wrapper”。
然后我们双击打开Sources目录下的system_wrapper.xdc,添加约束信息,管脚约束代码如下:
  1. create_clock -period 20.000 -name sys_clk [get_ports sys_clk]
  2. set_property PACKAGE_PIN R4 [get_ports sys_clk]
  3. set_property IOSTANDARD LVCMOS33 [get_ports sys_clk]
  4. set_property IOSTANDARD LVCMOS33 [get_ports sys_rst_n]
  5. set_property PACKAGE_PIN U2 [get_ports sys_rst_n]

  6. set_property IOSTANDARD LVCMOS33 [get_ports UART_rxd]
  7. set_property IOSTANDARD LVCMOS33 [get_ports UART_txd]
  8. set_property PACKAGE_PIN U5 [get_ports UART_rxd]
  9. set_property PACKAGE_PIN T6 [get_ports UART_txd]
  10. set_property IOSTANDARD LVCMOS33 [get_ports {led_tri_io[3]}]
  11. set_property IOSTANDARD LVCMOS33 [get_ports {led_tri_io[2]}]
  12. set_property IOSTANDARD LVCMOS33 [get_ports {led_tri_io[1]}]
  13. set_property IOSTANDARD LVCMOS33 [get_ports {led_tri_io[0]}]
  14. set_property PACKAGE_PIN Y2 [get_ports {led_tri_io[3]}]
  15. set_property PACKAGE_PIN V2 [get_ports {led_tri_io[2]}]
  16. set_property PACKAGE_PIN R3 [get_ports {led_tri_io[1]}]
  17. set_property PACKAGE_PIN R2 [get_ports {led_tri_io[0]}]
复制代码

最后在左侧Flow Navigator导航栏中找到PROGRAM AND DEBUG,点击该选项中的“Generate Bitstream”,对设计进行综合、实现、并生成Bitstream文件。
在生成Bitstream之后,在菜单栏中依次点击“File->Export->Export hardware”导出硬件,并在弹出的对话框中,勾选“Include bitstream”,在导出路径最后添加“/vitis”。然后在菜单栏依次点击“Tools->Launch Vitis”,启动Vitis软件。
6.4软件设计
在将硬件导出至Vitis,并打开Vitis开发环境后,创建应用工程的步骤都是一样的,这里不再赘述,新创建的应用工程命名为“axi_timer_intr”。
我们打开system_wrapper目录下的platform.spr文件,找到axi_timer_0,可以看到定时器的文档和导入示例,如图 6.4.1所示:
阿莫论坛发帖达芬奇专用14402.png

图 6.4.1 platform.spr文件

如果我们点击“Import Examples”,会弹出下图所示的导入示例界面,关于定时器有7个示例,根据施压你任务,我们选择第三个实例,如图 6.4.2所示:
阿莫论坛发帖达芬奇专用14574.png

图 6.4.2 导入示例

我们将根据官方实例来设计本次实验的软件部分。
这里我们不导入官方的例程,而是新建一个源文件。在timer/src目录上右键,依次点击“New->Source File”。在弹出的对话框中Source file一栏我们输入文件名“main.c”,然后点击“Finish”。
新建源文件之后,在左侧axi_timer_intr/src目录下可以看到main.c文件,同时在主页面已经打开了该文件的文本编辑框。我们在新建的main.c文件中输入以下代码:
  1. 1  #include <stdio.h>
  2. 2  #include "xparameters.h"
  3. 3  #include "xintc.h"
  4. 4  #include "xtmrctr.h"
  5. 5  #include "xil_exception.h"
  6. 6  #include "xgpio.h"
  7. 7  #include "xil_printf.h"
  8. 8  
  9. 9  #define LED_DEV_ID          XPAR_GPIO_0_DEVICE_ID   //LED ID
  10. 10 #define INTC_ID             XPAR_INTC_0_DEVICE_ID   //中断控制器ID
  11. 11 #define TMRCTR_DEVICE_ID    XPAR_TMRCTR_0_DEVICE_ID //定时器中断ID
  12. 12
  13. 13 #define TMRCTR_INTR_ID  XPAR_INTC_0_TMRCTR_0_VEC_ID //定时中断ID
  14. 14
  15. 15 #define XIL_EXCEPTION_ID_INT    16U                 //中断异常ID
  16. 16
  17. 17 #define LED_Channel     1
  18. 18
  19. 19 XIntc    Intc;     //中断控制器实例
  20. 20 XGpio    led_gpio; //LED实例
  21. 21 XTmrCtr  Timer;    //定时器实例
  22. 22
  23. 23 void timer_intr_hander(void *InstancePtr);
  24. 24
  25. 25 int main(){
  26. 26     print ("timer interrupt test\n");
  27. 27     //初始化LED
  28. 28     XGpio_Initialize(&led_gpio, LED_DEV_ID);
  29. 29     //为指定的GPIO信道设置所有独立信号的输入/输出方向
  30. 30     XGpio_SetDataDirection(&led_gpio, 1, 0);
  31. 31     //设置LED初始值
  32. 32     XGpio_DiscreteWrite(&led_gpio, 1, 0x0f);
  33. 33     //定时器初始化
  34. 34     XTmrCtr_Initialize(&Timer, TMRCTR_DEVICE_ID);
  35. 35     //为指定的计时器启用指定的选项。
  36. 36     XTmrCtr_SetOptions(&Timer, 0,XTC_INT_MODE_OPTION |    //中断操作
  37. 37                                  XTC_AUTO_RELOAD_OPTION | //自动加载
  38. 38                                  XTC_DOWN_COUNT_OPTION);  //递减计数
  39. 39
  40. 40     //设置指定计时器的重置值
  41. 41     XTmrCtr_SetResetValue(&Timer, 0, 50000000);
  42. 42     //设置计时器回调函数,指定的计时器满一个周期时驱动程序将调用该回调函数
  43. 43     XTmrCtr_SetHandler(&Timer, timer_intr_hander,&Timer);
  44. 44     //开启定时器
  45. 45     XTmrCtr_Start(&Timer, 0);
  46. 46     //中断控制器初始化
  47. 47     XIntc_Initialize(&Intc, INTC_ID);
  48. 48     //关联中断源和中断处理函数
  49. 49     XIntc_Connect(&Intc, TMRCTR_INTR_ID,
  50. 50                  (XInterruptHandler)XTmrCtr_InterruptHandler,&Timer);
  51. 51     //开启中断控制器
  52. 52     XIntc_Start(&Intc, XIN_REAL_MODE);
  53. 53     //使能中断控制器
  54. 54     XIntc_Enable(&Intc, TMRCTR_INTR_ID);
  55. 55         //设置并打开中断异常处理
  56. 56     Xil_ExceptionInit();
  57. 57         Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
  58. 58                 (Xil_ExceptionHandler)XIntc_InterruptHandler,
  59. 59                 &Intc);
  60. 60         Xil_ExceptionEnable();
  61. 61
  62. 62     while(1);
  63. 63 }
  64. 64
  65. 65 void timer_intr_hander(void *InstancePtr)  //回调函数
  66. 66 {
  67. 67     static int led_state = 0x00;
  68. 68     //检测定时器是否满一个计数周期
  69. 69     if (XTmrCtr_IsExpired(&Timer, 0)){
  70. 70         led_state = ~led_state;                       //LED状态翻转
  71. 71         XGpio_DiscreteWrite(&led_gpio, 1, led_state); //输出LED值
  72. 72     }
  73. 73 }
复制代码

代码第28到32行我们完成了对AXI GPIO的设置,接着代码第34到45行我们对定时器进行了一系列设置。代码第34行对AXI Timer初始化;代码第36到39行XTmrCtr_SetOptions函数为指定的定时器计数器(32bit计数器)启用指定的操作,在本次实验中,我们指定了XTC_INT_MODE_OPTION(启用中断控制)、XTC_AUTO_RELOAD_OPTION(自动加载操作)和XTC_DOWN_COUNT_OPTION(递减计数操作)三种操作。我们在XTmrCtr_SetOptions函数中设置了这三种操作,当定时器启用后,计数器就从生成值开始递减计数,计数到0时产生中断并重新从加载计数器中加载生成值,如此循环产生中断。代码第41行设置生成值,这里我们设为50000000,即0.5秒(由于处理器时钟频率为100M)。代码第43行设置回调函数,当指定的定时器满一个周期时驱动程序将调用该回调函数。代码第45行启动指定的定时器。
接下来代码第47到59行就是设置中断系统和中断异常处理,这两部分内容和之前的实验基本相同,需要注意的是,这里XIntc_Connect函数关联的中断处理函数不再是我们自定义的服务函数,而是官方提供的一个服务函数。
代码第64到70行就是我们在代码第43行指定的一个回调函数。当我们指定的定时器产生中断后,中断服务函数调用该回调函数。此时检测定时器是否计满一个计数周期,当定时器满一个周期后,LED翻转一次,并向AXI GPIO写入LED的值,如代码第68行所示。
保存main.c并编译工程。
6.5下载验证
首先我们将下载器与达芬奇开发板上的JTAG接口连接,下载器另外一端与电脑连接。然后使用USB连接线将USB UART接口与电脑连接,用于串口通信。最后连接开发板的电源,并打开电源开关。
打开Vitis的Terminal,然后开始下载程序,软件程序下载完成后,在下方的Terminal中可以看到应用程序打印的信息如图 6.5.1所示:
阿莫论坛发帖达芬奇专用18114.png

图 6.5.1 程序打印结果

并且观察到开发板上LED闪烁。实验结果图如下:
阿莫论坛发帖达芬奇专用18224.png

图 6.5.2 LED灯闪烁

6.6代码调试
代码调试之前,先要把Terminal关掉,否则在调试界面串口(Vitis Serial Terminal)中无法打印出信息。
打开调试界面:鼠标右击应用工程axi_timer_intr,选择“Debug As”,然后选择第一项“1 Launch on Hardware (System Debugger)”,如图 6.6.1所示:
阿莫论坛发帖达芬奇专用18480.png

图 6.6.1 打开调试界面

如果出现下图所示的WARNING界面,直接点击“OK”按钮,如果不想以后再出现,可以勾选“Do not show this warning again”。
阿莫论坛发帖达芬奇专用18618.png

图 6.6.2 WARNING提示界面

进入图 6.6.3所示的调试界面,程序首先从main 函数开始运行。
阿莫论坛发帖达芬奇专用18742.png

图 6.6.3 调试界面


图 6.6.3标注为1的位置是用于调试的工具栏;标注为2的位置可以观察程序中变量的值;标注为3的位置即为我们所要调试的代码,图中高亮的代码行就是接下来将要执行的代码。
请详细观察用于调试的工具栏界面,如图 6.6.4所示:
阿莫论坛发帖达芬奇专用18993.png

图 6.6.4 调试工具栏

图 6.6.4标注为1的按钮表示程序继续运行(Resume,快捷键F8);标注为2的按钮表示暂停(Suspend,只有程序在运行时才可以点击);标注为3的按钮表示单步执行(Step Into,快捷键F5);标注为4的按钮表示单步执行结束(Step Over,快捷键F6);标注为5的按钮表示执行完并返回(Step Return,快捷键F7)。
首先点击Vitis Serial Terminal 窗口的界面,接着点击右侧的红色框内的“+”按钮来连接串口,便于观察程序调试的结果。串口连接完毕后如图 6.6.5所示:
阿莫论坛发帖达芬奇专用19374.png

图 6.6.5 Vitis Serial Terminal

接下来开始调试代码。
分别双击行数25、26,设置两个断点(再次双击即可取消断点)。如图 6.6.6所示:
阿莫论坛发帖达芬奇专用19527.png

图 6.6.6 设置两处断点

点击“Step Over”图标或者按下快捷键 F6 来执行代码,高亮部分到28行时,说明前两个断点已经执行完毕,会在串口会打印信息。执行结果如图 6.6.7所示:
阿莫论坛发帖达芬奇专用19693.png

图 6.6.7 断点执行完毕

点击“Step Into”图标或者按下快捷键F5,开始跳转至XGpio_Initialize函数,如图 6.6.8所示:
阿莫论坛发帖达芬奇专用19838.png

图 6.6.8 执行XGpio_Initialize函数

可以继续点击“Step Into”图标查看代码,若想要立刻跳出XGpio_Initialize函数,只需要点击“Step Return”图标或者按下快捷键 F7,即跳出该函数准备执行XGpio_SetDataDirection函数。跳转结果如图 6.6.9所示:
阿莫论坛发帖达芬奇专用110068.png

图 6.6.9 跳出XGpio_Initialize函数

继续点击“Step Over”执行程序。待程序执行完32行的XGpio_DiscreteWrite函数后,开发板上的LED灯会全部被点亮。
点击“Resume”或者按下快捷键F8,程序一直执行下去。待整体程序执行完62行后,将看不到深色部分,同时可以观察到开发板上的LED灯不停地闪烁。
如果想要暂停执行,点击“Suspend”图标即可,重新点击“Resume”即可继续执行程序。
待程序调试完毕,点击右上角红色框内按钮即可回到退出调试回到Design界面。如图 6.6.10所示:
阿莫论坛发帖达芬奇专用110408.png

图 6.6.10 退出调试

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-25 17:02

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表