ZYNQ-Utlscale-RFSOC看门狗

ZYNQ-Utlscale-RFSOC看门狗复位

ZYNQ-Utlscale-RFSOC 看门狗的程序网上里程很少,开源资料也是几乎没有,最近需要用到这个功能,来来回回搞了一周才搞定。刚开始参考ZYNQ7000的资源,发现MPSOC不适用。很感谢下面的几篇文章,给我很大的帮助,我也是整合他们的代码,完成了该功能。

  • 首先是调试MPSOC中RESET软复位功能,通过arm来使系统复位,重启程序。但是是调试过程中发现,如果我要加更多的程序,系统掉电之后不能重新自启动。另外,如果系统跑飞、卡死,该功能也不能使系统复位(因为代码卡在了其他部分,不能执行复位的代码)。
  • 之后,我参考米联客的开发手册,调试了SWDT看门狗功能。但是该工程也只是验证、学习了看门狗的功能,并没有做到使系统复位。
  • 最后,看门狗实现软件复位。感谢该文章:记录一次ZYNQ Ultrascale+ MPSoC看门狗(WDTPS)填坑心得-CSDN博客 ,这篇文章很好整理了博主在开发的过程,并且最后附上了驱动代码。我用了该文章的代码,再根据前面的学习,给出了我自己的代码。

1.RESET复位程序

参考文章:Xilinx软件开发:如何通过软件复位MPSOC_mpsoc 复位-CSDN博客

zynq mpsoc 软复位 (xilinx.com)

我的代码:

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xil_io.h"
#include "sleep.h"

#define MPSOC_RESET_REASON_REG 0xFF5E0220   //16bit

#define MPSOC_RESET_CTRL_REG   0xFF5E0218 //寄存器RESET_CTRL
#define MPSOC_RESET_VALUE      0x11      //复位bit4 (Width=8)

void PsSoftwareReset(void)
{
    Xil_Out8(MPSOC_RESET_CTRL_REG, MPSOC_RESET_VALUE);  //复位
}

void getResetReason(void)
{
	int status;

	status = Xil_In16(MPSOC_RESET_REASON_REG);
	xil_printf("\n\rResetReason = 0x%.8X\n\r", status);
	if(status & 0x40)
		xil_printf("6 Software Debugger Reset\n\r");
	if(status & 0x20)
			xil_printf("5 Software System Reset\n\r");
	if(status & 0x10)
			xil_printf("4 External System Reset\n\r");
	if(status & 0x08)
			xil_printf("3 PS-only Reset\n\r");
	if(status & 0x04)
			xil_printf("2 Internal System Reset\n\r");
	if(status & 0x02)
			xil_printf("1 A system error triggered a POR reset\n\r");
	if(status & 0x01)
			xil_printf("0 the PS_POR_B reset signal pin was asserted\n\r");
	xil_printf("\n\r");
}

int main()
{
    init_platform();
    xil_printf("Hello World \n\r");
    getResetReason();
    sleep(2);
    PsSoftwareReset();

    print("PsSoftwareReset\n\r");

    print("Successfully ran Hello World application");
    cleanup_platform();
    return 0;
}

将程序固化到板子,会循环打印以下信息:

PMU-FW is not running, certain applications may not be supported.

Hello World 

PMU-FW is not running, certain applications may not be supported.该提示可不用管

观察电流或板子上的指示灯,表明芯片在重复 上电执行程序,之后掉电。

可以将PS端程序重置

2.看门狗程序测试

参考:米联客相关开发手册

zynq配置:

在这里插入图片描述

可以接一个ILA,观察SWDT的reset输出信号:

在这里插入图片描述

在vitis中,导入例程:

在这里插入图片描述

选择 xwdtps_polled_example

将官方程序进行以下修改:

#include "xparameters.h"
#include "xwdtps.h"
#include "xil_printf.h"
#include "sleep.h"

#define WDT_DEVICE_ID  		XPAR_XWDTPS_0_DEVICE_ID

int WdtPsPolledExample(u16 DeviceId);

/************************** Variable Definitions *****************************/

XWdtPs Watchdog;		/* Instance of WatchDog Timer  */

int main(void)
{
	int Status;

	xil_printf("WDT Polled Mode Example Test\r\n");

	Status = WdtPsPolledExample(WDT_DEVICE_ID);
	if (Status != XST_SUCCESS) {
		xil_printf("WDT Polled Mode Example Test Failed\r\n");
		return XST_FAILURE;
	}

	xil_printf("Successfully ran WDT Polled Mode Example Test\r\n");
	return XST_SUCCESS;
}

int WdtPsPolledExample(u16 DeviceId)
{
	int Status;
	u32 ExpiredTimeDelta1 = 0;
	XWdtPs_Config *ConfigPtr;
	u32 EffectiveAddress;	/* This can be the virtual address */

	/*
	 * Initialize the Watchdog Timer so that it is ready to use
	 */
	ConfigPtr = XWdtPs_LookupConfig(DeviceId);

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

	/*
	 * 设置XWDTPS_CCR_OFFSET 中XWDTPS_CCR_CRV_MASK=5,因此看门狗重启后,计数器是5FFF
	 */
	XWdtPs_SetControlValue(&Watchdog,
				(u8) XWDTPS_COUNTER_RESET, (u8) 5);


	/*
	 * 设置看门狗预分频器4096分频.
	 */
	XWdtPs_SetControlValue(&Watchdog,
				(u8) XWDTPS_CLK_PRESCALE,
				(u8) XWDTPS_CCR_PSCALE_4096);

	/*
	 *  使能复位,当看门狗计数到0产生一个复位.
	 */
	XWdtPs_EnableOutput(&Watchdog, XWDTPS_RESET_SIGNAL);

	/*
	 * 启动看门狗定时器.
	 */
	XWdtPs_Start(&Watchdog);

	/*
	 * 重启启动看门狗,看门狗计数器会以XWDTPS_CCR_OFFSET中设置的参数0xNNNFFF开始递减计数.
	 */
	XWdtPs_RestartWdt(&Watchdog);

	/*
	 * Determine how long it takes for the Watchdog Timer to expire
	 * for later processing.
	 */
	while (1) {
		xil_printf("WDT Restart ExpiredTimeDelta1=%d\r\n",ExpiredTimeDelta1);

		XWdtPs_RestartWdt(&Watchdog); //重启启动看门狗,看门狗计数器会以XWDTPS_CCR_OFFSET中设置的参数0xNNNFFF开始递减计数

		ExpiredTimeDelta1++;
		sleep(1);
		if(ExpiredTimeDelta1==20) //运行20S后强制进入5S等待,这样会产生超时,触发复位	PL端产生一个rst复位信号
		sleep(5);
		if (XWdtPs_IsWdtExpired(&Watchdog)){
			xil_printf("WDT times out ExpiredTimeDelta1=%d\r\n",ExpiredTimeDelta1);
			return XST_FAILURE;

		}
	}

	return XST_SUCCESS;
}

程序分析:

1.XWdtPs_LookupConfig函数:

ConfigPtr = XWdtPs_LookupConfig(DeviceId);通过 ID 值找到 SWDT 的地址参数。

XWdtPs_Config *XWdtPs_LookupConfig(u16 DeviceId) 这个函数的分析方法和前面课程中类似函数分析方法类似,目的是为了获取地址参数。这个函数负责通过 ID 值确定外设的地址空间

2.XWdtPs_SetControlValue 函数:

XWdtPs_SetControlValue(&Watchdog, (u8) XWDTPS_COUNTER_RESET, (u8) 5); 这句是为了设置SWDT的24bit计数器的值。

XWdtPs_SetControlValue(&Watchdog, (u8) XWDTPS_CLK_PRESCALE, (u8) XWDTPS_CCR_PSCALE_4096);这句是为了 设置分频系数。

3.XWdtPs_EnableOutput 函数:

XWdtPs_EnableOutput(&Watchdog, XWDTPS_RESET_SIGNAL);这句是为了使能当 SWDT 看门狗计数器溢出后产生一个复位。这就是我们前面实验结果用逻辑分析看到的。因为这个复位信号持续的时间很短,所以只能用在ILA抓波形。

4.XWdtPs_Start 函数:

XWdtPs_Start(&Watchdog);语句启动 SWDT 看门狗定时器。这个函数也是操作 XWDTPS_ZMR 寄存器,设置 XWDTPS_ZMR[0]为 1,使能 SWDT 运行

5.XWdtPs_RestartWdt 函数:

XWdtPs_RestartWdt(&Watchdog);这句设置 SWDT 重启寄存器,实现重启看门狗定时器。

6.XWdtPs_IsWdtExpired 函数:

XWdtPs_IsWdtExpired(&Watchdog);SWDT 的状态寄存器,查看定时计数器是否减计数到 0 了,通过判断状态寄存 器可以知道看门狗 SWDT 是否溢出了。

打印的结果:

WDT Polled Mode Example Test
WDT Restart ExpiredTimeDelta1=0
WDT Restart ExpiredTimeDelta1=1
WDT Restart ExpiredTimeDelta1=2
WDT Restart ExpiredTimeDelta1=3
WDT Restart ExpiredTimeDelta1=4
WDT Restart ExpiredTimeDelta1=5
WDT Restart ExpiredTimeDelta1=6
WDT Restart ExpiredTimeDelta1=7
WDT Restart ExpiredTimeDelta1=8
WDT Restart ExpiredTimeDelta1=9
WDT Restart ExpiredTimeDelta1=10
WDT Restart ExpiredTimeDelta1=11
WDT Restart ExpiredTimeDelta1=12
WDT Restart ExpiredTimeDelta1=13
WDT Restart ExpiredTimeDelta1=14
WDT Restart ExpiredTimeDelta1=15
WDT Restart ExpiredTimeDelta1=16
WDT Restart ExpiredTimeDelta1=17
WDT Restart ExpiredTimeDelta1=18
WDT Restart ExpiredTimeDelta1=19
WDT times out ExpiredTimeDelta1=20
WDT Polled Mode Example Test Failed

当打印到19时,等待5S,再打印出

WDT times out ExpiredTimeDelta1=20
WDT Polled Mode Example Test Failed

同时,FPGA的ILA采集的SWDT产生的reset信号:

在这里插入图片描述

以上,看门狗功能初步实现,下面就是将复位和计数等待结合起来。

3.看门狗实现软复位

参考文章:记录一次ZYNQ Ultrascale+ MPSoC看门狗(WDTPS)填坑心得-CSDN博客

文章写的很详细,我是参考这篇文章才测试出来的。

ZYNQMP的看门狗不能直接复位PS,而是通过PMU软件对PS进行复位

测试代码如下:

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xwdtps.h"
#include "xil_io.h"
#include "sleep.h"

/************************************Macros Definitions***************************************/
#define WDTPS_DEVICE_ID					XPAR_XWDTPS_1_DEVICE_ID
#define WDTPS_CLK_RATE_HZ				XPAR_XWDTPS_1_WDT_CLK_FREQ_HZ
#define WDTPS_CLK_PRESCALE				XWDTPS_CCR_PSCALE_4096

/************************************Variable definitions*************************************/
XWdtPs gWdtPsIns;
/*PMU_GLOBAL Base Address*/
#define PMU_GLOBAL_BASEADDR      					0xFFD80000
/*Register: PMU_GLOBAL_ERROR_SRST_EN_1 */
#define PMU_GLOBAL_ERROR_SRST_EN_1    				(PMU_GLOBAL_BASEADDR + 0x0000056C)
#define PMU_GLOBAL_ERROR_SRST_EN_1_LPD_SWDT_MASK    0x00001000
#define PMU_GLOBAL_ERROR_SRST_EN_1_FPD_SWDT_MASK    0x00002000
/*Register: PMU_GLOBAL_ERROR_EN_1 */
#define PMU_GLOBAL_ERROR_EN_1    					(PMU_GLOBAL_BASEADDR + 0x000005A0)
#define PMU_GLOBAL_ERROR_EN_1_LPD_SWDT_MASK    		0x00001000
#define PMU_GLOBAL_ERROR_EN_1_FPD_SWDT_MASK    		0x00002000
/*Register: PMU_GLOBAL_ERROR_SRST_DIS_1*/
#define PMU_GLOBAL_ERROR_SRST_DIS_1 				(PMU_GLOBAL_BASEADDR + 0x00000570)
#define PMU_GLOBAL_ERROR_SRST_DIS_1_LPD_SWDT_MASK   0x00001000
#define PMU_GLOBAL_ERROR_SRST_DIS_1_FPD_SWDT_MASK   0x00002000
/*Register: PERS_GLOB_GEN_STORAGE0*/
#define PMU_GLOVAL_PERS_GLOB_GEN_STORAGE0			(PMU_GLOBAL_BASEADDR + 0x00000050)
/*Register: ERROR_STATUS_1*/
#define PMU_GLOBAL_ERROR_STATUS_1					(PMU_GLOBAL_BASEADDR + 0x00000530)
#define PMU_GLOBAL_ERROR_STATUS_1_LPD_SWDT_MASK		0x00001000
#define PMU_GLOBAL_ERROR_STATUS_1_FPD_SWDT_MASK		0x00002000

static uint32_t hw_wdtps_convertTimeToCounter(XWdtPs *ins, uint32_t mseconds)
{
	double time;
	double counter_value;
	uint32_t crv;
	uint32_t prescaler;
	uint32_t prescaler_value;

	prescaler = XWdtPs_GetControlValue(ins, XWDTPS_CLK_PRESCALE);

	if (prescaler == XWDTPS_CCR_PSCALE_0008) {
		prescaler_value = 8;
	} else if (prescaler == XWDTPS_CCR_PSCALE_0064) {
		prescaler_value = 64;
	} else if (prescaler == XWDTPS_CCR_PSCALE_0512){
		prescaler_value = 512;
	} else if (prescaler == XWDTPS_CCR_PSCALE_4096) {
		prescaler_value = 4096;
	}else{
		prescaler_value = 0U;
	}

	time = (double)(prescaler_value) / (double)(WDTPS_CLK_RATE_HZ);

	counter_value = (double)mseconds / (double)1000.0f / time;
	crv = (uint32_t)counter_value;
	crv >>= 12; /*see ug1085 table 14-14 */
	/*CRV: Counter restart value. The counter is restarted with
	0xNFFF, where N is the value of this field.*/

	return crv;
}
/*init*/
int hw_wdtps_init(uint32_t expire_time_ms, uint8_t test)
{
	int ret = 0;
	XWdtPs_Config *cfg;
	uint32_t u32tmp;

	memset(& gWdtPsIns, 0, sizeof(XWdtPs));

	/*Config WDT*/
	cfg = XWdtPs_LookupConfig(WDTPS_DEVICE_ID);
	if(NULL == cfg){
		ret = -1;
		goto _end;
	}

	ret = XWdtPs_CfgInitialize(& gWdtPsIns, cfg, cfg->BaseAddress);
	if(ret != XST_SUCCESS){
		ret = -1;
		goto _end;
	}

	ret = XWdtPs_SelfTest(& gWdtPsIns);
	if(ret != XST_SUCCESS){
		ret = -1;
		goto _end;
	}

	/*Clear ERROR_STATUS_1 (PMU_GLOBAL) Register*/
	/*This is very important, otherwise, the CPU will be continuously reset!!!!!*/
	Xil_Out32(PMU_GLOBAL_ERROR_STATUS_1, PMU_GLOBAL_ERROR_STATUS_1_FPD_SWDT_MASK); /*write 1 to clear*/

	/*Disable timer*/
	XWdtPs_Stop(& gWdtPsIns);

	/*Set prescale*/
	XWdtPs_SetControlValue(& gWdtPsIns, (uint8_t)XWDTPS_CLK_PRESCALE, WDTPS_CLK_PRESCALE);

	/*Set counter reset value*/
	u32tmp = hw_wdtps_convertTimeToCounter(& gWdtPsIns, expire_time_ms);
	XWdtPs_SetControlValue(& gWdtPsIns, (uint8_t)XWDTPS_COUNTER_RESET, (u16)0xff);

	/*Output control*/
	if(! test)
		XWdtPs_EnableOutput(& gWdtPsIns, XWDTPS_RESET_SIGNAL);
	else
		XWdtPs_DisableOutput(& gWdtPsIns, XWDTPS_RESET_SIGNAL);

	/*enable generation of system reset by PMU due to SWDT0/1 */
	/*Write only register*/
	Xil_Out32(PMU_GLOBAL_ERROR_SRST_EN_1, PMU_GLOBAL_ERROR_SRST_EN_1_FPD_SWDT_MASK);

	/*enable SWDT0/1 System Watchdog Timer Error*/
	/*RW register*/
	u32tmp = Xil_In32(PMU_GLOBAL_ERROR_EN_1);
	u32tmp |= PMU_GLOBAL_ERROR_EN_1_FPD_SWDT_MASK; /*Full power CPU core reset*/
	Xil_Out32(PMU_GLOBAL_ERROR_EN_1, u32tmp);

	/*start timer*/
	XWdtPs_Start(& gWdtPsIns);
	XWdtPs_RestartWdt(& gWdtPsIns);

_end :
	return ret;
}
/*WDT feed*/
void hw_wdtps_feed(void)
{
	XWdtPs_RestartWdt(& gWdtPsIns);
}
/*Stop WDT*/
int hw_wdtps_stop(void)
{
	uint32_t u32tmp;

	if(gWdtPsIns.IsReady){
		XWdtPs_Stop(& gWdtPsIns);
	}

	/*Disable generation of system reset by PMU due to SWDT0/1 */
	/*Write only register*/
	Xil_Out32(PMU_GLOBAL_ERROR_SRST_DIS_1, PMU_GLOBAL_ERROR_SRST_DIS_1_FPD_SWDT_MASK);

	/*Disable SWDT0/1 System Watchdog Timer Error*/
	/*RW register*/
	u32tmp = Xil_In32(PMU_GLOBAL_ERROR_EN_1);
	u32tmp &= (~ PMU_GLOBAL_ERROR_EN_1_FPD_SWDT_MASK);
	Xil_Out32(PMU_GLOBAL_ERROR_EN_1, u32tmp);

	return 0;
}
/*WDT test*/
void hw_wdtps_test(void)
{
	int cnt = 0;
	while(1){
		if(XWdtPs_IsWdtExpired(& gWdtPsIns)){
			xil_printf("WDT Expired\n\r");
		}

		//XWdtPs_RestartWdt(& gWdtPsIns);
		sleep(1);
		xil_printf("time : %d\n", ++cnt);
	}
}


int main()
{
    init_platform();

    print("Hello World\n\r");
    print("Successfully ran Hello World application\n\r");
    hw_wdtps_init(100,0);
    hw_wdtps_test();
    cleanup_platform();
    return 0;
}

测试结果:串口每秒打印一个数字,持续43S后,系统断电。如果把程序固化进去,那么断电后会自动重启,重复执行以上结果。

代码分析:

XWdtPs_RestartWdt(& gWdtPsIns); 是喂狗程序,如果在 hw_wdtps_test()函数中执行此函数,那么系统将不会断电。

#define WDTPS_CLK_PRESCALE XWDTPS_CCR_PSCALE_4096 分频设置,想要改变看门狗定时器的计数时间,可以改变这个参数。

如何运用
看门狗就是为了防止程序跑飞、卡死在循环里,一般在自己的程序main()里执行 hw_wdtps_init(100,0);,之后XWdtPs_RestartWdt(& gWdtPsIns); 喂狗。如果程序跑飞、卡死,那么就是在规定时间内没有喂狗,系统就会复位。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值