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.

[参考译文] TM4C123GH6PM:边沿定时器没有测量上升沿之间的正确时间

Guru**** 2482155 points


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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/716001/tm4c123gh6pm-edge-timer-not-measuring-correct-time-between-rising-edges

器件型号:TM4C123GH6PM

我正在尝试配置宽定时器0、以使用边沿定时器功能计算脉冲序列的频率(~1kHz)。

配置代码:

//
//将 PLL 的时钟设置为以50MHz 运行。
//
ROM_SysCtlClockSet (SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHz |
SYSCTL_OSC_MAIN);

/*
*将输入引脚(PC4)配置为使用 CCP
*
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOC);
while (!SysCtlPeripheralReady (SYSCTL_Periph_GPIOC)){}
GPIOPinConfigure (GPIO_PC4_WT0CCP0);
GPIOPadConfigSet (GPIO_PORTC_BASE、GPIO_PIN_4、GPIO_Strength _2mA、GPIO_PIN_TYPE_STD_WPD);
GPIODirModeSet (GPIO_PORTC_BASE、GPIO_PORTC_BASE、GPIO_DIR_MODE_IN);
GPIOPinTypeTimer (GPIO_PORTC_BASE、GPIO_PIN_4);

/*
*在上升沿计时器模式中配置宽计时器0的计时器 A 模块、在周期模式中配置计时器 B
*
SysCtlPeripheralEnable (SYSCTL_Periph_WTIME0);
while (!SysCtlPeripheralReady (SYSCTL_Periph_WTIME0)){}
TimerConfigure (WTIMER 0_BASE、TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_CAP_TIME | TIMER_CFG_B_PERIODICRACRACASE);
TimerControlEvent (WTIMER0_BASE、TIMER_A、TIMER_EVENT_POS_EDGE);

/*
*设置定时器预分频和加载值
*
TimerLoadSet (WTIMER 0_BASE、TIMER_Both、250000);

/*
*设置定时器 CCP 和定时器超时的中断
*
TimerIntRegister (WTIMER 0_BASE、TIMER_A、TimerW0AInt);
TimerIntEnable (WTIMER 0_BASE、TIMER_CAP_EVENT);
IntEnable (INT_WTIME0A);

/*
*启用主中断
*
IntMasterEnable();

/*
*启用计时器
*
TimerEnable (WTIMER 0_BASE、TIMER_Both);

ISR:

/*
*获取发生的计时器中断类型、然后将其清除
*
TimerIntClear (WTIMER 0_BASE、TIMER_CAP_EVENT);

/*
*发生了 CCP 边沿捕获、计算另一个边沿的信号周期
*在这之前已被捕获
*
uint32_t ui32_snapshot = TimerValueGet (WTIMER 0_BASE、TIMER_A);
if (gui8_edge_flag){

int32_t i32_delta;

//计算时间增量
i32_delta = gui32_last_timer_val - ui32_snapshot;

/*
*检查计时器溢出:由于计时器处于递减计数模式、因此新快照
如果发生溢出、*值将大于最后一个值(因此时间增量将为
*为负。 如果发生溢出、则将计时器加载值添加到的差值
*计算真实时间差。
*
if (i32_delta < 0){
i32_delta +=定时器周期+ 1;
}

/*
*将时间增量存储到缓冲区中
*
xSemaphoreTakeFromISR (gp_time_delta_semaphore、NULL);
circbuf_write (&g_freq_buffer、(uint32_t) i32_delta);
xSemaphoreGiveFromISR (gp_time_delta_semaphore、NULL);

} 否则{
//设置标志
gui8_EDGE_FLAG = 1;
}

//更新计时器边沿的最后一个值
gui32_last_timer_val = ui32_snapshot;

我使用的计时器加载值为250000、根据计算结果、最小输入频率应为50MHz/250000 = 200Hz。 circbuf_write 只会向用作循环缓冲区的数组中添加一个值、并更新正在运行的缓冲区内容总和(我已使用其他代码)。 我使用测试方波输入信号(50%直流、500Hz、0-3.5V)来引起中断。 我正在使用调试器读取 i32_delta 的值、它的波动非常大:我不确定这是由于 Tiva 丢失了边沿还是其他我缺失的东西。  

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

    [引用 user="Harry Mander"]我正在使用调试器读取 i32_delta 的值,它的波动相当大[/引用]

    非常好地解释您的问题-清晰的书面叙述和代码演示-做得很好。   而且-这证明了您(第一个)在这里的帖子-这肯定是您在其他地方有过"体验"-但仍然很棒!

    我是否可以建议"亲吻"-作为最快、最简单和最有效的"此类龙的分层?"

    "kiss"指示您按如下方式指导(初始)焦点:

    • 确认(或重新确认)您的输入脉冲信号具有合适的(即具有 MCU 规格)"上升/下降"沿-并且没有"振铃"
    • 该信号最近是否测量并确认了其"接地引线"、以便"良好地连接" 到 MCU 板的接地端?
    • 您的信号的3V5电平是否超过 VDD 电平?   您(µs)是否查看了信号的边沿-示波器设置为"Δ V/分频?"   (注意"边沿瞬变"、该瞬变(偶数)进一步超过 VDD)
    • 由于"第2点和第3点(以上)"、我的团队最常使用 MCU 本身-作为"测试信号发生器!"   (消除接地故障、非法信号电平和"平台入侵")
    • 您会注意到'i32_delta'波动-但(任何)'delta'证明存在违反'kiss'的情况。  (因为它屏蔽了增量的"真正来源")   "更严格的限制"(因此很有洞察力)是"记录和回顾"每个输入信号的"TOA"(到达时间)-在连续信号边沿之间寻求(仅)一致(观察)的"延迟"。   您只需大幅增加计时器的加载值、并将每个捕获的时间记录到(足够深)缓冲器中、以便"事后"观察。
    • 查看缓冲区内容-而不是仅依靠调试器-可避免调试器可能引入的(任何)干扰或变量
    • 最好是定时器引脚(PC_4)享受64位(两个 A/B 组合)功能-如果(相反)它仅为32位-您的250K 负载-证明"超越了分离定时器的功能..."

    如图所示-"kiss"规定(非常)紧密(组成部分)-个人职能重点和衡量-在每个部分/流程的逐步和系统"认证"中-并且仅成功测试/验证每个部分之后"整合/加入"它们(一次一个)。    (请注意、供应商(部分)不愿意"亲吻"-而是发布(酷刑、多字(甚至句子)、描述)、从未证明:难以忘怀、指导和有效(敢说)"亲吻!"

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

    为了使输入捕捉正常工作、定时器需要自由运行并以其最大值0xFFFF 表示16位、或0xffffffff 表示32位、以便简化数学运算。 在0xFFFF/0xFFFF 以外的任何位置设置顶部需要更多的数学运算。

    2.确保理解"加载值"和"预分频器"之间的差异;

    在输入捕捉 ISR 中、您需要读取捕获的值、而不是计时器计数器值。

    希望这对您有所帮助。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    感谢您提供出色的调试建议。 事实证明计时器工作正常、我认为问题是由于堆空间不足(由于 FreeRTOS)而与循环缓冲代码混乱(动态创建)。 增加堆空间可以解决这个问题。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    如果我没有记错 TimerValueGet 会给出捕获的值。 从数据表中:"当检测到所选的输入事件时、在 GPTMTnR 和 GPTMTnPS 寄存器中捕获定时器计数器的当前值、并可由微控制器读取"。 TimerValueGet 的 return 语句为:

    return ((ulTimer=timer_A)? HWREG (ulBase + timer_O_TAR):
    HWREG (ulBase + timer_O_TBR); 

    因此、它似乎正在返回 GPTMTAR 寄存器的值。

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

    [引用用户="Danny F">3. 在输入捕捉 ISR 中、您将需要读取捕获的值、而不是计时器计数器值

    您认为、在("边沿计数"或"边沿计时"的"特殊情况"中 、(实际上)捕获了"计时器计数器"值吗?   因此-海报的方法 "完全正确!"

    如果需要"ammo"(文档)-过高的"证据"到达:

    11.3.2.4输入边沿计时模式
    当检测到所选的输入事件时, GPTMTnR 和 GPTMTnPS 寄存器中捕获定时器计数器的当前值...

    在该模式下、GPTMTnR 和 GPTMTnPS 寄存器保存所选输入事件发生的时间
    GPTMTnV 和 GPTMTnPV 寄存器保存自由运行定时器的值和自由运行预分频器的值。

    每次检测到一个(信号)边沿事件时、当前计数值被加载到 GPTMTnR 和中
    GPTMTnPS 寄存器、并保持该寄存器、直到检测到另一个(信号)边沿 ...

    寄存器19:GPTM Timer B 寄存器(GPTMTBR)、偏移量0x04C
      输入边沿计数和时间模式之外的所有情况下、该寄存器显示 Timer B 计数器的当前值。  在输入边沿计数模式中、该寄存器包含已经发生的边沿数。  在输入边沿定时模式中、该寄存器包含上一次边沿事件发生的时间。

    因此-虽然您的建议(或希望)(通常)是正确的-但它"符合" 边缘计时模式"强加的"特殊条件"。    没有这样的‘亲吻’——我们的海报给我们带来了痛苦!

    可以指出,最好 的“抗希望”……  证明  MCU 手册的"重点正确-阅读/审阅"-...

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

    感谢您的友好和慷慨之词-始终感激。   (尤其是-如 "已赚取")

    尽管(另一人)提出抗议、您的方法确实证明是正确的且成功的。    你的“方法的意识”——会“说服任何陪审团”——做得非常好!   (再次)