繁体   English   中英

我如何确定编译器何时缓存值而不是从正确的寄存器或内存位置读取它们?

[英]How do I determine when the compiler is caching values and not reading them from the proper registers or memory locations?

我遇到了一个问题,我在 ARM 处理器中轮询标志以完成 SPI 传输,并且它挂在 while 循环中。 我不完全确定发生了什么,我怀疑编译器实际上并没有获取存储在寄存器中的值。

//LPSPI1 is part of the ARM CMSIS ABI

void WriteCmdDataLCD(uint8_t *data_buffer, uint32_t data_length)
{
volatile uint32_t inc = 0;
...
while(inc < data_length)
{
    LPSPI1->TDR = *(data_buffer+inc);
    while(((LPSPI1->SR & LPSPI_SR_TDF_MASK) >> LPSPI_SR_TDF_SHIFT) == 0);
    LPSPI1->SR = LPSPI_SR_TDF_MASK;
    inc++;

}
...

LPSPI1 TX FIFO 有 16 个字深,如果我向该 FIFO 写入 16 个字或更少,则没有问题。 但是,当我写超过 16 个时,它就会卡在那个 while 循环中。 大概是因为 TDF(传输完成标志)永远不会评估为 1(完成)。 调试器的侵入性太大,因为如果我中断程序执行并重新启动它,它就会超出那个点。

ICACHE 和 DCACHE被禁用。 我对下一步感到茫然。

如果重要的话,ARM 处理器是 I.MXRT1060。

编辑:所以这是一个幻象问题,与硬件行为有关。 我需要重新考虑如何使用这个外围设备。

如何确定编译器何时缓存值

编译器不缓存任何东西(运行编译器时可能是内部的东西) 运行编译程序时的硬件可能会缓存一些东西。

ICACHE 和 DCACHE 被禁用。 我对下一步感到茫然。

然后什么都不会被缓存,你的问题根本不存在。 但即使您启用它们,Cortex-M7 也能保证内核对内存的访问是一致的。 在您的情况下,您轮询数据和核心读取(和写入)硬件寄存器和内存。

如果您在缓存打开的情况下使用 DMA - 您必须在访问数据之前使缓存无效。 但这里的情况并非如此。

这个问题和答案中有很多关于 volatile 的混淆。

澄清:

  1. volatile uint32_t inc = 0; - inc不必是不稳定的。
  2. 硬件寄存器在 NXP 提供的标头中声明为易失性。 没什么可担心的。 这些头文件被全世界成千上万的程序员使用。
  3. 数据缓冲区不必是易失性的。

您的支票可以简化为:

while(!(LPSPI1->SR & LPSPI_SR_TDF_MASK));

数据寄存器写入不正确。 应该是:

*(volatile uint8_t *)&LPSPI1->TDR = *(data_buffer+inc);

否则,编译器将生成 32 位写指令,并且 4 个值将存储在 FIFO 中而不是一个(您的数据 + 3 个零字节)。 这是一个非常常见的初学者陷阱。 在这里你可以看到生成代码的不同: https : //godbolt.org/z/x9Knd5

操作顺序不对(先看能不能写,再写)应该是:

while(!(LPSPI1->SR & LPSPI_SR_TDF_MASK));
*(volatile uint8_t *)&LPSPI1->TDR = *(data_buffer+inc);

如果没有完整的代码和对硬件的访问,几乎不可能回答为什么它在while循环中停止的问题。 我只能猜测。 可能外围设备配置不正确和/或检测到某些错误情况。 你从不检查错误标志。

想必是因为TDF(Transmission Done Flag)是Transmit Data Flag ,并不表示传输结束。

还有另一个称为TCF标志用于指示传输的结束。 我强烈建议你仔细阅读并理解Referance Manual的相关章节,然后开始编写软件

我如何确定编译器何时缓存值而不是从正确的寄存器或内存位置读取它们?

编译器可能想要“缓存”所有没有用volatile声明的值。

您可以创建一个测试:

unsigned int maybe_cached = REGISTER;
volatile unsigned int never_cached = REGISTER;

/* some code */

if(maybe_cached != never_cached){
    /* something had been cached */
}

PS,您至少应该对所有异步操作使用volatile

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM