我们发现 ESD 事件会导致 PCB 接口上 TMS320F2808芯片的频率发生变化。 根据 WD 设置、DSP 在大部分时间都能正确重新启动。 但是、有时接口会冻结并完全或部分无响应。
ESD 事件是通过螺丝刀从人体放电并到达接口(或机箱)的 GND 而产生的。
该芯片在外部晶振为20MHz 时以100MHz 的频率运行、在 ESD 事件期间、XCLKOUT 在复位期间更改为2.5MHz。 大多数时候、XCLKOUT 正确返回到100MHz 并且正常运行继续。 遗憾的是、有时它会停留在2.5MHz 或其他频率、例如0Mhz (XCLKOUT 保持高电平)、5MHz、17.5MHz、50MHz 甚至200MHz (!)。 低于100MHz 的频率会导致 DSP 冻结、从几乎只有 GPIO 在切换的已拆分 FW 中可以看出这一点。 在200MHz 时、GPIO 继续切换、但速率是其两倍。 有时在某些频率下(在200MHz 和50MHz 上可见)、调试似乎仍然可行。 将 JTAG、COM 和 CAN 接口连接到 PCB 可极大地提高对 ESD 事件的敏感度。 此外、在 main.c 中启用更多模块似乎会增加这些冻结事件的发生速度。 模块包括计时器中断、EEPROM、GPIO、SPI、UART、 闪存、RTC、CAN、PWM 以及我们自己的一些模块。
这些结果会提示监视 SYSCTRL 寄存器的 XCLK、PLLSTS、PLLCR 和 WD。 在详细介绍寄存器之前、请务必注意、在 ESD 事件期间、示波器(Sig借给 SDS1204X-E)在 Vdd (1.8V)、VDDIO (3.3V)和 X2 (外部20MHz 晶振)引脚上未出现毛刺脉冲。 这可能是因为电压尖峰太快、无法观察/触发。 在 ESD 事件期间、/XRS 引脚也保持不变。 目前、重点关注的是内部 DSP 寄存器。
main.c:
int main( void )
{
#if USE_PORT_CANOPEN
#else
is_programming = false;
#endif
_copy_code_from_flash_to_ram();
InitSysCtrl();
//modules_init();
EnableInterrupts();
SetDog();
EALLOW;
GpioCtrlRegs.GPAPUD.bit.GPIO16 = 1; // pullup off
GpioCtrlRegs.GPAMUX2.bit.GPIO16 = 0; // G16/EQEP1A/SPISIMOC/CANTXB
GpioCtrlRegs.GPADIR.bit.GPIO16 = 1; // 1:output, 0:input
GpioDataRegs.GPASET.bit.GPIO16 = 0; // Load output latch
EDIS;
for( ; ; )
{
RTASSERT_RESET(main_loop_active);
//ServiceDog();
GpioDataRegs.GPASET.bit.GPIO16 = 1;
delay(100);
GpioDataRegs.GPACLEAR.bit.GPIO16 = 1;
delay(100);
#if USE_PORT_CANOPEN
#else
if (is_programming) { //Exit loop if the start programming message was received
break;
}
#endif
//stackutils_check();
ServiceDog();
RTASSERT_IS_LESS(main_loop_active, 15000000);
} //End of the main loop
return 0;
}
InitSysCtrl()中的 InitPll (DSP28_PLLCR、DSP28_CLKINDIV)、其中 DSP28_PLLCR=10且 DSP28_CLKINDIV=0:
void InitPll(Uint16 val, Uint16 clkindiv)
{
volatile Uint16 iVol;
test++;
// Make sure the PLL is not running in limp mode
if (SysCtrlRegs.PLLSTS.bit.MCLKSTS != 0)
{
// Missing external clock has been detected (running in limp mode)
// Replace this line with a call to an appropriate
// SystemShutdown(); function.
//ResetProc();
// EALLOW;
// SysCtrlRegs.PLLSTS.bit.MCLKCLR = 1;
// EDIS;
asm(" ESTOP0");
//asm(" RPT #20 || NOP");
}
// CLKINDIV MUST be 0 before PLLCR can be changed from
// 0x0000. It is set to 0 by an external reset XRSn
if (SysCtrlRegs.PLLSTS.bit.CLKINDIV != 0)
{
SysCtrlRegs.PLLSTS.bit.CLKINDIV = 0;
}
// Change the PLLCR
if (SysCtrlRegs.PLLCR.bit.DIV != val)
{
//thread_enter_critical_registers();
EALLOW;
// Before setting PLLCR turn off missing clock detect logic
SysCtrlRegs.PLLSTS.bit.MCLKOFF = 1;
SysCtrlRegs.PLLCR.bit.DIV = val;
EDIS;
//thread_leave_critical_registers();
// Optional: Wait for PLL to lock.
// During this time the CPU will switch to OSCCLK/2 until
// the PLL is stable. Once the PLL is stable the CPU will
// switch to the new PLL value.
//
// This time-to-lock is monitored by a PLL lock counter.
//
// Code is not required to sit and wait for the PLL to lock.
// However, if the code does anything that is timing critical,
// and requires the correct clock be locked, then it is best to
// wait until this switching has completed.
// Wait for the PLL lock bit to be set.
// Note this bit is not available on 281x devices. For those devices
// use a software loop to perform the required count.
// The watchdog should be disabled before this loop, or fed within
// the loop via ServiceDog().
// Uncomment to disable the watchdog
DisableDog();
while(SysCtrlRegs.PLLSTS.bit.PLLLOCKS != 1)
{
// Uncomment to service the watchdog
// ServiceDog();
}
//thread_enter_critical_registers();
EALLOW;
SysCtrlRegs.PLLSTS.bit.MCLKOFF = 0;
SysCtrlRegs.PLLSTS.bit.CLKINDIV != clkindiv; // Disable CLKIN divide by 2
EDIS;
//thread_leave_critical_registers();
}
}
正常100MHz 运行期间的 SYSCTRL:

ESD 事件后的 SYSCTRL、其中 XCLKOUT 最终变为200MHz:

当 XCLKOUT=200MHz 时、SYSCTRL 短接 X2。 此时、当缺少时钟标志被置位(PLLSTS[MCLKSTS]=1)且 WD 不工作(无变化)时、XCLK 变为50MHz:
由于 PLLSTS[MCLKSTS]被置位、我假定 XCLKOUT 将在1-5MHz 范围内、而不是50MHz?

通过向 WDCR[WDCHK]写入故障模式来执行软件复位、同时在正常运行期间进行调试(XCLKOUT=100MHz)也会冻结 DSP (没有 GPIO 切换)。 当 WDCR[WDFLAG]切换时、XCLKOUT 会卡在2.5MHz。 PLLSTS[MCLKSTS]位未设置,因此我不确定是“跛行模式”还是其它模式。 对于该测试期间的 PLL 和 XCLK、观察到以下变化:
- PLLSTS[CLKINDIV]=0
- PLLCR[DIV]= 1010b -> PLLCR[DIV]= 0000b (默认值)
- PLLSTS[PLLLOCKS]= 1b ->未更改
- XCLK[XCLKDIV]= 10b -> XCLK[XCLKDIV]= 00b
现在的问题是、是否有任何方法可以复位 DSP、以便它在从 ESD 事件复位后恢复正常运行(它始终返回到100Mhz)? 该事件似乎不会破坏 DSP、但 WD 无法以某种方式复位、并且 XCLKOUT 被停留在看起来任意的 OSCCLK 倍数或甚至为0 (保持高电平)。 遗憾的是、JTAG 连接在大多数 ESD 事件期间丢失、因此无法读取寄存器、从而使调试变得困难。 此处的目标是将 DSP 重置为正常运行、以符合有关电气快速瞬态测试故障的认证要求。