MPSoC Standalone中使用看门狗swdt的注意事项
例子
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的寄存器。示例如下。
/* 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("%20s: %06d, ERROR_SRST_EN_1 Register: %08x \r\n",
__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("%20s: %06d, ERROR_EN_1 Register: %08x \r\n",
__func__, __LINE__,
Xil_In32(PMU_GLOBAL_ERROR_EN_1) );
看门狗复位的Fallback
但是MPSoC的FSBL发现是看门狗引起的复位后,会进入Fallback,再次复位。如果不希望再次复位,可以修改代码XFsbl_ResetValidation( ),请参考下面的代码注释“goto END”即可。
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_RESET\n\r");
// 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寄存器,检查配置是否生效,可以参考下列代码。
xil_printf("%20s: %06d, Zero Mode Register(00): %08x \r\n",
__func__, __LINE__,
XWdtPs_ReadReg(EffectiveAddress, XWDTPS_ZMR_OFFSET) );
xil_printf("%20s: %06d, Counter Control Register(04): %08x \r\n",
__func__, __LINE__,
XWdtPs_ReadReg(EffectiveAddress, XWDTPS_CCR_OFFSET) );
xil_printf("%20s: %06d, Status Register(08): %08x \r\n",
__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次后,不再清看门狗,打印井号,等看门狗复位。
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("%20s: %06d, timer: %08x = %08d at the beginning.\r\n",
__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: %d\r\n", __func__, __LINE__ );
return XST_FAILURE;
}
xil_printf("%20s: %06d, EffectiveAddress: %08x \r\n",
__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("%20s: %06d, Zero Mode Register(00): %08x \r\n",
__func__, __LINE__,
XWdtPs_ReadReg(EffectiveAddress, XWDTPS_ZMR_OFFSET) );
xil_printf("%20s: %06d, Counter Control Register(04): %08x \r\n",
__func__, __LINE__,
XWdtPs_ReadReg(EffectiveAddress, XWDTPS_CCR_OFFSET) );
xil_printf("%20s: %06d, Status Register(08): %08x \r\n",
__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("%20s: %06d, ERROR_SRST_EN_1 Register(08): %08x \r\n",
__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("%20s: %06d, ERROR_EN_1 Register(08): %08x \r\n",
__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("%20s: %06d, timer: %08x = %08d, after %d ms before loop.\r\n",
__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_num%50))
{
XTime_GetTime(&tCur2);
xil_printf("\n\r %04d loop - %07d ms: ", ui_loop_num, (tCur2-tCur)/100);
}
ui_loop_num++;
//xil_printf("XWdtPs_RestartWdt %s: %d, ui_loop_num:%u \r\n", __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: %d\r\n", __func__, __LINE__ );
return XST_SUCCESS;
}