该笔记类别主要是在自己学习时做的一些记录,方便自己很久不用忘掉时进行快速回忆
驱动层级图
通用GPIO设备驱动
宏
pin.h定义了高低电平,模式等的宏,应用层调用时使用该处的宏进行配置,底层驱动则更具该处宏的定义去执行具体功能。
#define PIN_LOW 0x00
#define PIN_HIGH 0x01
#define PIN_MODE_OUTPUT 0x00
#define PIN_MODE_INPUT 0x01
#define PIN_MODE_INPUT_PULLUP 0x02
#define PIN_MODE_INPUT_PULLDOWN 0x03
#define PIN_MODE_OUTPUT_OD 0x04
#define PIN_IRQ_MODE_RISING 0x00
#define PIN_IRQ_MODE_FALLING 0x01
#define PIN_IRQ_MODE_RISING_FALLING 0x02
#define PIN_IRQ_MODE_HIGH_LEVEL 0x03
#define PIN_IRQ_MODE_LOW_LEVEL 0x04
#define PIN_IRQ_DISABLE 0x00
#define PIN_IRQ_ENABLE 0x01
#define PIN_IRQ_PIN_NONE -1
结构体
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);
};
该结构体用于规范化底层GPIO驱动,底层驱动按照该结构体的函数编写,然后实例化它,作为通用GPIO驱动调用底层GPIO驱动的接口。
函数
注册函数:
int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data);
其一是用于告诉操作系统引脚设备的存在,其二是将底层驱动接口函数交付给通用驱动。该函数的调用在底层驱动中。
基本功能函数:
void rt_pin_mode(rt_base_t pin, rt_base_t mode);
void rt_pin_write(rt_base_t pin, rt_base_t value);
int rt_pin_read(rt_base_t pin);
rt_err_t rt_pin_attach_irq(rt_int32_t pin, rt_uint32_t mode,
void (*hdr)(void *args), void *args);
rt_err_t rt_pin_detach_irq(rt_int32_t pin);
rt_err_t rt_pin_irq_enable(rt_base_t pin, rt_uint32_t enabled);
应用层通过调用该通用函数接口实现功能,而这些通用函数接口实际上是又调用了底层驱动的接口函数。
底层GPIO设备驱动
根据芯片种类的不同,编写对应的驱动,但是必须完全符合通用驱动层提供的函数接口模型。改层的初始化函数和其他函数不同,会调用通用层的注册函数,然后在板级初始化的时候对其调用。
例如STM32F10X中的GPIO.c中
int stm32_hw_pin_init(void)
{
int result;
result = rt_device_pin_register("pin", &_stm32_pin_ops, RT_NULL);
return result;
}
该函数被宏定义到了板级自启动序列中去了
INIT_BOARD_EXPORT(stm32_hw_pin_init);
这里附提一下rtt的执行顺序
/* board init routines will be called in board_init() function */
#define INIT_BOARD_EXPORT(fn) INIT_EXPORT(fn, "1")
/* pre/device/component/env/app init routines will be called in init_thread */
/* components pre-initialization (pure software initilization) */
#define INIT_PREV_EXPORT(fn) INIT_EXPORT(fn, "2")
/* device initialization */
#define INIT_DEVICE_EXPORT(fn) INIT_EXPORT(fn, "3")
/* components initialization (dfs, lwip, ...) */
#define INIT_COMPONENT_EXPORT(fn) INIT_EXPORT(fn, "4")
/* environment initialization (mount disk, ...) */
#define INIT_ENV_EXPORT(fn) INIT_EXPORT(fn, "5")
/* appliation initialization (rtgui application etc ...) */
#define INIT_APP_EXPORT(fn) INIT_EXPORT(fn, "6")
这里看出,板级初始化时很靠前执行的,也可以通过startup.c中看到板级初始化函数
int rtthread_startup(void)
{
rt_hw_interrupt_disable();
/* board level initalization
* NOTE: please initialize heap inside board initialization.
*/
rt_hw_board_init();
/* show RT-Thread version */
rt_show_version();
/* timer system initialization */
rt_system_timer_init();
/* scheduler system initialization */
rt_system_scheduler_init();
#ifdef RT_USING_SIGNALS
/* signal system initialization */
rt_system_signal_init();
#endif
/* create init_thread */
rt_application_init();
/* timer thread initialization */
rt_system_timer_thread_init();
/* idle thread initialization */
rt_thread_idle_init();
/* start scheduler */
rt_system_scheduler_start();
/* never reach here */
return 0;
}