RT-Thread 学习笔记(六)——串口
串口设备结构体:
1 struct rt_serial_device 2 { 3 struct rt_device parent; 4 5 const struct rt_uart_ops *ops; 6 struct serial_configure config; 7 8 void *serial_rx; 9 void *serial_tx; 10 };
RTT设备结构体:
1 struct rt_device 2 { 3 struct rt_object parent; /**< inherit from rt_object */ 4 5 enum rt_device_class_type type; /**< device type */ 6 rt_uint16_t flag; /**< device flag */ 7 rt_uint16_t open_flag; /**< device open flag */ 8 9 rt_uint8_t ref_count; /**< reference count */ 10 rt_uint8_t device_id; /**< 0 - 255 */ 11 12 /* device call back */ 13 rt_err_t (*rx_indicate)(rt_device_t dev, rt_size_t size); 14 rt_err_t (*tx_complete)(rt_device_t dev, void *buffer); 15 16 /* common device interface */ 17 rt_err_t (*init)(rt_device_t dev); 18 rt_err_t (*open)(rt_device_t dev, rt_uint16_t oflag); 19 rt_err_t (*close)(rt_device_t dev); 20 rt_size_t (*read)(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size); 21 rt_size_t (*write)(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size); 22 rt_err_t (*control)(rt_device_t dev, rt_uint8_t cmd, void *args); 23 24 void *user_data; /**< device private data */ 25 };
串口初始化在rt_hw_usart_init()函数:
1 #if defined(RT_USING_UART3) 2 uart = &uart3; 3 config.baud_rate = BAUD_RATE_115200; 4 serial3.ops = &stm32_uart_ops; 5 serial3.config = config; 6 NVIC_Configuration(&uart3); 7 /* register UART1 device */ 8 rt_hw_serial_register(&serial3, "uart3", 9 RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, 10 uart); 11 #endif /* RT_USING_UART3 */
接着看一下串口注册rt_hw_serial_register():
1 rt_err_t rt_hw_serial_register(struct rt_serial_device *serial, 2 const char *name, 3 rt_uint32_t flag, 4 void *data) 5 { 6 struct rt_device *device; 7 RT_ASSERT(serial != RT_NULL); 8 device = &(serial->parent); //获取serial中parent成员的地址,并将地址赋值给device变量,之后操作device变量就是操作parent 9 device->type = RT_Device_Class_Char; 10 device->rx_indicate = RT_NULL; 11 device->tx_complete = RT_NULL; 12 device->init = rt_serial_init; 13 device->open = rt_serial_open; 14 device->close = rt_serial_close; 15 device->read = rt_serial_read; 16 device->write = rt_serial_write; 17 device->control = rt_serial_control; 18 device->user_data = data; 19 /* register a character device */ 20 return rt_device_register(device, name, flag); 21 }
注册函数有四个参数:
参数1:所要注册的串口,参数类型为串口结构体
参数2:串口名
参数3:串口读写等标志位
参数4:串口私有数据
实际上,这个串口注册函数在最后return时,调用rt_device_register(),在系统注册一个字符设备,前面的操作为填充serial结构体中的parent成员。
看下系统设备的注册函数rt_device_register():
1 rt_err_t rt_device_register(rt_device_t dev, 2 const char *name, 3 rt_uint16_t flags) 4 { 5 if (dev == RT_NULL) 6 { return -RT_ERROR; } 7 8 9 if (rt_device_find(name) != RT_NULL) //检查系统是否有重名,若有与name相同的设备则返回错误 10 { return -RT_ERROR; } 11 12 13 rt_object_init(&(dev->parent), RT_Object_Class_Device, name); 14 dev->flag = flags; 15 dev->ref_count = 0; 16 dev->open_flag = 0; 17 return RT_EOK; 18 }
其参数为:
1 /** 2 * This function registers a device driver with specified name. 3 * 4 * @param dev the pointer of device driver structure 5 * @param name the device driver's name 6 * @param flags the flag of device 7 * 8 * @return the error code, RT_EOK on initialization successfully. 9 */
在串口注册函数中有此三个参数的接收,不再赘述。
在系统设备注册函数中还是有个重要的函数:rt_object_init();
初始化对象,并将该对象添加到对象管理系统。
1 /** 2 * This function will initialize an object and add it to object system 3 * management. 4 * 5 * @param object the specified object to be initialized. 6 * @param type the object type. 7 * @param name the object name. In system, the object's name must be unique. 8 */ 9 void rt_object_init(struct rt_object *object, 10 enum rt_object_class_type type, 11 const char *name) 12 { 13 register rt_base_t temp; 14 struct rt_object_information *information; 15 #ifdef RT_USING_MODULE 16 /* get module object information */ 17 information = (rt_module_self() != RT_NULL) ? 18 &rt_module_self()->module_object[type] : &rt_object_container[type]; 19 #else 20 /* get object information */ 21 information = &rt_object_container[type]; 22 #endif 23 /* initialize object's parameters */ 24 /* set object type to static */ 25 object->type = type | RT_Object_Class_Static; 26 /* copy name */ 27 rt_strncpy(object->name, name, RT_NAME_MAX); 28 RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object)); 29 /* lock interrupt */ 30 temp = rt_hw_interrupt_disable(); 31 /* insert object into information object list */ 32 rt_list_insert_after(&(information->object_list), &(object->list)); 33 /* unlock interrupt */ 34 rt_hw_interrupt_enable(temp); 35 }
到这里就得说一下RTThread的设备框架了:(以下均为参考官方文档http://www.rt-thread.org/document/site/zh/1chapters/06-chapter_device/)
从系统框架结构图中可以看到,将I/O设备分为了三层,I/O设备管理模块对上层提供抽象的设备的操作接口,对底层驱动提供了一套驱动框架。
另外,RTThread的设备模型是建立在内核对象模型的基础之上的,设备也被当做是一类对象,纳入对象管理器。每个对象都由基对象派生而来,继承其父对象的基本属性,再派生出它自己的私有属性。(对象编程思想,看看java,写几个类就明白了)。我觉得下图中的基类改为基对象更贴切。
然后再回过头来看程序:rt_object_init()
首先看参数:
参数1:要被初始化的对象结构体
参数2:对象的类型
参数3:对象的名字,在系统内,此名称必须是独一无二的
首先先说参数3,从最开始的串口设备注册到现在,一直挂着这个参数,现在终于找到放到哪了,看对象结构体的定义:
1 struct rt_object 2 { 3 char name[RT_NAME_MAX]; /**< name of kernel object */ 4 rt_uint8_t type; /**< type of kernel object */ 5 rt_uint8_t flag; /**< flag of kernel object */ 6 7 #ifdef RT_USING_MODULE 8 void *module_id; /**< id of application module */ 9 #endif 10 rt_list_t list; /**< list node of kernel object */ 11 };
看到没?看到没??看到没???第一个成员就是!!!
这个就是内核对象的基对象结构体,Base structure of Kernel object,自己翻译体会体会。
然后看第二个参数——队象的类型:
还是直接上代码:
1 /** 2 * The object type can be one of the follows with specific 3 * macros enabled: 4 * - Thread 5 * - Semaphore 6 * - Mutex 7 * - Event 8 * - MailBox 9 * - MessageQueue 10 * - MemHeap 11 * - MemPool 12 * - Device 13 * - Timer 14 * - Module 15 * - Unknown 16 * - Static 17 */ 18 enum rt_object_class_type 19 { 20 RT_Object_Class_Thread = 0, /**< The object is a thread. */ 21 #ifdef RT_USING_SEMAPHORE 22 RT_Object_Class_Semaphore, /**< The object is a semaphore. */ 23 #endif 24 #ifdef RT_USING_MUTEX 25 RT_Object_Class_Mutex, /**< The object is a mutex. */ 26 #endif 27 #ifdef RT_USING_EVENT 28 RT_Object_Class_Event, /**< The object is a event. */ 29 #endif 30 #ifdef RT_USING_MAILBOX 31 RT_Object_Class_MailBox, /**< The object is a mail box. */ 32 #endif 33 #ifdef RT_USING_MESSAGEQUEUE 34 RT_Object_Class_MessageQueue, /**< The object is a message queue. */ 35 #endif 36 #ifdef RT_USING_MEMHEAP 37 RT_Object_Class_MemHeap, /**< The object is a memory heap */ 38 #endif 39 #ifdef RT_USING_MEMPOOL 40 RT_Object_Class_MemPool, /**< The object is a memory pool. */ 41 #endif 42 #ifdef RT_USING_DEVICE 43 RT_Object_Class_Device, /**< The object is a device */ 44 #endif 45 RT_Object_Class_Timer, /**< The object is a timer. */ 46 #ifdef RT_USING_MODULE 47 RT_Object_Class_Module, /**< The object is a module. */ 48 #endif 49 RT_Object_Class_Unknown, /**< The object is unknown. */ 50 RT_Object_Class_Static = 0x80 /**< The object is a static object. */ 51 };
第九个成员就是我们在操作的设备对象。
再说下参数1,说完继续干串口。。。。
参数1就是定义的串口设备serial的系统设备parent的基对象parent
简单来看就是serial->parent->parent
****************************************************************
下面干点无聊的事,把三个结构体放一起试试,我就是想这样玩。。。
1 struct rt_serial_device 2 { 3 //struct rt_device parent; 4 { 5 //struct rt_object parent; /**< inherit from rt_object */ 6 7 { 8 char name[RT_NAME_MAX]; /**< name of kernel object */ 9 rt_uint8_t type; /**< type of kernel object */ 10 rt_uint8_t flag; /**< flag of kernel object */ 11 12 #ifdef RT_USING_MODULE 13 void *module_id; /**< id of application module */ 14 #endif 15 rt_list_t list; /**< list node of kernel object */ 16 }; 17 18 enum rt_device_class_type type; /**< device type */ 19 rt_uint16_t flag; /**< device flag */ 20 rt_uint16_t open_flag; /**< device open flag */ 21 22 rt_uint8_t ref_count; /**< reference count */ 23 rt_uint8_t device_id; /**< 0 - 255 */ 24 25 /* device call back */ 26 rt_err_t (*rx_indicate)(rt_device_t dev, rt_size_t size); 27 rt_err_t (*tx_complete)(rt_device_t dev, void *buffer); 28 29 /* common device interface */ 30 rt_err_t (*init)(rt_device_t dev); 31 rt_err_t (*open)(rt_device_t dev, rt_uint16_t oflag); 32 rt_err_t (*close)(rt_device_t dev); 33 rt_size_t (*read)(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size); 34 rt_size_t (*write)(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size); 35 rt_err_t (*control)(rt_device_t dev, rt_uint8_t cmd, void *args); 36 37 void *user_data; /**< device private data */ 38 } 39 40 //const struct rt_uart_ops *ops; 41 { 42 rt_err_t (*configure)(struct rt_serial_device *serial, struct serial_configure *cfg); 43 rt_err_t (*control)(struct rt_serial_device *serial, int cmd, void *arg); 44 45 46 int (*putc)(struct rt_serial_device *serial, char c); 47 int (*getc)(struct rt_serial_device *serial); 48 49 50 rt_size_t (*dma_transmit)(struct rt_serial_device *serial, const rt_uint8_t *buf, rt_size_t size, int direction); 51 } 52 //struct serial_configure config; 53 { 54 rt_uint32_t baud_rate; 55 56 57 rt_uint32_t data_bits : 4; 58 rt_uint32_t stop_bits : 2; 59 rt_uint32_t parity : 2; 60 rt_uint32_t bit_order : 1; 61 rt_uint32_t invert : 1; 62 rt_uint32_t bufsz : 16; 63 rt_uint32_t reserved : 4; 64 } 65 66 void *serial_rx; 67 void *serial_tx; 68 };
这样咱们就可以看一看这个串口设备结构体里到底都是什么鬼了,看能看懂的,看不懂的放放,八成是你现在用不着的,用的着的时候再仔细研究。
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
调试窗口直观看一下:
先写这么多,还在学习中。。。