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.

[参考译文] TMDSCNCD28379D:使用 CPU 定时器1作为时基的时序问题

Guru**** 2502205 points


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

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1027423/tmdscncd28379d-timing-issue-using-cpu-timer1-as-time-base

器件型号:TMDSCNCD28379D

您好!

在数字信号输出(GPIO44)被置位后、控制器应该至少40微秒检查一个数字信号输入(GPIO40)。
在运行时间内、大部分时间工作正常、也就是说、GPIO40在 GPIO44被置位40微秒后被测试。 但是、在 GPIO44置1后仅8微秒左右才对 GPIO40进行测试。 我正在尝试了解为什么会发生这种情况、并解决该问题。

代码结构:
代码被加载到闪存并从 RAM 运行。
CPU 定时器1用作20微秒的时基、其溢出标志被轮询以推进相关计数器。


一个可能相关的问题:
Timer1被重新加载(相同的20微秒周期)但在重新加载命令之前不会停止。 这是否与问题有关? 如果恰好  在指示计时器重新加载(CpuTimer1Regs.TCR.all = 0x8C20;)的时间(时钟)时设置计时器溢出标志(计时器达到零)、则溢出标志是否仍保持设置?

随附了一个非常简化和简化的代码、用于演示问题发生的位置。


非常感谢您的帮助。

多维尔

#include "F28x_Project.h"						
//====================================================================
// Functions prototypes
//====================================================================
void ConfigGpio(void);
void Timer1_counters_increment(void);
void function1(void);
//====================================================================
// Variables 
//====================================================================
Uint32 Counter;
Uint32 Flag;
//====================================================================
// main()
//====================================================================
void main(void)
{
    InitSysCtrl();
    DINT;
    InitPieCtrl();
    InitGpio();
    ConfigGpio();
    IER = 0x0000;
    IFR = 0x0000;
    InitPieVectTable();
    InitCpuTimers();  
    EINT;
    ERTM;  
    ConfigCpuTimer(&CpuTimer1, 150, 20u);	// Timer1 serves as 20 microseconds time base
    CpuTimer1Regs.TCR.all = 0x8C00;
    GpioDataRegs.GPACLEAR.bit.GPIO0 = 1;
    GpioDataRegs.GPBCLEAR.bit.GPIO44 = 1;
    
    while(1)
    {
        function1();
    }
	
}	// END of main()

//====================================================================
// Functions definitions
//====================================================================

void ConfigGpio(void)
{
    EALLOW;
    GpioCtrlRegs.GPAGMUX1.all	&= ~0xf0f3cfff;
    GpioCtrlRegs.GPAMUX1.all	&= ~0xf0f3cfff;
    GpioCtrlRegs.GPBGMUX1.all	&= ~0x0f0fffff;
    GpioCtrlRegs.GPBMUX1.all	&= ~0x0f0fffff;
    GpioCtrlRegs.GPAGMUX1.all	|=  0x00000000;
    GpioCtrlRegs.GPAMUX1.all	|=  0x00000500;
    GpioCtrlRegs.GPBGMUX1.all	|=  0x00000000;
    GpioCtrlRegs.GPBMUX1.all	|=  0x00000005;
    GpioCtrlRegs.GPAPUD.all	= 0xC4FF0D3F;
    GpioCtrlRegs.GPBPUD.all	= 0x00003C84;
    GpioCtrlRegs.GPACTRL.all = 0x1E004B4B;
    GpioCtrlRegs.GPBCTRL.all = 0x1E1E1E1E;
    GpioCtrlRegs.GPAQSEL1.all = 0xA0008000;
    GpioCtrlRegs.GPBQSEL1.all = 0x000A2A8F;
    GpioDataRegs.GPADAT.all = 0x00000000;
    GpioDataRegs.GPBDAT.all = 0x00000000;
    GpioCtrlRegs.GPAODR.all = 0x00000000;
    GpioCtrlRegs.GPBODR.all = 0x00000003;
    GpioCtrlRegs.GPADIR.all = 0xC4FF0D0F;
    GpioCtrlRegs.GPBDIR.all = 0x00003084;
    EDIS;
}

void Timer1_counters_increment(void)
{
	CpuTimer1Regs.TCR.all = 0x8C00;	// Resets CPU-Timer 1 overflow flag. Timer runs free
	Counter++;
}

void function1(void)
{
    if(Flag == 0)
    {
        GpioDataRegs.GPBSET.bit.GPIO44 = 1;
        CpuTimer1Regs.TCR.all = 0x8C20;	//Clear timer interrupt flag and reload timer
        Counter = 0;	//Reset counter
        while (Counter < 2)	// count 40 microseconds after GPIO44 is set
        {
        		if (CpuTimer1Regs.TCR.bit.TIF)
        		{
        			Timer1_counters_increment();
        		}	
        }
        Flag = 1;	// Flag that 40 microseconds were counted
        if (GpioDataRegs.GPBDAT.bit.GPIO40)	// After 40 microseconds GPIO40 is tested
        {
        		GpioDataRegs.GPASET.bit.GPIO0 = 1;	// Set GPIO0 to indicate that GPIO44 is high
        }
    }
}


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

    尊敬的 Dvir:

    您能帮助我了解如何重现问题吗? 我尝试运行此代码、发现 延迟是一致的。  

    您在实际应用中是否有 ISR?

    此致、

    Veena

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

    您好、Veena、

    感谢您的快速响应。

    实际上、我不知道如何重现此问题、因为它仅发生一次(在多次发生所有事情都正常 且需要40微秒延迟的情况后)、并 导致 使用该卡的原型系统跳闸。

    随附的代码是 原型应用中使用的真实代码的一个非常精简和简化的子集。 它是一个简化的子集、显示了代码中出现问题的位置。 实际代码非常复杂、并且实现了一种状态机、其中几乎所有的 GPIO 都用于许多输入和输出、包括12个 ADC 通道。 如果没有真实系统、则无法运行真实代码、因为代码将立即进入"跳闸模式"、其中不会使用发生问题的代码子集。

    代码中仅使用轮询、 不使用或允许 ISR。

    我想检查您是否可以在计时器的使用和指导方式中看到问题。

    也许我们可以首先检查计时器的操作是否正确。 我在文档中找不到重新加载之前是否需要停止计时器。 请注意 、在清除计时器溢出标志并使用只写指令" CpuTimer1Regs.TCR.bit.TSS = 0x8C20;"将计时器重新加载到第82行的附加代码中之前、计时器不会停止(使用指令"CpuTimer1Regs.TCR.all = 0x8C20;")。 该过程是否正常且具有失效防护功能、或者是否应在溢出标志清除和重新加载指令之前停止计时器? 如果定时器在指令 " CpuTimer1Regs.TCR.ALL = 0x8C20;"之前没有停止、 并且在精确的 CPU 时钟周期定时器达到零(完成计数20微秒)并尝试设置溢出标志(即、 该指令试图清除该标志、而定时器试图同时设置该标志)?

    此致、

    多维尔

     

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

    尊敬的 Dvir:

    我将再次查看该代码、并在明天返回给您。

    此致、

    Veena

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

    您好、Veena、

    谢谢你。 我们不胜感激。

    此致、

    多维尔

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

    尊敬的 Dvir:

    几个问题:

    1、为什么不通过将 TCR 值设置为0x8C20来重新加载 Timer1_COUNTERS_INDE递增()内部的计数器、剩余20us 的时间显示为0x8C00?

    2.一旦40uS 已过去并且您设置了 FLAG = 1、您是否可以通过写入 TSS=1来停止 CPUTIMER?

    我认为您的评估可能是正确的。 因为当您在函数的开头重新加载计数器时、计数器仍在运行。

    此致、

    Nirav

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

    你好 Nirav

    感谢您的回答。 请参阅下面对您的问题的答复。

    1、为什么不通过将 TCR 值设置为0x8C20来重新加载 Timer1_COUNTERS_INDE递增()内部的计数器、剩余20us 的时间显示为0x8C00?

    [Dvir] 重新加载在"Timer1_counters_increment ()"之前完成、以便精确计数40微秒。 如果重新加载将在 "Timer1_COUNTER_INDEINCENTS ()"中完成、则时间将超过40微秒、因为会轮询该标志并且不使用中断。 最有可能在定时器到达0并设置溢出标志后的一段时间内完成轮询。

    2.一旦40uS 已过去并且您设置了 FLAG = 1、您是否可以通过写入 TSS=1来停止 CPUTIMER?

    [DIVR]在实际代码中、我将此计时器用于其他操作、但随附的简化代码中未显示此计时器。 因此、需要计时器来保持运行。  

    您是否可以在文档中找到或询问有关溢出标志问题的开发? 问题是:如果在同一 CPU 时钟周期、定时器(硬件)试图设置溢出标志、但软件试图将其清除并重新加载定时器(指令"CpuTimer1Regs.TCR.All = 0x8C20;")、谁拥有优先级、硬件或软件? 溢出标志是否会被清除或保持置位?

    此致、

    多维尔

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

    尊敬的 Dvir:

    软件写入溢出标志和由于计数器过期而生成的溢出标志都是异步事件。 此外、当 CPU 定时器到期时、溢出信号会在锁存到 TCR 寄存器之前通过时钟同步器逻辑、因此会有几个周期的延迟。

    由于这两个事件都是异步事件、如果溢出标志在 SW 写入寄存器后出现、那么 TIF 标志将在 SW 写入后立即被置位(即0x8C20)。

    如果要重新加载计数器、为什么运行 CPU 计时器很重要? 因为您没有等待 CPU 定时器过期、这意味着在重新加载之前、您不会在函数1中检查溢出标志。 因此、即使 CPU 计时器正在运行、当您进入此函数时、您希望重新加载计时器、这本质上是开始和停止操作、对吧? 也许我错过了完整的图片。

    此致、

    Nirav

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

    Nirav、您好!

    触发此查询是我们使用控制卡的原型系统发生的意外事件。

    附加的代码是应用程序使用的实际代码中一个非常简化和简化的部分。 随附的代码演示了实际代码中出现问题的位置。

    发生的 情况是 、在许多一切正常的情况下、存在一个事件、其中实际代码中与"function1()"等效的段花费8微秒、而不是40微秒。 我正在寻找可能导致此类行为的错误或故障。

    如果定时器到期、但由于延迟、定时器溢出标志将在 SW 写入(0x8C20)后置1、那么它可以解释"function1 ()"持续时间从40微秒减少到20微秒 ("计数器"变量将立即从0增加到1、然后需要20微秒的另一个计时器周期到达2并终止 while 循环)、但不会增加到8微秒。 此外、我今天尝试通过在 SW 指令0x8C20之前添加一条新的线来故意创建此类事件。 新行直接写入定时器计数器寄存器 TIM。 我已经尝试将其设置为0-10的值范围、但非这些值会导致在 SW 指令 0x8C20之后设置 TIF。 因此、该问题可能不会导致该事件。

    我可能会在今天的调查中获得领导:

    与附加的示例代码相比、应用程序中实际代码中"function1()"的等效 while 循环包含更多例程。 该 while 环路的周期约为4微秒。 可以合理地假设事件中的 while 循环恰好循环两次、然后终止。 这可以解释事件中的8微秒持续时间。 现在、如果这一假设正确、问题是什么导致它仅循环两次(而不是大约10次)。 如果"计数器"变量每循环周期递增一次、而不是每20微秒计时器过期一次、这可能会解释这种行为。 但是、什么会导致"计数器"在循环周期中递增? 您是否熟悉过去 TIF "卡住"在设定位置且无法清除的任何事件(如果可能、这可能 会解释此类行为)?

    需要考虑的另一个因素是代码执行期间的某种溢出。 可能有一些溢出到"计数器"存储器位置、堆栈溢出或类似情况。 但是、我目前找不到证据表明这种情况可能发生。

    正如您提到 的、在 SW 指令0x8C20期间定时器正在运行并且未停止这一事实似乎与事件无关。

     

    此致、

    多维尔

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

    尊敬的 Dvir:

    否、清除后、TIF 不应"卡住"在设定位置、不知道有任何此类问题。 也许您可以在写入0x8C20后检查是否清除 TIF 标志。

    此致、

    Nirav

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

    Nirav、您好!

    是的、我已经检查了 TIF 标志、它是被清除的。

    但是、从今天开始有一个发现:

    我今天已经检查了生成的汇编代码、链接器 cmd 文件和实际代码的输出内存映射文件。  

    发生问题的代码片段会拆分为两个后续内存块:RAMLS3和 RAMLS4。 边界恰好位于两个处理实际代码的汇编操作码与简化代码等效的代码之间、同时循环"while (Counter < 2)// count 40 us after GPIO44 is set (while (计数器< 2)//计数40 us)"。 这是否与问题有关?

    它是一个分布在存储器块后续部分的完整函数。 该函数位于存储器地址0x00009e77至0x0000a4c6上、如上所述、边界恰好位于发生问题的代码段中。 值得一提的是,到目前为止,它只发生过一次,但在某些情况下,它运转良好。

    实际代码:

    汇编代码相关段(汇编代码中的存储器位置偏移地址0x00009989)-边界位于第3259行和3260行之间。 第3260行中的分支指向 while 循环外部的代码行(终止 while 循环-->这似乎正好是问题所在,while 循环在单次出现时比预期的提前终止):

    链接器文件相关的存储器块(联合块):

    链接器文件相关段为.text:

    相关存储器映射文件段- 嵌套有问题代码段的相关"父"函数为"_bit":

    您能在这里看到一个可能导致问题的问题吗? 还是 发生问题的代码段位于存储器块边界上只是巧合? 就我记忆中的函数而言、不应在非连续块之间拆分、 但连续块又如何呢?

    此致、

    多维尔

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

    尊敬的 Dvir:

    这是一个有趣的发现。 它感觉是偶然的并且不相关的、只有当 TIF 标志被设定时、它才能够中断 while 环路、所以内存边界不应该影响读取不正确的 TIF 标志。 但我想您建议代码永远不会跳回到 while 循环并终止、除非堆栈损坏、否则这似乎是不可能的。

    但这似乎很奇怪、因为它在大多数时间都能正常工作。 老实说、我们需要将问题重复到根本原因。

    此致、

    Nirav

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

    Nirav、您好!

    我们仍在尝试重现此问题。 我们正在构建一个设置、使我们能够在发生问题的地方运行该精确代码。

    同时、我们 再次查看了器件勘误表、看看我们是否可以找到相关问题。

     在芯片勘误表 SPRZ412L 的第32页中、出现了"Memory:Prepetching Beyond Valid Memory"问题。 我们已经检查了内存块 M1、GS1、GS15的分配情况、所有 这些似乎都很好、并且在建议范围内。 我们只想验证只有这3个内存块受到此问题的影响、所有其他内存块都不受影响、对吗?

    还有一个问题、即发生所发出指令的代码是独立应用程序、该代码被加载(引导)到 闪存并从 RAM 运行(初始化时、代码的所有部分都从闪存复制到 RAM)。 当上述测试设置完成且代码独立运行时、是否有方法通过 CCS 通过调试器连接到 controlCARD?

    此致、

    多维尔

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

    更正- GS11而不是 GS1

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

    尊敬的 Dvir:

    是的、这些是唯一受影响的3个 RAM 内存块。

    是的、您可以连接到调试器、您可能需要等待引导、然后配置引导至闪存。 之后、您应该能够单步执行代码。

    此致、

    Nirav