工具与软件:
我们面临以下问题:在涉及数百个器件的批量生产过程中、我们确定了3、4个 MSP430FR2355微控制器、表现出非常奇怪的行为。 经过进一步分析、我们观察到这些器件进入某种锁定状态。
该设置涉及三个 MSP 连接在一个电路板上、如下所示:
- 主 FPGA 通过 SPI 连接到每个 MSP。
- FPGA 生成单端24MHz 时钟信号、该信号提供给第一个 MSP。
- 第一个 MSP 将24MHz 时钟转发至第二个 MSP、第二个 MSP 将时钟转发至下一个 MSP、从而使用创建菊花链时钟配置 XIN 和 MCLK_OUT 引入抖动。
- 对于编程、我们使用了 Spy-Bi-Wire 接口。 FPGA 对第一个 MSP 进行编程、第一个 MSP 通过 Spy-Bi-Wire 接口对第二个 MSP 进行编程、依此类推、从而形成菊花链 Spy-Bi-Wire 编程配置。
- 我们希望 MSP 的时钟输出保持稳定、并使下一个 MSP 保持复位状态、以避免在转换或瞬态条件下出现任何与时钟相关的问题。
使用此设置、我们可以完全控制每个 MSP、并能够对其进行编程和管理。 但是、如果链中的第一个或第二个 MSP 发生故障、后续器件会对该故障变得敏感。 例如、如果第一个或第二个 MSP 停止为链中的下一个 MSP 生成时钟信号、整个系统将受到影响。
在3-4受影响的装置中、我们观察到以下行为:
- 在启动期间、MSP 有时会进入锁定状态并保持卡滞。
- 处于此状态时、不会为链中的下一个 MSP 生成输出时钟。
- 通过 Spy-Bi-Wire 接口重置器件可能是不可能的、也可能是非常困难的。
- 在大多数情况下、器件可以正常工作、而不会出现任何问题。
经过进一步调查、我们怀疑在 MCLK 从内部800kHz 时钟转换到外部24MHz 时钟期间、器件进入了锁定状态。 请查看以下代码片段以了解潜在问题并提供有关如何检测和防止此状态的建议。
此问题并不会出现在每个设备上、我们有数百个 MSP 没有出现此问题。
void main(void) { /* Stop watchdog timer */ WDT_A_hold(WDT_A_BASE); __delay_cycles(20000); init_ports(); SPI_init(); UART_init(); // Activate port configuration PMM_unlockLPM5(); memcpy((void*)ram_iv, (void*)fram_iv, sizeof(ram_iv)); SysCtl_enableRAMBasedInterruptVectors(); init_CS(); RTClock_init(); RTClock_start(); ADCC_init(); GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P2, GPIO_PIN6, GPIO_PRIMARY_MODULE_FUNCTION); //GPIO_setAsInputPinWithPullUpResistor(SBW_OUT_PORT, SBW_OUT_DAT_PIN); GPIO_setOutputHighOnPin(SBW_OUT_PORT, SBW_OUT_DAT_PIN); reset_MSP_SBW(); get_ID(); init_ctrl(); init_registers(); SPI_enable(1); _EINT(); } void init_ports(void) { // XIN and MCLK_OUT GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P2, GPIO_PIN7, GPIO_SECONDARY_MODULE_FUNCTION); //GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P2, GPIO_PIN6, GPIO_PRIMARY_MODULE_FUNCTION); GPIO_setAsOutputPin(GPIO_PORT_P2, GPIO_PIN6); GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN6); // SBW pins //GPIO_setAsInputPinWithPullUpResistor(SBW_OUT_PORT, SBW_OUT_DAT_PIN); GPIO_setAsOutputPin(SBW_OUT_PORT, SBW_OUT_DAT_PIN); GPIO_setOutputLowOnPin(SBW_OUT_PORT, SBW_OUT_DAT_PIN); //GPIO_setAsInputPinWithPullDownResistor(SBW_OUT_PORT, SBW_OUT_CLK_PIN); GPIO_setAsOutputPin(SBW_OUT_PORT, SBW_OUT_CLK_PIN); GPIO_setOutputLowOnPin(SBW_OUT_PORT, SBW_OUT_CLK_PIN); } void init_CS(void) { // Configure two FRAM waitstate as required by the device datasheet for MCLK // operation at 24MHz(beyond 8MHz) _before_ configuring the clock system. FRAMCtl_configureWaitStateControl(FRAMCTL_ACCESS_TIME_CYCLES_2); //Enable HF/LF mode HWREG16(CS_BASE + OFS_CSCTL6) |= XTS_1; //Switch OFF XT1 oscillator and enable BYPASS mode HWREG16(CS_BASE + OFS_CSCTL6) |= (XT1BYPASS_1 | XT1AUTOOFF_1 | XT1HFFREQ_3); do { GPIO_setOutputLowOnPin(GPIO_PORT_P4, GPIO_PIN1); //Clear XT1 and DCO fault flags HWREG8(CS_BASE + OFS_CSCTL7) &= ~(XT1OFFG | DCOFFG); // Clear the global fault flag. In case the XT1 caused the global fault // flag to get set this will clear the global error condition. If any // error condition persists, global flag will get again. HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG; GPIO_setOutputHighOnPin(GPIO_PORT_P4, GPIO_PIN1); } while (HWREG8(SFR_BASE + OFS_SFRIFG1) & OFIFG); // Test oscillator fault flag GPIO_setOutputLowOnPin(GPIO_PORT_P4, GPIO_PIN1); CS_initClockSignal(CS_ACLK, CS_XT1CLK_SELECT, CS_CLOCK_DIVIDER_640); // ACLK = 37500Hz CS_initClockSignal(CS_MCLK, CS_XT1CLK_SELECT, CS_CLOCK_DIVIDER_1); // MCLK = 24MHz CS_initClockSignal(CS_SMCLK, CS_XT1CLK_SELECT, CS_CLOCK_DIVIDER_1); // SMCLK = 24MHz }