本帖最后由 FPGA课程 于 2024-9-25 17:30 编辑
软件版本:VIVADO2021.1
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
实验平台:米联客-MLK-H3-CZ08-7100开发板
板卡获取平台:https://milianke.tmall.com/
登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!
1概述
看门狗是芯片内部的一个具有定时计数的功能模块,当启用看门狗功能后,系统软件必须定时“喂狗”,CPU程序跑飞异常后,就不能“喂狗”这样看门狗定时器就会产生超时,超时后一般会复位整个系统。
本文实验介绍ZYNQ自带的私有看门狗定时器的使用:
实验目的:
1:了解私有看门狗定时器的概念
2:了解私有看门狗定时器的功能寄存器
3:使用SDK自带代码测试门狗定时器的定时器工作模式和门狗模式。
2系统框图
3中断资源概述
PS的CPU0和CPU1各有1个私有定时器。上图中,红色部分为PS的私有中断资源,本文中demo就是以CPU0的定时器中断使用作为演示方案。CPU0的定时器中断经过中断控制派发器派发给CPU0。CPU0的私有看门狗定时器IRQ ID=30。
4定时器资源介绍
Zynq的PS的CPU0和CPU1各包含1个私有定时器以及一个私有看门狗定时器并且共享一个全局定时器。另外Zynq的PS还有TTC0以及TTC1定制控制器。每个TTC定时器里面包含三个定时器/计数器。本文所讲解的是CPU0的私有看门狗定时器中断的使用。 看门狗需要不停的“喂狗”,在这里就是不停的读预加载寄存器再写入预加载寄存器。如果不能及时喂狗,那么看门狗就会超时,并且产生一个复位输出。 本方案中只对CPU0的私有看门狗定时器进行说明。 Zynq的私有定时器和看门狗定时器具有以下共同的特性: 1-定时计数器位宽为32位,当达到0时产生中断 2-参考时钟为CPU时钟的1/2,比如CPU是666.6666M 那么定时器的参考时钟为333.3333M 3-有一个8bit预分频器,可以对参考时钟进一步分频 4-有一个可配置的预加载寄存器 5-可配置为单次模式或者自动重载模式 看门狗定时器多了以下功能: 1-当看门狗没有及时“喂狗”导致的系统复位输出 2-看门狗定时器可以设置为定时器模式或者看门狗模式 5私有定看门狗时器的寄存器
在UG585中没有关于私有看门狗定时器的详细说明,我们通过SDK代码的理解补充了这部分说明。私有看门狗定时器的基地址为0xF8F00620。CPU的私有看门狗定时器一共有6个寄存器:
XSCUWDT_LOAD寄存器XSCUWDT_LOAD_OFFSET(0x00U) Field Name | Bits | Type | Reset Value | Description | XSCUWDT_LOAD | 31:0 | 至少 可写 | 0x0 | 私有看门狗定时器的预加载值 |
XSCUWDT_COUNTER寄存器XSCUWDT_COUNTER_OFFSET (0x04U) Field Name | Bits | Type | Reset Value | Description | XSCUWDT_COUNTER | 31:0 | 至少 可读 | 0x0 | 私有看门狗定时器的计数器 |
XSCUWDT_CONTROL寄存器XSCUWDT_CONTROL_OFFSET (0x08U) Field Name | Bits | Type | Reset Value | Description | XSCUWDT_CONTROL | 31:0 | R/W | 0x0 | 私有看门狗定时器的控制寄存器 15~8bit:预分频设置 3bit:当为看门狗模式,设置1为看门狗 2bit:当为定时器模式,设置1为中断使能 1bit:当为1自动重载使能 0bit:当为1表示看门狗使能 |
XSCUWDT _ISR寄存器XSCUWDT _ISR_OFFSET (0x0CU) Field Name | Bits | Type | Reset Value | Description | XSCUWDT_ISR | 31:0 | R/W | 0x0 | 私有看门狗定时器的中断寄存器 0bit:当为1的时候表示发生中断 |
XSCUWDT_RST_STS寄存器XSCUWDT_RST_STS_OFFSET (0x10U) Field Name | Bits | Type | Reset Value | Description | XSCUWDT_RST_STS | 31:0 | R/W | 0x0 | 私有看门狗定时器的复位状态寄存器 0bit:当为1代表定时器超时并且发送一个复位 |
XSCUWDT_DISABLE寄存器XSCUWDT_DISABLE_OFFSET (0x14U) Field Name | Bits | Type | Reset Value | Description | XSCUWDT_DISABLE | 31:0 | R/W | 0x0 | 第一次写入0x12345678U 第二次写入0x87654321U 会设置控制寄存器的bit-3为0,这样设置为定时器模式 | 6搭建SOC系统工程详细的搭建过程这里不再重复,对于初学读者如果还不清楚如何创建SOC工程的,请学习“01Vitis Soc开发入门”这篇文章。 6.1SOC系统工程直接使用已经搭建好的“01Vitis Soc开发入门”这篇文章中的工程。
6.2编译并导出平台文件以下步骤简写,有不清楚的看第一篇文章。 1:单击Block文件à右键àGenerate the Output ProductsàGlobalàGenerate。 2:单击Block文件à右键à Create a HDL wrapper(生成HDL顶层文件)àLet vivado manager wrapper and auto-update(自动更新)。 3:添加配套工程路径下uisrc/04_pin/fpga_pin.xdc约束文件 4:生成Bit文件。 5:导出到硬件: FileàExport HardwareàInclude bitstream 6:导出完成后,对应工程路径的soc_hw路径下有硬件平台文件:system_wrapper.xsa的文件。根据硬件平台文件system_wrapper.xsa来创建需要Platform平台。
7搭建Vitis-sdk工程创建soc_base sdk platform和APP工程的过程不再重复,如果不清楚请参考本章节第一个demo。 7.1创建SDK Platform工程
右击soc_base编译,编译的时间可能会有点长 7.2创建APP工程利用SDK自带的程序对看门狗定时器2种工作模式测试。
xscuwdt_intr_example是SDK库函数自带的函数,采用的是看门狗定时器的定时器模式
xscuwdt_polled_example是SDK库函数自带的函数,采用的是看门狗定时器的看门狗模式
8程序分析函数的分析办法可以参考“PS私有定时器实验”中的程序分析,我们这里只对重点函数相关的寄存器说明。 8.1定时器模式在定时器模式下,看门狗定时器的功能和定时器的使用非常类似,这里对SDK自带的demo进行部分修改 - int ScuWdtIntrExample(XScuGic *IntcInstancePtr, XScuWdt * WdtInstancePtr,u16 WdtDeviceId, u16 WdtIntrId)
- {
- int Status;
- u32 Timebase = 0;
- u32 ExpiredTimeDelta = 0;
- XScuWdt_Config *ConfigPtr;
- /*
- * Initialize the ScuWdt driver.
- */
- ConfigPtr = XScuWdt_LookupConfig(WdtDeviceId);
- /*
- * 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;
- }
- XScuWdt_SetTimerMode(WdtInstancePtr); //设置看门狗定时器的工作模式为定时器模式
- XScuWdt_LoadWdt(WdtInstancePtr, TIMER_LOAD_VALUE); //设置看门狗定时器的预加载值
- XScuWdt_EnableAutoReload(WdtInstancePtr); //使能自动重载模式
- Status = WdtSetupIntrSystem(IntcInstancePtr, WdtInstancePtr, WdtIntrId); //设置看门狗定时器的中断函数
- if (Status != XST_SUCCESS) {
- return XST_FAILURE;
- }
- XScuWdt_Start(WdtInstancePtr); //启动看门狗定时器
- while (1)
- {
- }
- return XST_SUCCESS;
- }
复制代码
之后每次定时中断产生后串口打印输出
- static void WdtIntrHandler(void *CallBackRef)
- {
- /*
- * WDT timed out and interrupt occurred, let main test loop know.
- */
- XScuWdt *WdtInstancePtr = CallBackRef;
- timer_counter++;
- printf("timer_counter = %u\n",timer_counter);
- XScuWdt_WriteReg(WdtInstancePtr->Config.BaseAddr,
- XSCUWDT_ISR_OFFSET,
- XSCUWDT_ISR_EVENT_FLAG_MASK);
- }
复制代码
1:XScuWdt_SetTimerMode()函数通过写入XSCUWDT_DISABLE寄存器会设控制寄存器XSCUWDT_CONTROL的bit-3为0这样看门狗工作于定时器模式,就是一个定时器。
2:XScuWdt_LoadWdt()函数给看门狗预加载寄存器XSCUWDT_LOAD初值
3:WdtSetupIntrSystem()函数
4:XScuWdt_Start()函数启动定时器
5:XScuWdt_RestartWdt()函数重新加载预加载寄存器,会更新计数器为预加载值,可以防止看门狗复位信号输出
8.2看门狗模式看门狗需要不停的“喂狗”,在这里就是不停的读预加载寄存器再写入预加载寄存器。如果不能及时喂狗,那么看门狗就会超时,并且产生一个复位输出,复位系统。由于while循环中不停的喂狗,所以这个程序正常运行期间不会产生看门狗超时,但是如果用TF卡启动,程序运行 结束后,会产生看门狗超时后导致的系统复位,这样会看到看程序不停的启动,停止。 - int ScuWdtPolledExample(XScuWdt * WdtInstancePtr, u16 DeviceId)
- {
- int Status;
- XScuWdt_Config *ConfigPtr;
- int Count = 0;
- /*
- * Initialize the SCU Private Wdt driver so that it is ready to use.
- */
- 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;
- }
- XScuWdt_SetWdMode(WdtInstancePtr); //设置为看门狗模式
- /*
- * Load the watchdog counter register.
- */
- XScuWdt_LoadWdt(WdtInstancePtr, WDT_LOAD_VALUE); //设置预加载值寄存器
- XScuWdt_Start(WdtInstancePtr); //启动看门狗
- while (Count < 20) {
- sleep(1);
- Count++;
- XScuWdt_RestartWdt(WdtInstancePtr); //需要不停的喂狗
- }
- return XST_SUCCESS;
- }
复制代码
9方案演示
9.1硬件准备
实验需要用到JTAG下载器、USB转串口外设,另外需要把核心板上的2P模式开关设置到JTAG模式,即ON ON
9.2实验结果当运行定时器模式,程序运行后每1S会中断并输出中断次数
由于开发板不支持SD卡启动,因此看门狗实验暂时无法实现。
|