打印
[应用相关]

STM32上实现驱动注册initcall机制

[复制链接]
561|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
药无尘|  楼主 | 2022-9-15 15:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
一、前言

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


使用特权

评论回复
沙发
药无尘|  楼主 | 2022-9-15 15:43 | 只看该作者
二、代码
头文件:
#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);

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

使用特权

评论回复
板凳
药无尘|  楼主 | 2022-9-15 15:44 | 只看该作者
三、代码
gitee:https://gitee.com/schuck/cola_os
girhub:https://github.com/sckuck-bit/cola_os

使用特权

评论回复
地板
qiufengsd| | 2022-10-25 22:18 | 只看该作者
借助于 linux内核中的initcall机制被调用?

使用特权

评论回复
5
maudlu| | 2022-10-25 22:39 | 只看该作者
initcall是kernel经典设计机制之一

使用特权

评论回复
6
loutin| | 2022-11-1 10:08 | 只看该作者
静态编译进内核和动态加载两种方式了吗?  

使用特权

评论回复
7
kkzz| | 2022-11-1 10:37 | 只看该作者
如何开启initcall         

使用特权

评论回复
8
maqianqu| | 2022-11-1 15:04 | 只看该作者
使用一个字符串声明你的驱动初始化函数,那么所有的驱动初始化函数都存在内存中一个连续的段中,系统启动以后,会从这个段的第一个函数开始

使用特权

评论回复
9
SantaBunny| | 2022-11-2 20:57 | 只看该作者

initcall是kernel设计机制之一

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

79

主题

619

帖子

2

粉丝