再看驱动模型
从zephyr驱动模型一文可以看到Zephyr下一个驱动实现的几大要素:
- driver name
- driver init函数
- driver各种操作函数driver_api
- driver配置信息driver_cfg
- driver的数据信息driver_data
从驱动使用层面上来说,因为初始化是编译期已经固定好(参见zephyr驱动模型一文), 运行期会自动初始化,所以只用关注各种操作函数也就是driver_api
驱动实现步骤
- Step1: 找到驱动头文件,理解驱动提供操作API的作用和参数含义
- Step2: 在驱动头文件中,对应操作API和driver_api内操作函数指针
- Step3: 在驱动代码中实现driver_api函数指针的函数,添加driver_data和driver_cfg
- Step4: 实现driver初始化函数
- Step5: 使用DEVICE_AND_API_INIT注册初始化函数,和实现好的driver_api
LED示例
Step1
找到驱动头文件include/led.h,理解驱动提供的API作用和参数含义,Zephyr为LED驱动定义了下面4种方法:
- 点亮LED
__syscall int led_on(struct device *dev, u32_t led); - 关闭LED
__syscall int led_off(struct device *dev, u32_t led); - 闪烁LED,delay_on亮灯时间 ms,delay_off 熄灯时间ms
__syscall int led_blink(struct device *dev, u32_t led, u32_t delay_on, u32_t delay_off); - 设置LED亮度,value亮度值, 百分比
__syscall int led_set_brightness(struct device *dev, u32_t led, u8_t value);
Step2
找到对应的led_driver_api
1 | typedef int (*led_api_blink)(struct device *dev, u32_t led, |
Step3
具体的实现就按照你的硬件自由发挥了,一般情况下led_driver_api内规定的API不能少,例如下面就是nrf52_moderate的led api.
1 | static int nrf52_led_blink(struct device *dev, u32_t led, |
通常情况下,驱动内部需要自己管理一些数据和配置,这些可以放driver_data和driver_cfg。例如nrf52_moderate的led不需要配置就只需要定义driver_data
1 | struct nrf52led_data { |
Step4
实现driver初始化函数,driver的初始化函数会在上电时被调用,这也是必须要实现的,里面的代码也是根据你对驱动设计而来,自由发挥。
1 | static int nrf52_led_init(struct device *dev) |
Step 5
将前面定义好的初始化函数,driver_api,driver_data,driver_cfg注册,注册的时候会绑定一个字符串形式的驱动名,之后用驱动的时候会根据这个字符串来查找驱动
1 | DEVICE_AND_API_INIT(nrf52_led, "NRF_52", |
其它一些驱动的模型定义
GPIO
API
- 配置PIN, flags指定pin的IN/OUT,是否pull-down/up, 是否是中断,中断触发方式,flag定义参见include/dt-binding/gpio/gpio.h
static inline int gpio_pin_configure(struct device *port, u32_t pin,int flags) - 设置PIN输出电平value
static inline int gpio_pin_write(struct device *port, u32_t pin, u32_t value) - 读取PIN输入电平value
static inline int gpio_pin_read(struct device port, u32_t pin, u32_t value) - 设置PIN中断callback,此时将callback函数保存在callback
static inline void gpio_init_callback(struct gpio_callback *callback, gpio_callback_handler_t handler, u32_t pin_mask) - 为中断添加callback
static inline int gpio_add_callback(struct device port, struct gpio_callback callback) - 移除中断callback
static inline int gpio_remove_callback(struct device port, struct gpio_callback callback) - 使能指定pin上的callback
static inline int gpio_pin_enable_callback(struct device *port, u32_t pin) - 关闭指定pin上的callback
static inline int gpio_pin_disable_callback(struct device *port, u32_t pin) - 获取gpio上中断pending情况0:没有中断pengding, 非0:有中断pending
__syscall int gpio_get_pending_int(struct device *dev);
driver_api
1 | typedef int (*gpio_config_t)(struct device *port, int access_op, |
PWM
API
- 设置PWM属性,period: pwm周期ms, pulse: pwm pulse宽度 ms
static inline int pwm_pin_set_usec(struct device *dev, u32_t pwm, u32_t period, u32_t pulse)
driver_api
1 | typedef int (*pwm_pin_set_t)(struct device *dev, u32_t pwm, |