如何使用sct文件、icf文件来定位不同的内存存储变量(cortex-m3平台)keil+iar
好久沒寫博客了,快到國慶了,經歷了一些項目和坑,還是要保持記錄的好習慣,好記性不如爛筆頭嘛。
目前使用了cortex-m3內核的兩款單片機:stm32f1和lpc1768的,雖說是cm3內核,但是兩個芯片添加的外設是有區別的,很多外設的使用方式也是各有千秋,st在國內比較火,全國研討會如火如荼,每年都有。lpc1768是屬于NXP半導體,前身是飛利浦半導體,也算是老牌的半導體公司,相比較stm32,國內入門的論壇沒有stm32火爆,但我相信質量過得去。
兩款單片機都是比較老了,stm32f1是2007年發布的,lpc1768是估計2009年左右,具體不清楚,我是看標準庫上是這個日期,因此猜測。
雖然不是老的芯片,但是市場依然有供應。
可以作為arm入門的基礎芯片。
stm32f103zet是512flash,64ksram,而且是連續的sram分布,那么程序上使用基本上不用過多考慮;而lpc1768也是有64ksram的,但是是分為3個區域的,32ksram作為普通的sram,和stm32f1類似,使用無區別,但是另外兩個16kb的內存空間是在另外的地址空間,手冊原文:
The LPC17xx contain a total of 64 kB on-chip static RAM memory. This includes the main 32 kB SRAM, accessible by the CPU and DMA controller on a higher-speed bus, and two additional 16 kB each SRAM blocks situated on a separate slave port on the AHB multilayer matrix.
LPC17xx總共包含64 kB片上靜態RAM存儲器。 其中包括可由高速總線上的CPU和DMA控制器訪問的主32 kB SRAM,以及位于AHB多層矩陣上獨立從端口上的兩個附加16 kB SRAM塊。
總結起來就是,32ksram的起始地址0x1000 0000,大小0x8000=64kb
兩個附加16 kB SRAM塊的起始地址0x2007C000,而且是連續的,下面的計算可見一斑。
hex(0x2007C000+0x8000)= 0x20084000
hex(0x2007C000+0x4000)= 0x20080000
因此在keil設置中,可以設置兩個32kb的內存空間,而且如果使用了分散加載文件,那么兩個附加16 kB內存就可以完全利用起來了,lpc1768這個設計的原因是想兩個內存空間可以再單片機運行的過程中,分別取數據,快加usb和ethernet數據的讀寫,和普通的變量區分開來————論壇大佬解釋的。具體鏈接找不到了。。
如何使用呢?sct文件的使用參考了硬漢論壇的pdf文檔,H7系列的。
這里首先使用stm32來演示下:
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x08000000 0x00080000 { ; load region size_region
ER_IROM1 0x08000000 0x00080000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
.ANY (+XO)
}
RW_IRAM1 0x20000000 0x00008000 { ; RW data
.ANY (+RW +ZI)
}
; RW data - 32KB SRAM
RW_IRAM2 0x20008000 0x00008000 {
*(.RAM_D1)
}
}
我把64kb分成兩個32kb的空間,keil需要設置linker界面,使用自定義的sct文件
ac6.14編譯器實例:
定義全局變量:
__attribute__((section (".RAM_D1"))) uint32_t AXISRAMBuf[10];
__attribute__((section (".RAM_D1"))) uint32_t temp = 0;
下面的語句也是合法的,
uint8_t UART_TX_BUF[10] __attribute__((section(".ARM.__at_0x2000B00A"))); //就是將串口發送的數據定位到RAM中起始地址為0X2000b00A
編譯之后,可以在map文件看到這幾個變量的具體地址
temp 0x20008000 Data 4 main.o(.RAM_D1)
AXISRAMBuf 0x20008004 Data 40 main.o(.RAM_D1)
UART_RX_BUF 0x2000b000 Data 10 main.o(.ARM.__at_0x2000b000)
UART_TX_BUF 0x2000b00a Data 10 main.o(.ARM.__at_0x2000B00A)
那么就是成功的,如果使用AC5編譯器
__attribute__((section (".RAM_D1"))) uint32_t AXISRAMBuf[10];
__attribute__((section (".RAM_D1"))) uint32_t temp = 0;
AXISRAMBuf[0] = 11;
temp= 11;
優化等級-00
AXISRAMBuf 0x20008000 Data 40 main.o(.RAM_D1)
temp 0x20008028 Data 4 main.o(.RAM_D1)
優化等級-03
temp 0x20008000 Data 4 main.o(.RAM_D1)
AXISRAMBuf 0x20008004 Data 40 main.o(.RAM_D1)
優化等級-03
temp只定義,代碼中不試用
AXISRAMBuf 0x20008000 Data 40 main.o(.RAM_D1)
可見,編譯會把代碼中不適用的變量,在linker的時候就,不分配空間了,相當于刪除了這個變量
lpc1768的芯片小技巧:
使用iar編譯器,測試通過,也記錄下:
使用兩個sram的方法參見博客鏈接:
https://blog.csdn.net/liming0931/article/details/108887551
定義變量,int val_addr @0x2007C000;
編譯后map文件如下:
val_addr 0x2007'c000 0x4 Data Gb main.o [1]
成功!
keil平臺下有兩種方法可以將lpc1768的兩個內存使用起來
1、keil選項設置
ac5編譯器定義變量,uint32_t variable2 __attribute__((at(0x2007C42C))); // Place at 0x2007C000(因為lpc1768的庫文件core_cm3.h,不支持ac6,暫時使用ac5)
0x2007C42C這個地址需要查看map文件后在自定義地址,否則就會出現linker警告,比如0x2007C004,
linking...
.KEIL5OUTcheck.axf: Warning: L6918W: Execution region RW_IRAM2 placed at 0x2007c000 needs padding to ensure alignment 4 of main.o(.ARM.__AT_0x2007C004).
為啥呢?
意思是0x2007c000 到0x2007c007的空間沒有使用。定義到0x2007c000鏈接就沒有警告了,因為uart_data_to_linux,uart_data_to_g0這兩個變量占用的空間比較大,linker自動將該變量分配到0x2007c000之后的內存地址中了,但是如果不適用iram2,那么只能分配到iram1中。
2、使用自定義的sct文件
iram2 記得不要打鉤。
然后定義變量:
uint32_t variable2 __attribute__((at(0x2007C050))); // Place at0x2007C050
__attribute__((section(".RAM_D1"))) uint32_t AXISRAMBuf[10];
__attribute__((section(".RAM_D1"))) uint32_t AXISRAMBuf2[10]
map文件如下:具體負
AXISRAMBuf 0x2007c000 Data 40 main.o(.RAM_D1)
AXISRAMBuf2 0x2007c028 Data 40 main.o(.RAM_D1)
variable2 0x2007c050 Data 4 main.o(.ARM.__AT_0x2007C050)
keil的linker模式是優先分配__attribute__((section(".RAM_D1")))這種形式定義的變量,如果使用下面的方式:
uint32_t variable2 __attribute__((at(0x2007C000))); // Place at0x2007C000
__attribute__((section(".RAM_D1"))) uint32_t AXISRAMBuf[10];
__attribute__((section(".RAM_D1"))) uint32_t AXISRAMBuf2[10]
linker報錯,也無法生產map文件
.KEIL5OUTcheck.axf: Error: L6985E: Unable to automatically place AT section main.o(.ARM.__AT_0x2007C000) with required base address 0x2007c000. Please manually place in the scatter file using the --no_autoat option.
--no_autoat具體怎么使用,暫時不了解。
具體的link而使用方法,可以參考arm linker參考文件
總結:
使用__attribute__((at(0x2007C004))); 這種方法需要自己計算內存的地址相對比較麻煩,__attribute__((section(".RAM_D1")))
使用__attribute__((section(".RAM_D1"))) ,省去了手動計算地址的麻煩,相對簡單。ac5,ac6通用的。
總結
以上是生活随笔為你收集整理的如何使用sct文件、icf文件来定位不同的内存存储变量(cortex-m3平台)keil+iar的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: KVM安装、镜像创建(一)
- 下一篇: Unicode字符编码表