利用__attribute__((section("name")))构建初始化函数表

在嵌入式学习工作中经常初始化一个硬件就写一个初始化函数,基本都要到主函数中调用进行初始化,main函数都要改变。当利用__attribute__((section("name")))这个属性就可以构造一个初始化函数表,这样每次初始化一个硬件啥的就不用到main函数中去调用初始化函数。式在RTT初始化函数和Linux初始化驱动模块也是类似这样做的。

attribute的用法

http://www.keil.com/support/man/docs/armcc/armcc_chr1359124982450.htm

代码

  • 头文件
#ifndef _HARDWARE_INIT_H_
#define _HARDWARE_INIT_H_

#if defined(__CC_ARM) || defined(__CLANG_ARM)   /* ARMCC Complier */
    #define INIT_SECTION(x)      __attribute__((section(x))) 
    #define INIT_USED            __attribute__((used))     
#elif defined(__ICCARM__)                      /* IAR ARMCC Complier */

#elif defined(__GNUC__)                        /* GNUC Complier */

#else
    #error "not support tool chain"
#endif

typedef void (*init_func)(void);

typedef struct{
	init_func _init_func;
}init_func_t;

#define INIT_EXPORT(handler)                                                  \
	INIT_USED init_func_t _init_##handler##_func INIT_SECTION("INIT_LIST") =  \          //INIT_LIST自定义段名
	{                                                                         \
		handler,                                                              \
	}
	
void sys_init(void);

#endif
  • 源文件
    在MDK中使用下面方式获得自定义段的起始和终止地址。
static init_func_t *init_list_begin;
static init_func_t *init_list_end;

void sys_init(void)
{
	init_func_t *index;
#if defined(__CC_ARM) || defined(__CLANG_ARM) 
    extern const int INIT_LIST$$Base;   
    extern const int INIT_LIST$$Limit;
    init_list_begin = (init_func_t *)&INIT_LIST$$Base;   //获得段起始地址
    init_list_end   = (init_func_t *)&INIT_LIST$$Limit;  //获得结束段地址
#elif defined(__ICCARM__)                      /* IAR ARMCC Complier */

#elif defined(__GNUC__)                        /* GNUC Complier */

#endif
	for(index = init_list_begin; index < init_list_end; index++)
	{
		index->_init_func();
	}
}
  • 初始化函数使用INIT_EXPORT修饰
void MY_USART_Init(void)
{
	__MY_USART_Init(115200);
}
INIT_EXPORT(MY_USART_Init);

用INIT_EXPORT修饰过的函数都会定义一个函数指针在自定义的section——INIT_LIST,这个自定义的段由编译器静态分配。

  • 主函数中调用sys_init()
 int main(void)
 {			 
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	 
	sys_init();	

   	while(1)
	{
		software_timer_main_loop();
	}
}	 
posted @ 2020-03-01 23:07  guangjieMVP  阅读(1237)  评论(0编辑  收藏  举报