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
<span style="color:#000000"><code> PRESERVE8 <span style="color:#880000">//PRESERVE8指定了以下的代码位8字节对齐</span>
THUMB <span style="color:#880000">//THUMB指定了接下来的代码为THUMB指令集</span>
; Vector Table Mapped <span style="color:#000088">to</span> Address <span style="color:#006666">0</span> at Reset
AREA RESET, <span style="color:#4f4f4f">DATA</span>, READONLY <span style="color:#880000">//此语句声明RESET数据段</span>
EXPORT __Vectors <span style="color:#880000">//导出向量表标号,EXPORT作用类似于C语言中的extern</span>
<span style="color:#000088">IMPORT</span> <span style="color:#4f4f4f">|</span>Image$<span style="color:#4f4f4f">$ARM_LIB_STACK</span>$<span style="color:#4f4f4f">$ZI</span>$<span style="color:#4f4f4f">$Limit</span><span style="color:#4f4f4f">|</span></code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
<span style="color:#000000"><code>__Vectors DCD <span style="color:#4f4f4f">|</span>Image$<span style="color:#4f4f4f">$ARM_LIB_STACK</span>$<span style="color:#4f4f4f">$ZI</span>$<span style="color:#4f4f4f">$Limit</span><span style="color:#4f4f4f">|</span> ; Top of <span style="color:#4f4f4f">Stack</span>
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler
DCD HardFault_Handler
DCD MemManage_Handler
DCD BusFault_Handler
DCD UsageFault_Handler
</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
<span style="color:#000000"><code><span style="color:#880000">; Reset Handler</span>
Reset_Handler
PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR <span style="color:#4f4f4f">R0</span>, =SystemInit //系统初始化
BLX <span style="color:#4f4f4f">R0</span>
LDR <span style="color:#4f4f4f">R0</span>, =__main
BX <span style="color:#4f4f4f">R0</span>
ENDP</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
QN908X.scf
<span style="color:#000000"><code>LR_m_text m_interrupts_start m_text_start+m_text_size-m_interrupts_start <span style="color:#880000"> //加载区 名称 起始地址 地址范围 </span>
{ ; <span style="color:#4f4f4f">load</span> region size_region
VECTOR_ROM m_interrupts_start m_interrupts_size<span style="color:#880000"> //执行区名称 起始地址 地址范围 </span>
{ ; <span style="color:#4f4f4f">load</span> address = execution address<span style="color:#880000"> //执行域和加载域一致</span>
* (RESET,+FIRST)<span style="color:#880000"> //将RESET代码放在区首,最开始执行 FIRST属性符表示放在最开始 </span>
}
ER_m_text m_text_start m_text_size { ; <span style="color:#4f4f4f">load</span> address = execution addres<span style="color:#880000">s//执行域和加载域一致</span>
* (InRoot$$Sections)
.ANY (+RO)<span style="color:#880000"> //只读代码和数据放在此区域 </span>
}
<span style="color:#880000">#if (defined(__ram_vector_table__))</span>
VECTOR_RAM m_interrupts_ram_start <span style="color:#009900">EMPTY</span> m_interrupts_ram_size {
}
<span style="color:#880000">#else</span>
VECTOR_RAM m_interrupts_start <span style="color:#009900">EMPTY</span> <span style="color:#006666">0</span> {
}
<span style="color:#880000">#endif</span>
RW_m_data m_data_start m_data_size-Stack_Size-Heap_Size { ; RW data
.ANY (+RW +ZI) <span style="color:#880000"> //RW,ZI 放入此处 </span>
*(in_ram)
}
ARM_LIB_HEAP +<span style="color:#006666">0</span> <span style="color:#009900">EMPTY</span> Heap_Size { ; Heap region growing up <span style="color:#880000"> //+0其实就是从前面一个域的末地址开始</span>
}
;ARM_LIB_STACK m_data_start+m_data_size <span style="color:#009900">EMPTY</span> -Stack_Size { ; Stack region growing down<span style="color:#880000"> //-Stack_Size 栈由高地址向低地址</span>
ARM_LIB_STACK +<span style="color:#006666">0</span> ALIGN <span style="color:#006666">8</span> <span style="color:#009900">EMPTY</span> Stack_Size { ; Stack region growing up
}
}</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
.map文件
<span style="color:#000000"><code>==============================================================================
Memory Map of the image
Image Entry point : <span style="color:#006666">0x00000111</span>
Load Region LR_m_text (Base: <span style="color:#006666">0x00000000</span>, Size: <span style="color:#006666">0x00004ba0</span>, Max: <span style="color:#006666">0x0007d800</span>, ABSOLUTE)
Execution Region VECTOR_ROM (Base: <span style="color:#006666">0x00000000</span>, Size: <span style="color:#006666">0x00000110</span>, Max: <span style="color:#006666">0x00000110</span>, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
<span style="color:#006666">0x00000000</span> <span style="color:#006666">0x00000110</span> Data RO <span style="color:#006666">4</span> RESET startup_qn908x<span style="color:#009900">.o</span>
Execution Region ER_m_text (Base: <span style="color:#006666">0x00000110</span>, Size: <span style="color:#006666">0x000049ec</span>, Max: <span style="color:#006666">0x0007d6f0</span>, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
<span style="color:#006666">0x00000110</span> <span style="color:#006666">0x00000000</span> Code RO <span style="color:#006666">1650</span> * <span style="color:#009900">.ARM</span><span style="color:#009900">.Collect</span>$$$$<span style="color:#006666">00000000</span> mc_w<span style="color:#009900">.l</span>(entry<span style="color:#009900">.o</span>)
<span style="color:#006666">0x00000110</span> <span style="color:#006666">0x00000004</span> Code RO <span style="color:#006666">1782</span> <span style="color:#009900">.ARM</span><span style="color:#009900">.Collect</span>$$$$<span style="color:#006666">00000003</span> mc_w<span style="color:#009900">.l</span>(entry4<span style="color:#009900">.o</span>)
<span style="color:#006666">0x00000114</span> <span style="color:#006666">0x00000004</span> Code RO <span style="color:#006666">1785</span> <span style="color:#009900">.ARM</span><span style="color:#009900">.Collect</span>$$$$<span style="color:#006666">00000004</span> mc_w<span style="color:#009900">.l</span>(entry5<span style="color:#009900">.o</span>)
<span style="color:#006666">0x00000118</span> <span style="color:#006666">0x00000000</span> Code RO <span style="color:#006666">1787</span> <span style="color:#009900">.ARM</span><span style="color:#009900">.Collect</span>$$$$<span style="color:#006666">00000008</span> mc_w<span style="color:#009900">.l</span>(entry7b<span style="color:#009900">.o</span>)
<span style="color:#006666">0x00000118</span> <span style="color:#006666">0x00000000</span> Code RO <span style="color:#006666">1789</span> <span style="color:#009900">.ARM</span><span style="color:#009900">.Collect</span>$$$$<span style="color:#006666">0000000</span>A mc_w<span style="color:#009900">.l</span>(entry8b<span style="color:#009900">.o</span>)
<span style="color:#006666">0x00000118</span> <span style="color:#006666">0x00000008</span> Code RO <span style="color:#006666">1790</span> <span style="color:#009900">.ARM</span><span style="color:#009900">.Collect</span>$$$$<span style="color:#006666">0000000</span>B mc_w<span style="color:#009900">.l</span>(entry9a<span style="color:#009900">.o</span>)
<span style="color:#006666">0x00000120</span> <span style="color:#006666">0x00000000</span> Code RO <span style="color:#006666">1792</span> <span style="color:#009900">.ARM</span><span style="color:#009900">.Collect</span>$$$$<span style="color:#006666">0000000</span>D mc_w<span style="color:#009900">.l</span>(entry10a<span style="color:#009900">.o</span>)
<span style="color:#006666">0x00000120</span> <span style="color:#006666">0x00000000</span> Code RO <span style="color:#006666">1794</span> <span style="color:#009900">.ARM</span><span style="color:#009900">.Collect</span>$$$$<span style="color:#006666">0000000</span>F mc_w<span style="color:#009900">.l</span>(entry11a<span style="color:#009900">.o</span>)
<span style="color:#006666">0x00000120</span> <span style="color:#006666">0x00000004</span> Code RO <span style="color:#006666">1783</span> <span style="color:#009900">.ARM</span><span style="color:#009900">.Collect</span>$$$$<span style="color:#006666">00002714</span> mc_w<span style="color:#009900">.l</span>(entry4<span style="color:#009900">.o</span>)
<span style="color:#006666">0x00000124</span> <span style="color:#006666">0x00000180</span> Code RO <span style="color:#006666">5</span> <span style="color:#009900">.text</span> startup_qn908x<span style="color:#009900">.o</span>
......
Execution Region VECTOR_RAM (Base: <span style="color:#006666">0x04000400</span>, Size: <span style="color:#006666">0x00000110</span>, Max: <span style="color:#006666">0x00000110</span>, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
<span style="color:#006666">0x04000400</span> <span style="color:#006666">0x00000110</span> Zero RW <span style="color:#006666">1</span> VECTOR_RAM<span style="color:#009900">.bss</span> anon$$obj<span style="color:#009900">.o</span>
Execution Region RW_m_data (Base: <span style="color:#006666">0x04000510</span>, Size: <span style="color:#006666">0x000001d0</span>, Max: <span style="color:#006666">0x0001f2f0</span>, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
<span style="color:#006666">0x04000510</span> <span style="color:#006666">0x00000038</span> Data RW <span style="color:#006666">334</span> <span style="color:#009900">.data</span> multitimer<span style="color:#009900">.o</span>
<span style="color:#006666">0x04000548</span> <span style="color:#006666">0x00000008</span> Data RW <span style="color:#006666">506</span> <span style="color:#009900">.data</span> fsl_debug_console<span style="color:#009900">.o</span>
<span style="color:#006666">0x04000550</span> <span style="color:#006666">0x00000048</span> Data RW <span style="color:#006666">615</span> <span style="color:#009900">.data</span> pin_mux<span style="color:#009900">.o</span>
<span style="color:#006666">0x04000598</span> <span style="color:#006666">0x00000001</span> Data RW <span style="color:#006666">1129</span> <span style="color:#009900">.data</span> fsl_clock<span style="color:#009900">.o</span>
<span style="color:#006666">0x04000599</span> <span style="color:#006666">0x00000003</span> PAD
<span style="color:#006666">0x0400059c</span> <span style="color:#006666">0x0000000c</span> Data RW <span style="color:#006666">1530</span> <span style="color:#009900">.data</span> fsl_qn_qdec_ex_function<span style="color:#009900">.o</span>
<span style="color:#006666">0x040005a8</span> <span style="color:#006666">0x00000004</span> Data RW <span style="color:#006666">1808</span> <span style="color:#009900">.data</span> mc_w<span style="color:#009900">.l</span>(mvars<span style="color:#009900">.o</span>)
<span style="color:#006666">0x040005ac</span> <span style="color:#006666">0x00000004</span> Data RW <span style="color:#006666">1813</span> <span style="color:#009900">.data</span> mc_w<span style="color:#009900">.l</span>(errno<span style="color:#009900">.o</span>)
<span style="color:#006666">0x040005b0</span> <span style="color:#006666">0x00000100</span> Zero RW <span style="color:#006666">114</span> <span style="color:#009900">.bss</span> unity<span style="color:#009900">.o</span>
<span style="color:#006666">0x040006b0</span> <span style="color:#006666">0x00000010</span> Zero RW <span style="color:#006666">505</span> <span style="color:#009900">.bss</span> fsl_debug_console<span style="color:#009900">.o</span>
<span style="color:#006666">0x040006c0</span> <span style="color:#006666">0x00000020</span> Zero RW <span style="color:#006666">889</span> <span style="color:#009900">.bss</span> fsl_flexcomm<span style="color:#009900">.o</span>
Execution Region ARM_LIB_HEAP (Base: <span style="color:#006666">0x040006e0</span>, Size: <span style="color:#006666">0x00000000</span>, Max: <span style="color:#006666">0x00000000</span>, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
<span style="color:#006666">0x040006e0</span> <span style="color:#006666">0x00000000</span> Zero RW <span style="color:#006666">2</span> ARM_LIB_HEAP<span style="color:#009900">.bss</span> anon$$obj<span style="color:#009900">.o</span>
Execution Region ARM_LIB_STACK (Base: <span style="color:#006666">0x040006e0</span>, Size: <span style="color:#006666">0x00000800</span>, Max: <span style="color:#006666">0x00000800</span>, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
<span style="color:#006666">0x040006e0</span> <span style="color:#006666">0x00000800</span> Zero RW <span style="color:#006666">3</span> ARM_LIB_STACK<span style="color:#009900">.bss</span> anon$$obj<span style="color:#009900">.o</span></code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
你可以对比的看.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域后面初始化栈。