STM32 にドライバー登録 initcall メカニズムを実装する

再版: STM32 でのドライバー登録 initcall メカニズムの実装

1. コード

コードアプリケーション層とハードウェア層の分離管理は達成されていますが、コードにはまだ問題があり、LED制御やGPIOポートなどの各ハードウェアの初期化が必要であり、初期化関数bsp_led_init(); this関数は、次のように main 関数を呼び出して初期化する必要があります。

void bsp_init(void)
{
    
    
    bsp_rcc_init();
    bsp_tick_init();
    bsp_led_init();
    bsp_usart_init();
}

これに関する問題は、ドライバーのペアが多数あり、100 個のハードウェア ドライバーが追加された場合、使用されるのは 50 個のみで、残りのソース ファイルはコンパイルに参加しません。このとき、対応する初期化ファイルを削除するのを忘れた場合、 main 関数では、エラーが報告されます。この操作は非常に面倒であり、単一のドライバー ファイルを効果的に分離することはできません。

そこで、この問題を解決する方法が提供されます。このメソッドは、Linux kernel-initcall メカニズムに由来します。詳しい説明はネット上にたくさんありますので、ここでは詳しく説明しません。

読める:

キールのイメージ:

https://www.cnblogs.com/idle_man/archive/2010/12/18/1910158.html

Linux initcall メカニズム (カーネルにコンパイルされたドライバー用):

https://www.cnblogs.com/downey-blog/p/10486653.html

2. コード

ヘッド ファイル:


#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);

このように、ヘッダー ファイルには外部インターフェイス関数はありません。

3. コード

ジーティー:

https://gitee.com/schuck/cola_os

ギットハブ:

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

4. ヘッダファイルの解釈


#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

おすすめ

転載: blog.csdn.net/weixin_42640280/article/details/128939653