系列文章目录
F28335-WatchDog简介和应用———Demo1中断应用-Demo2复位应用
1背景
系统需要一定的自恢复功能,防止程序跑飞
,看门狗(WatchDog Timer)本质:该功能实际是一个定时器电路
,一个输入两个输出;
输入:又称喂狗(Kicking the dog or service the dog);
输出:一个连接在F28335复位端,一个连接到中断信号端。
一、看门狗原理简介
原理大致是通过程序设定一定时间期限(计数值上限),当使能看门狗模块后,计数器从零开始计数,再未到达计数值上限时(当然计数值上限需要满足程序模块正常运行需要的时间),进行喂狗操作(本质是给计数器清零),如果超过了计数值上限未清零(或称未喂狗),那么该模块便会产生一个复位的时钟信号, 强制使CPU复位,改变程序的所处的错误状态。
外部时钟OSCCLK
经过512分频以及WDCR预分频
后得到看门狗时钟WDCLK。当WDDIS为0,则看门狗开始工作(即为8位计数器提供时钟),当计数器达到阈值之前使用WDKET寄存器分次写入0x55和0xAA
(简称为密钥)便可以将计数器清零。若计数器溢出(或者看门狗控制寄存器WDCR配置有误)会产生一个512个OSCCLK时钟低电平信号(满足28335低电平复位需要的时间),至于产生复位信号WDRST
还是中断信号WDINT
由寄存器SCSR的WDENINT
决定。
二、寄存器简介
正如上面看门狗电路图所示,看门狗寄存器主要有以下:
系统控制和状态寄存器(SCSR);
看门狗复位秘钥(WDKEY);
看门狗控制寄存器(WDCR);
重点说明SCSR和WDCR寄存器,两者在配置看门狗开启和关闭的过程中非常重要。
WDOVERRIDE的配置解析:该位的描述如上为R/W1C-1(可读/可写-写1清零。 系统重置为1),
写数据:
_写1_会使该位清零不能对控制寄存器WDCR的WDDI(看门狗失能位)进行配置;
_写 0_无影响。
读数据:
读值为1 :可以改变控制寄存器WDCR的WDDI。(手册中描述 –n表示系统重置后的值,是可以读到1的,与写1清零不冲突)
读值为0:若被写1清0,将保持这个状态直到系统重置。
WDCR寄存器用来控制看门狗的使/失能以及预分频数,大家可以通过上图或TI的官方文档获取更详细的信息和说明(若图片不清晰)。
Demo1-中断应用
网上有很多对TI中断应用例程的分析例如下面这篇博文:TI DSP 28335 看门狗(WatchDog)及通过看门狗实现中断。看门狗中断模式的下代码分析
参考对TI例程代码的具体分析,例程使用了看门狗中断的功能,通过两个全局变量LoopCount和WakeCount分别计数程序循环次数以及看门狗中断次数,了解程序的基础上重点掌握
的是对于看门狗计数时间的判断:
例如:WDCR的WDPS
可以配置看门狗计数时钟频率。
公式:Timeout period = 1 / (OSCCLK / (512 * prescaler * 256) ).
其中:OSCCLK
为晶振频率,系统时钟是通过PLL
倍频得到的。(研旭开发板例程晶振频率为30MHZ,倍频为 5,所以系统时钟频率为150MHZ)。presclaer
是前面提到的预分频值,可以在寄存器WDCR的描述进行查看,256含义2^8
(计数器是八位的)。
例如:当WPS为111时,64分频。
看门狗定时周期 Timeout period=279.62ms;
系统理论时钟为:
551264*256=41943040. (运行主程序的系统时钟是5倍频后的频率,所以计算理论时钟周期数,需要在分频数和计数周期数前乘5)。
实际中通过使能clock功能测试出来的时钟周期数为4194300左右。
Demo2复位应用
程序代码进行软件复位烧录到内部flash中运行,使用自带的F28335.cmd文件即可,将28335_RAM_INK.cmd文件排除在编译目录之外。同时特别注意以下几个问题:
- 烧录到flash进行软件复位调试时,只有软件进入连接界面(如下图所示)后,再在用户程序中打断点才可以进入断点标记处,具体的理论区别是内部flash调试需要进行硬件断点的调试(断点的描述为 H/W BP),这样我们才可以在内部flash模式下进行断点调试。
- 其次我们在硬件断点调试的时候,一定要将启动模式选择对应的GPIO87、GPIO86、GPIO85、GPIO84四个管脚置高(即选择从内部flash启动),只有这样我们代码不喂狗产生复位时程序才能按照对应的流程进行运行。
- 程序代码中需要注意的是主函数增加了
MemCopy(&RamfuncsLoadStart, &RamfuncsLoadEnd, &RamfuncsRunStart);
InitFlash();
F28335.cmd
文件中的SECTION部分增加了如下代码:
ramfuncs : LOAD = FLASHD,
RUN = RAML0,
LOAD_START(_RamfuncsLoadStart),
LOAD_END(_RamfuncsLoadEnd),
RUN_START(_RamfuncsRunStart),
PAGE = 0
进行上述操作的原因是因为,在在DSP程序烧入flash后,为了使得程序运行时间和ram中一样,需要将程序搬运到ram里面。网上通常教的方法是利用memcopy函数,将需要搬迁到Ram的函数从Flash搬运至Ram中。
复位程序代码如下(参考了DSP28335如何使用看门狗模块进行程序重启这篇文章):
#include "DSP2833x_Device.h" // Headerfile Include File
#include "DSP2833x_Examples.h" // Examples Include File
#include "leds.h"
// Global variables for this example
Uint32 LoopCount;
typedef int16 bool_t;
extern Uint16 RamfuncsLoadStart;
extern Uint16 RamfuncsLoadEnd;
extern Uint16 RamfuncsRunStart;
void main(void)
{
// Step 1. Initialize System Control:PLL, WatchDog, enable Peripheral Clocks.This example function is found in the DSP2833x_SysCtrl.c file.
InitSysCtrl();
// Step 2. Initalize GPIO:
// This example function is found in the DSP2833x_Gpio.c file and illustrates how to set the GPIO to it's default state.
InitGpio(); // Skipped for this example
// Step 3. Clear all interrupts and initialize PIE vector table: Disable CPU interrupts
DINT;
// Initialize PIE control registers to their default state.The default state is all PIE interrupts disabled and flags are cleared.
// This function is found in the DSP2833x_PieCtrl.c file.
InitPieCtrl();
MemCopy(&RamfuncsLoadStart, &RamfuncsLoadEnd, &RamfuncsRunStart);
InitFlash();
// Disable CPU interrupts and clear all CPU interrupt flags:
IER = 0x0000;
IFR = 0x0000;
// Initialize the PIE vector table with pointers to the shell Interrupt
// Service Routines (ISR).
// This will populate the entire table, even if the interrupt is not used in this example. This is useful for debug purposes.
InitPieVectTable();
// Step 4. Initialize all the Device Peripherals:
LED_Init();
// Clear the counters
LoopCount = 0; // Count times through idle loop
GpioDataRegs.GPASET.bit.GPIO0=1;
DSP28x_usDelay(10000);
// Reset the watchdog counter
ServiceDog();
// Enable the watchdog
EALLOW;
SysCtrlRegs.WDCR = 0x0028;
SysCtrlRegs.SCSR = 0;
EDIS;
// Step 6. IDLE loop. Just sit and loop forever
for(;;)
{
LoopCount++;
// Uncomment ServiceDog to just loop here
// ServiceDog();
DSP28x_usDelay(100);
GpioDataRegs.GPACLEAR.bit.GPIO0=1;
DSP28x_usDelay(100);
}
}
总结
本文结合文中所述的博文教程,将自己实际调试过程中遇到的问题,已经对应的解决方法记录下来,加深记忆,巩固对WatchDog模块的应用。
参考文献
本文测试实验过程中参考了以下博文: