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.

[参考译文] MSP430G2231:SPI 中断未被处理

Guru**** 2582405 points
Other Parts Discussed in Thread: MSP430G2452

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/609446/msp430g2231-spi-interrupt-does-not-get-served

器件型号:MSP430G2231
主题中讨论的其他器件:MSP430G2452

大家好、


我目前正在研究一个将计时器 A 和 SPI 与中断一起使用的应用。

计时器 A 允许定期执行任务、而 SPI 用于接收可能影响任务操作的命令。

SPI 每隔几 ms 接收一次新命令。

一切都正常、但时间(大约每30分钟一次)不会为 SPI ISR 提供服务、从而锁定更远的活动。

执行应用程序调试时、会出现以下情况:

  • Timer A IF 为0
  • 如果位为1、则为 SPI 计数器
  • GIE 和 SPI USIIE 位都是有效的。

从这张图片中、我看不到不应提供来自 SPI 的 ISR 的任何原因。

在主循环内、有一段代码用于检查 SPI 计数器 IF。

如果它们删除了代码的这一部分、中断将始终得到处理。

在位校验期间、寄存器不被写入、只被读取、并且在调试部分中该位保持为1 (正如它应该的那样)

  • 我无法解释这种奇怪的行为、也无法解释为什么不提供 ISR。

编程环境为 CCS、代码优化处于4级。

  • 我想知道这种奇怪的行为是否与一些优化有关
  • 我会要求将应用程序减小到最小大小以重现该行为、以便更轻松地进行调试。
  • 我需要仔细检查它们是否有用于所有未使用的中断的中断陷阱。
  • 是否有其他要推荐的测试?

谢谢、

日落

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

    您好、Sunset、

    MSP430是主器件还是从器件?
    SPI 的运行频率是多少?
    MSP430的运行频率是多少?

    您的初始想法是坚实的。 这里需要添加的一点是、定时器中断的优先级比 USI 中断高。 由于您的计时器中断会更改 USI SPI 的状态、您可能会在这里遇到竞争情况、导致 USI 处于意外状态。 尤其是在定时器中断在任何时候关闭 USI SPI 中断时。 跟踪状态机偏离正轨的位置、最好是连接一个逻辑分析仪来探测 SPI 线路以及任何可用的用于"GPIO 调试"技术的可用 GPIO。 我会切换不同的 GPIO (或切换模式、具体取决于可用于调试的数量)、以指示计时器正在进行的不同状态更改。 将其与 SPI 线路上发送的内容相匹配、以查看内容偏离正轨的位置。 您还希望尝试更快地引发错误、因此缩短交易之间的时间、从而获得更多交易可能会加剧问题。

    如果您正处于竞争状态、并且可以选择进行额外的 SW 标志检查以检查并查看是否完成了正确的 SPI 事务序列。 其他选项包括增加 MCLK 和 SPI CLK 以更快地处理字节、并更快地传输数据、这也会有所帮助。

    另请参阅以下应用手册、了解更多调试思路。 它专为 USCI/eUSCI 而构建、因此确切的寄存器和中断将有所不同、但一些调试技术可应用于任何 SPI 外设、并可提供有关如何解决问题的想法。 (例如我之前建议的 GPIO 调试+逻辑分析仪测量值。)  www.ti.com/.../slaa734

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

    您好、JH、
    设置:我们是 SPI 从器件、预计在16个 CLK 脉冲之后会有一个 SPI-ISR。 CLK 速度约为100kHz。
    以下 func 的目的是检测意外的 CLK 脉冲、这可能导致主器件和从器件变为异步状态:即、主器件认为它发送 CLK 脉冲 nr。 1、而从器件已经需要 CLK 脉冲2。 其理念是:当 CS 处于低电平(无效)时、USICNT 必须始终为16。 如果情况不是这样、我们复位 SPI-unit:强制 MISO 为低电平、复位 USICNT 并重新加载 USISR。 CS 是 P1.4。

    以下函数在主循环中非常频繁地调用。 使用该代码、我们将丢失 SPI 中断。
    我们已经完成了 Sunset 建议的操作:SW 确实仅包含 SPI-ISR、不包含其他 INT 和调用以下函数的主循环。 因此、只有大约75%的 SPI-INT 得到满足。 预计每隔大约8ms 进行一次 SPI INT。 CPU 运行频率为1MHz。

    void hw_SPI_DetectRxError()
    {
    if ((P1IN & BIT4)==0 )
    {
    _disable_interrupts ();
    
    if (((((USICNT & 0x1F)<16)&&((P1IN & BIT4)=0))){
    
    USICNT &=~0xISR;
    USICNT |= 0xUSICT=0
    
    ;USICT=0;USICT=0
    ;USICITE=USITE=USICT=0;USICLICT=0;USICKITE=USITE=USICT=0;USICKITE=USICT0 ~
    USISR = WAKE_TARGET_TIME_S_MAX + SW_VERSION_NR;
    HW_SPI_CTRL_s.InShiftCmd_vau16 = 0;
    }
    _ENABLE_INTERRUPTS ();
    }
    




    删除 AM 函数时、SPI-ISR 速率为100%。

    我们现在考虑实施以下解决方案。 似乎工作正常、但我们需要确认我们不会遇到类似问题:

    if (((P1IN & P1MSK_CS)=0)// CS = 0
    &&(spiOutShift_U16!= USISR)// ShiftRegister-content 已移位
    )
    {
    _disable_interrupts ();
    if ((((P1IN & P1MSK_CS)=0)
    &&(Shift_USISR)
    
    =
    0x000_USBIST_SET);/ DCMP1IN_USBIST_SET = 0xUS000_D/ DCMP= USCMP= USCMP0
    (USCMP1IN_DEBUG)
    
    
    
    USICTL0 |= USIGE;
    USICTL0 &=~USIGE;
    
    //默认计数和 TX 值
    USICNT = USICNT_INIT;
    spiOutShift_U16 = OUT_SHIFT_RESET_VALUE;
    USISR = spiShift_U16;
    HW_SPI_CTRL_s.InShiftCmd_vau16 = OUT_DBG
    
    
    
    }
    ;DBCLRIN_TRUT_0;DBPUT_ING_TRUT_SET (0
    



    在加载 USISR 的所有位置、我们还会将内容复制到 spiOutShift_U16中以进行比较。

    来自客户公司的 Peter Strbek

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

    我无法确认您的解决方法是否适用于100%的案例、因为我不确定您的原始问题是什么。 话虽如此、我确实看到了未对齐的可能性、具体取决于 SPI 时钟的速度。 如果您的 SPI 事务以显著的速率进行、并且您仅以1MHz 运行、那么我可以看到、由于您是如何在全局范围内打开/关闭中断、您会遇到未对齐或缺失的字符。 我还建议使用逻辑分析器和 GPIO 调试标志来查看何时进入 SPI ISR、SPI 事务需要多长时间以及在此例程期间在主代码中全局关闭中断的时间/时序。 在这里、您可以看到时序可能偏离的位置、并找到问题。 因此、一种解决方案是增加 MCLK 频率、以便 CPU 始终处于上升状态。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、JH、
    感谢您的回复。

    首先、我必须道歉:我给您发送了错误的不起作用版本代码。 正确答案应为:
    void hw_spi_detectRxError()


    if (((USICNT & 0x1F)< 16)&&((P1IN & BIT4)=0)

    disable_interrupts ();

    if (((USICNT & 0x1F)< 16)&&((P1IN & BIT4)=0)

    USICNT &=~0x1F;
    USICNT |= USICNT4;
    USISR=0x0000;
    USICTL0 |= USIGE;
    USICTL0 &=~USIGE;
    USISR = WAKE_TARGET_TIME_S_MAX + SW_VERSION_NR;
    HW_SPI_CTRL_s.InShiftCmd_vau16 = 0;

    enable_interrupts ();



    SPI 如下所示:
    - CS 变为高电平=活动
    - 500µs μ s 延迟
    - 100kHz 时16个 CLK 脉冲
    - 100µs μ s 延迟
    - CS 变为 LO =未激活

    在 ISR 内部、我们切换调试引脚。 在正常情况下、我们看到引脚在最后一个 CLK 脉冲后切换22µs。 当错误发生时、直到 CS 变为 LO、ISR 才会启动。 这意味着、在上述代码执行某些操作之前、ISR 有足够的时间进行处理。

    如果没有高于 ISR 的代码、ISR 将达到100%。
    系统中没有其他 ISR、并且-除了上述代码之外-没有 INT 禁用。

    我们尝试通过轮询 SPI-INT-Flag 来替换 ISR:Result:完全一样! 这意味着 ISR 不会被阻止、而是 INT-Flag 未被设置。 我们怀疑最近对 USICNT 的读取会导致问题、因为在正常情况下、只有第一个"if"被执行。

    您能否检查最近对 USICNT 的读取是否会阻止 INT-FLAG 置位?

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

    在论坛上发布代码时、您能否使用"用户丰富格式"选项。 准备好粘贴代码后、单击 按键并粘贴 inthat 窗口、以便为可读性进行格式化。

    我一直在与 Sunset 离线讨论这一点。 如果您愿意发送简单的代码示例、将问题演示到 Sunset、我们可以尝试在类似器件(MSP430G2452)上重现错误。 它具有相同的 USI 模块、因此应表现出相同的行为。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我已经从 Sunset 获得了代码、并将能够在明天尝试复制。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    线程之后的线程、

    此讨论已离线。 一旦找到解决方案、就会更新线程。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    此主题之后的主题:

    我已经能够重现他们的问题(恒定 SPI 中断)并解决这个问题。 器件按预期工作、但应用程序在 SPI 模式下使用 USI 模块的情况下运行。 主要问题是处于 SW 复位状态时 USI 的行为。 以下文本可在器件的用户指南中找到、并说明了软件复位的工作原理(第14.2.1节):

    当 USI 软件复位位位、USISWRST、被置位时、标志 USIIFG、USISTTIFG、 USISTP 和 USIAL
    将保持其复位状态。 不为 USISR 和 USICNTx 计时、它们的内容不受影响。

    这里的问题是 SPI 模块使用的唯一中断与 USIIFG 有关,其默认状态为‘1’或 SET。 这意味着在 SWRST 中清除标志不起作用、因为 SWRST 保持标志置1。 如果您还启用了 USI 计数器中断(USIIE)、这意味着在 SWRST 中、USI 模块将持续触发其中断。

    为了确保不会发生这种状态、针对 SPI 初始化 USI 和/或从 SWRST 出来的过程应该如下。

    •初始化 SPI 的 USI 寄存器、同时确保 USICTL1中的 USIIE 位未被置位。
    •初始化 USICNT、使其不为空。
    •将 USI 模块从 SWRST 中取出[USICTL0 &=~(0x01);或 USICTL0 &=~(USISWRST);]
    •清除 USICTL1中的 USIFG
    •在 USICTL1中启用 USIIE

    进入 SWRST 状态的过程应如下所示:

    •禁用 USICTL1中的 USIIE 位
    •将 USI 模块置于 SWRST [USICTL0|=(0x01);或 USICTL0|=(USISWRST);]