搜索
bottom↓
回复: 1

【正点原子FPGA连载】第九章定时器中断实验--摘自【正点原子】领航者 ZYNQ 之嵌入式开发指南

[复制链接]

出0入234汤圆

发表于 2020-7-25 11:27:30 | 显示全部楼层 |阅读模式
本帖最后由 正点原子 于 2020-10-24 10:22 编辑

1)实验平台:正点原子领航者ZYNQ开发板
2)平台购买地址:https://item.taobao.com/item.htm?&id=606160108761
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/fpga/zdyz_linhanz.html
4)对正点原子FPGA感兴趣的同学可以加群讨论:876744900
QQ群头像.png
5)关注正点原子公众号,获取最新资料


100846rel79a9p4uelap24.jpg

100846f1ce1fg14zbg0va4.png

第九章定时器中断实验



定时器作为PS的重要组成部分,可以不受CPU的干预,自己独立运行,来完成计时、定时、中断以及计算来自MIO或EMIO引脚的信号脉冲宽度等。本章我们将向大家介绍定时器以及定时器中断的使用方法。
本章包括以下几个部分:
11.1简介
1.2实验任务
1.3硬件设计
1.4软件设计
1.5下载验证


简介
在ZYNQ嵌入式系统中,定时器的资源是非常丰富的,每个Cortex-A9处理器都有各自独立的32位私有定时器和32位看门狗定时器,这两个CPU同时共享一个64位的全局定时器(GT)。除此之外,PS中还有一个24位的系统看门狗定时器(SWDT)和两个TTC(Triple Timer Counters)。系统看门狗定时器可以在系统发生灾难性的故障时(如PS中的PLL工作异常)发出信号,使得系统程序重新启动,保证了系统安全可靠的运行。TTC用于计算来自MIO引脚或EMIO引脚的信号脉冲宽度,每个TTC都有三个独立的计数器。
定时器的系统框图如图 9.1.1所示:
阿莫论坛发帖领航者专用11111111111111461.png

图 9.1.1 定时器系统框图

图中的几种定时器都有连接到中断控制器(Interrupt Controller),我们可以很方便的使用定时器来完成定时器中断的实验。其中私有定时器(CPU Private Timer)是最为常用的,本次实验是基于私有定时器来完成定时器的中断实验。
私有定时器的时钟频率为CPU时钟频率的一半,如ARM的工作时钟频率为666.666Mhz,则私有定时器的时钟频率为333.333Mhz。私有定时器的特性如下:
1、32位计数器,当计数器递减至0后产生中断;
2、8位预分频计数器,可以更好的控制中断周期;
3、可以配置单次定时或者自动重载模式;
4、通过配置起始计数值来设置定时时间。
实验任务
本章的实验任务是通过定时器的中断,每200ms控制一次PS LED灯的亮灭。
硬件设计
从实验任务我们可以画出如下的系统框图,DDR3中存放和运行程序、Timer定时器产生定时中断、UART打印信息、MIO驱动LED外设。虽然本实验可以不需要UART控制器,不过为了方便打印一些信息,此处我们加上UART。
阿莫论坛发帖领航者专用11111111111111999.png

图 9.3.1 系统框图

由于ARM处理器自带了私有定时器,因此本次实验在搭建嵌入式系统时,不需要额外添加定时器,只需在ZYNQ嵌入式最小系统中添加UART和MIO。
首先创建Vivado工程,工程名为“timer_intr_led”,然后创建Block Design设计(system.bd)并添加ZYNQ7 Processing System模块。接下来按照《“Hello World”实验》中的步骤2-7、2-8分别配置PS的UART和DDR控制器,并移除PS中与PL端交互的接口信号,外设IO引脚配置界面如下图所示:
阿莫论坛发帖领航者专用111111111111111308.png

图 9.3.2 外设IO引脚配置界面

勾选UART0对应的引脚14和15,同时勾选GPIO MIO。
嵌入式系统最终搭建的框图如下:
阿莫论坛发帖领航者专用111111111111111420.png

图 9.3.3 嵌入式系统框图界面

软件设计
在将硬件导出至SDK,并打开SDK开发环境后,创建应用工程的步骤都是一样的,这里不再赘述,新创建的应用工程命名为timer_intr_led。
我们打开timer_intr_led_bsp目录下的system.mss文件,找到scutimer,可以看到定时器的文档和导入示例,如图 9.4.1所示:
阿莫论坛发帖领航者专用111111111111111662.png

图 9.4.1 system.mss文件

如果我们点击Import Examples,会弹出下图所示的导入示例界面,关于定时器有2个示例,如下图所示:
阿莫论坛发帖领航者专用111111111111111783.png

图 9.4.2 导入示例

感兴趣的朋友可以参考下官方提供的定时器例程,其中xscutimer_intr_example是定时器中断的示例。
这里我们不导入官方的例程,而是新建一个源文件。在timer/src目录上右键,选择New->Source File。在弹出的对话框中Source file一栏我们输入文件名“main.c”,然后点击“Finish”。
新建源文件之后,在左侧timer_intr_led/src目录下可以看到main.c文件,同时在主页面已经打开了该文件的文本编辑框。我们在新建的main.c文件中输入以下代码:
  1. 1   #include "xparameters.h"
  2. 2   #include "xscutimer.h"
  3. 3   #include "xscugic.h"
  4. 4   #include "xgpiops.h"
  5. 5   #include "xil_exception.h"
  6. 6   #include "xil_printf.h"
  7. 7   
  8. 8   #define TIMER_DEVICE_ID     XPAR_XSCUTIMER_0_DEVICE_ID   //定时器ID
  9. 9   #define INTC_DEVICE_ID      XPAR_SCUGIC_SINGLE_DEVICE_ID //中断ID
  10. 10  #define TIMER_IRPT_INTR     XPAR_SCUTIMER_INTR           //定时器中断ID
  11. 11  #define GPIO_DEVICE_ID      XPAR_XGPIOPS_0_DEVICE_ID     //宏定义 GPIO_PS ID
  12. 12  #define MIO_LED             0                            //led连接到 MIO0
  13. 13  
  14. 14  //私有定时器的时钟频率 = CPU时钟频率/2 = 333MHz
  15. 15  //0.2s闪烁一次,0.2*1000_000_000/(1000/333) - 1 = 3F83C3F
  16. 16  #define TIMER_LOAD_VALUE    0x3F83C3F                    //定时器装载值
  17. 17  
  18. 18  XScuGic Intc;               //中断控制器驱动程序实例
  19. 19  XScuTimer Timer;            //定时器驱动程序实例
  20. 20  XGpioPs Gpio;               //GPIO设备的驱动程序实例
  21. 21  
  22. 22  //MIO引脚初始化
  23. 23  int mio_init(XGpioPs *mio_ptr)
  24. 24  {
  25. 25      int status;
  26. 26  
  27. 27      XGpioPs_Config *mio_cfg_ptr;
  28. 28      mio_cfg_ptr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
  29. 29      if (NULL == mio_cfg_ptr)
  30. 30          return XST_FAILURE;
  31. 31      status = XGpioPs_CfgInitialize(mio_ptr, mio_cfg_ptr,
  32. 32              mio_cfg_ptr->BaseAddr);
  33. 33      if (status != XST_SUCCESS)
  34. 34          return XST_FAILURE;
  35. 35  
  36. 36      //设置指定引脚的方向: 0 输入, 1 输出
  37. 37      XGpioPs_SetDirectionPin(&Gpio, MIO_LED, 1);
  38. 38      //使能指定引脚输出: 0 禁止输出使能, 1 使能输出
  39. 39      XGpioPs_SetOutputEnablePin(&Gpio, MIO_LED, 1);
  40. 40      return XST_SUCCESS;
  41. 41  }
  42. 42  
  43. 43  //定时器初始化程序
  44. 44  int timer_init(XScuTimer *timer_ptr)
  45. 45  {
  46. 46      int status;
  47. 47      //私有定时器初始化
  48. 48      XScuTimer_Config *timer_cfg_ptr;
  49. 49      timer_cfg_ptr = XScuTimer_LookupConfig(TIMER_DEVICE_ID);
  50. 50      if (NULL == timer_cfg_ptr)
  51. 51          return XST_FAILURE;
  52. 52      status = XScuTimer_CfgInitialize(timer_ptr, timer_cfg_ptr,
  53. 53              timer_cfg_ptr->BaseAddr);
  54. 54      if (status != XST_SUCCESS)
  55. 55          return XST_FAILURE;
  56. 56  
  57. 57      XScuTimer_LoadTimer(timer_ptr, TIMER_LOAD_VALUE); // 加载计数周期
  58. 58      XScuTimer_EnableAutoReload(timer_ptr);            // 设置自动装载模式
  59. 59  
  60. 60      return XST_SUCCESS;
  61. 61  }
  62. 62  
  63. 63  //定时器中断处理程序
  64. 64  void timer_intr_handler(void *CallBackRef)
  65. 65  {
  66. 66      //LED状态,用于控制LED灯状态翻转
  67. 67      static int led_state = 0;
  68. 68      XScuTimer *timer_ptr = (XScuTimer *) CallBackRef;
  69. 69      if(led_state == 0)
  70. 70          led_state = 1;
  71. 71      else
  72. 72          led_state = 0;
  73. 73      //向指定引脚写入数据: 0 或 1
  74. 74      XGpioPs_WritePin(&Gpio, MIO_LED,led_state);
  75. 75      //清除定时器中断标志
  76. 76      XScuTimer_ClearInterruptStatus(timer_ptr);
  77. 77  }
  78. 78  
  79. 79  //定时器中断初始化
  80. 80  void timer_intr_init(XScuGic *intc_ptr,XScuTimer *timer_ptr)
  81. 81  {
  82. 82      //初始化中断控制器
  83. 83      XScuGic_Config *intc_cfg_ptr;
  84. 84      intc_cfg_ptr = XScuGic_LookupConfig(INTC_DEVICE_ID);
  85. 85      XScuGic_CfgInitialize(intc_ptr, intc_cfg_ptr,
  86. 86              intc_cfg_ptr->CpuBaseAddress);
  87. 87      //设置并打开中断异常处理功能
  88. 88      Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
  89. 89              (Xil_ExceptionHandler)XScuGic_InterruptHandler, intc_ptr);
  90. 90      Xil_ExceptionEnable();
  91. 91  
  92. 92      //设置定时器中断
  93. 93      XScuGic_Connect(intc_ptr, TIMER_IRPT_INTR,
  94. 94            (Xil_ExceptionHandler)timer_intr_handler, (void *)timer_ptr);
  95. 95  
  96. 96      XScuGic_Enable(intc_ptr, TIMER_IRPT_INTR); //使能GIC中的定时器中断
  97. 97      XScuTimer_EnableInterrupt(timer_ptr);      //使能定时器中断
  98. 98  }
  99. 99  
  100. 100 //main函数
  101. 101 int main()
  102. 102 {
  103. 103     int status;
  104. 104     xil_printf("SCU Timer Interrupt Test \r\n");
  105. 105
  106. 106     mio_init(&Gpio);                 //MIO引脚初始化
  107. 107     status = timer_init(&Timer);     //定时器初始化
  108. 108     if (status != XST_SUCCESS) {
  109. 109         xil_printf("Timer Initial Failed\r\n");
  110. 110         return XST_FAILURE;
  111. 111     }
  112. 112     timer_intr_init(&Intc,&Timer);   //定时器中断初始化
  113. 113     XScuTimer_Start(&Timer);         //启动定时器
  114. 114
  115. 115     while(1);
  116. 116     return 0;
  117. 117 }
复制代码

在代码的第16行定义了定时器的装载值TIMER_LOAD_VALUE,定时器在运行时,初始值为定时器的装载值,当定时器的装载值递减至0后,产生中断,通过修改装载值的大小,来控制LED灯亮灭的时间。需要说明的是,私有定时器的时钟频率等于CPU时钟频率的一半,因此私有定时器的时钟频率约为333Mhz。
在程序的main函数中,首先对MIO引脚和定时器进行初始化。初始化完成后,函数返回初始化的结果,如果初始化失败,打印错误信息并返回;如果初始化成功,则开始执行定时器中断初始化函数(timer_intr_init),并启动定时器。最后主程序会一直停留在while无限循环,如代码中第100行至第117行代码所示。
在代码的第22行至第41行完成了对MIO引脚的初始化。在代码的第43行至第61行完成了对定时器的初始化。其中XScuTimer_LoadTimer函数设置定时器的装载值,输入的参数即为宏定义TIMER_LOAD_VALUE。XScuTimer_EnableAutoReload函数将定时器设置成自动装载模式,从而循环产生定时器的中断。
在代码的第79行至第98行完成了定时器中断的初始化。程序首先对中断控制器进行初始化,随后设置并打开中断异常处理的功能。接下来为定时器中断设置中断处理函数,通过XScuGic_Connect函数进行设置,这里设置的定时器中断处理函数为timer_intr_handler。XScuGic_Enable函数使能GIC中的定时器中断,XScuTimer_EnableInterrupt函数使能定时器中断。
在代码的第84行至第98行是定时器中断处理函数,由于定时器的装载值等于0x3F83C3F(十进制:66599999),CPU的时钟频率约为333Mhz,因此每隔200ms进入此中断函数。程序中定义一个静态变量led_state,用于控制LED灯的翻转。每进入一次中断函数,led_state的状态改变一次,并将led_state的值写入MIO_LED引脚,从而控制LED灯的亮灭。最后通过XScuTimer_ClearInterruptStatus函数来清除中断标志。
下载验证
首先我们将下载器与领航者底板上的JTAG接口连接,下载器另外一端与电脑连接。然后使用Mini USB连接线将USB_UART接口与电脑连接,用于串口通信。最后连接开发板的电源,并打开电源开关。
在SDK软件下方的SDK Terminal窗口中点击右上角的加号设置并连接串口。然后在应用工程uart_intr_loop上右击,选择“Run As”,然后选择第一项“1 Launch on Hardware (System Debugger)”。
软件程序下载完成后,在下方的SDK Terminal中可以看到应用程序打印的信息“SCU Timer Interrupt Test”,如下图所示:
阿莫论坛发帖领航者专用111111111111117149.png

图 9.5.1 程序打印结果

接下来观察开发板,可以看到,核心板上的LED2(PS LED)每隔200ms亮灭一次,如图 9.5.2所示,说明本次实验在领航者ZYNQ开发板上面下载验证成功。
阿莫论坛发帖领航者专用111111111111117314.png

图 9.5.2 开发板实验现象

至此,定时器中断实验的讲解已经结束。最后,我们来教大家如何对代码进行调试。
在应用工程timer_intr_led上右击,选择“Debug As”,然后选择第一项“1 Launch on Hardware (System Debugger)”,如下图所示:
阿莫论坛发帖领航者专用111111111111117504.png

图 9.5.3 打开调试界面

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

图 9.5.4 WARING提示界面

在弹出的下图所示界面中,点击“Yes”按钮,如果不想以后再出现该界面,可以点击
“Remember my decision”。
阿莫论坛发帖领航者专用111111111111117769.png

图 9.5.5 确认进入调试界面

进入下图所示的调试界面,程序首先从main函数开始运行。
阿莫论坛发帖领航者专用111111111111117860.png

图 9.5.6 开始调试界面

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

图 9.5.7 工具栏

图 9.5.7标注为1的图标表示程序继续运行(Resume,快捷键F8);标注为2的图标表示暂停(Suspend,只有程序在运行时才可以点击);标注为3的图标表示单步执行(Step Info,快捷键F5);标注为4的图标表示单步执行结束(Step Over,快捷键F6);标注为5的图标表示执行完并返回(Step Return,快捷键F7)。同时,也可以点击菜单栏的Run,找到调试按钮,如下图所示:
阿莫论坛发帖领航者专用111111111111118334.png

图 9.5.8 点击Run界面

我们首先点击SDK Terminal窗口的界面,便于观察程序调试的结果,如下图所示:
阿莫论坛发帖领航者专用111111111111118438.png

图 9.5.9 窗口打印界面

接下来开始调试代码。点击Step Over图标或者按下快捷键F6来执行代码,执行结果如下图所示:
阿莫论坛发帖领航者专用111111111111118547.png

图 9.5.10 窗口打印结果

此时,执行完xil_printf函数,并在窗口中显示打印的结果。接下来点击Step Info图标或者按下快捷键F5,开始跳转至mio_init函数,如下图所示:
阿莫论坛发帖领航者专用111111111111118689.png

图 9.5.11 进入mio_init函数

如果此时想要迅速跳出mio_init函数,只需要点击Step Return图标或者按下快捷键F7,跳转结果如下图所示:
阿莫论坛发帖领航者专用111111111111118816.png

图 9.5.12 跳出函数

调试界面支持设置断点,直接双击行号前面蓝色区域的位置设置断点,再次按下可取消断点。如在第135行位置设置断点,双击第135行前面蓝色区域的位置,如下图所示:
阿莫论坛发帖领航者专用111111111111118954.png

图 9.5.13 设置断点

接下来点击Resume图标或者按下快捷键F8,程序可执行至断点位置,如下图所示:
阿莫论坛发帖领航者专用111111111111119054.png

图 9.5.14 程序执行至断点处

再次双击第135行前面蓝色区域的位置可取消断点。此时继续点击Resume图标或者按下快捷键F8,程序会一直执行下去,此时可以看到开发板上的LED2每隔两秒亮灭一次。如果想要暂停程序的执行,点击Suspend图标即可。
如果要退出Debug界面,点击下图中的图标即可。
阿莫论坛发帖领航者专用111111111111119251.png

图 9.5.15 退出Debug界面



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

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出16170入6148汤圆

发表于 2020-8-1 09:41:03 来自手机 | 显示全部楼层
打赏!

庆祝论坛“打赏”功能实施, 现在开始发技术主题,可以获得打赏
https://www.amobbs.com/thread-5735948-1-1.html
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-4-25 07:24

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

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