简体   繁体   English

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

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

I am running into a problem where I am polling flags in an ARM processor for SPI transmission completion and it hangs in the while loop.我遇到了一个问题,我在 ARM 处理器中轮询标志以完成 SPI 传输,并且它挂在 while 循环中。 I am not entirely sure what is going on and I suspect that the compiler is not actually fetching the value stored in the register.我不完全确定发生了什么,我怀疑编译器实际上并没有获取存储在寄存器中的值。

//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++;

}
...

The LPSPI1 TX FIFO is 16 words deep, if I write 16 words or less to this FIFO there is no problem. LPSPI1 TX FIFO 有 16 个字深,如果我向该 FIFO 写入 16 个字或更少,则没有问题。 However, when I write more than 16 then it gets stuck in that while loop.但是,当我写超过 16 个时,它就会卡在那个 while 循环中。 Presumably because TDF (Transmission Done Flag) never evaluates to 1 (for complete).大概是因为 TDF(传输完成标志)永远不会评估为 1(完成)。 The debugger is too invasive because if I break program execution and restart it, it gets beyond that point.调试器的侵入性太大,因为如果我中断程序执行并重新启动它,它就会超出那个点。

ICACHE and DCACHE are disabled. ICACHE 和 DCACHE被禁用。 I am at a loss for next steps.我对下一步感到茫然。

If it matters, the ARM processor is the I.MXRT1060.如果重要的话,ARM 处理器是 I.MXRT1060。

Edit: So this is a phantom problem and is hardware behavior related.编辑:所以这是一个幻象问题,与硬件行为有关。 I need to rethink how to use this peripheral.我需要重新考虑如何使用这个外围设备。

How do I determine when the compiler is caching values如何确定编译器何时缓存值

The compiler is not caching anything (maybe something internal when the compiler is run) The hardware when you run the compiled program might cache something.编译器不缓存任何东西(运行编译器时可能是内部的东西) 运行编译程序时的硬件可能会缓存一些东西。

ICACHE and DCACHE are disabled. ICACHE 和 DCACHE 被禁用。 I am at a loss for next steps.我对下一步感到茫然。

Then nothing will be cached and your problem simply does not exist.然后什么都不会被缓存,你的问题根本不存在。 But even if you enable them Cortex-M7 guarantees that the core accesses to the memory is coherent.但即使您启用它们,Cortex-M7 也能保证内核对内存的访问是一致的。 In your case, you poll for the data and core reads (and writes) hardware registers and memory.在您的情况下,您轮询数据和核心读取(和写入)硬件寄存器和内存。

If you use DMA with the cache ON - you will have to invalidate the cache before accessing the data.如果您在缓存打开的情况下使用 DMA - 您必须在访问数据之前使缓存无效。 But it is not the case here.但这里的情况并非如此。

There is a lot of confusion about the volatile in this question and answers.这个问题和答案中有很多关于 volatile 的混淆。

To clarify:澄清:

  1. volatile uint32_t inc = 0; - inc does not have to be volatile. - inc不必是不稳定的。
  2. Hardware registers are declared as volatile in the NXP provided headers.硬件寄存器在 NXP 提供的标头中声明为易失性。 Nothing to worry about.没什么可担心的。 Those headers are used by thousands of programmers around the world.这些头文件被全世界成千上万的程序员使用。
  3. data buffers do not have to be volatile.数据缓冲区不必是易失性的。

Your check can be simplified to:您的支票可以简化为:

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

The data register write is incorrect.数据寄存器写入不正确。 It shuld be:应该是:

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

otherwise, the compiler will generate 32 bit write instruction and 4 values will be stored in the FIFO instead of one (your data + 3 zero bytes).否则,编译器将生成 32 位写指令,并且 4 个值将存储在 FIFO 中而不是一个(您的数据 + 3 个零字节)。 It is a very common beginners trap.这是一个非常常见的初学者陷阱。 Here you can see the difference in the generated code: https://godbolt.org/z/x9Knd5在这里你可以看到生成代码的不同: https : //godbolt.org/z/x9Knd5

The order of operation is incorrect (you should first check if you can write, then write) it shuld be:操作顺序不对(先看能不能写,再写)应该是:

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

The question of why it stops in the while loop is almost impossible to answer without the full code and access to your hardware.如果没有完整的代码和对硬件的访问,几乎不可能回答为什么它在while循环中停止的问题。 I can only guess.我只能猜测。 Probably the peripheral is not correctly configured and/or some error conditions are detected.可能外围设备配置不正确和/或检测到某些错误情况。 You never check the error flags.你从不检查错误标志。

Presumably because TDF (Transmission Done Flag) It is Transmit Data Flag and it does not indicate the end of the transmission.想必是因为TDF(Transmission Done Flag)是Transmit Data Flag ,并不表示传输结束。

There is another flag called TCF used to indicate the end of the transfer.还有另一个称为TCF标志用于指示传输的结束。 I strongly advise to read carefully and with understanding the relevant chapter of the Referance Manual , then start to write the software我强烈建议你仔细阅读并理解Referance Manual的相关章节,然后开始编写软件

How do I determine when the compiler is caching values and not reading them from the proper registers or memory locations?我如何确定编译器何时缓存值而不是从正确的寄存器或内存位置读取它们?

The compiler might want to "cache" all values which are not declared with volatile .编译器可能想要“缓存”所有没有用volatile声明的值。

You might create a test:您可以创建一个测试:

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

/* some code */

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

PS you should use volatile at atleast for all asynchronous operations. PS,您至少应该对所有异步操作使用volatile

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

相关问题 读取内存映射的 IO 寄存器如何(来自数据表)并在 mmap 中使用它们 - reading Memory-Mapped IO registers How to (from datasheet) and using them in mmap 如何确定Linux中是否未分配特定的内存位置 - How to determine if specific memory locations are unallocated in Linux 如何从内存和其中的数组释放结构 - how do I release a struct from memory and arrays within them 如何查看 .bss 中静态变量的内存位置? - How do I see the memory locations of static variables within .bss? 如何确定结构的内存布局? - How do I determine the memory layout of a structure? 如何确定要使用的C / C ++编译器? - How do I determine which C/C++ compiler to use? 如何在C中动态分配内存并确定数组大小? - How do I allocate memory and determine array sizes dynamically in C? 如何确定此 memory 更改/损坏的来源? - How do I determine the source of this memory change/corruption? C:我如何模拟8086寄存器? - C: How do I simulate 8086 registers? 从文件中读取 c 中的结构数组中的 dma 结构时,如何分配 memory - How do you allocate memory when reading from a file for a dma struct in a struct array in c
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM