Xilinx-ZYNQ7000系列-学习笔记(2):私有看门狗(AWDT)的使用

Xilinx-ZYNQ7000系列-学习笔记(2):私有看门狗(AWDT)的使用

一、WDT简介

在嵌入式系统中,为了使系统在工作异常情况下能自动复位,一般都需要引入看门狗程序,用来监测程序不至于“跑飞”。
看门狗其实就是一个可以在一定时间内被复位的 计数器。当看门狗启动后,计数器开始自动计数,经过一定时间,如果没有被复位,计数器清零就会对CPU产生一个复位信号使 系统重启(俗称“被狗咬”)。系统正常运行时,需要在看门狗允许的时间间隔内对计数器 清零(俗称“喂狗”),不让复位信号产生。
简单的来说就是在执行程序之前给看门狗计数器赋一个初值(假设是1000),在程序开始执行时,看门狗计数器开始减少,1000->999->998……,这时候你需要进行计数器重置,假设在500的时候(时间由自己定,看你把喂狗程序加在哪里),计数器会重新变为1000。如果不进行计数器重置使得计数器减到0,那么看门狗程序启动程序复位功能,系统进行复位。

二、看门狗种类

2.1 独立看门狗

独立看门狗有其内部自带的时钟驱动,即使主时钟发生故障,它仍能够正常工作。它的喂狗时间可以自由选择,大多数情况下独立看门狗用在对时间精度要求不是很高的地方。

优点:无须配置,上电即用。无法禁用,系统必须按时喂狗,系统恢复能力高。
缺点:无法灵活配置溢出时间,无法禁用,灵活性降低。

2.2 窗口看门狗

根据系统时钟分频得到需要的时钟驱动,如果系统时钟发生故障,那么看门狗也无效。它的喂狗时间需要设置一个窗口值(小于装载到计数器的初始值),在除了窗口值以外的时间不可以进行喂狗操作,大多数情况下窗口看门狗用在对时间精度要求较高的地方。

优点:时间精度的把握较好,可以固定在某一时间范围内进行喂狗。
缺点:无法灵活配置溢出时间,超出窗口值的系统无法使用

2.3 私有看门狗与系统看门狗

此类看门狗一般是由CPU内部自带,将一个芯片中的计数器作为看门狗,通过程序的初始化,写入初值,设置溢出值,并启动计数器,具体区别参考数据手册

ug585-Zynq-7000-TRM.pdf

优点:可以通过程序改变溢出时间;可以随时禁用
缺点:需要初始化;如果程序在初始化、启动完成前跑飞或在禁用后跑飞,看门狗就无法复位系统,这样看门狗的作用就没有了,系统恢复能力降低。

PS:CPU内部自带的看门狗一般是一些比较高级的CPU或是对程序要求比较高的地方用得到。本文重点讲解 2.3的私有看门狗,其余两种看门狗请参考如下。

https://www.cnblogs.com/zhoubatuo/p/6143754.html

三、看门狗的使用方法

3.1 私有看门狗与系统看门狗

每个Cortex-A9处理器都有自己私有的32位定时器和32位看门狗定时器,这两个处理器共享一个全局64位计数器,它们的频率都为CPU频率的1/2。而在系统级,有一个24位看门狗计时器和两个16位三重计时器/计数器,系统级看门狗定时器的频率为CPU频率的1/4或1/6。
本文采用的是私有看门狗,下图为系统内部两个看门狗所处位置以及关系图。
Xilinx-ZYNQ7000系列-学习笔记(2):私有看门狗(AWDT)的使用_第1张图片
私有看门狗

每个CPU均具有一个私有定时器(PT)及一个私有看门狗(AWDT),且只能由各自的CPU进行操作,因此称为私有的。私有定时器及私有看门狗的主要特点如下:
• 32位计数单元归零时将产生中断信号;
• 具有一个8位的时钟分频器;
• 可配置成单次触发或自动装载模式;
• 计数器的初始值可设。
私有看门狗只能对各自CPU本身进行监视,如监视CPU程序是否跑飞,但却无法对另一个CPU进行监视,也无法对芯片内部锁相环等关键时钟环节进行监视,亦无法向PL或芯片外部输出复位信号,这些功能将由系统看门狗实现。

系统看门狗

不同于私有看门狗(AWDT),系统看门狗(SWDT)可监视更多的环节(如PS部分的锁相环等),其功能也相对复杂,现将其特点总结如下:

  • 具有24位计数单元;
  • 时钟输入可选为内部CPU时钟、内部PL侧时钟、外部引脚提供的时钟;
  • 计数单元溢出时可产生的信号有向PS发出中断请求、向PS或PL或MIO发出复位信号;
  • 溢出时间可设置为 32760 - 68719476736,时钟频率为100 MHz时对应的时间为330us-687.2s;
  • 中断请求信号及复位信号的脉宽可根据需要设定,中断请求信号脉宽可设为2-32个时钟周期,复位信号脉宽可设为2-256个时钟周期, 系统看门狗整体结构图如下:
    Xilinx-ZYNQ7000系列-学习笔记(2):私有看门狗(AWDT)的使用_第2张图片

3.2 配置WDT程序

由于私有看门狗属于PS端,所以在vivado环境中不需要对block块进行设置。

PS :如果需要使用系统看门狗的话,使用PL时钟则需要写分频verilog语句,使用MIO处则需要在block的ZYNQ硬件中选择SWDT。

私有看门狗代码如下:

#include "xparameters.h"
#include "xscuwdt.h"
#include "xil_printf.h"
#include 
#include "stdio.h"

#define WDT_DEVICE_ID		XPAR_SCUWDT_0_DEVICE_ID


int watchdog(XScuWdt * WdtInstancePtr, u16 DeviceId,float number);

XScuWdt Watchdog;		/* Cortex SCU Private WatchDog Timer Instance */

int main(void)
{
	int Status;
	int Count = 0;
	Status = watchdog(&Watchdog, WDT_DEVICE_ID,10);
	if (Status != XST_SUCCESS) {
		xil_printf("start the watchdog timer fail!\r\n");
		return XST_FAILURE;
	}
	while (Count < 5) {
		sleep(1);
		Count++;
		printf("the second is %d \n",Count);
		//XScuWdt_RestartWdt(WdtInstancePtr);
	}
	xil_printf("the watchdog timer will restart the system \r\n");
	return XST_SUCCESS;
}

int watchdog(XScuWdt * WdtInstancePtr, u16 DeviceId,float number)
{
	int Status;
	XScuWdt_Config *ConfigPtr;
	u32 result;
	/*
	 * Initialize the SCU Private Wdt driver so that it is ready to use.
	 */
	 xil_printf("start the watchdog time``r successful! \r\n");
	ConfigPtr = XScuWdt_LookupConfig(DeviceId);

	/*
	 * This is where the virtual address would be used, this example
	 * uses physical address.
	 */
	Status = XScuWdt_CfgInitialize(WdtInstancePtr, ConfigPtr,
					ConfigPtr->BaseAddr);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Put the watchdog timer in watchdog mode.
	 */
	XScuWdt_SetWdMode(WdtInstancePtr);

	/*
	 * Load the watchdog counter register.
	 */
	result = (unsigned long)(333333333*number);
	XScuWdt_LoadWdt(WdtInstancePtr,result);

	/*
	 * Start the ScuWdt device.
	 */
	XScuWdt_Start(WdtInstancePtr);

	return XST_SUCCESS;
}

代码解析:

  1. #include “xscuwdt.h”,调用系统看门狗的头文件 ,其中包括看门狗的一些初始值配置、启动、喂狗等函数,在使用看门狗前请务必调用此文件。
  2. XScuWdt_LookupConfig,用来配置WDT的设备ID号,ID号在#include "xparameters.h"中可以找到。
  3. XScuWdt_CfgInitialize,初始化WDT计数器。
  4. XScuWdt_SetWdMode,通过设置看门狗控制寄存器的WD模式位,将看门狗定时器置于看门狗模式。
  5. XScuWdt_LoadWdt,给WDT计数器装初值,这里我对此函数进行了封装。已知CPU的时钟频率为666.6666Mhz,即WDT的时钟频率为333.33Mhz,可得倒计时1s计数器需要配置的初值为333_333_333,对计数器赋的初值可以直接写在number变量中(本文赋值为10s)。
  6. XScuWdt_Start,开启看门狗计数器。
  7. XScuWdt_RestartWdt,计数器重置函数,俗称“喂狗”,需要写在看门狗复位程序之前的位置,确保系统不会进行复位。

下面的程序是对wdt进行测试:

	while (Count < 5) {
		sleep(1);
		Count++;
		printf("the second is %d \n",Count);
		XScuWdt_RestartWdt(WdtInstancePtr);
	}

  • 做法一:给计数器赋初值为10s,在循环中启动喂狗程序,程序会在5S后跳出循环,之后在10s后由于没有喂狗功能,系统复位。

  • 做法二:同样给计数器赋初值为10s,禁用喂狗程序,程序会直接在10s后进行系统复位。

做法一的系统在15s后进行复位,而做法二的系统却在10s后进行复位,这告诉我们,XScuWdt_RestartWdt函数成功地“拖延”了系统复位5s,也就是说每循环一次,都给计数器重新赋值为10s,一共循环了5次正好5s,看门狗程序成功实现。

四、总结

通过学习watch dog timer程序,我学习到了计数器、系统复位等知识,并且能够区分看门狗之间的区别,通常看门狗程序运用于要求较高的程序中,避免程序跑飞。使用看门狗时一定要清楚系统执行所需的时间,保证系统执行时间<看门狗复位时间,否则会发生系统还没有执行完就复位的情况,喂狗的时间节点一定要把握好,确保看门狗能够发挥出最大作用。

PS:有需要看门狗封装好的函数私信我,希望能够与大家一起学习进步!

你可能感兴趣的:(Xilinx-FPGA)