-
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));
#endifreturn 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收数据的流程等