在上一篇博客中,我们查看了 Zynq All Programmable SoC 中每个 CPU 提供的私有计时器。在本博客中,我们将了解 Zynq SoC 的私有看门狗定时器,以及如何使用它,我们将查看其使用示例。
参考:
❝UG585 CH8 Timer
每个A9处理器都有私有的32位定时器和32位看门狗定时器。两个处理器共享一个64位定时器。这些定时器的时钟始终是的CPU频率的1/2(CPU_3x2x)。
然而,在我们研究如何配置和使用 Zynq 看门狗之前,我认为最好先了解一下为什么需要看门狗定时器以及看门狗是如何工作的。看门狗解决了无响应软件的必然性,并为这个问题提供了可靠的解决方案。无论最终应用是什么,所有工程师都希望提供可靠的解决方案,优秀的系统设计人员知道他们必须针对所有可能性进行设计。
系统工程团队必须采取许多步骤来确保可靠的设计。第一步是建立定义系统及其软件行为的需求基线。然后,工程团队按照软件生命周期实施这些要求,其中包括:
设计文档的生成
软件设计和源代码
验证策略是否已达到要求
大多数设计将包括确保软件能够对系统故障做出合理响应的方法。这些故障可能会产生两种影响之一——允许软件继续运行,同时保持完整或减少的服务,或者完全无法响应。当软件无法响应时,看门狗定时器可以重新启动系统或确保系统安全的发生故障。(安全关键系统和软件的问题是一个复杂的问题,需要的空间比我在这里详细介绍的要多。)
从最简单的意义上说,看门狗是一个从预加载值开始倒计时的计时器。当软件应用程序执行时,它会定期重置看门狗。如果软件未能重置看门狗,它的计数将达到零,然后看门狗电路复位处理器。当软件正常运行时,看门狗计数永远不会达到零。如果软件由于某种原因出现故障,则看门狗不会复位,计数达到零,处理器复位,软件重新启动。许多系统都有一个寄存器,它在看门狗触发时设置了一个位。此功能允许系统从看门狗复位中恢复过来,同时注意看门狗触发了复位这一事实。
Zynq SoC 中的两个 ARM Cortex-A9 处理器中的每一个都有一个私有看门狗定时器。这些私有看门狗可以用作像私有计时器(在本系列的上一篇博客文章中讨论过)这样的计时器,也可以用作看门狗。Zynq 看门狗定时器通过六个寄存器控制:
看门狗加载寄存器(Watchdog Load Register):保存看门狗定时器倒计时的值。在自动重载模式下,看门狗计数器重置为存储在该寄存器中的值。写入该寄存器将导致看门狗计数器寄存器重置为此值。
看门狗计数器寄存器(Watchdog Counter Register):这是看门狗计数器本身。是递减计数器。根据看门狗模式,写入该寄存器会重新加载计数器。在看门狗模式下,该寄存器只能通过写入看门狗加载寄存器来更新。
看门狗控制寄存器(Watchdog Control Register):该寄存器控制看门狗(定时器或看门狗)的配置、预分频器设置、中断启用、自动重载模式以及看门狗在其当前配置模式下的启用。
看门狗中断状态寄存器(Watchdog Interrupt Status Register):包含一个事件标志,显示计数器何时达到零。写入该寄存器会重置它。
看门狗复位状态寄存器(Watchdog Reset Status Register):该寄存器仅包含一位,仅由上电复位(不是看门狗触发的复位)清除。它也可以通过软件应用程序清除。复位状态位允许软件确定重启的原因是否是由看门狗超时引起的。
看门狗禁用寄存器(Watchdog Disable Register):当看门狗设置为定时器模式时,该寄存器需要写入两个特定模式以启用看门狗控制寄存器中的看门狗模式位。
正如我们在 Zynq SoC 的私有定时器中看到的那样,Zynq 软件开发环境提供了许多可用于配置和驱动看门狗的函数和宏。这些包含在#include "xscuwdt.h" 中。该文件使工具能够:
测试看门狗是否过期
加载看门狗
启动、停止和重新启动看门狗
设置看门狗模式
配置和初始化看门狗
以下示例将看门狗配置为不刷新的传统看门狗,以便看门狗在超时时复位 Zynq SoC。然后,示例代码检查以确定在看门狗复位(例如上电复位或看门狗超时)后复位的原因,并通过 STDOUT 报告此情况。按下按钮启动私人(专用)定时器,点亮 LED,并启动看门狗。为了做到这一切,我们按照标准方法配置看门狗,就像我们迄今为止使用来自 xparameters.h 的数据和配置例程对所有外设所做的那样:
//defineprivatewatchdog#defineWDT_DEVICE_IDXPAR_SCUWDT_0_DEVICE_ID#defineINTC_DEVICE_IDXPAR_SCUGIC_SINGLE_DEVICE_ID#defineWDT_IRPT_INTRXPAR_SCUWDT_INTR#defineWDT_LOAD_VALUE0xFF//看门狗配置
WCHConfigPtr=XScuWdt_LookupConfig(WDT_DEVICE_ID);
XScuWdt_CfgInitialize(&WdtInstance,WCHConfigPtr,WCHConfigPtr->BaseAddr);
XScuWdt_LoadWdt(&WdtInstance,WDT_LOAD_VALUE);
XScuWdt_Start(&WdtInstance);
在初始化和加载看门狗之后,接下来的步骤是启用中断(在中断配置函数内)并将看门狗设置为看门狗功能,而不是使用 XScuWdt_SetWdMode() 函数的定时器功能:
//setupthewatchdog
XScuGic_Connect(GicInstancePtr,WdtIntrId,(Xil_ExceptionHandler)WdtIntrHandler,
(void*)WdtInstancePtr);
//设置看门狗
XScuWdt_SetWdMode(WdtInstancePtr);
如果我们希望在定时器模式下使用看门狗,我们可以调用函数:XScuWdt_SetTimerMode()这就是为什么我设置中断以触发在定时器模式下运行的看门狗并为看门狗声明一个空的中断服务程序,在这种情况下将被调用。
我们可以使用读取看门狗复位状态寄存器的函数来查看最后一次复位是否是由于看门狗事件:
XScuWdt_IsWdtExpired(InstancePtr)
下图显示了当处理器从上电复位和按下按钮以启用看门狗定时器时发生的复位上电时通过 STDOUT 输出的结果:
先前的复位状态保持存储在其中的看门狗事件的状态通过 XScuWdt_IsWdtExpired() 访问的看门狗复位状态寄存器。
此示例的源代码:
❝https://gitee.com/openfpga/zynq-chronicles/blob/master/main_part16.c