利用__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();
	}
}	 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章