CMSIS 到底是什麼
CMSIS的意思是Cortex Micro-controller Software Interface Standard,微控制器軟件接口標準, 是 Cortex-M 處理器系列的與供應商無關的硬件抽象層。CMSIS 可實現與處理器和外設之間的一致且簡單的軟件接口,從而簡化軟件的重用,縮短微控制器開發人員新手的學習過程,並縮短新設備的上市時間。
如何使用CMSIS,需要哪些文件?
以Freescale Kinetis L系列舉例。
獨立於編譯器的文件:
● Cortex-M3內核及其設備文件(core_cm3.h + core_cm3.c)
─ 訪問Cortex-M0內核及其設備:NVIC等
─ 訪問Cortex-M0的CPU寄存器和內核外設的函數
● 微控制器專用頭文件(device.h) - MKL25Z4.h
─ 指定中斷號碼(與啓動文件一致)
─ 外設寄存器定義(寄存器的基地址和佈局)
─ 控制微控制器其他特有的功能的函數(可選)
● 微控制器專用系統文件( system_device.c) – system_MKL25Z4.h + system_MKL25Z4 .c
─ 函數SystemInit,用來初始化微控制器
–函數 void SystemCoreClockUpdate (void); 用於獲取內核時鐘頻率
─SystemCoreClock,該值代表系統時鐘頻率
─ 微控制器的其他功能(可選)
● 編譯器啓動代碼(彙編或者C)( startup_device.s) - startup_MKL25Z4.s for Keil
─ 微控制器專用的中斷處理程序列表(與頭文件一致)
以QN9080的啓動文件進行ARM啓動流程講解
startup_QN908X.s
PRESERVE8 //PRESERVE8指定了以下的代碼位8字節對齊
THUMB //THUMB指定了接下來的代碼爲THUMB指令集
; Vector Table Mapped to Address 0 at Reset
AREA RESET, DATA, READONLY //此語句聲明RESET數據段
EXPORT __Vectors //導出向量表標號,EXPORT作用類似於C語言中的extern
IMPORT |Image$$ARM_LIB_STACK$$ZI$$Limit|
__Vectors DCD |Image$$ARM_LIB_STACK$$ZI$$Limit| ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler
DCD HardFault_Handler
DCD MemManage_Handler
DCD BusFault_Handler
DCD UsageFault_Handler
; Reset Handler
Reset_Handler
PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit //系統初始化
BLX R0
LDR R0, =__main
BX R0
ENDP
QN908X.scf
LR_m_text m_interrupts_start m_text_start+m_text_size-m_interrupts_start //加載區 名稱 起始地址 地址範圍
{ ; load region size_region
VECTOR_ROM m_interrupts_start m_interrupts_size //執行區名稱 起始地址 地址範圍
{ ; load address = execution address //執行域和加載域一致
* (RESET,+FIRST) //將RESET代碼放在區首,最開始執行 FIRST屬性符表示放在最開始
}
ER_m_text m_text_start m_text_size { ; load address = execution address//執行域和加載域一致
* (InRoot$$Sections)
.ANY (+RO) //只讀代碼和數據放在此區域
}
#if (defined(__ram_vector_table__))
VECTOR_RAM m_interrupts_ram_start EMPTY m_interrupts_ram_size {
}
#else
VECTOR_RAM m_interrupts_start EMPTY 0 {
}
#endif
RW_m_data m_data_start m_data_size-Stack_Size-Heap_Size { ; RW data
.ANY (+RW +ZI) //RW,ZI 放入此處
*(in_ram)
}
ARM_LIB_HEAP +0 EMPTY Heap_Size { ; Heap region growing up //+0其實就是從前面一個域的末地址開始
}
;ARM_LIB_STACK m_data_start+m_data_size EMPTY -Stack_Size { ; Stack region growing down //-Stack_Size 棧由高地址向低地址
ARM_LIB_STACK +0 ALIGN 8 EMPTY Stack_Size { ; Stack region growing up
}
}
.map文件
==============================================================================
Memory Map of the image
Image Entry point : 0x00000111
Load Region LR_m_text (Base: 0x00000000, Size: 0x00004ba0, Max: 0x0007d800, ABSOLUTE)
Execution Region VECTOR_ROM (Base: 0x00000000, Size: 0x00000110, Max: 0x00000110, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x00000000 0x00000110 Data RO 4 RESET startup_qn908x.o
Execution Region ER_m_text (Base: 0x00000110, Size: 0x000049ec, Max: 0x0007d6f0, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x00000110 0x00000000 Code RO 1650 * .ARM.Collect$$$$00000000 mc_w.l(entry.o)
0x00000110 0x00000004 Code RO 1782 .ARM.Collect$$$$00000003 mc_w.l(entry4.o)
0x00000114 0x00000004 Code RO 1785 .ARM.Collect$$$$00000004 mc_w.l(entry5.o)
0x00000118 0x00000000 Code RO 1787 .ARM.Collect$$$$00000008 mc_w.l(entry7b.o)
0x00000118 0x00000000 Code RO 1789 .ARM.Collect$$$$0000000A mc_w.l(entry8b.o)
0x00000118 0x00000008 Code RO 1790 .ARM.Collect$$$$0000000B mc_w.l(entry9a.o)
0x00000120 0x00000000 Code RO 1792 .ARM.Collect$$$$0000000D mc_w.l(entry10a.o)
0x00000120 0x00000000 Code RO 1794 .ARM.Collect$$$$0000000F mc_w.l(entry11a.o)
0x00000120 0x00000004 Code RO 1783 .ARM.Collect$$$$00002714 mc_w.l(entry4.o)
0x00000124 0x00000180 Code RO 5 .text startup_qn908x.o
......
Execution Region VECTOR_RAM (Base: 0x04000400, Size: 0x00000110, Max: 0x00000110, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x04000400 0x00000110 Zero RW 1 VECTOR_RAM.bss anon$$obj.o
Execution Region RW_m_data (Base: 0x04000510, Size: 0x000001d0, Max: 0x0001f2f0, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x04000510 0x00000038 Data RW 334 .data multitimer.o
0x04000548 0x00000008 Data RW 506 .data fsl_debug_console.o
0x04000550 0x00000048 Data RW 615 .data pin_mux.o
0x04000598 0x00000001 Data RW 1129 .data fsl_clock.o
0x04000599 0x00000003 PAD
0x0400059c 0x0000000c Data RW 1530 .data fsl_qn_qdec_ex_function.o
0x040005a8 0x00000004 Data RW 1808 .data mc_w.l(mvars.o)
0x040005ac 0x00000004 Data RW 1813 .data mc_w.l(errno.o)
0x040005b0 0x00000100 Zero RW 114 .bss unity.o
0x040006b0 0x00000010 Zero RW 505 .bss fsl_debug_console.o
0x040006c0 0x00000020 Zero RW 889 .bss fsl_flexcomm.o
Execution Region ARM_LIB_HEAP (Base: 0x040006e0, Size: 0x00000000, Max: 0x00000000, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x040006e0 0x00000000 Zero RW 2 ARM_LIB_HEAP.bss anon$$obj.o
Execution Region ARM_LIB_STACK (Base: 0x040006e0, Size: 0x00000800, Max: 0x00000800, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x040006e0 0x00000800 Zero RW 3 ARM_LIB_STACK.bss anon$$obj.o
你可以對比的看.scf 和.map文件,.map文件就是依據.scf文件來進行加載域和執行域的確定的。
我們可以看到VECTOR_ROM和ER_m_text的兩個加載域和執行域是一致的。
這個圖是我網上找的,具體地址界限並不和上面的程序一致。
下面我把具體的啓動流程列出來:
復位狀態後,CM4的第一件事就是讀取下列兩個 32位整數的值:
(1)從地址0x0000,0000處取出 MSP 的初始值。
(2)從地址0x0000,0004處取出 PC的初始值——這個值是復位向量,LSB 必須是1 。 然後從這個值所對應的地址處取指。
注意,這與傳統的ARM 架構不同——其實也和絕大多數的其它單片機不同。傳統的RM 架構總是從 0 地址開始執行第一條指令。它們的 0 地址處總是一條跳轉指令。在 CM3中,0 地址處提供 MSP 的初始值,然後就是向量表(向量表在以後還可以被移至其它位置)。
CM3上電後的向量表在復位函數裏做一些系統的初始化: MSP賦值,SystemInit
arm的啓動代碼一般是用匯編寫的,在堆棧建立以後纔可以運行C代碼,因爲C函數調用需要把參數,函數返回地址入棧,堆棧沒有建立是不能運行C代碼的。
這裏的SystemInit雖然在.c文件裏,但內部代碼全是對寄存器的操作,本身也沒有參數和返回值,所有編譯出來全是代碼段,沒有變量什麼的。所以不會因爲堆棧還沒有建立就不能執行。然後調用系統函數__main(); (IAR跳轉到__iar_program_start)
_main 直接跳轉到 __scatterload,__scatterload 執行代碼和數據複製以及 ZI 數據的清零。根據分散加載文件,拷貝RW數據到RAM,在RAM空間裏建立ZI的數據空間,建立運行時的映像存儲器映射.
然後跳轉到 __rt_entry(運行時的入口)則負責初始化 C 庫。還設置應用程序的棧和堆,初始化庫函數及其靜態數據。
這時應用程序的堆棧建立了,跳轉到main()函數,運行用戶代碼。
上面startup中的|Image$$ARM_LIB_STACK$$ZI$$Limit| 什麼意思???
__Vectors 第一個DCD就是 |Image$$ARM_LIB_STACK$$ZI$$Limit|
這是什麼意思呢?這時候可以求助KEIL的Help工具。
在Linker User Guide的7.1.4中講解了如何在分散加載文件scatter中指定棧和堆。
當你在分散加載文件中定義了兩個自定義的執行域ARM_LIB_HEAP和ARM_LIB_STACK,這會引起ARM的library去用 |Image$$ARM_LIB_STACK$$ZI$$Limit|的值來執行__user_setup_stackheap()函數。
|Image$$ARM_LIB_STACK$$ZI$$Limit|
的意思是Address of the byte beyond the end of the ZI output section in the execution region.
在執行域的ZI域後面初始化棧。