This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] MSP430FR5989:中断丢失时出现意外的计时器 B 行为

Guru**** 2380390 points
Other Parts Discussed in Thread: MSP430FR5989
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1236244/msp430fr5989-unexpected-timer-b-behavior-where-an-interruption-is-lost

器件型号:MSP430FR5989

您好!

TimerB 出现意外行为导致 WDT 复位。 我正在使用的微控制器是 MSP430FR5989。

上下文:
微控制器会定期调用一个例程、对适合在一个 ACLK 周期内的 SMCLK 节拍数进行计数。
此例程首先将 TimerA (由 ACLK 提供)置于捕获模式(即触发它的模块)、从而禁用中断并"暂停"持续运行的 DMA。
这可以防止计时器设置 CCIFG、因为其 CCTL 寄存器的 CM 字段设置为"无捕捉"。

一旦 DMA 暂停、系统看门狗就会启动、超时为2ms、这对于
此例程的执行时间(ACLK 频率= 32kHz -> ACLK 周期~ 30us)。

然后执行 SMCLK 节拍计数器代码、该代码已按如下方式实现:

__no_init static volatile UCHAR WDTResetCause;
UINT16 CountTicks( void )
{
	UINT16 startTA0R, stopTA0R, deltaTA0R;
	istate_t local_istate = __get_interrupt_state();
	__disable_interruption();

	TA1CTL_bit.TAIFG = false;
	TA1CCTL0_bit.CAP = true;

	WDTResetCause = 0xAA;
	WDTCTL = WDTPW | WDTPW | WDTCNTCL | WDTSSEL0 | WDTIS2 | WDTIS1 | WDTIS0;

	TB0CCR1 = TB0R + 1;
	TB0CCTL1_bit.CCIFG = false;

	while ( ! TB0CCTL1_bit.CCIFG ) {
	}

	startTA0R = TA0R;
	TB0CCR1 += 1;
	TB0CCTL1_bit.CCIFG = false;

	while ( ! TB0CCTL1_bit.CCIFG ) {
	}

	stopTA0R = TA0R;
	deltaTA0R = stopTA0R - startTA0R;

	WDTCTL = WDT_STOP;
	WDTResetCause = 0x00;

	TA1CCTL0_bit.CAP = false;
	__set_interrupt_state(local_istate);
	
	return deltaTA0R;
}

TimerA0配置:

	TA1CTL = TASSEL__ACLK		
	         | ID__1			
	         | MC__CONTINUOUS	
	         | TACLR;
	         
	TA1CCTL0 = !CAP		
	           | OUTMOD_0	
	           | !CCIE;
	
	TA1EX0 = TAIDEX_0;

计时器 B1配置:

	TB0CTL = TBSSEL__ACLK		
	         | ID__1			
	         | MC__CONTINUOUS	
	         | TBCLGRP_0		
	         | CNTL_0			
	         | TBCLR;

	TB0CCTL1 = !CAP	
	           | OUTMOD_0
	           | CLLD_0
	           | !CCIE;	
	
	TB0EX0 = TBIDEX_0;

DMA 配置:

	DMA0CTL_bit.DMAEN = false;				

	DMACTL4_bit.DMARMWDIS = true;		

	DMACTL0 = ( DMACTL0 & ~DMA0TSEL_31 )
	          | DMA0TSEL__TA1CCR0;			

	DMA0CTL |= !DMADT0						
	           |  !DMADSTINCR0 | !DMADSTINCR1
	           |  DMASRCINCR0 | DMASRCINCR1	
	           |  !DMASRCBYTE				
	           |  !DMADSTBYTE				
	           |  !DMALEVEL					
	           |  !DMAIFG					
	           |  !DMAIE					
	           |  !DMAABORT					
	           |  !DMAREQ;					

错误描述:

我们几个使用同一微控制器(MSP430FR5989)的器件已由在此例程中启动的看门狗进行复位。 这表示 TimerB 中断
标志已丢失或计时器初始化与其递增之间代码执行超过30us (1个 ACLK 节拍)。 无论哪种方式、程序都必须等待将近2秒
发起一个安全装置复位。
此外、我阅读了微控制器的勘误表、想要寻找中断标志丢失的可能解释、而且我发现、根据勘误表 DMA7、
如果在包含中断标志的模块寄存器的读取-写入-修改执行期间 DMA 请求开始执行、那么可能会丢失模块中断。

仅供参考、发生故障的器件只有此例程是相同的、程序的其余部分及其硬件完全不同且独立。 此外、
他们已经运行了很长一段时间没有问题(现在是1.5年)。
很多其他设备的固件与它们完全相同、并且不会出现此问题、因此这实际上不是一个反复出现的问题。

我试图通过模拟 DMA7勘误表的情况重现错误、但我没有运气。

Question:
前面所述的理论(尤其是 DMA7勘误表)是否可能导致此错误? 如果是、如何重现错误?
还有其他可以尝试的东西吗?

其他信息:
DCO 频率= 8MHz
MCLK 和 SMCLK 频率= 4MHz
ACLK 频率= 32kHz

__no_init static volatile UCHAR WDTResetCause;
UINT16 CountTicks( void )
{
	UINT16 startTA0R, stopTA0R, deltaTA0R;
	istate_t local_istate = __get_interrupt_state();
	__disable_interruption();

	TA1CTL_bit.TAIFG = false;
	TA1CCTL0_bit.CAP = true;

	WDTResetCause = 0xAA;
	WDTCTL = WDTPW | WDTPW | WDTCNTCL | WDTSSEL0 | WDTIS2 | WDTIS1 | WDTIS0;

	TB0CCR1 = TB0R + 2;
	TB0CCTL1_bit.CCIFG = false;

	while ( ! TB0CCTL1_bit.CCIFG ) {
	}

	startTA0R = TA0R;
	TB0CCR1 += 1;
	TB0CCTL1_bit.CCIFG = false;

	while ( ! TB0CCTL1_bit.CCIFG ) {
	}

	stopTA0R = TA0R;
	deltaTA0R = stopTA0R - startTA0R;

	WDTCTL = WDT_STOP;
	WDTResetCause = 0x00;

	TA1CCTL0_bit.CAP = false;
	__set_interrupt_state(local_istate);
	
	return deltaTA0R;
}

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    > TB0CCR1 = TB0R + 1;
    > TB0CCTL1_bit.CCIFG = false;

    我很确定这里有一场比赛。 如果 ACLK 恰好在这两条语句之间发生节拍、那么您将丢失 IFG、并且必须等待计时器循环运行(2s)。 下面的类似序列有(大部分)完整的30us 可运行、但这一个受到(未知)初始条件的影响。

    我认为、仅仅对这两条语句重新排序没有帮助、因为 TB0R 必须"计数到"CCR1才能触发比较匹配。 我建议您增加+2而不是+1、因为(在限制范围内)您不会真的关心第一次触发何时发生、只有第一次和第二次之间的差值。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Bruce、您好!

    感谢您的快速响应。

    ´s、我同意、我在这里上传的代码中有一场比赛。 然而、在实际代码中 有 TB0CCR = TB0R + 2。 我一定是在抄本代码中犯了一个错误。

    我编辑了我的帖子。