查看: 1433|回复: 1

[原创] MCUXpresso IDE初始化

[复制链接]

该用户从未签到

656

主题

6312

帖子

0

超级版主

Rank: 8Rank: 8

积分
20039
最后登录
2024-4-26
发表于 2021-7-26 15:49:03 | 显示全部楼层 |阅读模式
本帖最后由 小恩GG 于 2021-7-26 15:50 编辑

ELF文件
ELF文件(Executable and Linkable Format)的内部格式如下所示,
d6fbe1b7-5107-49ad-b1a6-4a654099d213.png

图 1


而格式中间的sections(节)存储的对应目标类型的详情如下所示。

  • .text: 放编译好的二进制可执行代码
  • .data: 已经初始化好的全局变量
  • .rodata: 只读数据,例如字符串常量、const 的变量
  • .bss: 未初始化全局变量,运行时会置 0
  • .symtab: 符号表,记录的则是函数和变量
  • .strtab: 字符串表、字符串常量和变量名

虽然数据段中的data、bss section(节) 也跟代码段一样,作为ELF文件的一部分会被一并烧录到Flash中,但在加载程序代码后,它却要寻址到RAM中的地址,所以在MCU启动后,跳转到Main()函数之前,需要将ELE文件格式中的数据段悉数拷贝到对应的RAM区域内。

ResetISR()

正如前文所讲,在RT MCU启动成功后,跳转到应用程序的main()之前,会先跳到ResetISR()中断函数内进行“系统环境”的初始化工作,而其中最重要的一项:即是将ELE文件格式中的数据段拷贝到对应的RAM区域内。 通常ResetISR()中断函数定义在startup文件中,而不同的IDE提供的startup文件又不一样,故ResetISR()中断函数也会有所区别,本篇讨论的是基于MCUXpresso IDE的ResetISR()中断函数,代码具体如下所示。

  1. void ResetISR(void) {

  2.     // Disable interrupts
  3.     __asm volatile ("cpsid i");


  4. #if defined (__USE_CMSIS)
  5. // If __USE_CMSIS defined, then call CMSIS SystemInit code
  6.     SystemInit();
  7. #else
  8.     // Disable Watchdog
  9.     volatile unsigned int *WDOG1_WCR = (unsigned int *) 0x400B8000;
  10.     *WDOG1_WCR = *WDOG1_WCR & ~(1 << 2);
  11.     volatile unsigned int *WDOG2_WCR = (unsigned int *) 0x400D0000;
  12.     *WDOG2_WCR = *WDOG2_WCR & ~(1 << 2);
  13.     // Write watchdog update key to unlock
  14.     *((volatile unsigned int *)0x400BC004) = 0xD928C520;
  15.     // Set timeout value
  16.     *((volatile unsigned int *)0x400BC008) = 0xFFFF;
  17.     // Now disable watchdog via control register
  18.     volatile unsigned int *RTWDOG_CS = (unsigned int *) 0x400BC000;
  19.     *RTWDOG_CS = (*RTWDOG_CS & ~(1 << 7)) | (1 << 5);

  20. #endif // (__USE_CMSIS)

  21.     //
  22.     // Copy the data sections from flash to SRAM.
  23.     //
  24.     unsigned int LoadAddr, ExeAddr, SectionLen;
  25.     unsigned int *SectionTableAddr;

  26.     // Load base address of Global Section Table
  27.     SectionTableAddr = &__data_section_table;

  28.     // Copy the data sections from flash to SRAM.
  29.     while (SectionTableAddr < &__data_section_table_end) {
  30.         LoadAddr = *SectionTableAddr++;
  31.         ExeAddr = *SectionTableAddr++;
  32.         SectionLen = *SectionTableAddr++;
  33.         data_init(LoadAddr, ExeAddr, SectionLen);
  34.     }

  35.     // At this point, SectionTableAddr = &__bss_section_table;
  36.     // Zero fill the bss segment
  37.     while (SectionTableAddr < &__bss_section_table_end) {
  38.         ExeAddr = *SectionTableAddr++;
  39.         SectionLen = *SectionTableAddr++;
  40.         bss_init(ExeAddr, SectionLen);
  41.     }


  42. #if !defined (__USE_CMSIS)
  43. // Assume that if __USE_CMSIS defined, then CMSIS SystemInit code
  44. // will setup the VTOR register

  45.     // Check to see if we are running the code from a non-zero
  46.     // address (eg RAM, external flash), in which case we need
  47.     // to modify the VTOR register to tell the CPU that the
  48.     // vector table is located at a non-0x0 address.
  49.     unsigned int * pSCB_VTOR = (unsigned int *) 0xE000ED08;
  50.     if ((unsigned int *)g_pfnVectors!=(unsigned int *) 0x00000000) {
  51.         *pSCB_VTOR = (unsigned int)g_pfnVectors;
  52.     }
  53. #endif // (__USE_CMSIS)
  54. #if defined (__cplusplus)
  55.     //
  56.     // Call C++ library initialisation
  57.     //
  58.     __libc_init_array();
  59. #endif

  60.     // Reenable interrupts
  61.     __asm volatile ("cpsie i");

  62. #if defined (__REDLIB__)
  63.     // Call the Redlib library, which in turn calls main()
  64.     __main();
  65. #else
  66.     main();
  67. #endif

  68.     //
  69.     // main() shouldn't return, but if it does, we'll just enter an infinite loop
  70.     //
  71.     while (1) {
  72.         ;
  73.     }
  74. }
复制代码
代码分析

在ResetISR()中断函数中,如下代码片段根据__data_section_table、__data_section_table_end、__bss_section_table、__bss_section_table_end以彼此相邻的三个变量(4个byte)为一组来分别提取数据拷贝源地址、数据拷贝目的地址及拷贝数据的字节量,从而实现Data_section,BSS_Section初始化,流程框图如下所示。

  1. // Copy the data sections from flash to SRAM.
  2.     while (SectionTableAddr < &__data_section_table_end) {
  3.         LoadAddr = *SectionTableAddr++;
  4.         ExeAddr = *SectionTableAddr++;
  5.         SectionLen = *SectionTableAddr++;
  6.         data_init(LoadAddr, ExeAddr, SectionLen);
  7.     }

  8.     // At this point, SectionTableAddr = &__bss_section_table;
  9.     // Zero fill the bss segment
  10.     while (SectionTableAddr < &__bss_section_table_end) {
  11.         ExeAddr = *SectionTableAddr++;
  12.         SectionLen = *SectionTableAddr++;
  13.         bss_init(ExeAddr, SectionLen);
  14.     }
复制代码

ea9ac7db-7e09-4782-a82f-2fd7afc43c8c.png

图 2

那么上图中的__data_section_table、__data_section_table_end、__bss_section_table、__bss_section_table_end存储在ELF文件的哪个位置呢? 以evkmimxrt1064_hello_world工程为例,我们可以通过查看Map文件获知上述四个变量存储在中断向量表的尾部区域,如下所示。

0e6b8b85-8981-4c83-8e03-10ade6c64b3a.png

图 3

从中可以看出data_section和bss_section需映射在RAM区域的0x20000000和0x20000404地址,并且区域大小分别为0x404和0x108。 为了验证data_section和bss_section映射地址是否正确,通过命令readelf -S evkmimxrt1064_hello_world.axf查看这个ELF文件中所有的Section信息(如图4所示),可以发现data_section和bss_section映射地址和大小确如上文所讲。

7ed204bb-46ef-421c-8eec-a7c0cf8d79df.png

图 4

欢迎留言和我分享你的疑惑和见解 ,也欢迎收藏或转发




回复

使用道具 举报

该用户从未签到

0

主题

1

帖子

0

新手上路

Rank: 1

积分
17
最后登录
2021-8-30
发表于 2021-8-10 16:30:53 | 显示全部楼层
您好,请教一下,如果应用程序代码不是从0x00000000开始,假设从0x00008000开始,如何更改vector table的地址?
回复 支持 反对

使用道具 举报

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

本版积分规则

关闭

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

Archiver|手机版|小黑屋|恩智浦技术社区

GMT+8, 2024-4-27 12:36 , Processed in 0.125238 second(s), 21 queries , MemCache On.

Powered by Discuz! X3.4

Copyright © 2001-2024, Tencent Cloud.

快速回复 返回顶部 返回列表