• RT-thread 设备驱动组件之PIN设备


          在RT-thread 2.0.0正式版中引入了pin设备作为杂类设备,其设备驱动文件pin.c在rt-thread-2.0.1componentsdriversmisc中,主要用于操作芯片GPIO, 如点亮led,按键等。同时对于相应的芯片平台,需要自行编写底层gpio驱动,如gpio.c。本文主要涉及的pin设备文件有:驱动框架文件(pin.c,pin.h),底层硬件驱动文件(gpio.c,gpio.h)。在应用用PIN设备时,需要在rtconfig.h中宏定义#define RT_USING_PIN。

    一、PIN设备驱动框架

    在pin.c中定义了一个静态的pin设备对象static struct rt_device_pin _hw_pin,其中结构体类型struct rt_device_pin在pin.h中定义为:

    /* pin device and operations for RT-Thread */
    struct rt_device_pin
    {
        struct rt_device parent;
        const struct rt_pin_ops *ops;
    };
    struct rt_device_pin_mode
    {
        rt_uint16_t pin;  //pin index in pins[] of gpio.c
        rt_uint16_t mode;
    };
    struct rt_device_pin_status
    {
        rt_uint16_t pin;  //pin index in pins[] of gpio.c
        rt_uint16_t status;
    };
    
    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 */
    };

    在pin.c中主要实现了_pin_read,_pin_write,_pin_control三个函数,同时将这三个函数注册为_hw_pin设备的统一接口函数:

    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;
    
        _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;
    
        _hw_pin.ops                 = ops;
        _hw_pin.parent.user_data    = user_data;
    
        /* register a character device */
        rt_device_register(&_hw_pin.parent, name, RT_DEVICE_FLAG_RDWR);
    
        return 0;
    }

    最后,在pin.c文件中将rt_pin_mode,rt_pin_write,rt_pin_read三个函数加入到finsh的函数列表中,用于调试。 

    二、底层硬件驱动

    在gpio.c中主要实现struct rt_pin_ops中的三个接口函数:stm32_pin_mode,stm32_pin_write,stm32_pin_read:

    const static struct rt_pin_ops _stm32_pin_ops =
    {
        stm32_pin_mode,
        stm32_pin_write,
        stm32_pin_read,
    };

    同时注册 _hw_pin设备,其设备名称为“pin”,PIN设备硬件初始化:

    int stm32_hw_pin_init(void)
    {
        rt_device_pin_register("pin", &_stm32_pin_ops, RT_NULL);
        return 0;
    }
    INIT_BOARD_EXPORT(stm32_hw_pin_init);//stm32_hw_pin_init will be called in rt_components_board_init()

     三、PIN设备初始化

    在gpio.c中修改使用的IO口数组:

    /* STM32 GPIO driver */
    struct pin_index
    {
        int index;
        uint32_t rcc;
        GPIO_TypeDef *gpio;
        uint32_t pin;
    };
    
    /* LED ->PD12,PD13,PD14,PD15; USER Button->PA0 */
    static const struct pin_index pins[] =
    {
        { 0, RCC_AHB1Periph_GPIOD, GPIOD, GPIO_Pin_12},  //green
        { 1, RCC_AHB1Periph_GPIOD, GPIOD, GPIO_Pin_13},  //orange
        { 2, RCC_AHB1Periph_GPIOD, GPIOD, GPIO_Pin_14},  //red
        { 3, RCC_AHB1Periph_GPIOD, GPIOD, GPIO_Pin_15},  //blue
        { 4, RCC_AHB1Periph_GPIOA, GPIOA, GPIO_Pin_0},   //user button
    };

           此外在gpio_pin.c的外设初始化函数中,需要先调用rt_device_open函数(尽管该函数没有在底层实现),保证pin设备对象类的设备引用计数值ref_count不为0,这样才可正常使用rt_device_control,rt_device_write,rt_device_read函数操作GPIO口:

    static struct rt_device_pin_mode led_mode[]=
    {
        {0,PIN_MODE_OUTPUT},
        {1,PIN_MODE_OUTPUT},
        {2,PIN_MODE_OUTPUT},
        {3,PIN_MODE_OUTPUT},
    };
    
    static struct rt_device_pin_status led_status[]=
    {
        {0,PIN_HIGH}, /* 0:green on  */
        {1,PIN_HIGH}, /* 1:orange on  */
        {2,PIN_HIGH}, /* 2:red on  */
        {3,PIN_HIGH}, /* 3:blue on  */
                    
        {0,PIN_LOW},  /* 4:green off */
        {1,PIN_LOW},  /* 5:orange off  */
        {2,PIN_LOW},  /* 6:red off  */
        {3,PIN_LOW},  /* 7:blue off  */
    };
    
    /* it can't be PIN_MODE_INPUT_PULLUP, or the key always will keep PIN_HIGH status */
    static struct rt_device_pin_mode key_mode = {4,PIN_MODE_INPUT};
    static struct rt_device_pin_status key_status = {4,PIN_LOW};
    
    static struct rt_device_pin * pin_device;
    static rt_err_t gpio_pin_init(const char * pin_device_name)
    {    
        pin_device = (struct rt_device_pin *)rt_device_find(pin_device_name);
        if(pin_device == RT_NULL)
        {
            rt_kprintf("pin device for gpio %s not found!
    ", pin_device_name);
            return -RT_ENOSYS;
        }
        
        /* oflag has no meaning for pin device , so set to RT_NULL */
        if(rt_device_open(&pin_device->parent, RT_NULL) == RT_EOK)
        {
            /* init led */
            for(int i=0; i<(sizeof(led_mode)/sizeof(led_mode[0])); i++)
            {
                rt_device_control(&pin_device->parent, RT_NULL, &led_mode[i]);
                rt_device_write(&pin_device->parent, RT_NULL, &led_status[i], sizeof(led_status[i]));//init all led PIN_HIGH
            }
            
            /* init key */
            rt_device_control(&pin_device->parent, RT_NULL, &key_mode);
        }
        
        return 0;
    }
    
    int rt_gpio_pin_init(void)
    {    
        gpio_pin_init("pin");
        
        return 0;
    }
    INIT_APP_EXPORT(rt_gpio_pin_init);
  • 相关阅读:
    分享一些书籍,方方面面,很多值得一读
    C#网络爬虫--多线程处理强化版
    图书管理系统
    jquery完成界面无刷新加载登陆注册
    springboot jar项目 改为war项目
    nginx 配置文件配置(ssl和代理80端口)
    linux 安装mysql8.0
    linux redis安装和启动,远程链接
    linux nginx 安装启动
    linux tar方式安装配置jdk
  • 原文地址:https://www.cnblogs.com/King-Gentleman/p/4649713.html
Copyright © 2020-2023  润新知