【问题标题】:Reading MSP430 IO register too quickly?读取 MSP430 IO 寄存器太快?
【发布时间】:2011-12-31 21:43:47
【问题描述】:

我正在开发一个系统,其中 MSP430 通过其 SPI 总线与另一个芯片进行通信。我正在通过 SPI 总线发送一系列设置命令,并在从芯片的就绪线上轮询。我使用 IAR 作为我的 IDE,并且我正在编译代码而没有任何优化。代码看起来像这样:

for(int i = 0; i < NUM_SETUP_COMMANDS; i++)
{
    SendSetupCommand(); //puts data in SPI Tx buffer, sets Chip select low

    while(P1IN & 0x40) //wait for Chip ready line to go low
    {
        for(int x; x < 1024; x++)
        { 
            //do nothing 
        }
    }

    HandleReadyLine(); //Transmit/Receive data on SPI bus
 }

无论有没有空的内部 for 循环,这段代码都能正常工作。所有设置消息都通过 SPI 总线正确传输。如果没有内部 for 循环,此代码块大约需要 10 秒。使用内部 for 循环,此代码块大约需要 100 毫秒。

似乎尽可能快地读取 P1IN,如果没有内部 for 循环,会导致 P1IN 无法尽快更新。这有道理吗?添加/删除内部 for 循环会导致如此剧烈的时间变化是否有明确的原因?

【问题讨论】:

  • 查看 asm,确认内部循环没有被优化。还要验证 while 行是否正在执行您希望它执行的操作。请注意,在循环之后重新读取 P1IN 不会在 while 行看到的状态下看到 0x40 位。如果您正在优化内部循环,那么内部循环就会消失,如果不进行优化,那可能就是您看不到输入状态变化的原因。
  • 我确实检查了 asm 并且内部循环没有被优化出来。 “请注意,在循环之后重新读取 P1IN 不会在 while 行看到的状态下看到 0x40 位”-您能否进一步解释该语句,我认为我没有遵循。需要注意的一点是,无论有无 for 循环,P1IN 最终都会改变状态。它最终会起作用,只是没有 for 循环似乎需要更长的时间。
  • 另外,感谢您的回复和建议
  • 如果您在 while 循环中读取 P1IN,这是一个示例,如果您希望能够在循环后稍后读取 P1IN 并期望相同的值(也许调试您看到的问题)那是位的单独采样并且可以是单独的状态。如果您想保留 while 循环中的样本,请将其分配给某些东西 while(1) { x=P1IN; if(x&0x40==0) 中断; } 用 x&0x40 做一些事情
  • 这与您需要内部循环的问题无关,但 PORT1 能够在从高到低转换时触发中断。所以配置中断后你可以清零标志,然后在P1IFG & 0x40为真时中断循环。

标签: c embedded msp430


【解决方案1】:

应该没什么区别。

一些调试建议:

我建议将内部循环的迭代次数减少到零,看看这是否会改变系统时序。还可以尝试将内部循环换成 nop,看看是否有相同的效果。您还可以查看生成的程序集,看看两个编译之间是否有任何明显的东西。最后,(如果可以的话)确定 SPI 行的范围,看看两者之间的行为是否有任何差异。

【讨论】:

  • 我确实尝试过更改内部循环的迭代。我发现如果 for 循环运行的迭代次数少于 650 次左右,那么它的行为就与没有 for 循环一样。我没有尝试过使用 nop。我下次试试。不幸的是,我无法访问 SPI 线路。我只能访问几个 GPIO 测试点。
  • 感谢调试建议。
  • 想法 #1 - 如果在第一次读取 P1IN 之前延迟 100 毫秒会发生什么?想法 #2 - 让 SendSetupCommand() 等到发送缓冲区为空,以确保外部 IC 在 while 循环开始之前收到消息。
  • 我已经很久没有问这个问题了,我意识到我从来没有接受过答案。感谢您的建议。
【解决方案2】:

循环可能已优化。 确保它未优化的一种方法是执行虚拟计算,例如

for(int i = 0; i < NUM_SETUP_COMMANDS; i++)
{
    SendSetupCommand(); //puts data in SPI Tx buffer, sets Chip select low

    while(P1IN & 0x40) //wait for Chip ready line to go low
    {
        volatile unsigned int i;
        for(int x; x < 1024; x++)
        { 
            j++; 
        }
    }
    HandleReadyLine(); //Transmit/Receive data on SPI bus
}

这里的关键是“volatile”关键字,它禁止编译器对变量 j 进行优化,因此你的循环不应该被删除。

【讨论】:

  • 关于微控制器世界中的“volatile”关键字的一点说明:Volatile 用于由 ISR(中断服务程序)和主代码访问的变量。每次访问时都应从 RAM 中获取这些变量。如果某种形式的优化将它放在寄存器中,以便更快地访问,并且当时 ISR 想要访问它:ISR 将访问 RAM 而不是寄存器。因此,可能存在同一变量的两个不同版本。可能具有不同的值,这很糟糕......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-24
  • 1970-01-01
相关资源
最近更新 更多