MPSoC Standalone中使用swdt的注意事项

2022-12-09 14:00:47 浏览数 (1)

例子

MPSoC swdt是一个简单的看门狗,只有四个寄存器。可以参考xwdtps_polled_example.c使用MPSoC swdt。xwdtps_polled_example.c只测试swdt是否超时,没有使能复位。如果需要复位,搜索代码“XWdtPs_DisableOutput(&Watchdog, XWDTPS_RESET_SIGNAL)”,改为“XWdtPs_EnableOutput(&Watchdog, XWDTPS_RESET_SIGNAL)”。

设置PMU寄存器

但是MPSoC PMU会管理芯片复位。如果要使用MPSoC swdt,在设置MPSoC swdt的寄存器以外,还有设置PMU的寄存器。示例如下。

代码语言:javascript复制
	/* Enable generation of system reset by PMU due to SWDT0/1 */
	RegValue = Xil_In32(PMU_GLOBAL_ERROR_SRST_EN_1);
	RegValue |= XFSBL_WDT_MASK;
	Xil_Out32(PMU_GLOBAL_ERROR_SRST_EN_1, RegValue);
	xil_printf(" s: d, ERROR_SRST_EN_1 Register: x rn",
				__func__, __LINE__,
				Xil_In32(PMU_GLOBAL_ERROR_SRST_EN_1) );

	/* Enable SWDT0/1 System Watchdog Timer Error */
	RegValue = Xil_In32(PMU_GLOBAL_ERROR_EN_1);
	RegValue |= XFSBL_WDT_MASK;
	Xil_Out32(PMU_GLOBAL_ERROR_EN_1, RegValue);
	xil_printf(" s: d, ERROR_EN_1 Register: x rn",
				__func__, __LINE__,
				Xil_In32(PMU_GLOBAL_ERROR_EN_1) );

看门狗复位的Fallback

但是MPSoC的FSBL发现是看门狗引起的复位后,会进入Fallback,再次复位。如果不希望再次复位,可以修改代码XFsbl_ResetValidation( ),请参考下面的代码注释“goto END”即可。

代码语言:javascript复制
static u32 XFsbl_ResetValidation(void)
{
	u32 Status;
	u32 FsblErrorStatus;
#ifdef XFSBL_WDT_PRESENT
	u32 ResetReasonValue;
	u32 ErrStatusRegValue;
#endif
	/**
	 *  Read the Error Status register
	 *  If WDT reset, do fallback
	 */
	FsblErrorStatus = XFsbl_In32(XFSBL_ERROR_STATUS_REGISTER_OFFSET);

#ifdef XFSBL_WDT_PRESENT
	ResetReasonValue = XFsbl_In32(CRL_APB_RESET_REASON);

	/**
	 * Check if the reset is due to system WDT during
	 * previous FSBL execution
	 */
	if ((ResetReasonValue & CRL_APB_RESET_REASON_PMU_SYS_RESET_MASK)
			== CRL_APB_RESET_REASON_PMU_SYS_RESET_MASK) {
		ErrStatusRegValue = XFsbl_In32(PMU_GLOBAL_ERROR_STATUS_1);
		if(((ErrStatusRegValue & XFSBL_WDT_MASK) == XFSBL_WDT_MASK) &&
			(FsblErrorStatus == XFSBL_RUNNING)) {
			/* Clear the SWDT0/1 reset error */
			XFsbl_Out32(PMU_GLOBAL_ERROR_STATUS_1, XFSBL_WDT_MASK);
		/**
		 * reset is due to System WDT.
		 * Do a fallback
		 */
		Status = XFSBL_ERROR_SYSTEM_WDT_RESET;
		XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_SYSTEM_WDT_RESETnr");
	        // goto END;  // Continue to boot after wdt reset. 
		}
	}
#endif
	/**
	 * Mark FSBL running in error status register to
	 * detect the WDT reset while FSBL execution
	 */
	if (FsblErrorStatus != XFSBL_RUNNING) {
		XFsbl_Out32(XFSBL_ERROR_STATUS_REGISTER_OFFSET,
						  XFSBL_RUNNING);
	}

	/**
	 *  Read system error status register
	 * 	provide FsblHook function for any action
	 */

	Status = XFSBL_SUCCESS;
#ifdef XFSBL_WDT_PRESENT
END:
#endif
	return Status;
}

看门狗复位的MULTI_BOOT

Fallback再次复位后,由于更新了MULTI_BOOT的值,会搜索后续的BOOT.BIN。如果单板后面没有BOOT.BIN,甚至只有一个BOOT.BIN,单板会停住。如果不想使用这个特性,搜索“XFsbl_UpdateMultiBoot(RegValue 1U);”, 改为“XFsbl_UpdateMultiBoot(RegValue);”。

查看swdt寄存器

调试时可能需要查看swdt寄存器,检查配置是否生效,可以参考下列代码。

代码语言:javascript复制
	xil_printf(" s: d, Zero Mode Register(00): x rn",
				__func__, __LINE__,
				XWdtPs_ReadReg(EffectiveAddress, XWDTPS_ZMR_OFFSET) );

	xil_printf(" s: d, Counter Control Register(04): x rn",
				__func__, __LINE__,
				XWdtPs_ReadReg(EffectiveAddress, XWDTPS_CCR_OFFSET) );

	xil_printf(" s: d, Status Register(08): x rn",
				__func__, __LINE__,
				XWdtPs_ReadReg(EffectiveAddress, XWDTPS_SR_OFFSET) );

SWDT基地址

MPSoC 有三个SWDT,各自的基地址如下:

CSU_WDT: 0xFFCB0000 LPD SWDT: 0xFF150000 FPD WDT: 0xFD4D0000

SWDT超时时间计算

SWDT设置的参数有PSCALE,initial counter,ref_clk。 ref_clk在vivado的pcw里设置,vitis里通过XPAR_PSU_WDT_0_WDT_CLK_FREQ_HZ获取。本例中,XPAR_PSU_WDT_0_WDT_CLK_FREQ_HZ是99990005,对应时钟周期大约是10ns。在vitis里通过C代码设置SCALE,initial counter。C代码设置的initial counter只是counter的高12位,低12位是0xfff。本例中,initial counter被设置为0xff,实际的initial counter是0xff-fff,是十进制的1048575。SWDT超时时间=PSCALE * initial counter * 时钟周期。因此本例中,SWDT超时时间是10ns641048575,约等于671毫秒。

触发看门狗复位的代码

修改后,触发看门狗复位的WdtPsPolledExample代码如下。代码中,前500次先清看门狗,打印点号,然后延时10ms。500次后,不再清看门狗,打印井号,等看门狗复位。

代码语言:javascript复制
int WdtPsPolledExample(u16 DeviceId)
{
	int Status;
	u32 ui_loop_num = 0;
	XWdtPs_Config *ConfigPtr;
	u32 EffectiveAddress;	/* This can be the virtual address */

	u32 RegValue;

	XTime tCur = 0;
	XTime tCur2 = 0;

	/* Get Start time for Boot Device init. */
	XTime_GetTime(&tCur);

	xil_printf(" s: d, timer: x = d at the beginning.rn",
					__func__, __LINE__, tCur, tCur );

	/*
	 * Initialize the Watchdog Timer so that it is ready to use
	 */
	ConfigPtr = XWdtPs_LookupConfig(DeviceId);
        //  XPAR_PSU_WDT_0_WDT_CLK_FREQ_HZ 99990005  99-990-005

	/*
	 * 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) {
		xil_printf("WdtPsPolledExample XST_FAILURE %s: %drn", __func__, __LINE__ );
		return XST_FAILURE;
	}
	xil_printf(" s: d, EffectiveAddress: x rn",
				__func__, __LINE__, EffectiveAddress );

	/*
	 * Set the initial counter restart to the smallest value (0).
	 * 	Counter restart value - the counter is restarted with the value 0xNFFF,
	 * 	where N is the value of this field.
	 *
	 */
	XWdtPs_SetControlValue(&Watchdog,
				(u8) XWDTPS_COUNTER_RESET, (u8) 0xff);
        // XWDTPS_CCR_PSCALE_0064, 0xff-fff=1 048 575, 10ns*64*1048575 = 671 088 000 ns = 671 ms

	/*
	 * Set the initial Divider ratio at the smallest value.
	 */
	XWdtPs_SetControlValue(&Watchdog,
				(u8) XWDTPS_CLK_PRESCALE,
				(u8) XWDTPS_CCR_PSCALE_0064);

	/*
	 * Disable the RESET output.
	 */
	//XWdtPs_DisableOutput(&Watchdog, XWDTPS_RESET_SIGNAL);

	/*
	 * Enable the RESET output.
	 */
	XWdtPs_EnableOutput(&Watchdog, XWDTPS_RESET_SIGNAL);

	xil_printf(" s: d, Zero Mode Register(00): x rn",
				__func__, __LINE__,
				XWdtPs_ReadReg(EffectiveAddress, XWDTPS_ZMR_OFFSET) );

	xil_printf(" s: d, Counter Control Register(04): x rn",
				__func__, __LINE__,
				XWdtPs_ReadReg(EffectiveAddress, XWDTPS_CCR_OFFSET) );

	xil_printf(" s: d, Status Register(08): x rn",
				__func__, __LINE__,
				XWdtPs_ReadReg(EffectiveAddress, XWDTPS_SR_OFFSET) );

	/* Enable generation of system reset by PMU due to SWDT0/1 */
	RegValue = Xil_In32(PMU_GLOBAL_ERROR_SRST_EN_1);
	RegValue |= XFSBL_WDT_MASK;
	Xil_Out32(PMU_GLOBAL_ERROR_SRST_EN_1, RegValue);
	xil_printf(" s: d, ERROR_SRST_EN_1 Register(08): x rn",
				__func__, __LINE__,
				Xil_In32(PMU_GLOBAL_ERROR_SRST_EN_1) );

	/* Enable SWDT0/1 System Watchdog Timer Error */
	RegValue = Xil_In32(PMU_GLOBAL_ERROR_EN_1);
	RegValue |= XFSBL_WDT_MASK;
	Xil_Out32(PMU_GLOBAL_ERROR_EN_1, RegValue);

	xil_printf(" s: d, ERROR_EN_1 Register(08): x rn",
				__func__, __LINE__,
				Xil_In32(PMU_GLOBAL_ERROR_EN_1) );

	/*
	 * Start the Watchdog Timer.
	 */
	XWdtPs_Start(&Watchdog);

	/*
	 * Restart the Watchdog Timer.
	 */
	XWdtPs_RestartWdt(&Watchdog);

	/* Get Start time for Boot Device init. */
    //  COUNTS_PER_SECOND  XPAR_CPU_CORTEXA53_0_TIMESTAMP_CLK_FREQ 99990005   99 990 005
	XTime_GetTime(&tCur2);
	xil_printf(" s: d, timer: x = d, after %d ms before loop.rn",
					__func__, __LINE__, tCur2, tCur2, (tCur2-tCur)/100 );

	/*
	 * Verify that the Watchdog Timer does not timeout when restarted
	 * all the time, wait more than twice the amount of time it took for it
	 * to expire in the previous test.
	 */
	ui_loop_num = 0;

	while (1) {

		if(0==(ui_loop_numP))
		{
			XTime_GetTime(&tCur2);
			xil_printf("nr d loop - d ms: ", ui_loop_num, (tCur2-tCur)/100);
		}

		ui_loop_num  ;
		//xil_printf("XWdtPs_RestartWdt %s: %d, ui_loop_num:%u rn", __func__, __LINE__, ui_loop_num );

		if(ui_loop_num<=500)
		{
			/*
			 * Restart the Watchdog Timer as a normal application would.
			 */
			XWdtPs_RestartWdt(&Watchdog);
			xil_printf(".");
			usleep(10000);
		}
		else
		{
			xil_printf("#");
			usleep(10000); //
		}

	}

	xil_printf("WdtPsPolledExample XST_SUCCESS %s: %drn", __func__, __LINE__ );
	return XST_SUCCESS;
}

付汉杰 hankf@amd.com

0 人点赞