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.

[参考译文] EK-TM4C123GXL:TM4C123GXL 计时器的运行速度似乎快了两倍

Guru**** 2473260 points
Other Parts Discussed in Thread: ENERGIA

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/682781/ek-tm4c123gxl-tm4c123gxl--timer-seems-to-run-twice-fast

器件型号:EK-TM4C123GXL
主题中讨论的其他器件:EnergiaTM4C123

大家好、我正在尝试学习计时器。 我在互联网上看到了一个示例代码、并对照数据表检查了它、为配置选择的值看起来不错。

预期结果: 1秒红色 LED 亮起、1秒 LED 熄灭

实际结果:0.5秒红色 LED 亮起、0.5秒 LED 熄灭

这是我构建并加载到 TM4C 的代码。 代码是在 Keil uVISION 上开发的。 从“管理运行时环境”中,选择 CMSIS->Core and Device->Startup 软件组件。

#include "TM4C123.h" //器件标头

void delay_microsecond (uint32_t time);

int main ()
{

sysctl->RCGCGPIO |= 0x20; //解锁端口 F
GPIOF->DIR = 0x02; //将 PF1 (红色) LED 引脚设置为输出
GPIOF->DEN = 0x02; //数字使能 PF1 (红色) LED

while (1)
{
delay_microsecond (1000000);//等待1秒
GPIOF->data ^= 0x02; //切换 PF1的输出值
(红色 LED)}


void delay_microsecond (uint32_t time)
{
sysctl->RCGCTIMER |= 0x02;//启用 Timer1
Timer1->CTL = 0x00并提供时钟; // Timer 1-A 被禁用。
Timer1->CFG = 0x04; //选择16位定时器
Timer1->TAMR = 0x2; //设置周期定时器模式
Timer1->TAILR = 16 - 1; // 0到15 = 1微秒
Timer1->ICR = 0x1的16个周期; //清除 Timer1中的中断(此处不需要?)
Timer1->CTL = 0x01; //为
(int i = 0;i <时间;i++){启用计时器1A
while ((Timer1->RIS & 0x1)=0x00);
Timer1->ICR = 0x1; //每16个节拍清除计时器1A 中断
}

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

    我可以补充一下 您在发帖时所做的"非常好的工作"吗?   清晰描述-足够详细-并且(甚至)显示 "格式正确"代码。   (保持论坛神(有点)快乐... 尽管(甚至)他们不能**喜欢**您的帖子!”)   非常棒的诗意...

    [报价用户="Mehmet Kose "]我在互联网上看到了一个示例代码并对照数据表进行了检查[/quot]

    工作人员不是很清醒,我 (芝加哥是05:55 -周六)很喜欢这样一个事实:你花了额外的时间和精力来查看 MCU 手册-可能会探测关键计时器寄存器。   当然、"您和我的小型技术团队"、"相信互联网上记录的每一个字"、始终且仅此而已。   (确定-至少每个(其他)字...)

    虽然您的代码方法"DRM"通常不被认为是有效的(被允许的供应商和很少 的"确信"的外人(绝不是 Moi))、但"已注释掉了它"-使 DRM (几乎)可以忍受!   然而(另一个)"指出您的支持!"   (有/有很多!)

    在快速检查您组织有序且呈现良好的代码后、有两个"跳出"区域:

    •   MCU 的系统时钟出现"否/零"设置-是否可以将其"依赖"更改为 "始终运行@相同(已知)速率"-即使是"未初始化启动?"   除非定时器被"PIOSC"命令计时-知道(通常)需要系统时钟。   从 代码的注释中、"16个节拍= 1µS μ s"可以(合理地)证明您的"意图"是让 MCU 运行@ 16MHz。  但请注意-"意图"并不总是确保"器件合规性"。   当您询问计时器时、"了解实际 MCU 时钟速率"是强制性的。  (也许 CMSIS 会管理这一项...)
    • 看不见(我的眼睛)是任何"设置或配置"。 各种中断的计时器。   然而、您 的(用于循环) "旋转"-基于"原始中断!"的"存在/缺失"   您必须仔细检查以注意是否会发生此类中断-不满足"设置和/或配置"的要求。

    您的代码运行-以您所需的"两倍"速率切换 LED -这一事实证实了(甚至) DRM 代码可能(有时)... (几乎) 成功!   使用"此处的提示"或通过其他方式、您必须搜索"双倍 MCU 的计时器"时钟速率"的原因(视情况而定)。   再说一次-您是95%以上的"家"-做得不错...

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    喜欢 CMSIS 风格的方法 实际上、我自己编写了一组例程(github.com/.../CMSIS-framework-for-TM4-devices)。在我看来、基于结构的方法比 Luminary / TI 提供的方法好得多。

    您的代码也有详尽的文档记录。 继续这么做。

    至于您的问题、您可能需要检查计时器的时钟源、并查看某个位置是否存在意外的2分频。 我通常跟踪系统 CoreClock (如果使用 CMSIS 框架、则可用)以确保正确。

    此外、每个中断16个周期可能有点太难处理。 如果将 ILR 加载到更大的值、例如160-1或1600-1、请尝试查看代码是否正常工作。

    我还会使用1000000ul 来调用该延迟例程、只是为了保持代码可移植性-这是一种很好的习惯。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    BTW、您对是否需要在代码开始时关闭 ICR 的评论。 是的。 由于您不会在延迟例程结束时关闭计时器、计时器将继续滚动并可能溢出-不是在这里、而是可能溢出。

    因此、如果不清除 ICR、在这些情况下会将执行时间缩短1个周期/微秒。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    感谢您的鼓励! 我处理的原始代码不像这样清楚(在感到羞耻的同时承认)、我知道"未格式化-未注释"代码可能难以理解。
    与 Arduino 开发相比、我和 TI 产品还存在着爱情仇恨的关系、因为为其开发简单的程序非常详细、有时对于快速原型设计而言会很累(我知道 Energia IDE)。 但我决定在物联网事业上取得进步、德州仪器拥有精美的教育材料和各种各样的物联网产品。 因此、我决定以尽可能少的抽象来了解他们 MCU 的内部机构。 因此、我经常查看我所学习的每个主题的数据表。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    为了简化执行、我尝试在下面的延迟功能结束时停止和禁用时钟。 这种最佳做法是在我们完成计时器后"释放"计时器吗?

    void delay_millisecond (uint32_t time)
    {
    ...
    //此处未复制原始函数主体以防止混乱
    Timer1->CTL = 0x00; // Timer 1-A 被禁用。
    sysctl->RCGCTIMER &=~0x02;//禁用 Timer1的时钟
    } 

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

    我的错误是假设系统内核时钟默认为16 MHz、因为我没有编写任何代码来修改它。感谢 Danny F.和 CB1_MOBILE、我进一步调查了这个问题。 以下是结果。

    当我通过管理运行时环境->设备->启动在 Keil uVISION 中添加启动软件组件时,它会在 Project->Target->Device (在 Project Explorer 窗口中)下的项目中添加"system_TM4C123.c"文件。  该文件中有时钟配置定义和 SystemInit()函数。 以下是一些定义;

    #define CLOCK 设置1 //这会导致在初始化时使用 SystemInit()函数
    #define CFG_RCC_SYSDIV 4进行时钟配置 //这会导致50MHz 系统内核时钟速度(检查 TM4C123GH6PM 数据表)
    #define CFG_RCC_USESYSDIV 1 //启用系统时钟分频器(上面的值"4")
    #define CFG_RCC_PWRDN 0 //不要禁用 PLL
    #define CFG_RCC_BYPASS 0 //不要绕过 PLL
    #define PLL_CLK (400000000UL)// PLL 时钟为400MHz 

    我们可以看到 PLL 未被禁用/旁路、时钟设置被启用、SYSDIV 被选择为4。 根据上面的值和数据表中的信息(第223页-"使用 SYSDIV 和 SYSDIV2域")、 预期的系统时钟为400MHz / 2 /4 = 50MHz。 除数2是 在除数4被应用前的预除数。  为了在开始时防止时钟配置、我只需将 Clock_Setup 设置为0;

    #define CLOCK _SETUP 0 //在 SystemInit()函数中禁用时钟配置 

    由于没有外部时钟配置、因此 MCU 具有16 MHz 系统内核时钟速度。

    注:我将此帖子标记为"解决一个"。 我是否必须标记导致解决方案的其他帮助帖子?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我这次按照您的建议加载了 ILR 寄存器16000 - 1。 从那以后,它变得更加精确。 在此之前、我在53秒内有50个 LED 闪烁、而在50秒内没有50个 LED 闪烁。 这是因为环路开销太大了吗?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    "这种最佳做法是在我们完成计时器后"释放"计时器吗?"

    我不认为所有应用都存在通用的"最佳"做法。

    话虽如此、我通常会在应用中保留自由运行的时钟。 该时钟可以是 SysTick、也可以是任何计时器。 当从未使用的比较通道中产生大量长度不相等的延迟时、第二种方法特别有用。

    如果您希望坚持当前方法、我将从延迟例程中初始化计时器、并在延迟例程中重置计数器/标志。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    正如您所指出的那样、我的(第一个回答)"根据原始程序的时钟设置与您自己的时钟设置之间的"差异"、为您提供了良好的体验。"

    海报 Danny 对"过度参与中断"这一问题提出了一个很好的看法-让我使用(价值太小)的16。   对于您的16位计时器、如果您愿意"改进您的数学运算"、则可能会增加到16、000甚至64、000。    (16位最大值约为65.5K)   提高该值确实会(大幅)降低您的"环路开销"。

    对于"这个已解决"问题-适当的奖励应该针对您的响应者-在这里的案例中、我们相信海报 Danny 和我都应该获得这样的奖励...

    您可能会注意到、"此处的少数几个"采用 Keil 和 CMSIS、它们的组合操作"幕后"将隐藏您的"Helper Crüe 中的关键程序信息。"