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.

[参考译文] MSP430FR5739:读取定时器捕捉寄存器时数据损坏

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/722730/msp430fr5739-data-corruption-when-reading-timer-capture-register

器件型号:MSP430FR5739
主题中讨论的其他器件:MSP-EXP430FR5739

您好!

我正在尝试在 TB1上执行计时器捕获。 该计时器脱离 SMCLK (24MHz DCOCLK)运行、应与 CPU 同步。 我正在使用异步外部信号从 P2.2上的 CCI0A 在 CCR0上进行捕获。 外部信号可以非常快、大约为50kHz 甚至更高。

我一直在研究 SCS 同步模式及其使用时间/方式。 (请参阅  和 。) 在我的情况下、由于定时器使用的时钟源与 CPU 相同、我可以直接在软件中读取 TB1R、而无需执行任何技巧(例如软件触发的捕获或连续读取 TB1R)。 对于我的 CCR0外部捕捉、在 TB1R (可能)正在转换时、我应该使用 SCS 来避免异步捕捉。 因此、我的计时器配置如下:

TB1CTL = TBSSEL_2 | MC_2; //使用 SMCLK、连续模式
TB1CCTL0 = CM_3 | CCIS_0 | SCS | CAP;//双边沿、CCI0A、同步、捕捉模式 

实际上、我在任何时候读取 TB1R 都没有遇到任何问题。 但是、如果我在 不考虑 CCIFG 的情况下以紧密循环读取 TB1CCR0、我有时会遇到数据损坏。 以下代码将在大约10、000 - 200、000次迭代后失败:

void wait_for_halt (void){
uint16_t timer_current、timer_captured、timer_delta;
执行{
Timer_captured = TB1CCR0;
Timer_current = TB1R;
Timer_delta = timer_current - timer_captured;
} while (timer_delta < 300);
} 

但这始终通过测试 CCIFG 来实现:

void wait_for_halt (void){
uint16_t timer_current、timer_captured、timer_delta、timer_flag;
执行{
TB1CCTL0 &=~(CCIFG | COV);
Timer_captured = TB1CCR0; //此读取操作不会清除 CCIFG
Timer_flag = TB1CCTL0和 CCIFG;//如果 CCIFG 在读取期间出现、Timer_captured 无效
Timer_current = TB1R;
Timer_delta = timer_current - timer_captured;
} while (timer_flag!= 0 || timer_delta < 300);
} 

这通过读取寄存器两次来工作:

void wait_for_halt (void){
uint16_t timer_current、timer_captured、timer_redundant、timer_delta;
执行{
Timer_captured = TB1CCR0;
Timer_redundant = TB1CCR0;
Timer_current = TB1R;
Timer_delta = timer_current - timer_captured;
} while (timer_captured!= timer_redundant || timer_delta < 300);
} 

我的问题是:为什么我需要这样做? 我假设这些寄存器中没有任何一个是缓冲的。 这将解释为什么如果使用外部时钟来驱动定时器、那么您需要向后弯曲来读取 TB1R。 但是、为什么 我会对 TB1CCR0产生这个问题、尤其是在 SCS 同步模式被启用的情况下? 我想这会导致寄存器与计时器和 CPU 同步更新;这意味着我可以随时读取它。 或者同步是否会导致寄存器在我的读取发生的那一刻更新?

我已尝试禁用 SCS。 正如预期的那样、这会定期失败、以上实施均无帮助。

请注意、我了解可以通过简单地观察输入转换并在软件中跟踪时间来实现此示例。 但我需要能够在进入函数时立即检测到缺少信号。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    值得一提的是、我将 TI 编译器 v16.9.1.LTS 与-O2 -opt_for_speed=5搭配使用。 但是优化设置似乎对这个问题没有影响、因为它也存在-Ooff。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、Greg、

    我仍在检查您的问题。 但我想向你提出我到目前为止的一些看法。

    对于您的第一个代码、为什么即使没有进行捕获、也需要循环读取 TB1CCR0? 在器件的 UG 中、当捕获被执行时 TB1CCR0被载入 TB1R。
    此外、由于你只是循环读取寄存器、你如何被指示 TB1CCR0溢出。

    我将与我们的设计团队一起检查 TB1CCR0寄存器读/写的机制、然后回复您。 但我建议您通过 Timer_B CCIFG 来触发您的函数、这表示执行了捕获。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、Wei、

    感谢您关注我的问题。 感谢您付出的时间/努力。

    我不检查 CCIFG、因为这是额外的一步。 我不关心是否有新的捕获。 我要检查的是、300多个计时器计数缺少信号。 我通过计算(TB1R - TB1CCR0)并等待它>=300来实现这一点。

    2、只要我读取 TB1CCR0时得到的是最新的捕捉、而不是旧的捕捉、我就不关心 COV 条件是否存在。 这似乎符合预期。

    关于 CCIFG 上的触发:CCI0A 上的信号可能非常快。 它可能是几 MHz。 恐怕如果我在 CCIFG 上触发、那么当我读取 TB1CCR0时、我的读取会与另一个捕捉保持一致并导致数据损坏。 使用此损坏的读取来执行上述计算可能会导致值大于300、从而导致其过早退出循环。 (这是在第一个代码示例中发生的情况。)

    我已经测试了第2个和第3个代码示例、以用于50kHz 至21MHz 之间的信号。 两个版本都保持在环路中、直到信号下降到大约40kHz。

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

    感谢您的反馈。

    很抱歉、到目前为止、我没有时间与我们的设计团队一起检查您的问题、因为我忙于处理一些紧急情况、所以我今天无法回复您的任何想法。

    但我将在明天检查您的问题和反馈。 请原谅我迟到的回复。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    大家好、Greg Fudyler、

    感谢您的耐心等待。 今天、我已经和我们的设计所有者一起检查了 TB1CCR0寄存器读取/写入的机制。 但他仍在检查芯片内部的实现代码、因为计时器是一个早已设计好的成熟外设。

    我要再次表示抱歉,我下周早些时候将回复你,因为我将在本星期五下班。 但是、我将在下周一回来时尽快与我们的设计团队联系。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    谢谢你。 我期待下周收到您的回复。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    "我有时会遇到数据损坏。 "

    "数据损坏"是什么意思、您如何知道自己正在获得它?

    "在大约10、000 - 200、000次迭代后、以下代码将失败:"

    "失败"是什么意思?

    我认为、如果您想为您的代码做些什么、您所期望的以及您所得到的内容、这将对您的读者有所帮助。

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

    尊敬的 Danny:

    "我有时会遇到数据损坏。 "意味着我从寄存器中读取的值既不是最后一次捕获、也不是它之前的捕获、而是一个显然是随机的值。 如果我再次简单地读取寄存器、我会得到正确的值。

    现在、我说"显然是随机的"、但它并不是真正随机的。 我看到了单个位翻转。 例如、连续两次读取寄存器将有一个正好为512 (位9)的差值。 我的结论是、我有时会在寄存器发生变化时读取它。 启用 SCS 并将 SMCLK 作为时钟源、我认为不应发生这种情况。

    "以下代码将在大约10、000 - 200、000次迭代后失败:"表示循环在经过一些迭代后过早退出、即使(TB1R - TB1CCR0)的真实值未超过300。 (我已经看到这个计算回到了22、000范围内。) 这在第2个和第3个代码示例中不会发生。

    我要尝试的是检测输入引脚上缺少信号、定义为"在300个 SMCLK 周期内无转换"。 当信号降至~ 50kHz 以下时、它应退出环路。 但是、我要做的不是帖子的要点。 我不需要代码帮助。 我需要帮助了解计时器外设的底层机制、以便更好地了解我应该和不应该如何使用它。 也许这些信息也会帮助他人。

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

    您是否在调试器未运行的情况下尝试过它?

    我打包了该代码并将其放在 FR5739 Launchpad (修订版1.1、相当古老)上。 在调试器运行时、我会看到频繁的故障。 如果我禁用调试器、它将停止运行。 我的示波器现在已经等待了大约15分钟(可能是3500万个以上的循环)、但它尚未触发。

    我 不知道细节、但我很确定调试器会定期将其鼻子粘在您的执行中、这可能会导致这些干扰。

    只需确保我保持了您实验的精神:

    #include 
    #include 
    void wait_for_halt (void){
    uint16_t timer_current、timer_captured、timer_delta;
    执行{
    Timer_captured = TB1CCR0;
    Timer_current = TB1R;
    Timer_delta = timer_current - timer_captured;
    } while (timer_delta < 300);
    return;
    }
    
    #define LED8 BIT7 // P3.7
    #define LED7 BIT6 // P3.6
    #define LED6 BIT5 // P3.5
    #define LED5 BIT4 // P3.4
    #define Hz 1000000UL
    int
    main (void)
    {
    WDTCTL = WDTPW | WDTHOLD;//停止看门狗计时器
    P3OUT &=~(LED5|LED6|LED7|LED8);
    P3DIR |=(LED5|LED6|LED7|LED8);
    
    TB1CTL = TBSSEL_2 | MC_2; //使用 SMCLK、连续模式
    TB1CCTL0 = CM_3 | CCIS_0 | SCS | CAP;//双边沿、CCI0A、同步、捕捉模式
    P2SEL0 || BIT2; // P2.2作为 TB1.0 (CCI0A)
    P2SEL1 |= BIT2; //按表6-42
    
    P1SEL0 |= BIT2; // P1.2作为 TA1.1
    P1SEL1 &=~BIT2; //根据表6-39
    P1DIR |= BIT2;
    TA1CCTL1 = OUTMOD_7; //重置/设置
    #define CAP_Hz 50000UL
    TA1CCR1 = Hz/CAP_Hz/2;
    TA1CCR0 = Hz/CAP_Hz-1; // 50kHz
    TA1CTL = tassel_2 | ID_0 | MC_1 | TACLR;// SMCLK/1、向上[、清除]
    //现在将跳线 P1.2连接到 P2.2以在
    
    (1)
    {时获取信号
    wait_for_halt ();
    P3OUT ^= LED8;
    }/*NOTREACHED*/
    
    RETURN 0;
    } 

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

    有趣! 不可以、诚然、我没有在调试器运行的情况下尝试过它。 在我看来,没有发生干涉的情况。 我想调试器会间歇性地暂停 CPU 以执行它的任务。 将这种随机性注入时序可能会产生怪异的东西。 但是、删除该随机性并不一定意味着问题得到解决。 进行良性更改(例如每次通过循环时递增全局变量)可能会使问题再次出现。 我也看到了这种情况。

    您是否会想到在您完成所有这些设置的情况下运行几个实验? 尝试50kHz 和1MHz 之间的几种不同频率。 并尝试从外部器件生成信号。 对于异步时钟源、您可能会遇到不同的行为。

    此外、看起来您以1MHz 的频率运行 MCLK。 我的频率为24 MHz。 这实际上并不重要、但它确实会改变数字(例如300不再意味着40kHz)。

    感谢您抽出时间重现我的实验。 这是非常有益的。 但我确实应该提供完整的源文件、以使其更容易。 抱歉。

    下周我回到实验室时、我将进行更多实验。

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

    我对这种情况更有一些迷惑、实际上、它在更高的时钟/触发速率下似乎会失败。 我仍然不是完全相信“超自然”的解释,但我已经脱离了“自然”的解释。

    当 MCLK >= 8MHz/触发速率>= 500kHz 时、它似乎很可能重复(尽管并非总是相同的方式)发生故障。 (如您所述)添加甚至不相关的代码会导致症状发生变化、这一事实令人怀疑、更重要的是、这会使诊断变得困难。 我把它移到了 TB0、甚至被 FRAM 控制器愚弄了、但它没有明显的区别。

    我在 FR5969 (Launchpad)上放置了一个合理的传真、它在 MCLK=16MHz/TRIGGER=1MHz 时运行完美、无论是否使用调试器。 这表明代码显然没有什么不好的地方。 它还表明,不管它是什么,它都只限于 FR57代。

    我应该提到、我的 FR5739 Launchpad 上的 MCU 是"X"(预发布)器件、但我的 FR5969 LP 具有"M"(诚实、真实)器件。

    我想我将把它留在那里、看看魏的韦里罗格人是否有任何建议。

    完全披露:下面是我正在处理的内容:

    #include 
    #include 
    #define stats 0 //不收集统计数据(干扰结果?)
    #define SMCLK_MON 1. //将 SMCLK 输出到 P3.4
    #define NO_AUTO 0 //让 FRCTL 控制等待状态
    #define CAP_Hz 1000000UL
    #define Hz 24000000UL
    #IF (Hz!= 1000000UL)&&(Hz!= 8000000UL)&&(Hz!= 24000000UL)
    #ERROR "Fix Hz" //拼写错误提示!
    #endif
    stats
    uint16_t fail_CURR、fail_cap、fail_delta;
    #endif // stats
    void wait_for_halt (void){
    uint16_t timer_current、timer_captured、timer_delta;
    执行{
    Timer_captured = TB0CCR0;
    Timer_current = TB0R;
    Timer_delta = timer_current - timer_captured;
    } while (timer_delta < 400);//(2*Hz/CAP_Hz);// 300);
    #if stats
    FAIL_CAP = Timer_captured;
    FAIL_CURR =定时器_CURRENT;
    fail_delta = timer_delta;
    #endif // stats
    return;
    }
    
    void
    clk_init (void)
    {
    #if no_nAuto //清除 nAuto 并显式设置等待状态
    //等待状态(nAuto=0)根据 UG 表5-1
    #IF Hz == 1000000UL
    FRCTL0 = FWPW | NACCESS_0 | NPRECHG_0;// Was 0/0
    #Elif Hz = 8000000UL
    FRCTL0 = FWPW | NACCESS_0 | NPRECHG_0;// Was 0/0
    #Elif Hz = 24000000UL
    FRCTL0 = FWPW | naccess_2 | NPRECHG_1;// W为2/1
    #else
    #error "clk_init:fix Hz"
    #endif
    #endif // no_auto
    
    //启动时 DCO = 8MHz、但时钟分频器为/8。
    #if Hz ==1000000UL
    //已经有
    #else //需要设置一些内容
    CSCTL0_H = 0xA5;
    #IF Hz = 24000000UL
    CSCTL1 |= DCORSEL; //除了 DCOFSEL_3
    #endif // Hz=24M
    CSCTL3 = DIVA_0 + DIVS_0 + DIVM_0; //将所有分频器设置为0
    #endif // Hz=1M
    #if SMCLK_MON
    P3SEL0 |= BIT4; // SMCLK 输出(是的、那里也有一个 LED)
    P3SEL1 |= BIT4; //按表6-47
    P3DIR |= BIT4;
    #endif
    return;
    }
    #define LED8 BIT7 // P3.7
    #define LED7 BIT6 // P3.6
    #define LED6 BIT5 // P3.5
    #define LED5 BIT4 // P3.4
    int
    main (void)
    {
    WDTCTL = WDTPW | WDTHOLD;//停止看门狗计时器
    P3OUT &=~(LED5|LED6|LED7|LED8);
    P3DIR |=(LED5|LED6|LED7|LED8);
    clk_init ();
    
    TB0CTL_2 = TBSSL; //使用 SMCLK、连续模式
    TB0CCTL0 = CM_3 | CCIS_0 | SCS | CAP;//双边沿、CCI0A、同步、捕捉模式
    P2SEL0 || BIT1; // P2.1作为 TB0.0 (CCI0A)
    P2SEL1 |= BIT1; //按表6-42
    
    P1SEL0 |= BIT2; // P1.2作为 TA1.1
    P1SEL1 &=~BIT2; //根据表6-39
    P1DIR |= BIT2;
    TA1CCTL1 = OUTMOD_7; //重置/置
    TA1CCR1 = Hz/CAP_Hz/2;
    TA1CCR0 = Hz/CAP_Hz-1; // 50kHz
    TA1CTL = tassel_2 | ID_0 | MC_1 | TACLR;// SMCLK/1、向上[、清除]
    //现在将跳线 P1.2连接到 P2.1以在
    
    (1)
    {时获取信号
    wait_for_halt ();
    P3OUT ^= LED8;
    }/*NOTREACHED*/
    
    RETURN 0;
    }
    

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    感谢您进行这项检测工作。 有趣的是、它并不在所有器件上都表现出来。 实际上、我期待从芯片器件中获得一些答案。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    "我的结论是、我有时会在寄存器发生变化时读取它。"

    除非您的寄存器是16位的倍数、否则对其执行的任何操作都是原子操作。

    我想您应该再次询问自己要做什么以及现实与您的期望有何不同。 发生这种情况时、通常故障符合您的预期。

    "我要尝试的是检测到输入引脚上缺少信号"

    根据您对"缺少信号"的定义、有许多方法可以实现这一目的。 如果您将信号定义为完全逻辑转换、则最简单的方法是使用它来重置自由运行的计数器-可通过外部中断、计数器或输入捕捉来完成(就像您尝试执行的操作一样)。 或复位循环计数器、就像通常那样。

    也有一些模拟的处理方式。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我想你会误解我想传达的内容。 是的、寄存器读取是一个原子操作。 但这并不排除芯片底层硬件中的时序违规。

    您是否熟悉当定时器由异步外部时钟驱动时尝试读取 TB1R 的问题? 您可能会因为事物异步变化而产生垃圾。 寄存器中的单个位可能会被错误读取(即我引用的数据损坏)。 我认为这里也有类似的现象。

    是的、正确的做法是、有很多方法可以实现这种类型的信号缺失检测。 其中大多数不适合我的应用、因为信号具有如此高的频率。 软件循环实际上可能会错过所有的高脉冲、例如、具体取决于循环的时序与信号时序如何一致。

    但是,这一切都是不相关的。 我发现了我认为是勘误表或 MSP430芯片被误解的最低行为。 这就是我们在这里探讨的内容。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我想到了一些有助于诊断的东西。 将 WAIT_OR_HALT 函数转换为原始帖子中代码的第三个版本。 首先、确认它确实能够完美运行。 然后将条件更改为:

    } while (timer_captured => timer_redundant || timer_delta < 300); 

    当它退出循环时、比较 timer_captured 与 timer_redundant。 我希望您会看到在这两者之间有单个位翻转。 此外、(timer_current - timer_redundant)应生成小于300的正确答案。

    当我可以访问硬件时、我将在几个小时内亲自尝试。

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

    感谢您的患者。

    在与我们的设计团队核实后、我将再次简单总结计时器捕获功能机制。
    触发捕获事件时、在 TAxCCRn 寄存器中捕获定时器计数器寄存器的值 TAxR。 一旦触发另一个捕获事件(无论 CCIFG 是否被清除)、TAxCCRn 寄存器将被更新。
    2.如果 COV 被溢出置位、它将一直保持到被清除。 但是一旦触发新的捕获事件、TAxCCRn 寄存器将会更新。

    我在周末的时候参加了 Bruce、Denny 和您之间的讨论、非常感谢 做了侦探工作。

    但让我们重点关注您的原始问题。 您能否共享问题重复发生的整个原始代码、以便我们可以保持在同一页上?

    我想总结一下您原来的问题:当连续两次读取寄存器时、TAxCCRn 的位9会损坏。 对吧?

    请告诉我可以针对您的问题采取哪些措施? 如果需要、我希望从您的角度重复您的代码。 我们的设计团队也很乐意对您的问题进行进一步的仿真。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    感谢您确认 CCR 寄存器的行为。 这两点与我的观察和期望是一致的。

    我有以下基于 Bruce 代码的测试案例(非常感谢 Bruce):

    #include 
    #include 
    #define SMCLK_MON 1. //将 SMCLK 输出到 P3.4
    #define NO_AUTO 0 //让 FRCTL 控制等待状态
    #define CAP_Hz 100050UL
    #define Hz 24000000UL
    #IF (Hz!= 1000000UL)&&(Hz!= 8000000UL)&&(Hz!= 24000000UL)
    #ERROR "Fix Hz" //拼写错误提示!
    #endif
    
    uint16_t last、captured、redundant、current、delta;
    
    void wait_for_halt_TB0 (void){
    执行{
    Last =捕获;
    捕捉= TB0CCR0;
    冗余= TB0CCR0;
    电流= TB0R;
    Δ=电流-已捕获;
    } while (captured => redundant || delta < 400);
    }
    
    void wait_for_halt_TB1 (void){
    执行{
    Last =捕获;
    捕捉= TB1CCR0;
    冗余= TB1CCR0;
    电流= TB1R;
    Δ=电流-已捕获;
    } while (captured => redundant || delta < 400);
    }
    
    void
    clk_init (void)
    {
    #if no_nAuto //清除 nAuto 并显式设置等待状态
    //等待状态(nAuto=0)根据 UG 表5-1
    #IF Hz == 1000000UL
    FRCTL0 = FWPW | NACCESS_0 | NPRECHG_0;// Was 0/0
    #Elif Hz = 8000000UL
    FRCTL0 = FWPW | NACCESS_0 | NPRECHG_0;// Was 0/0
    #Elif Hz = 24000000UL
    FRCTL0 = FWPW | naccess_2 | NPRECHG_1;// W为2/1
    #else
    #error "clk_init:fix Hz"
    #endif
    #endif // no_auto
    
    //启动时 DCO = 8MHz、但时钟分频器为/8。
    #if Hz ==1000000UL
    //已经有
    #else //需要设置一些内容
    CSCTL0_H = 0xA5;
    #IF Hz = 24000000UL
    CSCTL1 |= DCORSEL; //除了 DCOFSEL_3
    #endif // Hz=24M
    CSCTL3 = DIVA_0 + DIVS_0 + DIVM_0; //将所有分频器设置为0
    #endif // Hz=1M
    #if SMCLK_MON
    P3SEL0 |= BIT4; // SMCLK 输出(是的、那里也有一个 LED)
    P3SEL1 |= BIT4; //按表6-47
    P3DIR |= BIT4;
    #endif
    return;
    }
    #define LED8 BIT7 // P3.7
    #define LED7 BIT6 // P3.6
    #define LED6 BIT5 // P3.5
    #define LED5 BIT4 // P3.4
    int
    main (void)
    {
    WDTCTL = WDTPW | WDTHOLD;//停止看门狗计时器
    P3OUT &=~(LED5|LED6|LED7|LED8);
    P3DIR |=(LED5|LED6|LED7|LED8);
    clk_init();
    
    TB0CTL = TBSSEL_2 | MC_2; //使用 SMCLK、连续模式
    TB0CCTL0 = CM_3 | CCIS_0 | SCS | CAP;//双边沿、CCI0A、同步、捕捉模式
    P2SEL0 |= BIT1; // P2.1作为 TB0.0 (CCI0A)
    P2SEL1 |= BIT1; //按表6-42
    
    TB1CTL = TBSSEL_2 | MC_2; //使用 SMCLK、连续模式
    TB1CCTL0 = CM_3 | CCIS_0 | SCS | CAP;//双边沿、CCI0A、同步、捕捉模式
    P2SEL0 |= BIT2; // P2.2作为 TB1.0 (CCI0A)
    P2SEL1 |= BIT2;
    
    P1SEL0 |= BIT2; // P1.2作为 TA1.1
    P1SEL1 &=~BIT2; //根据表6-39
    P1DIR |= BIT2;
    TA1CCTL1 = OUTMOD_7; //重置/置
    TA1CCR1 = Hz/CAP_Hz/2;
    TA1CCR0 = Hz/CAP_Hz-1; // 50kHz
    TA1CTL = tassel_2 | ID_0 | MC_1 | TACLR;// SMCLK/1、向上[、清除]
    //现在跳线 P1.2到 P2.1以在 TB0上获得信号
    //或跳线 P1.2到 P2.2以在 TB1上获取信号
    
    while (1)
    {
    Wait_for_Halt_TB0 ();
    P3OUT ^= LED8;
    }
    /*NOTREACHED*/
    返回0;
    } 

    我必须选择一个奇怪的捕捉频率(CAP_Hz)来使这个问题变得明显。 1MHz 和100kHz 从不退出循环。 这与添加额外代码或更改计时相关、对行为有影响。

    通过循环的每次迭代都应遵循以下规则:Last <= captured <= redundant < current (调整整数翻转)

    这就是我在这个特定的实现和 TB0上的这些数字中看到的:

    每次捕获最后一个之间的差值显示为16384。 有趣。 我尝试调整 CAP_Hz 、甚至在外部为其馈送时钟、但无论什么、它看起来都是16384。 FWiw、对于一组给定的条件(捕获频率、内部/外部源)、即使(错误)增量值也是相当可重复的+/- 1。

    我再次尝试使用 TB1。 它的故障比 TB0的预测性要低得多。 下面是我之前提到的512以及1536 (两个相邻位)的示例。

    我希望这能提供足够有用的信息。 再次感谢。

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

    我将尝试赶上您的测试、在该线程上似乎有很多测试、并尝试使用 FR5739运行目标板。 将不断更新我旁边的结果。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我只是注意到了一个拼写错误:
    >#if no_nAuto //清除 nAuto 并显式设置等待状态
    应该是
    >#if no_Auto //清除 nAuto 并显式设置等待状态

    一次都是正确的、所以我在放弃了这条路之后的某个时候怀疑有键盘滑动。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    没什么大不了的! 对我发布的结果有什么看法?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Greg、

    我想向您提供我这边的最新信息。

    我在 MSP-EXP430FR5738上运行代码、但在大约5分钟内从未运行到 P3OUT ^= LED8。

    2.我修改了 WAIT_for_HALT_TB0 (void)、如下所示:

    void wait_for_halt_TB0 (void){
    执行{
    P3OUT |= BIT4;
    Last =捕获;
    P3OUT |= BIT5;
    捕捉= TB0CCR0;
    P3OUT |= BIT6;
    冗余= TB0CCR0;
    P3OUT &=~(BIT4|BIT5|BIT6);
    电流= TB0R;
    Δ=电流-已捕获;
    } while (captured == redundant);
    } 

    我发现了根本原因、为什么 在冗余、 捕获和  最后 一个循环中获得不同的值。 请查看以下引脚示波器。

    您可以看到 while 环路的频率约为362kHz、而捕获事件为100kHz。 查看 P3.4/5/6、它显示了原始代码的三行的开头。 捕获事件(P1.2)在这些代码行的周期内非常容易加载。 也就是说、在您将值复制到最后、捕获和冗余期间、计时器将获得新的捕获事件。 我认为这就是您在单个环路中为这三个变量获取不同值的原因。

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

    让我们来确认一下您的设置。

    1. 请返回到我提供的代码。
    2. 您是否将 P1.2跳线至 P2.1? 请确保您的 P2.1上有一个信号、并且当您处于环路中时 TB0CCR0实际上会定期更新。
    3. 尝试略微更改 CAP_Hz、以查看这是否会导致环路退出。 似乎这种行为在不同芯片之间可能有所不同。
    4. 如果您仍然无法重现从循环退出的情况、请尝试另一个计时器。 在 P1.2和 P2.2之间连接跳线、 而是调用 WAIT_for_HALT_TB1。

    我要重申,问题不是最后的、被抓住的和多余的都是不同的。 这是预期的、因为捕获输入信号是异步的。

    如您所示、环路以362kHz 的频率运行、而捕捉输入为100kHz。 因此、您应该希望环路内不会出现多个变化。 有时零变化。 从不进行两次更改。 对吧?

    这不是我的示例中发生的情况(在我的 MSP-EXP430FR5739上)。 在循环退出后、我看到  最后一个、 捕获的和 冗余 的值彼此不同捕获的值最后一个的值不同一位(0x4000、位14)。 请再次查看:

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

    感谢您的快速反馈。 对于我在代码注释中跳过 P1.2至 P2.1的前2个问题、我会给您快速答复。

    对于问题3和4、当我离开另一个紧急情况时、我需要时间来解决。 今天下午(中国星期五)我会这样做,但我希望下星期一举行,因为今天我会忙于几次会议。

    我要再次感谢您的耐心等待、因为我们已经讨论了一周。 现在、我们已经从我们的设计专家那里得到了一些已被清除为涉及到的东西。 但我们似乎仍在为根本原因而努力。 如果您获得更多结果、请随时回复、我将每天检查您的反馈。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、Wei、

    感谢您迄今所做的一切。 我认为目前我无法做出任何贡献。 代码和结果应足以理解并重现问题。 我想大家可以从这里获取它。 这种情况并非在每个芯片上都发生。 但如果 Bruce 和我都能观察到这种行为、我相信您和您的同事也应该能够复制这种行为。 请继续尝试其他板、其他计时器等 请告诉我是否有任何具体的我可以帮助。

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

    当然、我将继续处理您的问题、并让您更新结果。 再次感谢您的患者。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Greg、

    我想为您提供一个快速更新。

    我已经在 TB1上重现了您的问题、也发现了一些奇怪的事情。 我将在明天进行一些深度调试后更新详细信息。

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

    很棒! 谢谢你。 我期待听到您的结果。

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

    您好、Gerg、

    感谢您的患者。

    今天、我进行了很多次测试、以更改代码的一点。 例如在环路中插入 NOP。 环路的周期似乎会影响问题、这应与您对 CAP_Hz 的描述保持一致。 现在、这个问题可以在我的板上随时重现。  

    void wait_for_halt_TB1 (void){
    执行{
    Last =捕获;
    P3OUT ^= BIT4;
    __no_operation();
    // __no_operation();
    // __no_operation();
    // __no_operation();
    // __no_operation();
    // __no_operation();
    捕捉= TB1CCR0;
    冗余= TB1CCR0;
    电流= TB1R;
    Δ=电流-已捕获;
    //}while (capted == redundant || delta < 400);
    } while (captured == redundant || captured == last);
    } 

    我需要让开发团队参与、为该代码执行一些器件级仿真、以便深入分析 TB0CCR0的行为。 仿真需要几天时间、因为我们的开发团队需要为您的案例设置器件环境。 我想通过电子邮件将此讨论移至离线状态、并在我们获得最终根本原因时返回 E2E。 可以给我发送电子邮件到 wei-zhao@ti.com 吗?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我只是一个感兴趣的旁观者、但我想知道结果如何。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、Bruce、

    再次感谢您对此问题的调查。 我将在工作结束后在该主题上发布根本原因和解决方案。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Greg、

    感谢您离线讨论。 我想在这里简要介绍一下我们的讨论情况。

    您看到最后一个、捕获的和冗余都是不同的根本原因是 、在捕获事件后、内部逻辑正在将 TB1R 值加载到 TB1CCR0寄存器时、软件从 TB1CCR0读取了错误的值。

    请找到我使用的以下测试代码。 P3.5&6表示软件正在读取 TB1CCR0进行捕获冗余

    测试结果如下。 当软件读取 TB1CCR0至被捕获时、每个失败的循环只发生在触发事件之后(line62)

    由于 UG 显示“定时器值被复制到 TBxCCRn 寄存器中”,内部逻辑的执行将需要一段时间来执行“复制”操作。 在此期间、TB1CCR0的值不应保持稳定、因此捕获事件期间的任何读取都会导致不可计数的值 CCR。  

    实际器件上 CCRx 寄存器值的稳定时间可能取决于 COR 电压、器件工艺、温度等。 因此、应避免在捕获事件期间读取 CCRx 寄存器。 建议的方法是处理由 CCIFG 触发的定时器中断服务例程中的捕获事件。 这应该是正常的方法。

    但对于您的情况 、我建议 使用比较模式( UG 中的第12.2.4.2节"比较模式")。 在此模式下、您可以将到期计数值设置为 TBxCLn。 然后启动计时器计数器、让计时器自行运行(同时、CPU 可以运行其他任务)。 将信号输入引脚配置为 GPIO 中断功能、如果发生转换、将触发 GPIO 中断、您可以在 GPIO 中断服务程序中清除计时器计数器(TBxR)。 如果在 TBxR 计数到 TBxCLn 值之前没有清除它、CCIFG 将被设置为触发一个定时器中断。

    此外、您喜欢的方法读取寄存器两次、如果值在两次读取之间匹配(基本上是我在文章中的第三个代码示例)、则只使用该值对您的情况很有用。 请注意、当您接近如此高的频率时、它可能会失败、以至于连续读取每次都会产生不同的答案。

     

    此外、对于您提到的 TB1R 读取、请注意 TB1R 在上升沿递增、CCR0在下降沿锁存 TB1R。 因此、如果 CPU 读取指令在下降沿执行、那么 当定时器和 CPU 使用同步时钟源时、它将一直读取 TB1R 就可以了。

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

    这对于 FR57代产品而言是特别的吗?