7884|2

36

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

【空调精灵】STM32F7-Disco首次运行 RT-Thread RTOS [复制链接]

本帖最后由 liuluqqzj 于 2015-10-30 15:13 编辑 STM32F7-DISCO评估板极简介
STM32F7-DISCO评估板基于STM32F746NG微控制器,板载资源丰富。板子的供电接口有四种选择:外部5v供电、5v st-link供电、USB-FS及USB-HS供电。通过反面的JP1跳帽选择供电方式,此处选择5v st-link即可。
烧写官方demo
从官网下载最新的st-link烧写工具,安装之后打开烧写工具,打开要烧写的hex文件(位于官方cube库的STM32Cube_FW_F7_V1.1.0\Projects\STM32746G-Discovery\Demonstration下),连接开发板的同时选择外部flash烧写算法,如下所示: 完成上述步骤后点击烧写验证即可。
获得RTT最新版本库
RTT为国产开源的实时嵌入式操作系统,类linux风格并附带有丰富的第三方库支持,从官方的github库中将最新版本克隆到本地。其代码库的组织结构如下所示: 其中bsp/下包含了rtt针对各种型号处理器的初始化模版工程,从中找到stm32f7-disco文件目录,可以看到里面包含有一个keil下的模版工程,此工程还不能直接使用,需要按照官方的指导手册来一步步配置,最终通过SCons来调用MDK工具链编译生成新工程project.uvprojx。由于官方文档描述十分详细此处不再赘述。
编译烧写新工程
在完成前两步的基础上,我们已经具备了针对f746的新工程,使用最新的keil ide打开该工程。如果ide中还没有安装stm32f7xx的芯片支持包,建议去keil官网直接下载安装,keil下的自动安装非常慢,而且多半会失败。
在更新了芯片库之后,点击编译会出现 Use MicroLIB的相关错误,解决方式:在工程选项中去除对C库的勾选,同时删除工程中重复添加的main.c及sram.c,如下所示: 完成上述工作之后,工程编译无错误,点击下载可以看到板子上位于复位按钮旁边的led1在闪烁。此处打开串口连接可以看到终端出现类似linux命令行的执行窗口。 至此,rtt在f746上的初次运行就完成了,此处描述较为简洁,详细的步骤还需要翻阅相关的用户手册及安装配置相关的软件环境。
RTT启动过程介绍
打开一个新工程首先会去查看main.c源文件,让人意外的是工程中的main.c干净的不像话…只有一条语句:return 0;但是板子的灯在闪烁,串口也有命令交互,因此可以肯定的是rtt已经启动了,只不过代码的初始化过程不在main.c中。
使用过IAR的童鞋应该知道IAR编译工程后在进入main.c之前添加了一段函数代码,此处采用的正是此机制,只不过换成了keil。MCU第一次上电运行的运行过程一般为:
  • 系统上电进入Reset_Handler中断,执行 SystemInit;
  • SystemInit完成系统时钟源及向量表的配置后,跳转到main函数;
  • 系统开始运行用户程序;
为了知道在跳转到main函数之前系统做了什么,通过调试开启单步运行可以看到,程序运行到此处: 从图中可以看到,不同的编译器在跳转到main函数之前执行所替代的函数各不相同,对于当前的keil工程,通过int $Sub$$main(void)来取代main函数的跳转,再通过int $Super$$main(void);跳回到main函数中。而系统的初始化过程则在int $Sub$$main(void);中完成。
在int rtthread_startup(void)中有一系列的rtt初始化函数,重点关注函数rt_hw_board_init();及rt_application_init();
  1. int rtthread_startup(void)
  2. {
  3. rt_hw_interrupt_disable(); // 关系统中断
  4. /* board level initalization
  5. * NOTE: please initialize heap inside board initialization.
  6. */
  7. rt_hw_board_init(); // 板级初始化,系统外设相关初始化,时钟,中断,内存,控制台
  8. /* show RT-Thread version */
  9. rt_show_version();
  10. /* timer system initialization */
  11. rt_system_timer_init(); // 初始化一组软件定时器
  12. /* scheduler system initialization */
  13. rt_system_scheduler_init(); // 系统调度器初始化
  14. /* create init_thread */
  15. rt_application_init(); // 创建初始化任务
  16. /* timer thread initialization */
  17. rt_system_timer_thread_init(); // 定时器任务,管理所有的定时器
  18. /* idle thread initialization */
  19. rt_thread_idle_init(); // 空闲任务
  20. /* start scheduler */
  21. rt_system_scheduler_start(); // 启动系统调度器
  22. /* never reach here */
  23. return 0;
  24. }
复制代码
rt_hw_board_init();函数中主要实现的是系统时钟及外设的初始化,见如下代码注释:
  1. /**
  2. * This function will initial STM32 board.
  3. */
  4. void rt_hw_board_init()
  5. {
  6. /* Configure the MPU attributes as Write Through */
  7. //mpu_init(); // 没有配置mpu
  8. /* Enable the CPU Cache */
  9. CPU_CACHE_Enable();
  10. /* STM32F7xx HAL library initialization:
  11. - Configure the Flash ART accelerator on ITCM interface
  12. - Configure the Systick to generate an interrupt each 1 msec
  13. - Set NVIC Group Priority to 4
  14. - Global MSP (MCU Support Package) initialization
  15. */
  16. HAL_Init(); // 硬件抽象层初始化,中断,systick配置
  17. /* Configure the system clock @ 200 Mhz */
  18. SystemClock_Config(); // 配置系统时钟
  19. /* init systick */
  20. SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND); // 又配置了一遍
  21. /* set pend exception priority */
  22. NVIC_SetPriority(PendSV_IRQn, (1 << __NVIC_PRIO_BITS) - 1); // 又配置了一遍
  23. #ifdef RT_USING_COMPONENTS_INIT // 已开启
  24. rt_components_board_init(); // 板载组件初始化
  25. #endif
  26. #ifdef RT_USING_EXT_SDRAM // 已开启
  27. rt_system_heap_init((void*)EXT_SDRAM_BEGIN, (void*)EXT_SDRAM_END); // 初始化外部内存
  28. sram_init();
  29. #else
  30. rt_system_heap_init((void*)HEAP_BEGIN, (void*)HEAP_END);
  31. #endif
  32. #ifdef RT_USING_CONSOLE
  33. rt_console_set_device(RT_CONSOLE_DEVICE_NAME); // 设置新控制台设备
  34. #endif
  35. }
复制代码
上述代码中调用了板级组件初始化函数rt_components_board_init,该函数体的代码如下所示:
  1. /**
  2. * RT-Thread Components Initialization for board
  3. */
  4. void rt_components_board_init(void)
  5. {
  6. #if RT_DEBUG_INIT // 未开启
  7. int result;
  8. const struct rt_init_desc *desc;
  9. for (desc = &__rt_init_desc_rti_start; desc < &__rt_init_desc_rti_board_end; desc ++)
  10. {
  11. rt_kprintf("initialize %s", desc->fn_name);
  12. result = desc->fn();
  13. rt_kprintf(":%d done\n", result);
  14. }
  15. #else
  16. const init_fn_t *fn_ptr;
  17. // led mpu sdram uart
  18. for (fn_ptr = &__rt_init_rti_start; fn_ptr < &__rt_init_rti_board_end; fn_ptr++)
  19. {
  20. (*fn_ptr)();
  21. }
  22. #endif
  23. }
复制代码
从代码上直观理解,fn_ptr为一个函数指针,__rt_init_rti_start及__rt_init_rti_board_end为函数指针的起始及结束地址,通过for循环来调用这一系列的指针函数来完成班级组件的初始化。
而fn_ptr所指向的函数究竟是什么,有两种方式可以探别,一种是在调试中的(*fn_ptr)();语句处打断点,每次运行到此处时进入函数内部执行,则可以看到当前for循环所调用的指针函数;另一种方式则是直观的看代码,查找这两个起始及结束地址的定义,出现如下代码:
  1. static int rti_start(void)
  2. {
  3. return 0;
  4. }
  5. INIT_EXPORT(rti_start, "0");// __rt_init_rti_start
  6. static int rti_board_end(void)
  7. {
  8. return 0;
  9. }
  10. INIT_EXPORT(rti_board_end, "1.end");// __rt_init_rti_board_end
复制代码
INIT_EXPORT的宏定义如下:
  1. <font color="rgb(222, 147, 95)"><font face="inherit">#define INIT_EXPORT(fn, level) \</font></font> <font color="rgb(178, 148, 187)"><font face="inherit">const</font></font> init_fn_t __rt_init_<font color="rgb(222, 147, 95)"><font face="inherit">##fn SECTION(".rti_fn."level) = fn</font></font>
复制代码
SECTION的宏定义如下:
  1. <font color="rgb(204, 102, 102)"><font face="inherit">#define</font></font> <font color="rgb(129, 162, 190)"><font face="inherit">SECTION</font></font>(x) __<font color="rgb(129, 162, 190)"><font face="inherit">attribute__</font></font>((<font color="rgb(129, 162, 190)"><font face="inherit">section</font></font>(x)))
复制代码
__attribute__为ARM编译器的扩展属性,realview编译工具手册中对其描述如下: 将 INIT_EXPORT(rti_start, "0");宏展开,得到的函数语句如下:
  1. <font color="rgb(178, 148, 187)"><font face="inherit">const</font></font> init_fn_t __rt_init_rti_start __attribute__((section(<font color="rgb(181, 189, 104)"><font face="inherit">".rti_fn.0"</font></font>))) = rti_start;
复制代码
因此__rt_init_rti_start为一个函数指针,指向rti_start函数,同时__attribute__的section属性将该函数指针放在名为.rti_fn.0的段中。同理__rt_init_rti_board_end也是一个函数指针,指向rti_board_end函数,同时指定该函数指针存放在.rti_fn.1.end段中。
程序分析到这里,已经明白了编译器中关于段的含义,但是.rti_fn.0段与.rti_fn.1.end段之间到底还存在哪些函数指针,则需要进一步分析。工程全局搜索宏INIT_EXPORT,可看到如下宏定义:
  1. /* board init routines will be called in board_init() function */
  2. #define INIT_BOARD_EXPORT(fn) INIT_EXPORT(fn, "1")
  3. /* device/component/fs/app init routines will be called in init_thread */
  4. /* device initialization */
  5. #define INIT_DEVICE_EXPORT(fn) INIT_EXPORT(fn, "2")
  6. /* components initialization (dfs, lwip, ...) */
  7. #define INIT_COMPONENT_EXPORT(fn) INIT_EXPORT(fn, "3")
  8. /* file system initialization (dfs-elm, dfs-rom, ...) */
  9. #define INIT_FS_EXPORT(fn) INIT_EXPORT(fn, "4")
  10. /* environment initialization (mount disk, ...) */
  11. #define INIT_ENV_EXPORT(fn) INIT_EXPORT(fn, "5")
  12. /* appliation initialization (rtgui application etc ...) */
  13. #define INIT_APP_EXPORT(fn) INIT_EXPORT(fn, "6")
复制代码
从宏定义中可以看到,根据编译器生成的段排列顺序,所有使用INIT_EXPORT(fn, "1")宏指定的指针函数都将介于.rti_fn.0段与.rti_fn.1.end段之间,即调用INIT_BOARD_EXPORT导出函数的语句处都会生成一个函数指针存放在这两个段之间。全局搜索INIT_BOARD_EXPORT,可以得知rt_components_board_init函数中的for循环调用的是以下函数:
其中stm32_hw_usart_init初始化并注册usart1设备,剩下的三个函数则是sdram、mpu及led引脚的初始化。
为了验证上述结论的正确性,打开工程生成的.map文件,全局搜索关键字.rti_fn.可以看到编译器放置在该段范围内的函数指针:
解决了stm32_hw_usart_init函数,剩下的rt_application_init则简单许多,该函数创建了一个主任务main_thread_entry,任务回调函数如下:
  1. /* the system main thread */ // 初始化的任务主体
  2. void main_thread_entry(void *parameter)
  3. {
  4. extern int main(void);
  5. extern int $Super$main(void);
  6. /* RT-Thread components initialization */
  7. rt_components_init();
  8. /* invoke system main function */
  9. #if defined (__CC_ARM)
  10. $Super$main(); /* for ARMCC. */ // 此时才会去调用main函数
  11. #elif defined(__ICCARM__) || defined(__GNUC__)
  12. main();
  13. #endif
  14. }
复制代码
该任务调用了rtt的组件初始化函数rt_components_init,该函数完成了一些系统的初始化服务,包括i2c、finsh、led_task等,分析过程同rt_components_board_init函数,不再赘述。任务的尾部才跳回到main函数中去处理用户代码。初始化的最后回到rtthread_startup函数中完成rtt的任务调度及启动。
更多精彩内容,欢迎访问 http://liuluqqzj.github.io/ www.miaoxiong.net
此帖出自stm32/stm8论坛

最新回复

撸主真牛牛,赞一个哟喂  详情 回复 发表于 2015-10-29 20:40
点赞 关注(2)
 

回复
举报

5263

帖子

239

TA的资源

管理员

沙发
 
多谢分享
此帖出自stm32/stm8论坛
加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身
 
 

回复

267

帖子

0

TA的资源

一粒金砂(高级)

板凳
 
撸主真牛牛,赞一个哟喂
此帖出自stm32/stm8论坛
 
个人签名

gitee/casy

 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/6 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表