一、前言
上一節我們實現了代碼應用層和硬件層的分離管理,但是代碼中還存在一個問題,每個硬件如LED控制,GPIO口需要初始化,初始化函數bsp_led_init();這個函數需要在主函數中調用初始化,類似這樣:
void bsp_init(void)
{
bsp_rcc_init();
bsp_tick_init();
bsp_led_init();
bsp_usart_init();
}
這樣存在的問題是:當有很對驅動,加入100個硬件驅動,我們只用到了了50個,剩下的源文件不參與編譯,此時如果忘記將主函數中的相應初始化刪除,就會報錯。這樣操作很麻煩,不能很好的實現單個驅動文件的隔離。那麼現在就提供解決此問題的方式。這個方式源自於Linux內核--initcall機制。具體講解網絡上很多,再次不在詳細說明。
二、參考資料
keil 之Image :https://www.cnblogs.com/idle_man/archive/2010/12/18/1910158.html
linux的initcall機制(針對編譯進內核的驅動) :https://www.cnblogs.com/downey-blog/p/10486653.html
三、代碼
頭文件
#ifndef _COLA_INIT_H_
#define _COLA_INIT_H_
#define __used __attribute__((__used__))
typedef void (*initcall_t)(void);
#define __define_initcall(fn, id) \
static const initcall_t __initcall_##fn##id __used \
__attribute__((__section__("initcall" #id "init"))) = fn;
#define pure_initcall(fn) __define_initcall(fn, 0) //可用作系統時鐘初始化
#define fs_initcall(fn) __define_initcall(fn, 1) //tick和調試接口初始化
#define device_initcall(fn) __define_initcall(fn, 2) //驅動初始化
#define late_initcall(fn) __define_initcall(fn, 3) //其他初始化
void do_init_call(void);
#endif
源文件
#include "cola_init.h"
void do_init_call(void)
{
extern initcall_t initcall0init$$Base[];
extern initcall_t initcall0init$$Limit[];
extern initcall_t initcall1init$$Base[];
extern initcall_t initcall1init$$Limit[];
extern initcall_t initcall2init$$Base[];
extern initcall_t initcall2init$$Limit[];
extern initcall_t initcall3init$$Base[];
extern initcall_t initcall3init$$Limit[];
initcall_t *fn;
for (fn = initcall0init$$Base;
fn < initcall0init$$Limit;
fn++)
{
if(fn)
(*fn)();
}
for (fn = initcall1init$$Base;
fn < initcall1init$$Limit;
fn++)
{
if(fn)
(*fn)();
}
for (fn = initcall2init$$Base;
fn < initcall2init$$Limit;
fn++)
{
if(fn)
(*fn)();
}
for (fn = initcall3init$$Base;
fn < initcall3init$$Limit;
fn++)
{
if(fn)
(*fn)();
}
}
在主進程中調用void do_init_call(void)進行驅動初始化,驅動註冊初始化時調用:
pure_initcall(fn) //可用作系統時鐘初始化
fs_initcall(fn) //tick和調試接口初始化
device_initcall(fn) //驅動初始化
late_initcall(fn)
舉個例子:
static void led_register(void)
{
led_gpio_init();
led_dev.dops = &ops;
led_dev.name = "led";
cola_device_register(&led_dev);
}
device_initcall(led_register);
這樣頭文件中就沒有有對外的接口函數了
四、代碼下載