我最近已經開始在STM32F4核板上編程。我剛纔發現閃存編程只能在有限的時間內完成(儘管這不是少數,但是它是一個評估板,它將被反覆編程以開發不同的項目)。之後,我讀了一些地方,可以直接編程到RAM而不是閃存,但找不到任何有關它的技術信息。從STM32的RAM執行代碼
有誰知道如何修改鏈接器/ makefile來編譯和鏈接要從RAM的起始地址執行的程序,而不是閃存?
PS:我用生成的代碼由STM32CubeMX對系統工作臺和腳本生成的Makefile項目
我最近已經開始在STM32F4核板上編程。我剛纔發現閃存編程只能在有限的時間內完成(儘管這不是少數,但是它是一個評估板,它將被反覆編程以開發不同的項目)。之後,我讀了一些地方,可以直接編程到RAM而不是閃存,但找不到任何有關它的技術信息。從STM32的RAM執行代碼
有誰知道如何修改鏈接器/ makefile來編譯和鏈接要從RAM的起始地址執行的程序,而不是閃存?
PS:我用生成的代碼由STM32CubeMX對系統工作臺和腳本生成的Makefile項目
首先的 - 不考慮節約閃光燈太多。當我開始使用微控制器時,我的計劃和你一樣,但後來得出結論,它根本沒有意義。一個STM32F4芯片的例子有一個閃存,保證最少 10000個寫/擦除週期。你將不得不每天編程你的董事會14次,每一天連續兩年達到這個價值。即使到了它,也不是說閃光燈立即停止工作。最有可能的是,您不應該指望在保證的20年內保留Flash內容。考慮到耐用性和通常使用週期,所有這些努力都是不值得的(平均而言,您的主板每天可能會看到幾次寫入/擦除週期,而且無論如何,您可能幾年後都不會玩這個遊戲)。特別是如果我們談論廉價的電路板。
TL; DR:只是不要嘗試保存閃存。這是不值得所有的麻煩。
如果你真的想從RAM 執行代碼和不會寫閃存可言,只記得這是僅可能與調試器。否則,你必須寫你的代碼到閃存,用一個小程序將它複製到RAM然後從那裏執行 - 這完全沒有意義,因爲你最初的想法是保存閃存。無論如何 - 如果你想這樣做,這很簡單,你所要做的就是修改鏈接腳本。首先從MEMORY
部分完全刪除「ROM」(或者可能是「flash」或者類似的)內存塊。現在用RAM內存塊替換已刪除內存的所有用途,所以你應該用「ram」替換所有「ROM」的出現(或者用「sram」或者那樣的「flash」替換掉)。在這個階段它應該實際上工作。你應該做的最後一件事是完全刪除代碼和功能來執行.data
節初始化 - 這將需要修改鏈接描述文件(確保本節的LMA與它的VMA相同),並將初始化代碼從Reset處理程序。
請注意,此過程工作,你應該:
對於您的Nucleo板,不幸的是第一個選項不可用,因爲BOOT1引腳(在本例中應該是高電平)短接到GND。
但是再次 - 只是不這樣做,這是不值得的麻煩。
cortex-m使用向量表,與全尺寸的arm不同,所以入口點是錯誤的,調試器必須進入復位或移除向量表,無論哪種方式都必須替換堆棧指針的初始化。 –
@old_timer - 您在評論中提出的所有問題根本無關緊要,因爲您可以調試程序(並且 - 在這種情況下 - 應該!)隨心所欲地執行任何操作。調試器可以調整PC以在任何你喜歡的地方啓動。它也可以調整堆棧指針。如果您想從RAM運行代碼,那麼使用STM32,您應該相應地設置BOOTx引腳,這隻會解決您提到的所有問題。 –
你在哪裏提到了bootx引腳?他們在覈板上發生了什麼? –
如果你最近開始使用它,那麼你需要很長時間纔會出現閃光。您可能會遇到驅動器完全錯誤,只需拔下插頭並重新插入電路板即可。我已經有這些東西多年了,還沒有磨損過閃存。不要說它不能做,它可以但你不可能在那裏,除非你寫了一個閃存甩掉程序,它穿着它。你需要openocd(或者其他一些調試器,也許你的IDE提供了這個功能,我不使用那些不能幫助的)。 openocd和gnu工具是微不足道的,所以要通過這個來解釋。
從正確的目錄,或從OpenOCD的
openocd -f stlink-v2-1.cfg -f stm32f4x.cfg
複製這些文件(一個或兩個可能依賴其他文件它們包括,可以拉那些或不惜一切代價)。
應該是這樣的結束,而不是退回到命令行
Info : stm32f4x.cpu: hardware has 6 breakpoints, 4 watchpoints
在另一個窗口
telnet localhost 4444
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
>
在該窗口中,你可以暫停處理器
> halt
stm32f4x.cpu: target state: halted
target halted due to debug-request, current mode: Thread
xPSR: 0x61000000 pc: 0x080000b2 msp: 0x20000ff0
>
全尺寸手臂處理器您的切入點是一條指令,您只需 開始執行。皮層-m使用矢量表,你不能在那裏分支。
.thumb_func
.global _start
_start:
stacktop: .word 0x20001000
.word reset
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.thumb_func
reset:
bl notmain
b hang
.thumb_func
hang: b .
理論上你可以跳轉到復位處理程序的地址,但鏈接腳本會想,在閃光燈,取決於什麼位置將無法正常工作。如果你依靠向量表來做到這一點,你的堆棧指針可能不會被設置。因此,而不是像這樣的工作,一個完整的示例的一部分
sram.s
.cpu cortex-m0
.thumb
.thumb_func
.global _start
_start:
ldr r0,stacktop
mov sp,r0
bl notmain
b .
.align
stacktop: .word 0x20001000
.thumb_func
.globl PUT32
PUT32:
str r1,[r0]
bx lr
.thumb_func
.globl GET32
GET32:
ldr r0,[r0]
bx lr
notmain.c
void PUT32 (unsigned int, unsigned int);
unsigned int GET32 (unsigned int);
int notmain (void)
{
unsigned int ra;
ra=GET32(0x20000400);
PUT32(0x20000404,ra);
PUT32(0x20000400,ra+1);
return(0);
}
sram.ld
MEMORY
{
rom : ORIGIN = 0x08000000, LENGTH = 0x1000
ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > ram
.rodata : { *(.rodata*) } > ram
.bss : { *(.bss*) } > ram
}
基本上取代ROM與RAM參考。 (如果gnu的連接腳本可能比這個更復雜,但是這可以正常工作,可以根據需要在這裏添加.data)。
arm-none-eabi-as --warn --fatal-warnings -mcpu=cortex-m0 flash.s -o flash.o
arm-none-eabi-gcc -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding -mcpu=cortex-m0 -mthumb -c notmain.c -o notmain.o
arm-none-eabi-ld -o notmain.flash.elf -T flash.ld flash.o notmain.o
arm-none-eabi-objdump -D notmain.flash.elf > notmain.flash.list
arm-none-eabi-objcopy notmain.flash.elf notmain.flash.bin -O binary
arm-none-eabi-as --warn --fatal-warnings -mcpu=cortex-m0 sram.s -o sram.o
arm-none-eabi-ld -o notmain.sram.elf -T sram.ld sram.o notmain.o
arm-none-eabi-objdump -D notmain.sram.elf > notmain.sram.list
arm-none-eabi-objcopy notmain.sram.elf notmain.sram.hex -O ihex
arm-none-eabi-objcopy notmain.sram.elf notmain.sram.bin -O binary
我構建了一個flash版本和一個sram版本的程序。
所以現在我們有我們的遠程登錄到OpenOCD的服務器,處理器被暫停,讓我們看看一個內存位置和改變它
> mdw 0x20000400
0x20000400: 7d7d5889
> mww 0x20000400 0x12345678
> mdw 0x20000400
0x20000400: 12345678
並運行我們新的基於SRAM的程序
> load_image /path/to/notmain.sram.elf
64 bytes written at address 0x20000000
downloaded 64 bytes in 0.008047s (7.767 KiB/s)
> resume 0x20000001
讓它運行,腳本速度可能仍然很慢,但肯定花時間鍵入停止命令是很多的。
> halt
stm32f4x.cpu: target state: halted
target halted due to debug-request, current mode: Thread
xPSR: 0x41000000 pc: 0x20000008 msp: 0x20001000
> mdw 0x20000400 10
0x20000400: 12345679 12345678 ce879a24 fc4ba5c7 997e5367 9db9a851 40d5083f fbfbcff8
0x20000420: 035dce6b 65a7f13c
>
使程序運行,程序讀取0x20000400保存到0x20000404增量和保存,爲0x20000400和它做了這一切。
> load_image /path/to/notmain.sram.elf
64 bytes written at address 0x20000000
downloaded 64 bytes in 0.008016s (7.797 KiB/s)
> resume 0x20000000
> halt
stm32f4x.cpu: target state: halted
target halted due to debug-request, current mode: Thread
xPSR: 0x41000000 pc: 0x20000008 msp: 0x20001000
> mdw 0x20000400 10
0x20000400: 1234567a 12345679 ce879a24 fc4ba5c7 997e5367 9db9a851 40d5083f fbfbcff8
0x20000420: 035dce6b 65a7f13c
>
所以我們沒有需要或與一個起始地址,你用BX這樣做,他們必須只推地址正確插入到PC,和/或做正確的事情對我們來說。
如果你只是修改你的鏈接腳本來替換RAM的RAM。
20000000 <_start>:
20000000: 20001000
20000004: 20000041
20000008: 20000047
2000000c: 20000047
20000010: 20000047
20000014: 20000047
20000018: 20000047
2000001c: 20000047
20000020: 20000047
20000024: 20000047
20000028: 20000047
2000002c: 20000047
20000030: 20000047
20000034: 20000047
20000038: 20000047
2000003c: 20000047
20000040 <reset>:
20000040: f000 f806 bl 20000050 <notmain>
20000044: e7ff b.n 20000046 <hang>
您可以使用0x20000041地址作爲您的入口點(恢復0x20000041),但您必須先處理堆棧指針。
通過做這樣的事情
> reg sp 0x20001000
sp (/32): 0x20001000
> reg sp
sp (/32): 0x20001000
> resume 0x20000041
注意,在論文的RAM比ROM和犯規需要等待狀態,你提高時鐘頻率,所以如果你這樣做增加在RAM中的時鐘頻率和調試更快只,如果您還沒有記住設置閃存等待狀態,則切換到閃存時可能會失敗......除此之外,如果您需要,可以整天在內存中開發程序的空間大大減少。
一個很好的功能是,您可以繼續停止和重新加載。我不知道在這個設備/調試器上,如果你打開緩存(一些cortex-m4s有緩存,如果不是全部的話),你必須小心確保當你改變程序時關閉。寫入內存是一個數據操作,取指令是指令取指操作,如果你在0x20000100執行一些指令並將其緩存到I緩存中,它可以落在指令緩存中。那麼你停止使用調試器,然後編寫一個新程序,包括緩存中的地址(0x20000100),當你運行它時,I cache沒有被刷新,所以你將運行緩存中的先前程序和數據中的新程序的混合充其量只是一場災難。因此,無論是以這種方式運行時都不要打開緩存,或想出解決方案(在停止程序之前清除緩存,使用重置按鈕在運行之間重置處理器,重新啓動等)。
你確定只有thumb2處理器上的''andcs'代碼? – EOF
只有thumb2沒有這樣的事情。 thumb2只是拇指的擴展。這就是反彙編器試圖從這些32位值中得出的值,它們是地址。 –
更大的問題是您希望代碼如何進入內存。你必須有一些連接到另一個設備,在重置後提供代碼(或者從閃存加載代碼到RAM中,但是這樣做的目的是失敗的[儘管你可以通過壓縮代碼在閃存中減少閃存寫入])。 – EOF
閃存編程可能有數千個,如果不是數萬個,你有沒有打過呢? –
除了@FreddieChopin的出色答案之外,還有兩點是關於在STM32上從RAM執行的; 1)對於大多數部件來說,RAM的尺寸比閃光燈大得多*,所以你會限制你的應用尺寸。 2)當從閃存運行時,讀/寫數據和指令訪問位於不同的總線上,並且閃存具有*加速器*,允許完整的1.25DMIPS/MHz的性能表現。從ram運行導致數據和指令訪問的總線爭用,並大大降低了執行速度。 – Clifford