2017-06-06 50 views
-1

我想在芯片的SRAM中存儲一個簡單的整數。 (Cortex M4) 我使用的程序是mbed在線。 我知道SRAM的地址從0x2000開始,芯片有4KB的內存。如何在STm32核子板(mbed)上寫入SRAM

我已閱讀數據表和位帶部分,但它對我來說沒有意義。

有人可以請我解釋一下,我可以如何在SRAM中存儲數字5並再次讀取它?

當前代碼是這樣的(C是用戶與按鈕改變的整數):
if(c==100){ temp=c; MBX_B0 = 1; // Word write temp = MBX_B7; // Word read
TIMER_B0 = temp; // Byte write return TIMER_B7; // Byte read } pc.printf("%d",temp);

它只是停止Ç== 100 值應該被保存後也POWER DOWN運行一次。

+1

如果您還沒有準備好,請閱讀本:[mbed內存型號(https://developer.mbed.org/handbook /內存模型)。 –

+1

在0x20000000處沒有帶有Cortex-M4內核和4K SRAM的STM32型號。你在使用什麼控制器? – berendi

回答

2

編輯,你的問題完全改變了答案,因爲你不感興趣的SRAM寫在所有,但閃存/ EEPROM ...

因此增加的主要部分,這個答案,您的評論是非常關鍵的位置:

但是,即使斷電後,該值是否存儲?難道SRAM 會代替普通RAM嗎? RAM =沒電時丟失數值, SRAM =沒有電時保持數值?

SRAM表示靜態RAM,RAM表示隨機存取存儲器。現在,隨着隨機部分與尋址有關,RAM根據該定義可以安全地用於諸如ROM(只讀存儲器)之類的東西,我可以尋址我想要的任何隨機地址還是隻能使用線性地址之後讀取這個東西其他每個規則。

約定是ROM是非易失性的,而RAM是易失性的,這裏是相關的術語。 ROM實現在技術上不是隻讀的PROM是可編程的ROM,這意味着可寫,所以有點可分解術語EPROM電可編程,EEPROM是電可擦除和可編程的。閃存是一種新型的電可擦除可編程ROM或非易失性存儲器。

這種意義上的揮發性意味着它可以或不能在電力循環中存活。揮發性意味着它不能以非揮發性手段。

SRAM中的S用於靜態確定,這個術語意味着它可能存活尤其是當你學習DRAM時,D意味着動態,並且假設一個在電源週期中存活而另一個不存在但遺憾的是不是他們所指的是什麼。相反,在這兩種情況下,他們必須處理仍然通電的內存,它們都是易失性存儲器。去看看這些在維基百科。靜態使用四個晶體管可以說,在經典的觸發器實現中有兩個反饋門,您可以將該位寫入高電平或低電平,只要電源沒有關閉,它就保持它不會忘記的值(只要電源保持開啓) 。 DRAM雖然使用了一個晶體管,並且在很大程度上依賴於該晶體管中的電容,有點像跛足的可充電電池,但您希望它記住1,您必須對其充電並快速放電(以毫秒爲單位),所以您必須不斷提醒它是一個還是一個零(刷新)。

所以靜態RAM是靜態的,因爲我們只需告訴它一次,它記住,動態RAM是動態的,因爲我們告訴dram系統該位是什麼,並且作爲一個系統,我們必須不斷提醒它通過讀取該位然後以特定頻率對該位進行重新編程/充電來完成。

DRAM價格便宜,可以在相同數量的晶體管中封裝四倍的位數,SRAM很快沒有複雜的開銷,也沒有刷新週期,它只是門,所以可以像其他的一樣快速運行門的速度與門做其他事情一樣快(處理指令)。一個微控制器在其ROM,PROM,EEPROM或閃存(其中現在有各種風味)中將具有某種形式的非易失性存儲器。有時候你可能會在eeprom中使用閃存和eeprom,這可能是因爲你需要在這裏提供的東西,有時爲了反向兼容的原因,他們有一個eeprom傳統接口,但它確實使用主閃存進行存儲。無論如何,您必須查看芯片和/或芯片系列的文檔。現在,在應用程序寫入片上非易失性存儲器(eeprom/flash)時,這很常見(儘管有很多例外)。文檔告訴你如何做到這一點。

而且這一切都很棒,但一些免費的建議是,如果你在幾小時或幾天內做錯了這件事,你可以把你的閃光燈磨損掉......這部分可以被刪除。理想情況下,您希望在您的電路板上支持檢測電源電壓下降,同時有足夠的大容量電容或電池或兩者來保持電路板/設備足夠長的時間,以便在需要最短時間的情況下保存電路板/不穩定的信息(理想情況下首先確認數值已經改變,否則不要刻錄擦除週期)。很容易實現,但仍然比閃光燈更好。

很多解決方案和意見,關於如何不會損耗你的閃光燈,可悲的是一些閃存硬件有邏輯,寫的水平,如果軟件和硬件都試圖分散東西,以減少磨損閃光他們可以相互抵制,做更多的傷害,而不是好的。

您的零件支持的寫入週期數量應記錄在數據表中,超過您使用此設備生成的產品的使用期限,它可能會忘記您寫的內容。這可能是10000次寫入所支持的最小值,但在測試中,您可能會達到10萬次,並且仍然可以運行一個設備。並不意味着他們的所有重置都將超過數據表中的評級,所以如果我在這麼多單位的時間內獲得新的價值並且產品的生命週期是我希望能夠達到如此多的單位時間,那麼我不能保存超過一些簡單的數學時間單位(每個存儲位置/擦除邊界等)。

所以,首先要學習如何在應用程序中擦除未使用的塊,然後向其中寫入內容,然後在恢復電源時查看它是否存在,如果不存在則嘗試使用eeprom。一般都有文檔記錄,而且在這些STM32器件上很容易完成。那麼一旦你知道如何去做,那就開始擔心你覺得你需要這麼做了。

有些汽車曾經注意到,當你把它們「關閉」,重新開始時鐘仍然有效,收音機會記住你最喜歡的電臺或空調記得你使用的最後一個溫度和風扇速度。但如果您斷開電池的部分或全部電量,則會丟失。他們沒有使用使用RAM(非易失性存儲器)的非易失性存儲器,而且電源剛剛熄滅,它們依靠電池備份。主板已經做好了,也許還會爲你的「CMOS」或「BIOS」設置做這些。電池支持的內存基本上是因爲內存不會失去電源,主電源可能會關閉,但電池仍然保持內存供電。這是另一個可以使用的設計解決方案,電池或超級電容(acitor),可能會認爲您從不需要存儲閃光燈,如果像汽車音響那樣,電池會很好地熄滅。

授予所有這一切都需要我以前的答案,爲了得到那個控制EEPROM /閃存你需要知道如何從程序訪問這些寄存器:

首先位綁紮不要求在這裏(爲了從ram中存儲/加載一些值),你是問如何寫入和讀取RAM中的特定地址,或者你在問如何使用位帶?通常情況下,你不會使用ram的位段功能,例如,該功能可以改變寄存器中的一個位子集,設計者因爲某種原因將單獨的項目打包到同一個寄存器中(像gpio引腳配置這樣的事情是有意義的,而你可能需要改變單個引腳的配置,而不用軟件中的讀 - 修改 - 寫入(硬件可能仍然需要進行讀 - 修改 - 寫))

當然你可以使用ram上的bitbanding功能, cortex-m允許我需要重新讀取它,除非你需要將單獨的東西打包成單個單詞(比如bitfields,但是甚至不以此爲開頭),否則它們並不一定有意義。 。

#define BITBAND_SRAM_REF 0x20000000 
#define BITBAND_SRAM_BASE 0x22000000 
#define BITBAND_SRAM(a,b) ((BITBAND_SRAM_BASE + (a-BITBAND_SRAM_REF)*32 + (b*4))) 
#define BITBAND_PERI_REF 0x40000000 
#define BITBAND_PERI_BASE 0x42000000 
#define BITBAND_PERI(a,b) ((BITBAND_PERI_BASE + (a-BITBAND_PERI_REF)*32 + (b*4))) 
#define MAILBOX   0x20004000 
#define TIMER    0x40004000 
#define MBX_B0    *((volatile unsigned int*)(BITBAND_SRAM(MAILBOX,0))) 
#define MBX_B7    *((volatile unsigned int*)(BITBAND_SRAM(MAILBOX,7))) 
#define TIMER_B0   *((volatile unsigned char*)(BITBAND_PERI(TIMER,0))) 
#define TIMER_B7   *((volatile unsigned char*)(BITBAND_PERI(TIMER,7))) 


MBX_B0 = 1; 

所以這些都不是特別的,或者與cortex-m或arm相關,只是基本的C代碼。 MBX_B0是你工作的宏觀落後

#define MBX_B0    *((volatile unsigned int*)(BITBAND_SRAM(MAILBOX,0))) 

宏然後

#define MAILBOX   0x20004000 
#define BITBAND_SRAM(a,b) ((BITBAND_SRAM_BASE + (a-BITBAND_SRAM_REF)*32 + (b*4))) 
#define BITBAND_SRAM_BASE 0x22000000 
#define BITBAND_SRAM_REF 0x20000000 

所以

0x22000000+(0x20004000-0x20000000)*32 + (0*4) 

= 0x22080000 

揮發性unsigned int的東西只是一個C語法的方式,採取像0x22080009一些常數,說這是我想指向的東西的地址

MBX_B0 = 1; 

裝置寫一個00000001解決0x22080000但是,因爲這是使用位條帶,這意味着設定地址0x20004000的位0的位1(位綁紮是非常特定於這些臂皮質 - 間核)

如果只是想寫值5在內存的某個位置,你可能只是

#define SOME_ADD *((volatile unsigned int*)(0x200) 
unsigned int x; 
SOME_ADD = 5; 
x = SOME_ADD; 

,並看到這一切爲你做你可以嘗試一下:

#define BITBAND_SRAM_REF 0x20000000 
#define BITBAND_SRAM_BASE 0x22000000 
#define BITBAND_SRAM(a,b) ((BITBAND_SRAM_BASE + (a-BITBAND_SRAM_REF)*32 + (b*4))) 
#define MAILBOX   0x20004000 
#define MBX_B0    *((volatile unsigned int*)(BITBAND_SRAM(MAILBOX,0))) 

#define SOME_ADD *((volatile unsigned int*)(0x200)) 

unsigned int fun (void) 
{ 
    unsigned int x; 

    MBX_B0 = 1; 

    SOME_ADD = 5; 
    x = SOME_ADD; 

} 

臂無 - EABI - 海合會-c -O2 so.c -o so.o arm-none-eabi-objdump -D等等。Ø

00000000 <fun>: 
    0: e3a0c001 mov r12, #1 
    4: e3a02005 mov r2, #5 
    8: e59f1010 ldr r1, [pc, #16] ; 20 <fun+0x20> 
    c: e59f3010 ldr r3, [pc, #16] ; 24 <fun+0x24> 
    10: e581c000 str r12, [r1] 
    14: e5832234 str r2, [r3, #564] ; 0x234 
    18: e5933234 ldr r3, [r3, #564] ; 0x234 
    1c: e12fff1e bx lr 
    20: 22080000 andcs r0, r8, #0 
    24: 20001000 andcs r1, r0, r0 

處理器加載地址0x20001000,在這種情況下,彙編程序選擇了立即0x234添加到,而不是把整個0x200在加載的地址,一個六...沒有不同的成本要麼方式,正如編寫的編譯器不需要對齊加載的值。

現在,如果你是不是需要打一個特定的地址(0x200或一些外設寄存器等),然後簡單地

unsigned int some_value; 
void fun (void) 
{ 
    some_value = 5; 
} 

需要編譯和鏈接它,看看原委:

00000004 <fun>: 
    4: e3a02005 mov r2, #5 
    8: e59f3004 ldr r3, [pc, #4] ; 14 <fun+0x10> 
    c: e5832000 str r2, [r3] 
    10: e12fff1e bx lr 
    14: 20000000 andcs r0, r0, r0 

Disassembly of section .bss: 

20000000 <some_value>: 
20000000: 00000000 andeq r0, r0, r0 

並且代碼現在將數字5存儲在ram中的某個位置(由鏈接器選擇)。

如果你閱讀arm文檔,你會發現它並不總是被支持,在某些內核中它是一個可選功能,這意味着當他們編譯芯片時,他們可以選擇不包含它。如果說實際上這是一個特定的芯片或家庭,你可能會發現他們忘記記錄一個或兩個比特帶地址(0x22000000,0x42000000),但將其存儲在庫中。我看過編譯器不能產生正確的指令,所以我寫了一個很小的兩行彙編函數,我可以抽象所有這樣的訪問,通過它有一個很好的副作用無論如何,強制像你在linux或其他驅動程序中的抽象。允許代碼更加有用,可以將訪問抽象爲軟件模擬,可以將訪問抽象爲邏輯模擬,可以通過mmap進行抽象,可以在內核驅動程序中使用,可以添加用於調試的printf圖層,單個如果你喜歡這種類型的調試,可以設置一個斷點,可以使用兩行asm作爲裸機來實現,或者如果你願意的話,可以使用一個通用的宏/定義來做易失性指針。因人而異。

注意局部變量

void fun (void) 
{ 
    unsigned int some_value; 
    some_value = 5; 
} 

不一定在RAM結束後,他們最好進入堆疊,但如果你優化(推薦在資源匱乏設備,如微控制器,除非MISRA可以得到優化掉或一些其他的要求阻止你使用優化器)。當然,上面的代碼是完全死代碼,導致一個簡單的回報:

00000000 <fun>: 
    0: e12fff1e bx lr 
+0

你也可以創建一個數組,如果你想編譯時間分配(不做運行時分配,這是一個單元沒有任何理由讓你擁有所有內存,只是使用它)應用程序使用一定數量的RAM,如果由於某種原因該塊必須對齊(不知道爲什麼這些設備),那麼只需使用固定地址就像易失性指針一樣,作爲負責任的程序員和軟件工程師,通過做適當的設計避免因爲其他原因而使用內存。 –

+0

但是,即使在斷電後,該值是否仍然存儲? SRAM不是用來代替普通RAM嗎? RAM =無電時丟失數值,SRAM =無電時保留數值? –

+0

@AlexM。不,SRAM在斷電時仍會丟失數據。只要電源供電,SRAM就會將數據保存在其存儲器中,與定期更新的DRAM不同。如果您希望跨電源週期保留值,則需要使用非易失性存儲器,如Flash或EEPROM。 –

0

一邊唸叨bitbanding,我發現這個代碼在Application Note

我複製出來,並編譯它。這應該讓你開始。

#define BITBAND_SRAM_REF 0x20000000 
#define BITBAND_SRAM_BASE 0x22000000 
#define BITBAND_SRAM(a,b) ((BITBAND_SRAM_BASE + (a-BITBAND_SRAM_REF)*32 + (b*4))) // Convert SRAM address 
#define BITBAND_PERI_REF 0x40000000 
#define BITBAND_PERI_BASE 0x42000000 
#define BITBAND_PERI(a,b) ((BITBAND_PERI_BASE + (a-BITBAND_PERI_REF)*32 + (b*4))) // Convert PERI address 
#define MAILBOX   0x20004000 
#define TIMER    0x40004000 // Mailbox bit 0 
#define MBX_B0    *((volatile unsigned int*)(BITBAND_SRAM(MAILBOX,0))) // Mailbox bit 7 
#define MBX_B7    *((volatile unsigned int*)(BITBAND_SRAM(MAILBOX,7))) // Timer bit 0 
#define TIMER_B0   *((volatile unsigned char*)(BITBAND_PERI(TIMER,0))) // Timer bit 7 
#define TIMER_B7   *((volatile unsigned char*)(BITBAND_PERI(TIMER,7))) 

int main(void) 
{ 
    unsigned int temp = 0; 

    MBX_B0 = 1;  // Word write  
    temp = MBX_B7; // Word read  
    TIMER_B0 = temp; // Byte write  
    return TIMER_B7; // Byte read 
} 

可有人請向我解釋,我怎麼能存儲例如在SRAM中的數5,並再看過嗎?

在上面的示例代碼中,temp位於RAM中。

如果你現在不在乎使用bitbanding,只聲明一個變量int x = 5將數字5存儲在RAM中。

+0

謝謝,但有人認爲我不明白我究竟該如何存儲該號碼,我是否將其聲明在您的代碼下?我要更改'temp'嗎?還有一件事是我怎麼讀取變量後,我更新了我的問題,你可能會再看看它 –