STM32上实现驱动注册initcall机制

 转载:STM32上实现驱动注册initcall机制  

一、代码

        实现了代码应用层和硬件层的分离管理,但是代码中还存在一个问题,每个硬件如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);

这样头文件中就没有有对外的接口函数了。

三、代码

gitee:

https://gitee.com/schuck/cola_os

girhub:

https://github.com/sckuck-bit/cola_os

四、头文件解读

#ifndef _COLA_INIT_H_
#define _COLA_INIT_H_
 
#define  __used  __attribute__((__used__)) //使用__used__属性
 
typedef void (*initcall_t)(void);   //定义函数指针类型
 
#define __define_initcall(fn, id) \   //定义注册函数宏

// 定义函数指针,函数指针名为:__initcall_##fn##id ,例如fn = test,id = 0; 
//则函数指针名为__initcalltest0;
    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 

参考文献:
C语言中"#"和"##"的用法

__attribute_unused__和__attribute_used__的作用

gcc的__attribute__编译属性

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值