系统启动流程图
RTThread系统启动流程图设备模型
image.png根据设备模型,我们可以清晰的知道,各种设备类,其实在系统中,都继承于设备基类,也就是rt_device类,而rt_device类,又继承于rt_object基类。
所以,按照模型是不是可以这样理解,所有不同设备的操作,其实在系统看来,都是rt_object的操作。
设备硬件初始化过程
rt_components_board_init() -> rt_hw_pin_init() -> rt_device_pin_register() -> rt_device_register() -> rt_object_init()
硬件Pin初始化
rt_hw_pin_init()函数,是pin设备的硬件初始化函数,该函数存放在drv_gpio.c文件中,通过INIT_BOARD_EXPORT(rt_hw_pin_init)宏定义,表示使用自动初始化功能,按照这种方式,rt_hw_usart_init() 函数就会被系统自动调用,那么它是在哪里被调用的呢?
用来实现自动初始化功能的宏接口定义详细描述如下表所示:
初始化顺序 | 宏接口 | 描述 |
---|---|---|
1 | INIT_BOARD_EXPORT(fn) | 非常早期的初始化,此时调度器还未启动 |
2 | INIT_PREV_EXPORT(fn) | 主要是用于纯软件的初始化、没有太多依赖的函数 |
3 | INIT_DEVICE_EXPORT(fn) | 外设驱动初始化相关,比如网卡设备 |
4 | INIT_COMPONENT_EXPORT(fn) | 组件初始化,比如文件系统或者 LWIP |
5 | INIT_ENV_EXPORT(fn) | 系统环境初始化,比如挂载文件系统 |
6 | INIT_APP_EXPORT(fn) | 应用初始化,比如 GUI 应用 |
根据rtthread系统启动流程图,可以看出,rt_components_board_init()
函数执行的比较早,主要初始化相关硬件环境,而执行这个函数时将会遍历通过 INIT_BOARD_EXPORT(fn)
申明的初始化函数表,并调用各个函数。
比如:INIT_BOARD_EXPORT( rt_hw_pin_init);
Pin设备注册
- rt_hw_pin_init(void)初始化函数
/* 在文件drv_gpio.c中实现 */
int rt_hw_pin_init(void)
{
int result;
result = rt_device_pin_register("pin", &_stm32_pin_ops, RT_NULL);
return result;
}
INIT_BOARD_EXPORT(rt_hw_pin_init);
- rt_device_pin_register() : Pin设备注册函数
在rt_hw_pin_init()函数被自动初始化调用后,会调用该Pin设备注册函数,将Pin类型的设备注册到系统中。
该函数在pin.c文件中,这个文件存于系统组件components\drivers目录下
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; //映射HAL固件库函数接口
_hw_pin.parent.user_data = user_data;
/* register a character device */
rt_device_register(&_hw_pin.parent, name, RT_DEVICE_FLAG_RDWR);
return 0;
}
- struct rt_pin_ops *ops操作函数定义如下,在文件drv_gpio.c中实现。
//在文件drv_gpio.c中存放
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);
}
static int stm32_pin_read(rt_device_t dev, rt_base_t pin)
{
int value;
const struct pin_index *index;
value = PIN_LOW;
index = get_pin(pin);
if (index == RT_NULL)
{
return value;
}
/* 库函数调用 */
value = HAL_GPIO_ReadPin(index->gpio, index->pin);
return value;
}
static void stm32_pin_mode(rt_device_t dev, rt_base_t pin, rt_base_t mode)
{
const struct pin_index *index;
GPIO_InitTypeDef GPIO_InitStruct;
index = get_pin(pin);
if (index == RT_NULL)
{
return;
}
/* Configure GPIO_InitStructure */
GPIO_InitStruct.Pin = index->pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
if (mode == PIN_MODE_OUTPUT)
{
/* output setting */
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
}
else if (mode == PIN_MODE_INPUT)
{
/* input setting: not pull. */
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
}
else if (mode == PIN_MODE_INPUT_PULLUP)
{
/* input setting: pull up. */
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
}
else if (mode == PIN_MODE_INPUT_PULLDOWN)
{
/* input setting: pull down. */
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
}
else if (mode == PIN_MODE_OUTPUT_OD)
{
/* output setting: od. */
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
}
/* 库函数调用 */
HAL_GPIO_Init(index->gpio, &GPIO_InitStruct);
}
/* 将硬件驱动层接口封装层结构体struct rt_pin_ops */
const static struct rt_pin_ops _stm32_pin_ops =
{
stm32_pin_mode,
stm32_pin_write,
stm32_pin_read,
stm32_pin_attach_irq,
stm32_pin_detach_irq,
stm32_pin_irq_enable,
};
分析以上代码可知,这几个函数都封装在
struct rt_pin_ops
PIN设备操作结构体中 ,stm32_pin_mode, stm32_pin_write, stm32_pin_read
调用了HAL库函数HAL_GPIO_xxx
;
PIN设备也是一种设备类型,继承于
struct rt_device_pin
,变量_hw_pin就是当前的PIN设备的结构体。
/* 文件 pin.h ,指针函数结构体,与上面定义的_stm32_pin_ops这个常量结构体是一一对应的关系*/
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);
};
//文件 pin.c
/* RT-Thread Hardware PIN APIs */
void rt_pin_mode(rt_base_t pin, rt_base_t mode)
{
RT_ASSERT(_hw_pin.ops != RT_NULL);
_hw_pin.ops->pin_mode(&_hw_pin.parent, pin, mode);
}
FINSH_FUNCTION_EXPORT_ALIAS(rt_pin_mode, pinMode, set hardware pin mode);
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);
int rt_pin_read(rt_base_t pin)
{
RT_ASSERT(_hw_pin.ops != RT_NULL);
return _hw_pin.ops->pin_read(&_hw_pin.parent, pin);
}
FINSH_FUNCTION_EXPORT_ALIAS(rt_pin_read, pinRead, read status from hardware pin);
以上三个接口rt_pin_mode, rt_pin_write, rt_pin_read
封装后,作为PIN设备管理接口,提供给应用层使用,在接口内部通过_hw_pin.ops->pin_read这种函数指针,其实调用的就是 stm32_pin_mode, stm32_pin_write, stm32_pin_read
函数,实现了应用层对硬件的操作功能。
驱动设备注册
所有的IO设备,都属于设备类型,关于设备的操作,内核有统一的调用接口,这些接口都放在device.c文件中。
rt_device_register函数存在于内核的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);
object对象初始化
所有的设备,都是继承于object对象,所以,最后Pin设备的初始化,会调用object初始化函数,将Pin设备增加到object list中。rt_object_init函数存在于内核的object.c文件中
void rt_object_init(struct rt_object *object,
enum rt_object_class_type type,
const char *name)
{
register rt_base_t temp;
struct rt_object_information *information;
/* get object information */
information = rt_object_get_information(type);
RT_ASSERT(information != RT_NULL);
/* initialize object's parameters */
/* set object type to static */
object->type = type | RT_Object_Class_Static;
/* copy name */
rt_strncpy(object->name, name, RT_NAME_MAX);
RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object));
/* lock interrupt */
temp = rt_hw_interrupt_disable();
/* insert object into information object list */
rt_list_insert_after(&(information->object_list), &(object->list));
/* unlock interrupt */
rt_hw_interrupt_enable(temp);
}
应用层接口使用示例如下:
void beep_on(void *args)
{
rt_kprintf("turn on beep!\n");
rt_pin_write(BEEP_PIN_NUM, PIN_HIGH);
}
void beep_off(void *args)
{
rt_kprintf("turn off beep!\n");
rt_pin_write(BEEP_PIN_NUM, PIN_LOW);
}
static void pin_beep_sample(void)
{
/* 蜂鸣器引脚为输出模式 */
rt_pin_mode(BEEP_PIN_NUM, PIN_MODE_OUTPUT);
/* 默认低电平 */
rt_pin_write(BEEP_PIN_NUM, PIN_LOW);
/* 按键0引脚为输入模式 */
rt_pin_mode(KEY0_PIN_NUM, PIN_MODE_INPUT_PULLUP);
/* 绑定中断,下降沿模式,回调函数名为beep_on */
rt_pin_attach_irq(KEY0_PIN_NUM, PIN_IRQ_MODE_FALLING, beep_on, RT_NULL);
/* 使能中断 */
rt_pin_irq_enable(KEY0_PIN_NUM, PIN_IRQ_ENABLE);
/* 按键1引脚为输入模式 */
rt_pin_mode(KEY1_PIN_NUM, PIN_MODE_INPUT_PULLUP);
/* 绑定中断,下降沿模式,回调函数名为beep_off */
rt_pin_attach_irq(KEY1_PIN_NUM, PIN_IRQ_MODE_FALLING, beep_off, RT_NULL);
/* 使能中断 */
rt_pin_irq_enable(KEY1_PIN_NUM, PIN_IRQ_ENABLE);
}
其他几个宏申明的初始化函数表调用
rt_components_init() 函数会在操作系统运行起来之后创建的 main 线程里被调用执行,这个时候硬件环境和操作系统已经初始化完成,可以执行应用相关代码。rt_components_init() 函数会遍历通过剩下的其他几个宏申明的初始化函数表。
/* 本段函数,存在于内核的components.c文件中,实现了系统启动的整个过程 */
void rt_application_init(void)/* 应用程序的初始化函数 */
{
rt_thread_t tid;
/* 创建主线程,在主线程中,进一步对系统进行除硬件以外的其他初始化工作 */
#ifdef RT_USING_HEAP
tid = rt_thread_create("main", main_thread_entry, RT_NULL,
RT_MAIN_THREAD_STACK_SIZE, RT_THREAD_PRIORITY_MAX / 3, 20);
RT_ASSERT(tid != RT_NULL);
#else
rt_err_t result;
tid = &main_thread;
result = rt_thread_init(tid, "main", main_thread_entry, RT_NULL,
main_stack, sizeof(main_stack), RT_THREAD_PRIORITY_MAX / 3, 20);
RT_ASSERT(result == RT_EOK);
/* if not define RT_USING_HEAP, using to eliminate the warning */
(void)result;
#endif
rt_thread_startup(tid);
}
/* the system main thread */
void main_thread_entry(void *parameter)
{
extern int main(void);
extern int $Super$$main(void);
/* RT-Thread components initialization */
rt_components_init(); /* 系统的其他初始化过程,在本函数中实现 */
/* invoke system main function */
#if defined (__CC_ARM)
$Super$$main(); /* for ARMCC. */
#elif defined(__ICCARM__) || defined(__GNUC__)
main();
#endif
}
网友评论