之前的文章“IAR Embedded Workbench中的MCU启动过程”介绍了IAR Embedded Workbench中的MCU启动过程:其中非常重要的一步是存储在RAM中的全局和静态变量的初始化。
本文主要介绍IAR Embedded Workbench中的初始化策略。
存储在RAM中的全局和静态变量的初始化
初始化初始值为0的存储在RAM中的全局和静态变量(比如 int i = 0;):
初始化初始值为非0的存储在RAM中的全局和静态变量(比如 int i = 1;),对应的初始值(Initialize variables)从相应的ROM拷贝到对应的RAM:
IAR Embedded Workbench中的初始化策略
initialize by copy
在ICF文件添加initialize by copy { readwrite };命令之后,Linker会自动添加对应的initializers,并在启动代码里面自动完成对应的初始化操作:
MAP文件中的INIT TABLE会列出对应的初始化信息:其中初始值为0的全局和静态变量会通过__iar_zero_init3函数进行初始化:初始化的时候__iar_zero_init3函数会对相关RAM区域进行写0操作,完成对初始值为0的全局和静态变量的初始化;初始值为非0的全局和静态变量会通过__iar_copy_init3函数进行初始化:对应的Initializer bytes放到ROM,初始化的时候__iar_copy_init3函数会把ROM中的Initializer bytes拷贝到RAM中,完成对初始值为非0的全局和静态变量的初始化:
注意:initialize by copy命令需要启动代码里面调用__iar_program_start进行初始化。
在ICF文件添加initialize by copy { readwrite };命令之后,Linker会自动添加对应的initializers,并在启动代码里面自动完成对应的初始化操作,对应的__iar_zero_init3函数和__iar_copy_init3函数都是通过__iar_program_start调用,所以需要使用__iar_program_start进行初始化:
如果没有调用__iar_program_start进行初始化,link的时候会提示类似下面的错误(__iar_data_init3函数会先后调用__iar_zero_init3函数和__iar_copy_init3函数):
initialize manually
如果代码里面没有使用__iar_program_start进行初始化,就不能使用initialize by copy初始化策略对初始值为非0的全局和静态变量进行自动初始化。可以使用initialize manually初始化策略对初始值为非0的全局和静态变量进行手动初始化(当然,代码里面使用了__iar_program_start进行初始化,也是可以使用initialize manually初始化策略对初始值为非0的全局和静态变量进行手动初始化的)。
如下所示:ICF文件中使用initialize manually对.data section进行手动初始化:.data section包含的是初始值为非0的全局和静态变量,放到MY_DATA block中,并把对应的MY_DATA block放到RAM;.data_init section包含的是初始值为非0的全局和静态变量的Initializer bytes,放到MY_DATA_INIT block中, 并把对应的MY_DATA_INIT block放到ROM:
然后需要在代码里面添加对应的手动初始化.data section的代码:其中#pragma section命令用于定义对应的section名字,然后对应的section操作符__section_begin, __section_end和section_size就可以分别获取对应section的开始地址,结束地址和大小。
MAP文件中.data section放到MY_DATA block中,放置到RAM,对应的.data_init section(Initializer bytes)放到MY_DATA_INIT block中,放置到ROM:
do not initialize
如果代码里面没有使用__iar_program_start进行初始化,就不能使用initialize by copy初始化策略对初始值为0的全局和静态变量进行自动初始化。可以使用do not initialize初始化策略对初始值为0的全局和静态变量进行手动初始化(当然,代码里面使用了__iar_program_start进行初始化,也是可以使用do not initialize初始化策略对初始值为0的全局和静态变量进行手动初始化的)。
如下所示,ICF文件中使用do not initialize对.bss section进行手动初始化:.bss section包含的是初始值为0的全局和静态变量,放到MY_BSS block中,并把对应的MY_BSS block放到RAM:
然后需要在代码里面添加对应的手动初始化.bss section的代码:其中#pragma section命令用于定义对应的section名字,然后对应的section操作符__section_begin, __section_end和section_size就可以分别获得对应section的开始地址,结束地址和大小。
MAP文件中.bss section放到MY_BSS block中,放置到RAM:
另外对于使用了__no_init的静态和全局变量,linker默认会放置到.noinit section,可以在ICF文件使用do not initialize命令,对应代码中不能对.noinit section进行初始化,这样.noinit section的内容在启动过程中不会有任何初始化操作。
注意事项
注意:如果静态和全局变量放到了用户定义的section,并且手动明确地赋初始值0(比如 int i = 0;),默认需要对这类变量进行copy初始化,而不是zero初始化。
如下所示,静态变量TaskLedRedCounter放到了用户定义的MY_SECTION section里面,并且手动明确地赋初始值0:
MAP文件中静态变量TaskLedRedCounter的Kind是inited,而不是uninit;并且INIT TABLE里面生成了对应的Initializer bytes:
这个跟通常的初始值为0的静态和全局变量的处理有点不一样,由于对应变量的Kind是inited,所以需要使用initialize manually初始化策略(跟初始值为非0的全局和静态变量进行手动初始化一样):
如下所示:ICF文件中使用initialize manually对MY_SECTION section进行手动初始化:
MAP文件中MY_SECTION section放到MY_DATA block中,放置到RAM,对应的Initializer bytes放到MY_DATA_INIT block中,放置到ROM:
如果想对上面的变量使用do not initialize初始化策略(跟初始值为0的全局和静态变量进行手动初始化一样),需要使用编译器选项--do_explicit_zero_opt_in_named_sections:
MAP文件中静态变量TaskLedRedCounter的Kind是zero,并且INIT TABLE只有__iar_zero_init3函数:
在ICF文件中像处理正常的.bss section一样:把MY_SECTION section放到MY_BSS section,同时使用do not initialize命令:
MAP文件中静态变量TaskLedRedCounter的Kind是期望的uninit:
更多关于Initialization decisions的信息,可以通过使能Linker > List > Generate log file > Initialization decisions选项来查看对应log文件中的信息:
总结
本文主要介绍了IAR Embedded Workbench中的初始化策略:initialize by copy, initialize manually和do not initialize,用户可以根据对应的需求来灵活合理地选择初始化策略:
1. 如果对应变量在启动过程中不能被初始化,需要使用do not initialize初始化策略,并且代码里面不能对相关变量进行任何初始化;
2. 如果启动代码使用了__iar_program_start:
-
如果没有特别的初始化需求,使用initialize by copy初始化策略
-
如果有特别的初始化需求,参考下面启动代码没有使用__iar_program_start的情况
3. 如果启动代码没有使用__iar_program_start:
-
对应变量的初始值非0,使用initialize manually,并且需要添加对应的代码把ROM中的Initializer bytes拷贝到对应的RAM区域
-
通常情况下,对应变量的初始值为0,使用do not initialize,并且需要添加对应的代码对相关RAM区域进行写0操作
-
如果变量放到了用户定义的section,并且手动明确地赋初始值0默认需要对这类变量进行copy初始化(使用initialize by copy初始化策略);需要使用编译器选项--do_explicit_zero_opt_in_named_sections实现zero初始化(使用do not initialize初始化策略)