RT-Thread GPIO 驱动

  • RTT与linux驱动相比有些不一样,相对而言,RTT的操作硬件的效率会更高。

  • RT-Thread的pin驱动为上层应用提供两套不同的API,一套是对接设备驱动框架。一套是封装好的API,用户层可以直接使用。

  •                                                        


     一、gpio_drv.c

  • 这个文件就是对各种基于stm32板子的gpio的操作做统一的抽象封装,最重要的就是后面的  return rt_device_pin_register("pin", &_stm32_pin_ops, RT_NULL);

     

  • const static struct rt_pin_ops _stm32_pin_ops =
    {
        stm32_pin_mode,
        stm32_pin_write,
        stm32_pin_read,
        stm32_pin_attach_irq,
        stm32_pin_dettach_irq,
        stm32_pin_irq_enable,
    };

  • _stm32_pin_ops 这个结构体里面的回调也都是在gpio_drv.c里面定义实现的。比如写GPIO的接口,显然通过static 就知道这个接口不会是给上层应用来使用。它应该是在注册到pin之后,会再次被封装一次,以另外一副模样展现给应用来用。我们接下来就去看看它是什么样子

     

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

  • 二 pin.c

  • 通过rt_device_pin_register直接就跟进到pin.c里面了,这个注册函数如下:
  • 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;
        _hw_pin.parent.user_data    = user_data;

        /* register a character device */
        rt_device_register(&_hw_pin.parent, name, RT_DEVICE_FLAG_RDWR);

        return 0;
    }

  • 这个里面主要是对_hw_pin赋值,从其名字来看应该是一个私有数据,果不其然,该文件前面就定义了这个变量。

     而且这个文件里面还提供了给应用来直接调用的接口:
    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);

  • 应用只需要提供操作的引脚信息和相应的值就可以通过该接口来操作gpio啦,egg:

  • #define LED0_PIN    GET_PIN(B, 5)
        rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
        rt_pin_write(LED0_PIN, PIN_HIGH);

  • 除了给私有数据赋值,以便对外提供操作接口外,函数的最后还调用了上一个抽象层提供的接口rt_device_register,以便用户通过统一设备层面来操作GPIO。在这一层次,进一步屏蔽硬件的差别,不管你是GPIO还是网卡,在我这个层次看来都是rt_device,都是通过统一接口来访问你。

  • 三 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);

  • 接着我们再来看看在这个层次怎么来写GPIO:

  • rt_size_t rt_device_write(rt_device_t dev,
                              rt_off_t    pos,
                              const void *buffer,
                              rt_size_t   size)

    {
        RT_ASSERT(dev != RT_NULL);
        RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);

        if (dev->ref_count == 0)
        {
            rt_set_errno(-RT_ERROR);
            return 0;
        }

        /* call device_write interface */
        if (device_write != RT_NULL)
        {
            return device_write(dev, pos, buffer, size);
        }

        /* set error code */
        rt_set_errno(-RT_ENOSYS);

        return 0;
    }

#define device_write    (dev->write)  //这里就挂接到了_hw_pin的_pin_write方法了

  • 当然,这个层次了,如果想写GPIO,那又是另外一个方法了:

  • device = rt_device_find("xxx");

  • rt_device_open(device, ...);
    rt_device_write(deivce, buffer, len);

  • 四、总结

  • 通过device统一访问的方式:

通过Pin接口来访问:

还有很多深入的工作没有能去做,比如DFS部分的没结合去看,利用gpio收数据的流程等

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值