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.

[参考译文] TM4C129XNCZAD:混淆精确数据总线错误

Guru**** 2392445 points
Other Parts Discussed in Thread: TM4C129XNCZAD

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/883761/tm4c129xnczad-confusing-precise-data-bus-error

器件型号:TM4C129XNCZAD

经过繁重的测试、我看到我的代码在 FaultISR 中最终出现了几次精确的数据总线错误。  在过去、我发现"在 Stellaris 微控制器中诊断软件故障"文档(AN01286)非常有用。  但是、在尝试完本文档中的所有内容后、我仍然会遇到这个问题。

当处于 FaultISR 函数中时、内核寄存器、故障寄存器和堆栈内存显示如下。

程序计数器不是代码的实际部分。  如下所示为 TM4C129XNCAD 数据表中的存储器映射、这将位于 SRAM 中。  此外、故障地址(0x20040000)也在 SRAM 中。  但是、请注意、尽管存储器映射中说 SRAM 从0x2000000到0x2006FFFF、但我相信有效区域将仅从0x20000000到0x2003FFFF、因为 TM4C129XNCAD 数据表中指出微控制器具有256K 的内部存储器(数据表的第8节、第633页) 我的 tm4c129xnczad.cmd 文件的 SRAM 长度指定为0x00040000。

堆栈上的链接寄存器(0x0000A001)确实指向实际代码(如下图所示)。  但是、据我所知、TCPLogWrite 函数中的代码是无害的。

问题:

  1. 0x20040000的总线故障是否表明我已超限数据区域?  例如、如果我通过一个数组进行索引、并在很大程度上越过最后一个索引到 SRAM 区域之外的点(即到达内存地址0x20040000)、我可能会得到什么结果?
  2. 可以肯定地说、问题可能发生在 TCPLogWrite 函数中、还是 LR 可能是一个红色的错误?

提前感谢任何人可能有的任何想法。

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

    我想正在发生的情况是、您的代码开始从 RAM 执行、然后进行访问超过 RAM 末尾。 遗憾的是、它可能在创建硬故障之前执行了几条指令。 您是否有意从 RAM 执行? 您当前是否正在使用 MPU? 否则、您可以对 MPU 进行编程、以禁止从 RAM 执行代码。 然后、您可能会在随机代码执行之前遇到 MPU 故障。 堆栈和 LR 应更有意义。

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

    [引用 user="Bob Crosby"]

    我想正在发生的情况是、您的代码开始从 RAM 执行、然后进行访问超过 RAM 末尾。 遗憾的是、它可能在创建硬故障之前执行了几条指令。 您是否有意从 RAM 执行? 您当前是否正在使用 MPU? 否则、您可以对 MPU 进行编程、以禁止从 RAM 执行代码。 然后、您可能会在随机代码执行之前遇到 MPU 故障。 堆栈和 LR 应更有意义。

    [/报价]

    Bob 您好-感谢您的回复。  我没有 MPU 相关经验。  查看 MPUCTRL 寄存器、可以看到它已被禁用:

    我在 TivaWare 中发现了一个 MPU_FAULT 示例、并在 TivaWare 外设驱动程序库部分19.3中找到了示例代码。  基于此、我已将以下内容添加到主代码顶部的代码中:

    ROM_MPURegionSet (0、SRAM_BASE、
    MPU_RGN_SIZE 256K | MPU_RGN_Perm_noexec |
    MPU_RGN_Perm_PRV_RW_USR_RW | MPU_RGN_ENABLE);
    
    ROM_IntEnable (FAULT_MPU);
    
    ROM_MPUEnable (MPU_CONFIG_HARDFLT_NMI); 

    您是否同意这是不允许从 RAM 执行代码的正确代码?

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

    是的、并且您需要在 NmiSR 的开头有一个断点。 让我知道你得到了什么。

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

    嗯...  我一定会做错事。  对 MPUEnable()的调用导致 FaultISR 被触发。  以下是我的代码:

    int main (void)
    {
    //禁用所有中断
    IntMasterDisable ();
    
    //从 PLL 以120MHz 运行。
    SysClockFreq = SysCtlClockFreqSet ((SYSCTL_XTAL_25MHz |
    SYSCTL_OSC_MAIN | SYSCTL_USE_PLL |
    SYSCTL_CFG_VCO_480)、120000000);
    
    MPURegionSet (0、SRAM_base、
    MPU_RGN_SIZE 256K | MPU_RGN_Perm_noexec |
    MPU_RGN_Perm_PRV_RW_USR_RW | MPU_RGN_ENABLE);
    
    IntEnable (FAULT_MPU);
    
    MPUEnable (MPU_CONFIG_HARDFLT_NMI);
    
    ... 

    也许我还需要做其他一些初始化?  在调用 MPUEnable()之前是否需要启用特定的外设???  我在示例中看不到这一点...  当 TivaWare Periph Lib 的 MPU.c 中的 MPUCTRL 寄存器设置为如下所示(MPUEnable 的最后一行)时、会发生故障:

    void
    MPUEnable (uint32_t ui32MPUConfig)
    {
    //
    //检查参数。
    //
    assert (!(ui32MPUConfig &~(MPU_CONFIG_PRIV_DEFAULT |
    MPU_CONFIG_HARDFLT_NMI)));
    
    //
    //根据用户传递的标志设置 MPU 控制位,
    //并设置使能位。
    //
    HWREG (NVIC_MPU_CTRL)= ui32MPUConfig | NVIC_MPU_CTRL_ENABLE;//导致故障
    }
    

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

    使用:

    MPURegionSet (0、SRAM_BASE、
    MPU_RGN_SIZE 256K | MPU_RGN_Perm_noexec |
    MPU_RGN_Perm_PRV_RW_RW | MPU_RGN_ENABLE);
    IntEnable (FAULT_MPU);
    MPUEnable (MPU_CONFIG_PRIV_DEFAULT);
    

    我们希望默认映射用于管理未专门设置的区域。

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

    啊、好的、谢谢。  我做了这个更改、在运行之前触发 FaultISR 的相同测试后、我不再触发 FaultISR、而是对一些如何脱离主循环的程序进行编程-我有一个 LED 在主循环中周期性闪烁、停止闪烁。  当我在调试器上点击"pause"时、我的内存对我来说毫无意义。  下图显示了寄存器、堆栈指针的存储器以及 PC 的反汇编。  此外、故障寄存器(FAULT_STAT 和 HFAULT_STAT)都为零。

    您提到我应该在 tm4c129xnczad_startup_ccs.cpp 中的 NmiSR 中设置一个断点、我就是这么做的。  我还将一个放入我的 MPUFaultISR 中。  这两个断点都没有被命中。  这些 ISR 非常简单。  它们仅包含一个 while (1);这是我放置断点的行。

    所以...  我不确定此时该怎么办。  有什么建议吗?

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

    您的器件正在从 ROM 空间执行。 我将在我的末尾执行一些测试、以查看我是否可以创建从 RAM 陷阱执行。

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

    啊、好的、我们通常会调用所有的 ROM_CALLS。  例如:

    ROM_SysCtlPeripheralEnable (SYSCTL_Periph_GPIOB);
    ROM_GPIOPinTypeGPIOInput (GPIO_PORTB_BASE、GPIO_PIN_7); 

    如果它有用、为了进行调试、我可以对我的所有源代码进行大量更改以删除"ROM_"、重新编译并重新测试。  您认为这会有所帮助吗?

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

    如果您在闪存中有足够的空间、则可以删除"ROM_"前缀。 然后例程将来自 driverlib.lib 库文件。 当您进入其中一个例程时、您可能会被问及源代码在哪里。 您可以导航到源文件并继续进行源代码调试。 同样、您也可以在 项目中包含来自 C:\ti\TivaWare_C_Series-2.1.4.178\driverlib 的特定源文件。 您可以将它们复制到您的项目空间中、也可以直接链接到它们。 然后、当您构建时、它将使用与项目其余部分相同的构建设置、并且调试器将知道源代码的位置。

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

    好的、明白了。  让我试一下、我会报告。  感谢您的持续帮助!

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

    好的、我执行了批量替换、将任何"ROM_"函数调用更改为"常规"调用。  当然、我仍然在那里有 MPURegionSet、MPUEnable 调用。  我在 NmiSR、FaultISR 和 MPUFaultISR 的 while (1)行上设置断点。  在进行测试时、它最终会命中 FaultISR 内部的断点、但绝不会达到其他断点-并且故障寄存器看起来与以前一样(0x20040000处的精确数据总线错误如下所示)。

    内核寄存器和堆栈也显示如下。  请注意、堆栈上的 PC 和 LR 现在指向实际代码并使其合理、并且 PC 所在的代码正在执行一些可能可疑的操作:具有可变迭代的循环内的指针算术。  我将更深入地检查这一点、看看故障是否来自哪里。  不过、有一个问题:我不点击 MPUFaultISR 是否会让您感到惊讶?

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

    [引用 user="Terence D"]我是否会意外地发现我没有点击 MPUFaultISR?

    是、否 我预期会出现 MPU 故障、但地址与我认为您可能从 RAM 执行时的地址不同。 由于故障地址仍然为0x20040000、因此它是一个总线硬故障(FaultISR)。 我怀疑从闪存而不是 ROM 运行库函数可能会使其更加清晰。 MPU 可能没有任何影响。 请告诉我您的调试是如何进行的。

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

    [引用 user="Bob Crosby"]

    Terence D
    我不点击 MPUFaultISR 是否会让您感到意外?

    是、否 我预期会出现 MPU 故障、但地址与我认为您可能从 RAM 执行时的地址不同。 由于故障地址仍然为0x20040000、因此它是一个总线硬故障(FaultISR)。 我怀疑从闪存而不是 ROM 运行库函数可能会使其更加清晰。 MPU 可能没有任何影响。 请告诉我您的调试是如何进行的。

    [/报价]

    啊、我想我看到您说的是什么。  我按如下方式配置了存储器区域:

    MPURegionSet (0、SRAM_BASE、
    MPU_RGN_SIZE 256K | MPU_RGN_Perm_noexec |
    MPU_RGN_Perm_PRV_RW_RW | MPU_RGN_ENABLE); 

    ...我敢肯定、如果我使用 MPU_RGN_Perm_PRV_NO_USR_NO 而不是 MPU_RGN_Perm_PRV_RW_USR_RW、我会遇到 MPU 故障。

    无论如何、我很确定我发现了问题:我们使用 LWIP、并计算我们发送/接收的消息的校验和。  在我们的末尾计算消息长度时出现错误、导致消息看起来非常大、因此在单步执行消息有效载荷数据时、我们关闭了 SRAM 的末尾、并到达存储器地址0x20040000、从而导致总线故障。  我现在正在修复该错误。

    非常感谢您的帮助!  我不确定如果没有你们、我会不会这么做的!