寫在前面
- 今天在搞STM32F4時(shí),用到了一部分特殊內(nèi)存——CCM。搜了搜網(wǎng)上沒多少介紹,索性自己查手冊(cè)。
- 某些芯片沒有CCM
基本架構(gòu)
??廢話少說,先看看這塊內(nèi)存特殊在哪里。官方的基本架構(gòu)說明如下: ??The main system consists of 32-bit multilayer AHB bus matrix that interconnects:
- Eight masters:
– Cortex? -M4 with FPU core I-bus, D-bus and S-bus – DMA1 memory bus – DMA2 memory bus – DMA2 peripheral bus – Ethernet DMA bus – USB OTG HS DMA bus - Seven slaves:
– Internal Flash memory ICode bus – Internal Flash memory DCode bus – Main internal SRAM1 (112 KB) – Auxiliary internal SRAM2 (16 KB) – AHB1 peripherals including AHB to APB bridges and APB peripherals – AHB2 peripherals – FSMC
??The bus matrix provides access from a master to a slave, enabling concurrent access and efficient operation even when several high-speed peripherals work simultaneously. The 64-Kbyte CCM (core coupled memory) data RAM is not part of the bus matrix and can be accessed only through the CPU. This architecture is shown in ??其架構(gòu)和之前的STM32F1x區(qū)別還是挺大的。由上可知,CCM共64KB,是直接掛在D-bus上的,除了CPU(即Cortex-M核)之外,誰都無法訪問。此外,由于CCM不屬于BusMatrix的一部分,所有也就不能被其他組件訪問,例如DMA控制器。 ??對(duì)于CCM,CPU能以最大的系統(tǒng)時(shí)鐘和最小的等待時(shí)間從CCM中讀取數(shù)據(jù)或者代碼。官方文檔說明了使用CCM的一些優(yōu)勢(shì):比如將頻繁讀取的數(shù)據(jù)放到CCM,將中斷函數(shù)放到CCM,這都能加快程序的執(zhí)行速度。
如何使用
使用方式一
??知道了這塊特殊內(nèi)存,那么我們?cè)趺磥硎褂盟??常用Keil的人應(yīng)該知道,在其配置中,有如下選項(xiàng): ??在默認(rèn)情況下,其中的IRAM2我們不選中,現(xiàn)在我們就可以選中該部分。這樣,Keil在生產(chǎn)代碼時(shí),就會(huì)自動(dòng)將變量分配到該部分RAM中了。具體的可以打開,Keil生成的.map 文件看看。
Execution Region RW_IRAM2 (Base: 0x10000000, Size: 0x00005ce4, Max: 0x00010000, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x10000000 0x00005ce4 Zero RW 16003 .bss ram2.o
Execution Region RW_IRAM1 (Base: 0x20000000, Size: 0x0001b360, Max: 0x00020000, ABSOLUTE, COMPRESSED[0x000000c8])
Base Addr Size Type Attr Idx E Section Name Object
0x20000000 0x00000001 Data RW 264 .data pbuf.o
0x20000001 0x00000001 Data RW 909 .data api_msg.o
注意:
- 如果僅僅定義幾個(gè)變量,可能Keil不會(huì)將其放到該RAM中。
- 我在用的時(shí)候,沒有選中RAM2,Keil仍然把部分內(nèi)存放到了RAM2中,不知為啥!
??但是,這樣就有一個(gè)問題:由于其只能被內(nèi)核訪問,一旦Keil將例如DMA用的內(nèi)存放到了該部分RAM中,那么DMA將不能工作! 那么怎么使用更合適呢?
使用方式二
??如前所說,直接讓編譯器自動(dòng)分配貌似不太合適,所以我們可以自己指定分配的內(nèi)存。這其中也有兩種方式。 ??第一種依靠分散加載文件(.sct) ,更強(qiáng)大,直接定義一個(gè)文件(例如,名字為 RAM2.c),將所有要放得變量均放到該文件中,然后如下修改分散加載文件。
LR_IROM1 0x0800C000 0x00100000 { ; load region size_region
ER_IROM1 0x0800C000 0x00100000 { ; load address = execution address
*.o (RESET, +First) ; 中斷向量表
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x00020000 { ; RW data
.ANY (+RW +ZI)
}
; 指定使用CCM
RW_IRAM2 0x10000000 0x00010000 {
RAM2.O (RAM2,+RW +ZI)
}
}
??還有一種方式就是直接使用編譯器指令:__attribute__ +at 。在定義變量時(shí),如下即可:
UINT32 EventNum __attribute__((at(0x10000000))) = 0;
??當(dāng)然,這種方式也可以稍微變化一下,使用__attribute__ +section 。給變量指定一個(gè)節(jié)區(qū)名字,然后在分散加載文件中指定節(jié)區(qū)位置。 ??如上處理編譯后,可查看map文件對(duì)應(yīng)部分內(nèi)存中變量的分配了。
關(guān)于系統(tǒng)
??我這搞這部分的時(shí)候,正好用了FreeRTOS。于是就像既然這部分只能給內(nèi)核訪問,為了內(nèi)存的合理利用,能不能直接將這部分內(nèi)存給系統(tǒng),剩下的給不就是想怎么用就怎么用了么?而且分給FreeRTOS 64KB的內(nèi)存正好符合我的設(shè)計(jì)需要! ??了解了上面的分散加載文件后,要將FreeRTOS放到RMA2中就非常簡(jiǎn)單了,根據(jù)使用的FreeRTOS的文件,只需要如下的分散加載文件即可。
RW_IRAM2 0x10000000 0x00010000 {
port.o (+RW +ZI)
queue.o (+RW +ZI)
tasks.o (+RW +ZI)
heap_4.o (+RW +ZI)
; 其他的用到的FreeRTOS的.o文件
}
??這樣就又有一個(gè)問題,如果使用動(dòng)態(tài)申請(qǐng)的內(nèi)存,則內(nèi)存還是在RAM2中,如果傳遞給DMA時(shí),則會(huì)出錯(cuò)!
注意: ??1. FreeRTOS中部分文件只有代碼,沒有數(shù)據(jù)(RW和ZI),例如:list.c,這樣就不能放到上面的分散加載文件中
注意事項(xiàng)
- 需要了解ARM的分散加載文件。
- 需要了解個(gè)別的編譯器指令
參考文檔
- STM32F407 Reference manual
|