查看: 2027|回复: 0

[STM32F469试用体验]启动代码及程序配置

[复制链接]
  • TA的每日心情
    开心
    2016-12-15 12:17
  • 签到天数: 3 天

    连续签到: 1 天

    [LV.2]偶尔看看I

    发表于 2016-6-1 13:37:46 | 显示全部楼层 |阅读模式
    分享到:
    上一篇讲述了如何使用MDK-ARM快速评估一个应用程序:按键调整LED灯的亮否。但仍然不知道该如何入手开始自己的开发,这一篇讲述程序是如何启动及用户程序的基本配置等内容,了解了这些就知道程序的来龙去脉,我们也可以根据需要添加自己的应用了。但,为了能够获取更多的信息,读者需要根据文中的提示,阅读更多的书籍资料,来补充背后的更加详细的内容。
    1.启动代码
    什么是启动代码?通俗的讲,启动代码是指应用程序工程为了进入C/C++语言程序前的配置工作而写的汇编代码。如果应用程序工程只使用汇编语言编写程序,那么就没有所谓的启动代码。绝大多数嵌入式应用程序都是使用C/C++编写的,即使内嵌了汇编程序,也是需要启动代码的,因为只要用到C/C++语言,就需要在正常试用C/C++之前对其进行初始化,没错,试用C/C++之前要对其进行初始化。更多信息请参考[1]《Libraries and Floating-Point Support User Guide》中的“The ARM C and C++ Libraries->Tailoring the C library to a new execution environ->Initialization of the execution environment and execution of the application”小节。
    启动代码除了完成C/C++库的初始化外,更重要的还需要根据Cortex-M内核的需要完成内核的配置和初始化。Cortex-M程序映像一般包括如下几个部分:1.向量表。2.C/C++启动例程。3.程序代码。4.C/C++库代码。一般情况下启动代码完成1和2,编译器会根据需要把C/C++库代码自动添加到程序映像中去。我们只需要关注自己的程序代码部分。但理解启动代码有助于理解程序的来龙去脉,并能够掌握程序的运行。
    向量表其实就是按照既定的顺序排列的数组,数组的每个成员都是内核定义好的内容,大小是4个字节。这个既定的顺序就是Cortex-M内核规定的,必须服从的,向量表即:栈顶指针、复位异常、不可屏蔽异常、硬件错误异常、MPU错误异常、总线错误异常、未定义指令异常等,还有其它的中断等。向量表中除了栈顶指针指向的是一个栈外,其它的都是函数指针,当异常或中断被触发时程序就会按照向量表中保存的函数指针调用该函数。这个触发、调用过程是内核自动实现的,所以向量表是有顺序的,比如,不能把复位异常和不可屏蔽异常的内容调换,否则执行的功能也就调换了,因为内核不知道函数指针指向的是哪个意义的功能函数,只知道调用这个函数指针并执行这个函数。更多细节参考[2]。
    MCU上电并从flash启动后,首先从向量表中取得第一个成员:栈顶指针,并赋值给MSP寄存器;然后再取得向量表中的第2个成员复位异常,并赋值给PC寄存器,这样MCU根据PC寄存器的内容就开始了程序的执行。为什么会首选取得栈顶指针而不是其它成员,这是因为有可能执行其它功能时会出现异常或中断,而此时需要有栈的支持,所以必须先把栈初始化完成,然后再执行其它功能,这样即使出现异常,程序也会根据异常处理错误。那如果在取第一个成员栈顶指针时出现异常怎么办?MCU会进入锁定状态,更多信息可以参考[2]。
    我们知道内核的执行其实是个状态机的执行,它按照既定的方案执行处理功能。而向量表就是状态机中非常重要的数据来源,那就是出现异常或中断时,状态机会自动获取向量表的内容,这也就是为什么向量表是有顺序的,当然,向量表也是有大小的,不同的内核有不同的大小。还有一个也是非常明确的,向量表的地址是确定的,对于状态机来说,只要从0x00000000地址处获取的就是栈顶指针,从0x00000004地址处获取的就是复位异常,等等依次类推。如果你的程序用不到除栈顶指针和复位异常外的其它向量成员,则可以不指定他们的值,这样状态机也就不会充其它向量成员中获取值,你的程序照样运行的很好,但这只是理论上如此,实际中你应当至少定义15个向量来满足基本的应用。
    STM32F469I-Disvoery使用的MCU:STM32F469NIH6是基于Cortex-M4内核的,Cotex-M4内核的向量表是确定的。我们参考GPIO_EXTI示例程序给的向量表来具体说明,见下图。

    通过上图可以看出,向量表被分成3个部分:栈顶指针、内核异常和外部中断。其中内核异常共有15个,外部中断上图只是截取的部分内容,一般可以多达60多个,这个根据具体的应用和内核的不同而不同,但根据实际应用你可以只定义程序需要的外部中断向量,但顺序、位置不能改变。比如你不使用“WWDG_IRQHandler”中断,但是这个位置必须预留,Cortex-M内核只知道从向量表的某个位置读取中断,不会判断中断具体执行什么功能。
    Cortex-M内核从0x00000004地址处获取的是复位异常Reset_Handler,并把Reset_Handler赋值给PC寄存器,从而开始执行程序。GPIO_EXTI示例程序给的复位异常如下图示。

    上图是一段汇编代码,如果你的程序只用汇编代码编写程序,那么Reset_Handler处就是你编程开始的地方。但我们试用C编写应用程序,所以复位异常会进行C库的初始化工作。上图196行处的“[WEAK]”表示如果你在其它地方也定义了Reset_Handler,那么使用你自己定义的函数,“[WEAK]”起到的作用类似函数重载。197和198行表示从外部引入这2个符号,其实这2个符号就是函数指针。SystemInit函数执行FPU初始化、时钟的简单初始化和外部RAM的初始化工作。外部的RAM需要首先完成初始化,以备后面的程序使用外部RAM。__main是C库的入口,它会执行拷贝变量到RAM并在必要时解压压缩的变量,初始化有初值的变量,然后再执行__rt_entry函数。__rt_entry函数会根据数据加载的配置来初始化栈和堆,然后初始化库函数,如果使用了C++特性,还会根据构造函数初始化所有的全局对象。接着__rt_entry函数调用main函数,开始用户应用程序。此处的main函数也就是main.c里面的main()函数。如果用户main函数退出,那么__rt_entry函数会调用exit函数来释放C库,如果使用了C++特性还会调用析构函数来释放全局对象,然后__rt_entry函数返回到__main函数,程序最后再返回到Reset_Handler异常中,最后内核无执行语句。一般情况下用户不应从main函数退出。
    上述总结如下图所示。

    关于全部启动代码的详细内容解析,还需要熟悉简单的ARM Cortex-M汇编语法和编译器汇编指令,后者根据不同的编译器又不同的编译器指令,MDK-ARM相关的汇编语法和汇编指令参考[3]《ARM Compiler v5.06 for µVision armasm User Guide》,其余的启动代码相对比较容易理解。
    2.程序配置
    进入main函数后就完全可以试用C编程了。GPIO_EXTI示例程序的main函数如下图所示。

    HAL_Init()是STM32Cube库中定义的函数,在调用任何库函数前必须首先调用此函数来初始化HAL库。HAL_Init()用来完成如下功能:
         
    • 配置Flash指令和数据欲取。  
    • 配置SysTick使之每隔1毫秒产生一个中断。此时使用的是HSI,即高速内部RC振荡器时钟。  
    • 设置NVIC组优先级为4。
    SystemClock_Config()函数用来配置系统运行在180MHz,这是通过试用外部高速晶振HSE和PLL来实现的。同时还会把外设的各个时钟初始化完毕。
    BSP_LED_Init()函数是板级支持函数,他把LED1初始化完成可以操作的外设,通过配置管脚的属性实现此功能。
    EXTI0_IRQHandler_Config()函数用来配置当用户按键时产生一个外部中断,此外部中断配置到了外部中断线0上,当产生中断后,会调用HAL_GPIO_EXTI_Callback()中断处理函数,在函数HAL_GPIO_EXTI_Callback()中使用BSP_LED_Toggle(LED1)来使得LED1根据用户的按键执行亮或灭的功能。
    最后main函数进入了一个无限循环,这也正是为什么在main的最后会有一个无限循环,即一般情况下用户应用程序不应从main函数退出。
    下图是通过按键使得LED1点亮的示意图。屏幕还有内容是因为此时的显示缓冲还未清除,重启一次后就没有显示内容了。

    3.参考资料
    [1] 《Libraries and Floating-Point Support User Guide》,ARM Compiler v5.06 for uVision ARM C and C++ Libraries and Floating-Point Support User Guide。
    [2] 《The Definitive Guide to Arm Cortex-M3 and Cortex-M4 Processors, Third Edition》。
    [3] 《ARM Compiler v5.06 for µVision armasm User Guide》
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    手机版|小黑屋|与非网

    GMT+8, 2024-11-19 08:50 , Processed in 0.112567 second(s), 16 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.