串口设备结构体:
struct rt_serial_device
{
struct rt_device parent;
const struct rt_uart_ops *ops;
struct serial_configure config;
void *serial_rx;
void *serial_tx;
};
struct rt_device
{
struct rt_object parent; /**< inherit from rt_object */
enum rt_device_class_type type; /**< device type */
rt_uint16_t flag; /**< device flag */
rt_uint16_t open_flag; /**< device open flag */
rt_uint8_t ref_count; /**< reference count */
rt_uint8_t device_id; /**< 0 - 255 */
/* device call back */
rt_err_t (*rx_indicate)(rt_device_t dev, rt_size_t size);
rt_err_t (*tx_complete)(rt_device_t dev, void *buffer);
/* common device interface */
rt_err_t (*init)(rt_device_t dev);
rt_err_t (*open)(rt_device_t dev, rt_uint16_t oflag);
rt_err_t (*close)(rt_device_t dev);
rt_size_t (*read)(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
rt_size_t (*write)(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
rt_err_t (*control)(rt_device_t dev, rt_uint8_t cmd, void *args);
void *user_data; /**< device private data */
};
#if defined(RT_USING_UART3)
uart = &uart3;
config.baud_rate = BAUD_RATE_115200;
serial3.ops = &stm32_uart_ops;
serial3.config = config;
NVIC_Configuration(&uart3);
/* register UART1 device */
rt_hw_serial_register(&serial3, "uart3",
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
uart);
#endif /* RT_USING_UART3 */
接着看一下串口注册rt_hw_serial_register():
rt_err_t rt_hw_serial_register(struct rt_serial_device *serial,
const char *name,
rt_uint32_t flag,
void *data)
{
struct rt_device *device;
RT_ASSERT(serial != RT_NULL);
device = &(serial->parent); //获取serial中parent成员的地址,并将地址赋值给device变量,之后操作device变量就是操作parent
device->type = RT_Device_Class_Char;
device->rx_indicate = RT_NULL;
device->tx_complete = RT_NULL;
device->init = rt_serial_init;
device->open = rt_serial_open;
device->close = rt_serial_close;
device->read = rt_serial_read;
device->write = rt_serial_write;
device->control = rt_serial_control;
device->user_data = data;
/* register a character device */
return rt_device_register(device, name, flag);
}
注册函数有四个参数:
参数1:所要注册的串口,参数类型为串口结构体
参数2:串口名
参数3:串口读写等标志位
参数4:串口私有数据
实际上,这个串口注册函数在最后return时,调用rt_device_register(),在系统注册一个字符设备,前面的操作为填充serial结构体中的parent成员。
看下系统设备的注册函数rt_device_register():
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) //检查系统是否有重名,若有与name相同的设备则返回错误
{ return -RT_ERROR; }
rt_object_init(&(dev->parent), RT_Object_Class_Device, name);
dev->flag = flags;
dev->ref_count = 0;
dev->open_flag = 0;
return RT_EOK;
}
/**
* This function registers a device driver with specified name.
*
* @param dev the pointer of device driver structure
* @param name the device driver's name
* @param flags the flag of device
*
* @return the error code, RT_EOK on initialization successfully.
*/
在串口注册函数中有此三个参数的接收,不再赘述。
在系统设备注册函数中还是有个重要的函数:rt_object_init();
初始化对象,并将该对象添加到对象管理系统。
/**
* This function will initialize an object and add it to object system
* management.
*
* @param object the specified object to be initialized.
* @param type the object type.
* @param name the object name. In system, the object's name must be unique.
*/
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;
#ifdef RT_USING_MODULE
/* get module object information */
information = (rt_module_self() != RT_NULL) ?
&rt_module_self()->module_object[type] : &rt_object_container[type];
#else
/* get object information */
information = &rt_object_container[type];
#endif
/* 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);
}
从系统框架结构图中可以看到,将I/O设备分为了三层,I/O设备管理模块对上层提供抽象的设备的操作接口,对底层驱动提供了一套驱动框架。
另外,RTThread的设备模型是建立在内核对象模型的基础之上的,设备也被当做是一类对象,纳入对象管理器。每个对象都由基对象派生而来,继承其父对象的基本属性,再派生出它自己的私有属性。(对象编程思想,看看java,写几个类就明白了)。我觉得下图中的基类改为基对象更贴切。
然后再回过头来看程序:rt_object_init()
首先看参数:
参数1:要被初始化的对象结构体
参数2:对象的类型
参数3:对象的名字,在系统内,此名称必须是独一无二的
首先先说参数3,从最开始的串口设备注册到现在,一直挂着这个参数,现在终于找到放到哪了,看对象结构体的定义:
struct rt_object
{
char name[RT_NAME_MAX]; /**< name of kernel object */
rt_uint8_t type; /**< type of kernel object */
rt_uint8_t flag; /**< flag of kernel object */
#ifdef RT_USING_MODULE
void *module_id; /**< id of application module */
#endif
rt_list_t list; /**< list node of kernel object */
};
看到没?看到没??看到没???第一个成员就是!!!
这个就是内核对象的基对象结构体,Base structure of Kernel object,自己翻译体会体会。
然后看第二个参数——队象的类型:
还是直接上代码:
/**
* The object type can be one of the follows with specific
* macros enabled:
* - Thread
* - Semaphore
* - Mutex
* - Event
* - MailBox
* - MessageQueue
* - MemHeap
* - MemPool
* - Device
* - Timer
* - Module
* - Unknown
* - Static
*/
enum rt_object_class_type
{
RT_Object_Class_Thread = 0, /**< The object is a thread. */
#ifdef RT_USING_SEMAPHORE
RT_Object_Class_Semaphore, /**< The object is a semaphore. */
#endif
#ifdef RT_USING_MUTEX
RT_Object_Class_Mutex, /**< The object is a mutex. */
#endif
#ifdef RT_USING_EVENT
RT_Object_Class_Event, /**< The object is a event. */
#endif
#ifdef RT_USING_MAILBOX
RT_Object_Class_MailBox, /**< The object is a mail box. */
#endif
#ifdef RT_USING_MESSAGEQUEUE
RT_Object_Class_MessageQueue, /**< The object is a message queue. */
#endif
#ifdef RT_USING_MEMHEAP
RT_Object_Class_MemHeap, /**< The object is a memory heap */
#endif
#ifdef RT_USING_MEMPOOL
RT_Object_Class_MemPool, /**< The object is a memory pool. */
#endif
#ifdef RT_USING_DEVICE
RT_Object_Class_Device, /**< The object is a device */
#endif
RT_Object_Class_Timer, /**< The object is a timer. */
#ifdef RT_USING_MODULE
RT_Object_Class_Module, /**< The object is a module. */
#endif
RT_Object_Class_Unknown, /**< The object is unknown. */
RT_Object_Class_Static = 0x80 /**< The object is a static object. */
};
第九个成员就是我们在操作的设备对象。
参数1就是定义的串口设备serial的系统设备parent的基对象parent
简单来看就是serial->parent->parent
****************************************************************
下面干点无聊的事,把三个结构体放一起试试,我就是想这样玩。。。
struct rt_serial_device
{
//struct rt_device parent;
{
//struct rt_object parent; /**< inherit from rt_object */
{
char name[RT_NAME_MAX]; /**< name of kernel object */
rt_uint8_t type; /**< type of kernel object */
rt_uint8_t flag; /**< flag of kernel object */
#ifdef RT_USING_MODULE
void *module_id; /**< id of application module */
#endif
rt_list_t list; /**< list node of kernel object */
};
enum rt_device_class_type type; /**< device type */
rt_uint16_t flag; /**< device flag */
rt_uint16_t open_flag; /**< device open flag */
rt_uint8_t ref_count; /**< reference count */
rt_uint8_t device_id; /**< 0 - 255 */
/* device call back */
rt_err_t (*rx_indicate)(rt_device_t dev, rt_size_t size);
rt_err_t (*tx_complete)(rt_device_t dev, void *buffer);
/* common device interface */
rt_err_t (*init)(rt_device_t dev);
rt_err_t (*open)(rt_device_t dev, rt_uint16_t oflag);
rt_err_t (*close)(rt_device_t dev);
rt_size_t (*read)(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
rt_size_t (*write)(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
rt_err_t (*control)(rt_device_t dev, rt_uint8_t cmd, void *args);
void *user_data; /**< device private data */
}
//const struct rt_uart_ops *ops;
{
rt_err_t (*configure)(struct rt_serial_device *serial, struct serial_configure *cfg);
rt_err_t (*control)(struct rt_serial_device *serial, int cmd, void *arg);
int (*putc)(struct rt_serial_device *serial, char c);
int (*getc)(struct rt_serial_device *serial);
rt_size_t (*dma_transmit)(struct rt_serial_device *serial, const rt_uint8_t *buf, rt_size_t size, int direction);
}
//struct serial_configure config;
{
rt_uint32_t baud_rate;
rt_uint32_t data_bits : 4;
rt_uint32_t stop_bits : 2;
rt_uint32_t parity : 2;
rt_uint32_t bit_order : 1;
rt_uint32_t invert : 1;
rt_uint32_t bufsz : 16;
rt_uint32_t reserved : 4;
}
void *serial_rx;
void *serial_tx;
};
name,内核对象的名字,"uart3",系统独一无二的
type,对象的类型,RT_Object_Class_Device设备对象
open_flag,设备打开标志
reference,设备引用计数
device_id,设备id
两个回调函数:
rx_indicate
tx_complete
接下来,通用设备接口:
init
open
close
read
write
control
user_data:设备私有数据指针
下面一堆串口操作函数指针:
configure
control
putc
getc
dma_transmit
紧接着是串口配置信息,包括8N1,串口缓冲区大小等:
baud_rate
data_bits
stop_bits
parity
bit_order
invert
bufsz
下面是串口发送和接收区缓存地址指针:
serial_rx
serial_tx
先写这么多,还在学习中。。。