簡體   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