美文网首页
Pin驱动分析

Pin驱动分析

作者: huojusan | 来源:发表于2019-05-24 23:46 被阅读0次

    系统启动流程图

    RTThread系统启动流程图

    设备模型

    image.png

    根据设备模型,我们可以清晰的知道,各种设备类,其实在系统中,都继承于设备基类,也就是rt_device类,而rt_device类,又继承于rt_object基类。
    所以,按照模型是不是可以这样理解,所有不同设备的操作,其实在系统看来,都是rt_object的操作。

    设备硬件初始化过程

    rt_components_board_init() -> rt_hw_pin_init() -> rt_device_pin_register() -> rt_device_register() -> rt_object_init()

    硬件Pin初始化

    rt_hw_pin_init()函数,是pin设备的硬件初始化函数,该函数存放在drv_gpio.c文件中,通过INIT_BOARD_EXPORT(rt_hw_pin_init)宏定义,表示使用自动初始化功能,按照这种方式,rt_hw_usart_init() 函数就会被系统自动调用,那么它是在哪里被调用的呢?

    用来实现自动初始化功能的宏接口定义详细描述如下表所示:

    初始化顺序 宏接口 描述
    1 INIT_BOARD_EXPORT(fn) 非常早期的初始化,此时调度器还未启动
    2 INIT_PREV_EXPORT(fn) 主要是用于纯软件的初始化、没有太多依赖的函数
    3 INIT_DEVICE_EXPORT(fn) 外设驱动初始化相关,比如网卡设备
    4 INIT_COMPONENT_EXPORT(fn) 组件初始化,比如文件系统或者 LWIP
    5 INIT_ENV_EXPORT(fn) 系统环境初始化,比如挂载文件系统
    6 INIT_APP_EXPORT(fn) 应用初始化,比如 GUI 应用

    根据rtthread系统启动流程图,可以看出,rt_components_board_init()函数执行的比较早,主要初始化相关硬件环境,而执行这个函数时将会遍历通过 INIT_BOARD_EXPORT(fn)申明的初始化函数表,并调用各个函数。
    比如:INIT_BOARD_EXPORT( rt_hw_pin_init);

    Pin设备注册

    • rt_hw_pin_init(void)初始化函数
    /* 在文件drv_gpio.c中实现 */
    int rt_hw_pin_init(void)
    {
        int result;
        result = rt_device_pin_register("pin", &_stm32_pin_ops, RT_NULL);
        return result;
    }
    INIT_BOARD_EXPORT(rt_hw_pin_init);
    
    • rt_device_pin_register() : Pin设备注册函数

    在rt_hw_pin_init()函数被自动初始化调用后,会调用该Pin设备注册函数,将Pin类型的设备注册到系统中。
    该函数在pin.c文件中,这个文件存于系统组件components\drivers目录下

    int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data)
    {
        _hw_pin.parent.type         = RT_Device_Class_Miscellaneous;
        _hw_pin.parent.rx_indicate  = RT_NULL;
        _hw_pin.parent.tx_complete  = RT_NULL;
    
    #ifdef RT_USING_DEVICE_OPS
        _hw_pin.parent.ops          = &pin_ops;
    #else
        _hw_pin.parent.init         = RT_NULL;
        _hw_pin.parent.open         = RT_NULL;
        _hw_pin.parent.close        = RT_NULL;
        _hw_pin.parent.read         = _pin_read;
        _hw_pin.parent.write        = _pin_write;
        _hw_pin.parent.control      = _pin_control;
    #endif
    
        _hw_pin.ops                 = ops;   //映射HAL固件库函数接口
        _hw_pin.parent.user_data    = user_data;
    
        /* register a character device */
        rt_device_register(&_hw_pin.parent, name, RT_DEVICE_FLAG_RDWR);
    
        return 0;
    }
    
    • struct rt_pin_ops *ops操作函数定义如下,在文件drv_gpio.c中实现。
    //在文件drv_gpio.c中存放
    static void stm32_pin_write(rt_device_t dev, rt_base_t pin, rt_base_t value)
    {
        const struct pin_index *index;
    
        index = get_pin(pin);
        if (index == RT_NULL)
        {
            return;
        }
        /* 库函数调用 */
        HAL_GPIO_WritePin(index->gpio, index->pin, (GPIO_PinState)value);
    }
    
    static int stm32_pin_read(rt_device_t dev, rt_base_t pin)
    {
        int value;
        const struct pin_index *index;
    
        value = PIN_LOW;
    
        index = get_pin(pin);
        if (index == RT_NULL)
        {
            return value;
        }
        /* 库函数调用 */
        value = HAL_GPIO_ReadPin(index->gpio, index->pin);
    
        return value;
    }
    
    static void stm32_pin_mode(rt_device_t dev, rt_base_t pin, rt_base_t mode)
    {
        const struct pin_index *index;
        GPIO_InitTypeDef GPIO_InitStruct;
    
        index = get_pin(pin);
        if (index == RT_NULL)
        {
            return;
        }
    
        /* Configure GPIO_InitStructure */
        GPIO_InitStruct.Pin = index->pin;
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    
        if (mode == PIN_MODE_OUTPUT)
        {
            /* output setting */
            GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
            GPIO_InitStruct.Pull = GPIO_NOPULL;
        }
        else if (mode == PIN_MODE_INPUT)
        {
            /* input setting: not pull. */
            GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
            GPIO_InitStruct.Pull = GPIO_NOPULL;
        }
        else if (mode == PIN_MODE_INPUT_PULLUP)
        {
            /* input setting: pull up. */
            GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
            GPIO_InitStruct.Pull = GPIO_PULLUP;
        }
        else if (mode == PIN_MODE_INPUT_PULLDOWN)
        {
            /* input setting: pull down. */
            GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
            GPIO_InitStruct.Pull = GPIO_PULLDOWN;
        }
        else if (mode == PIN_MODE_OUTPUT_OD)
        {
            /* output setting: od. */
            GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
            GPIO_InitStruct.Pull = GPIO_NOPULL;
        }
        /* 库函数调用 */
        HAL_GPIO_Init(index->gpio, &GPIO_InitStruct);
    }
    
    /* 将硬件驱动层接口封装层结构体struct  rt_pin_ops */
    const static struct rt_pin_ops _stm32_pin_ops =
    {
        stm32_pin_mode,
        stm32_pin_write,
        stm32_pin_read,
        stm32_pin_attach_irq,
        stm32_pin_detach_irq,
        stm32_pin_irq_enable,
    };
    

    分析以上代码可知,这几个函数都封装在struct rt_pin_opsPIN设备操作结构体中 ,stm32_pin_mode, stm32_pin_write, stm32_pin_read调用了HAL库函数HAL_GPIO_xxx

    PIN设备也是一种设备类型,继承于struct rt_device_pin,变量_hw_pin就是当前的PIN设备的结构体。

    /* 文件 pin.h ,指针函数结构体,与上面定义的_stm32_pin_ops这个常量结构体是一一对应的关系*/
    struct rt_pin_ops
    {
        void (*pin_mode)(struct rt_device *device, rt_base_t pin, rt_base_t mode);
        void (*pin_write)(struct rt_device *device, rt_base_t pin, rt_base_t value);
        int (*pin_read)(struct rt_device *device, rt_base_t pin);
    
        /* TODO: add GPIO interrupt */
        rt_err_t (*pin_attach_irq)(struct rt_device *device, rt_int32_t pin,
                          rt_uint32_t mode, void (*hdr)(void *args), void *args);//设置中断回调函数
        rt_err_t (*pin_detach_irq)(struct rt_device *device, rt_int32_t pin);
        rt_err_t (*pin_irq_enable)(struct rt_device *device, rt_base_t pin, rt_uint32_t enabled);
    };
    
    //文件 pin.c
    /* RT-Thread Hardware PIN APIs */
    void rt_pin_mode(rt_base_t pin, rt_base_t mode)
    {
        RT_ASSERT(_hw_pin.ops != RT_NULL);
        _hw_pin.ops->pin_mode(&_hw_pin.parent, pin, mode);
    }
    FINSH_FUNCTION_EXPORT_ALIAS(rt_pin_mode, pinMode, set hardware pin mode);
    
    void rt_pin_write(rt_base_t pin, rt_base_t value)
    {
        RT_ASSERT(_hw_pin.ops != RT_NULL);
        _hw_pin.ops->pin_write(&_hw_pin.parent, pin, value);
    }
    FINSH_FUNCTION_EXPORT_ALIAS(rt_pin_write, pinWrite, write value to hardware pin);
    
    int  rt_pin_read(rt_base_t pin)
    {
        RT_ASSERT(_hw_pin.ops != RT_NULL);
        return _hw_pin.ops->pin_read(&_hw_pin.parent, pin);
    }
    FINSH_FUNCTION_EXPORT_ALIAS(rt_pin_read, pinRead, read status from hardware pin);
    

    以上三个接口rt_pin_mode, rt_pin_write, rt_pin_read封装后,作为PIN设备管理接口,提供给应用层使用,在接口内部通过_hw_pin.ops->pin_read这种函数指针,其实调用的就是 stm32_pin_mode, stm32_pin_write, stm32_pin_read函数,实现了应用层对硬件的操作功能。

    驱动设备注册

    所有的IO设备,都属于设备类型,关于设备的操作,内核有统一的调用接口,这些接口都放在device.c文件中。
    rt_device_register函数存在于内核的device.c文件中

    rt_err_t rt_device_register(rt_device_t dev,
                                const char *name,
                                rt_uint16_t flags)
    {
        if (dev == RT_NULL)
            return -RT_ERROR;
    
        if (rt_device_find(name) != RT_NULL) 查找设备,确定该设备是否注册过
            return -RT_ERROR;
    
        rt_object_init(&(dev->parent), RT_Object_Class_Device, name);
        dev->flag = flags;
        dev->ref_count = 0;
        dev->open_flag = 0;
    
    #if defined(RT_USING_POSIX)
        dev->fops = RT_NULL;
        rt_wqueue_init(&(dev->wait_queue));
    #endif
    
        return RT_EOK;
    }
    RTM_EXPORT(rt_device_register);
    

    object对象初始化

    所有的设备,都是继承于object对象,所以,最后Pin设备的初始化,会调用object初始化函数,将Pin设备增加到object list中。rt_object_init函数存在于内核的object.c文件中

    void rt_object_init(struct rt_object         *object,
                        enum rt_object_class_type type,
                        const char               *name)
    {
        register rt_base_t temp;
        struct rt_object_information *information;
    
        /* get object information */
        information = rt_object_get_information(type);
        RT_ASSERT(information != RT_NULL);
    
        /* initialize object's parameters */
    
        /* set object type to static */
        object->type = type | RT_Object_Class_Static;
    
        /* copy name */
        rt_strncpy(object->name, name, RT_NAME_MAX);
    
        RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object));
    
        /* lock interrupt */
        temp = rt_hw_interrupt_disable();
    
        /* insert object into information object list */
        rt_list_insert_after(&(information->object_list), &(object->list));
    
        /* unlock interrupt */
        rt_hw_interrupt_enable(temp);
    }
    

    应用层接口使用示例如下:

    
    void beep_on(void *args)
    {
        rt_kprintf("turn on beep!\n");
    
        rt_pin_write(BEEP_PIN_NUM, PIN_HIGH);
    }
    
    void beep_off(void *args)
    {
        rt_kprintf("turn off beep!\n");
    
        rt_pin_write(BEEP_PIN_NUM, PIN_LOW);
    }
    
    static void pin_beep_sample(void)
    {
        /* 蜂鸣器引脚为输出模式 */
        rt_pin_mode(BEEP_PIN_NUM, PIN_MODE_OUTPUT);
        /* 默认低电平 */
        rt_pin_write(BEEP_PIN_NUM, PIN_LOW);
    
        /* 按键0引脚为输入模式 */
        rt_pin_mode(KEY0_PIN_NUM, PIN_MODE_INPUT_PULLUP);
        /* 绑定中断,下降沿模式,回调函数名为beep_on */
        rt_pin_attach_irq(KEY0_PIN_NUM, PIN_IRQ_MODE_FALLING, beep_on, RT_NULL);
        /* 使能中断 */
        rt_pin_irq_enable(KEY0_PIN_NUM, PIN_IRQ_ENABLE);
    
        /* 按键1引脚为输入模式 */
        rt_pin_mode(KEY1_PIN_NUM, PIN_MODE_INPUT_PULLUP);
        /* 绑定中断,下降沿模式,回调函数名为beep_off */
        rt_pin_attach_irq(KEY1_PIN_NUM, PIN_IRQ_MODE_FALLING, beep_off, RT_NULL);
        /* 使能中断 */
        rt_pin_irq_enable(KEY1_PIN_NUM, PIN_IRQ_ENABLE);
    }
    

    其他几个宏申明的初始化函数表调用

    rt_components_init() 函数会在操作系统运行起来之后创建的 main 线程里被调用执行,这个时候硬件环境和操作系统已经初始化完成,可以执行应用相关代码。rt_components_init() 函数会遍历通过剩下的其他几个宏申明的初始化函数表。

    /* 本段函数,存在于内核的components.c文件中,实现了系统启动的整个过程  */
    void rt_application_init(void)/* 应用程序的初始化函数 */
    {
        rt_thread_t tid;
    
    /* 创建主线程,在主线程中,进一步对系统进行除硬件以外的其他初始化工作 */
    #ifdef RT_USING_HEAP
        tid = rt_thread_create("main", main_thread_entry, RT_NULL,
                               RT_MAIN_THREAD_STACK_SIZE, RT_THREAD_PRIORITY_MAX / 3, 20);
        RT_ASSERT(tid != RT_NULL);
    #else
        rt_err_t result;
    
        tid = &main_thread;
        result = rt_thread_init(tid, "main", main_thread_entry, RT_NULL,
                                main_stack, sizeof(main_stack), RT_THREAD_PRIORITY_MAX / 3, 20);
        RT_ASSERT(result == RT_EOK);
        
        /* if not define RT_USING_HEAP, using to eliminate the warning */
        (void)result;
    #endif
    
        rt_thread_startup(tid);
    }
    
    /* the system main thread */
    void main_thread_entry(void *parameter)
    {
        extern int main(void);
        extern int $Super$$main(void);
    
        /* RT-Thread components initialization */
        rt_components_init();  /* 系统的其他初始化过程,在本函数中实现 */
    
        /* invoke system main function */
    #if defined (__CC_ARM)
        $Super$$main(); /* for ARMCC. */
    #elif defined(__ICCARM__) || defined(__GNUC__)
        main();
    #endif
    }
    

    相关文章

      网友评论

          本文标题:Pin驱动分析

          本文链接:https://www.haomeiwen.com/subject/ohpozqtx.html