看来军爷这几天被检查逮到了……
军爷先休息几天吧,也等等大家
解决链接时候的六个警告:
1、分散加载文件中的四个警告
需要在分散加载文件中,将空的区域使用EMPTY属性标识,说明这个空间是预留的。这样编译器就不会警告了
EMPTY 属性,i就是告诉链接器这是我要保留一个空白内存块,你别管了。修改后的sct文件如下:
LOAD_INTERFLASHROM 0x08000000 0x00100000 { ; load region size_region
EXEC_INTERROM 0x08000000 0x00100000 { ; load address = execution address
* (.vector,+First) ; 1024k
*(InRoot$$Sections)
.ANY (+RO)
}
EXEC_VECTORRAM 0x20000000 EMPTY 0x00000400 { ; vector table region in ram
} ; 1k
EXEC_BSSDATARAM 0x20000400 0x00001c00 { ; zi and rw data region in ram
.ANY (+RW +ZI)
} ; 7k
EXEC_SYSTEMRAM 0x20002000 EMPTY 0x00018000 { ; ut/kernel management region
} ; 100k
EXEC_USERRAM 0x2001b000 EMPTY 0x00001000 { ; user manual region in ram
} ; 4k
EXEC_STACKRAM 0x2001c000 EMPTY 0x00000000 { ; default stack top
} ; 0k
ARM_LIB_HEAP 0x2001A000 EMPTY 0x500 ; 这是为了使用printf之类的系统库设置的
{
}
ARM_LIB_STACK 0x2001A500 EMPTY 0x500
{
}
} ; sum: 112k
2、解决链接时候的警告
警告1、.\out\kernel-rom.axf: Warning: L6306W: '~PRES8 (The user did not require code to preserve 8-byte data objects)' section knl_dispatch.o(.text) should not use the address of 'REQ8 (Code was permitted to depend on the 8-byte aligment of 8-byte data items)' function knl_power_low.
警告2、.\out\kernel-rom.axf: Warning: L6306W: '~PRES8 (The user did not require code to preserve 8-byte data objects)' section knl_int.o(.text) should not use the address of 'REQ8 (Code was permitted to depend on the 8-byte aligment of 8-byte data items)' function knl_timer_handler.
解决这两个警告,参考http://www.keil.com/support/docs/3268.htm
注意这个即可:All C code generated by the RealView compiler assumes that stack allocation is aligned on 8-byte boundaries. You must ensure that the assembler interrupt handler has an 8-byte aligned stack by specifying the PRESERVE8 directive at the beginning of your assembly file.
于是我在发出警告的两个文件里边,.text段之前加了PRESERVE8,警告就消除了
参考上边的一段红字,PRESERVE8这个关键字用来声明字节对齐的。声明之后,链接器就不会警告这里没有对齐了。
于是在knl_int.s和knl_dispatch中的所有.text段前面加上PRESERVE8关键字,警告就消除了。
格式是这样的:
PRESERVE8
AREA |.text|,CODE,READONLY
THUMB
GLOBAL Csym(enaint) [CODE]
。。。。。。。。。。。。。。。。
继续更新,开始玩转开发板的硬件部分
EM-SAM3S开发板例子工程中的启动文件分析
【预备知识】
Cortex-M3内核规定,起始地址必须存放堆顶指针,而第二个地址则必须存放复位中断入口向量地址,这样在Cortex-M3内核复位后,会自动从起始地址的下一个32位空间取出复位中断入口向量,跳转执行复位中断服务程序。对比ARM7/ARM9内核,Cortex-M3内核则是固定了中断向量表的位置而起始地址是可变化的。
【启动分析】
在例子程序中,MCU启动时,会将vector中定义的第二个地址作为程序的入口地址。即Reset_Handler。
至于为什么会从vector加载,可以查看分散加载文件(.sct)。这里有这么一段:
Vector_region 0x400000
{
board_cstartup_keil.o (vectors, +FIRST)
}
这个声明就是让链接器将board_cstartup_keil.o加载到0x400000。
而0x400000就是内部flash的起始地址:
board_cstartup_keil.o由board_cstartup_keil..c生成。这个文件中,定义了两个东西:__vector_table[]和static void _Reset_Handler( void )
__vector_table就是中断向量表,__vector_table的第二个地址就是_Reset_Handler。因此,MCU启动时将向量表加载完成后,就开始执行_Reset_Handler这个函数。
在这个函数中跳转到main函数。好了,花花丽丽的C开始了。
(至于为什么加载到了0x400000是__vector_table而不是_Reset_Handler,那是因为那个+FIRST这个属性)
【总结一下】
1、在分散加载文件中,设置程序加载到的位置。加载到0x400000这个地址的,就会在启动时候执行。
2、这里的启动文件有很简单的两个东西,中断向量表和函数_Reset_Handler。中断向量表的第二个地址就是复位中断程序入口地址。
3、汇编文件workaround.s没用了。删掉里边的内容都没关系。于是一行汇编代码都没有了,这也算是自己写sct文件的好处吧。
一种设置寄存器的宏定义方法
#define EEFC_FMR_FWS_Pos 8
#define EEFC_FMR_FWS_Msk (0xfu << EEFC_FMR_FWS_Pos) /**< \brief (EEFC_FMR) Flash Wait State */
#define EEFC_FMR_FWS(value) ((EEFC_FMR_FWS_Msk & ((value) << EEFC_FMR_FWS_Pos)))
在程序中使用时候:
EFC->EEFC_FMR = EEFC_FMR_FWS(3);
=((EEFC_FMR_FWS_Msk & ((3) << EEFC_FMR_FWS_Pos)))
=(0xfu << EEFC_FMR_FWS_Pos) & ((3) << EEFC_FMR_FWS_Pos)))
=(0xfu << 8) & ((3) << 8))
再看看寄存器:
EFC->EEFC_FMR = EEFC_FMR_FWS(3);
这句代码刚好就设置了FWS寄存器,省去了很多手动计算还提高了代码的可读性。
设置时钟的步骤(一点垃圾翻译)
设置时钟步骤:
1、打开主振荡器
设置寄存器CKGR_MOR中的MOSCXTEN域可使能主时钟。用户可以通过写CKGR_MOR中的MOSCXTST域来定义一个主时钟的启动时间。一旦这个寄存器被正确配置,用户必须等待寄存器PMC_SR中的MOSCXTS位被置位。这个过程可以通过查询状态寄存器完成,如果PMC_IER中相应的中断打开也可以通过中断来检测。
2、检查主振荡器频率
在某些情况下,用户可能需要精确地测量主时钟的频率。这个测量可以通过CKGR_MCFR寄存器来完成。
一旦寄出器CKGR_MCFR中的MAINFRDY域被设置,用户就可以读寄存器CKGR_MCFR中的MAINF域了。这个读出的数字是主时钟在慢时钟十六个周期内所运行的周期。
3、设置PLL和分频器
所有的PLL金额分频器参数都是通过寄存器CKGR_PLLxR来配置完成的。
DIV域是用来控制分频器的,当PLL被使用时,它必须被设置成1。默认情况下,DIV域被设置为0,这就意味值分频器被关闭了。(没有频率输出)
MUL域是PLL的倍频系数。这个参数可以被设置为从0到2047之间的值。如果MUL被设置为0,PLL将会被关闭,其他情况下PLL的输出频率=PLL的输入频率×(MUL+1)
PLLCOUNT域指定了在CKGR_PLLR 被置位之后,PMC_SR 寄存器中的LOCK位被置位之前,要经历的慢时钟周期数。
当PMC_PLL寄存器被写入时,用户必须等待PMC_SR中的LOCK位被置位。这个过程可以通过查询或者中断来完成。
寄存器CKGR_PLLR中的所有参数可以通过一次写操作完成。在一些情况下,一下这些位会被拉低,以指明PLL没有准备好:MUL、DIV被修改、lock位。
当PLL锁定时,LOCK位被重新置位。用户在使用PLL之前必须等待LOCK置位。
4、选择主时钟和处理器时钟
主时钟和处理器时钟可以通过寄存器PMC_MCKR来配置。
CSS域用来选择主时钟的驱动源。默认情况下主时钟会被选择。
PRES域用来控制主时钟的分频。用户可在一下几个值中选择分频系数:(1, 2, 3, 4, 8, 16, 32, 64)
5、可编程时钟的选择
可编程时钟通过寄存器PMC_SCER,
PMC_SCDR PMC_SCSR控制。
6、使能外设时钟
当所有以上步骤都完成时,可通过寄存器PMC_PCER0, PMC_PCER1, PMC_PCDR0 and PMC_PCDR1来使能或者失能外设时钟。
比较麻烦的一个东西。我玩了几天51就转过来的,那里没的总线时钟。
ARM7里边也有,但是没这么复杂。
计算CM3的时钟并记住,还是有点难度的
有奖活动 | |
---|---|
【有奖活动】分享技术经验,兑换京东卡 | |
话不多说,快进群! | |
请大声喊出:我要开发板! | |
【有奖活动】EEPW网站征稿正在进行时,欢迎踊跃投稿啦 | |
奖!发布技术笔记,技术评测贴换取您心仪的礼品 | |
打赏了!打赏了!打赏了! |