设备驱动

上一节说到了如何使用RT-Thread的设备接口,但对于底层来说,如何编写一个设备驱动程序可能会更为重要,这节将详细描述如何编写一个设备驱动程序,并以STM32上的一个串口设备为例子进行说明。

设备驱动必须实现的接口

在6.1节中提及了RT-Thread设备接口类,我们着重看看其中包含的一套公共设备接口(类似上节说的设备访问接口,但面向的层次已经不一样,这里是面向底层驱动):

  1. /* 公共的设备接口(由驱动程序提供) */
  2. rt_err_t (*init) (rt_device_t dev);
  3. rt_err_t (*open) (rt_device_t dev, rt_uint16_t oflag);
  4. rt_err_t (*close)(rt_device_t dev);
  5. rt_size_t (*read) (rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size);
  6. rt_size_t (*write)(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size);
  7. rt_err_t (*control)(rt_device_t dev, rt_uint8_t cmd, void *args);

这些接口也是上层应用通过RT-Thread设备接口进行访问的实际底层接口(如 设备操作接口与设备驱动程序接口的映射 ):

设备操作接口与设备驱动程序接口的映射

即这些驱动实现的底层接口是上层应用最终访问的落脚点,例如上层应用调用rt_device_read接口进行设备读取数据操作,上层应先调用rt_device_find获得相对应的设备句柄,而在调用rt_device_read时,就是使用这个设备句柄所对应驱动的driver_read。上述的接口是一一对应关系。

I/O设备模块提供的这六个接口(rt_device_init/open/read/write/control),对应到设备驱动程序的六个接口(driver_init/open/read/write/control等),可以认为是底层设备驱动必须提供的接口:

+———————+———————————————————————————-+| 方法名称 | 方法描述 |+==============+=======================================================+| init |设备的初始化。设备初始化完成后,设备控制块的flag会被置 || |成已激活状态(RT_DEVICE_FLAG_ACTIVATED)。如果设备控制块 || |中的flag标志已经设置成激活状态,那么再运行初始化接口时 || |,会立刻返回,而不会重新进行初始化。 |+———————+———————————————————————————-+| open |打开设备。有些设备并不是系统一启动就已经打开开始运行; || |或者设备需要进行数据接收,但如果上层应用还未准备好,设 || |备也不应默认已经使能并开始接收数据。所以建议在写底层驱 || |动程序时,在调用open接口时才使能设备。 |+———————+———————————————————————————-+| close |关闭设备。建议在打开设备时,设备驱动自行维护一个打开计 || |数,在打开设备时进行+1操作,在关闭设备时进行-1操作, || |当计数器变为0时,进行真正的关闭操作。 |+———————+———————————————————————————-+| read |从设备中读取数据。参数pos指出读取数据的偏移量,但是有些|| |设备并不一定需要指定偏移量,例如串口设备,设备驱动应忽 || |略这个参数。而对于块设备来说,pos以及size都是以块设备的|| |数据块大小做为单位的。例如块设备的数据块大小是512,而参|| |数中pos = 10, size = 2,那么驱动应该返回设备中第10个块 || |(从第0个块做为起始),共计2个块的数据。这个接口返回的 || |类型是rt_size_t,即读到的字节数或块数目。正常情况下应 || |该会返回参数中size的数值,如果返回零请设置对应的errno值|+———————+———————————————————————————-+| write |向设备中写入数据。参数pos指出写入数据的偏移量。与读操作|| |类似,对于块设备来说,pos以及size都是以块设备的数据块 || |大小做为单位的。这个接口返回的类型是rt_size_t,即真实写|| |入数据的字节数或块数目。正常情况下应该会返回参数中size || |的数值,如果返回零请设置对应的errno值。 |+———————+———————————————————————————-+| control |根据不同的cmd命令控制设备。命令往往是由底层各类设备驱 || |动自定义实现。例如参数RT_DEVICE_CTRL_BLK_GETGEOME,意思|| |是获取块设备的大小信息。 |+———————+———————————————————————————-+

设备驱动实现的步骤

在实现一个RT-Thread设备时,可以按照如下的步骤进行(对于一些复杂的设备驱动,例如以太网接口驱动、图形设备驱动,请参看网络组件、GUI部分章节):

  • 按照RT-Thread的对象模型,扩展一个对象有两种方式:
    • 定义自己的私有数据结构,然后赋值到RT-Thread设备控制块的user_data指针上;
    • 从struct rt_device结构中进行派生。
  • 实现RT-Thread I/O设备模块中定义的6个公共设备接口,开始可以是空函数(返回类型是rt_err_t的可默认返回RT_EOK);
  • 根据自己的设备类型定义自己的私有数据域。特别是在可能有多个相类似设备的情况下(例如串口1、2),设备接口可以共用同一套接口,不同的只是各自的数据域(例如寄存器基地址);
  • 根据设备的类型,注册到RT-Thread设备框架中。

    STM32F10x的串口驱动

以下例子详细分析了STM32F10x的串口驱动,也包括上层应该如何使用这个设备的代码。STM32F10x串口驱动代码,详细的中文注释已经放在其中了。

目前的串口驱动采用了从struct rt_device结构中进行派生的方式,派生出rt_serial_device。STM32F10x的串口驱动包括公用的rt_serial_device串口驱动框架和属于STM32F10x的uart驱动两部分。串口驱动框架位于components/drivers/serial/serial.c中,向上层提供如下函数:

  • rt_serial_init
  • rt_serial_open
  • rt_serial_close
  • rt_serial_read
  • rt_serial_write
  • rt_serial_control
    uart驱动位于bsp/stm32f10x/drivers/usart.c中,向上层提供如下函数:

  • stm32_configure

  • stm32_control
  • stm32_putc
  • stm32_getc
    uart驱动位于底层,实际运行中串口驱动框架将调用uart驱动提供的函数。例如:应用程序调用rt_device_write时,实际调用关系为:
  1. rt_device_write ==> rt_serial_write ==> stm32_putc

下面将首先列出串口驱动框架的代码,由于我们仅以中断接收和轮询发送方式来举例,其他接收和发送方式的代码将省略。驱动框架代码如下:

  1. /* RT-Thread设备驱动框架接口 */
  2.  
  3. /* serial.h部分内容开始 */
  4. /* Default config for serial_configure structure */
  5. #define RT_SERIAL_CONFIG_DEFAULT \
  6. { \
  7. BAUD_RATE_115200, /* 115200 bits/s */ \
  8. DATA_BITS_8, /* 8 databits */ \
  9. STOP_BITS_1, /* 1 stopbit */ \
  10. PARITY_NONE, /* No parity */ \
  11. BIT_ORDER_LSB, /* LSB first sent */ \
  12. NRZ_NORMAL, /* Normal mode */ \
  13. RT_SERIAL_RB_BUFSZ, /* Buffer size */ \
  14. 0 \
  15. }
  16.  
  17. /* 串口配置结构体 */
  18. struct serial_configure
  19. {
  20. rt_uint32_t baud_rate;
  21.  
  22. rt_uint32_t data_bits :4;
  23. rt_uint32_t stop_bits :2;
  24. rt_uint32_t parity :2;
  25. rt_uint32_t bit_order :1;
  26. rt_uint32_t invert :1;
  27. rt_uint32_t bufsz :16;
  28. rt_uint32_t reserved :4;
  29. };
  30.  
  31. /*
  32. * Serial FIFO mode
  33. */
  34. struct rt_serial_rx_fifo
  35. {
  36. /* software fifo */
  37. rt_uint8_t *buffer;
  38.  
  39. rt_uint16_t put_index, get_index;
  40. };
  41.  
  42. /* 串口设备结构体 */
  43. struct rt_serial_device
  44. {
  45. struct rt_device parent;
  46.  
  47. const struct rt_uart_ops *ops;
  48. struct serial_configure config;
  49.  
  50. void *serial_rx;
  51. void *serial_tx;
  52. };
  53. typedef struct rt_serial_device rt_serial_t;
  54.  
  55. /**
  56. * uart operators
  57. * 函数的具体实现在bsp/stm32f10x/drivers/usart.c中
  58. */
  59. struct rt_uart_ops
  60. {
  61. rt_err_t (*configure)(struct rt_serial_device *serial, struct serial_configure *cfg);
  62. rt_err_t (*control)(struct rt_serial_device *serial, int cmd, void *arg);
  63.  
  64. int (*putc)(struct rt_serial_device *serial, char c);
  65. int (*getc)(struct rt_serial_device *serial);
  66.  
  67. rt_size_t (*dma_transmit)(struct rt_serial_device *serial, const rt_uint8_t *buf, rt_size_t size, int direction);
  68. };
  69. /* serial.h部分内容结束 */
  70.  
  71. /* 以下为serial.c的内容 */
  72. /* 轮询接收 */
  73. rt_inline int _serial_poll_rx(struct rt_serial_device *serial, rt_uint8_t *data, int length)
  74. {
  75. /* 代码省略 */
  76. }
  77.  
  78. /* 轮询发送 */
  79. rt_inline int _serial_poll_tx(struct rt_serial_device *serial, const rt_uint8_t *data, int length)
  80. {
  81. int size;
  82. RT_ASSERT(serial != RT_NULL);
  83.  
  84. size = length;
  85. while (length)
  86. {
  87. /*
  88. * to be polite with serial console add a line feed
  89. * to the carriage return character
  90. */
  91. if (*data == '\n' && (serial->parent.open_flag & RT_DEVICE_FLAG_STREAM))
  92. {
  93. serial->ops->putc(serial, '\r');
  94. }
  95.  
  96. /* 实际调用usart.c中的stm32_putc,
  97. * serial->ops中包含uart驱动中的4个函数指针,
  98. * 在usart.c的rt_hw_usart_init函数中,向系统注册设备之前对其赋值 。
  99. */
  100. serial->ops->putc(serial, *data);
  101.  
  102. ++ data;
  103. -- length;
  104. }
  105.  
  106. return size - length;
  107. }
  108.  
  109. /* 中断接收
  110. * 中断处理函数rt_hw_serial_isr将收到的数据放到接收buffer里,
  111. * 此函数从接收buffer里取出数据
  112. */
  113. rt_inline int _serial_int_rx(struct rt_serial_device *serial, rt_uint8_t *data, int length)
  114. {
  115. int size;
  116. struct rt_serial_rx_fifo* rx_fifo;
  117.  
  118. RT_ASSERT(serial != RT_NULL);
  119. size = length;
  120.  
  121. rx_fifo = (struct rt_serial_rx_fifo*) serial->serial_rx;
  122. RT_ASSERT(rx_fifo != RT_NULL);
  123.  
  124. /* read from software FIFO */
  125. while (length)
  126. {
  127. int ch;
  128. rt_base_t level;
  129.  
  130. /* disable interrupt */
  131. level = rt_hw_interrupt_disable();
  132. if (rx_fifo->get_index != rx_fifo->put_index)
  133. {
  134. ch = rx_fifo->buffer[rx_fifo->get_index];
  135. rx_fifo->get_index += 1;
  136. if (rx_fifo->get_index >= serial->config.bufsz) rx_fifo->get_index = 0;
  137. }
  138. else
  139. {
  140. /* no data, enable interrupt and break out */
  141. rt_hw_interrupt_enable(level);
  142. break;
  143. }
  144.  
  145. /* enable interrupt */
  146. rt_hw_interrupt_enable(level);
  147.  
  148. *data = ch & 0xff;
  149. data ++; length --;
  150. }
  151.  
  152. return size - length;
  153. }
  154.  
  155. /* 中断发送 */
  156. rt_inline int _serial_int_tx(struct rt_serial_device *serial, const rt_uint8_t *data, int length)
  157. {
  158. /* 代码省略 */
  159. }
  160.  
  161. /* DMA接收 */
  162. rt_inline int _serial_dma_rx(struct rt_serial_device *serial, rt_uint8_t *data, int length)
  163. {
  164. /* 代码省略 */
  165. }
  166.  
  167. /* DMA发送 */
  168. rt_inline int _serial_dma_tx(struct rt_serial_device *serial, const rt_uint8_t *data, int length)
  169. {
  170. /* 代码省略 */
  171. }
  172.  
  173. static rt_err_t rt_serial_init (struct rt_device *dev)
  174. {
  175. rt_err_t result = RT_EOK;
  176. struct rt_serial_device *serial;
  177.  
  178. RT_ASSERT(dev != RT_NULL);
  179. /* 获得真实的serial设备对象 */
  180. serial = (struct rt_serial_device *)dev;
  181.  
  182. /* initialize rx/tx */
  183. serial->serial_rx = RT_NULL;
  184. serial->serial_tx = RT_NULL;
  185.  
  186. /* 实际调用usart.c中stm32_configure函数,对串口波特率等进行配置。
  187. * serial->config包含配置数据,在usart.c的rt_hw_usart_init函数中,向系统注册设备之前进行赋值。
  188. */
  189. if (serial->ops->configure)
  190. result = serial->ops->configure(serial, &serial->config);
  191.  
  192. return result;
  193. }
  194.  
  195. /* 打开设备 */
  196. static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
  197. {
  198. struct rt_serial_device *serial;
  199.  
  200. RT_ASSERT(dev != RT_NULL);
  201. serial = (struct rt_serial_device *)dev;
  202.  
  203. /* check device flag with the open flag */
  204. if ((oflag & RT_DEVICE_FLAG_DMA_RX) && !(dev->flag & RT_DEVICE_FLAG_DMA_RX))
  205. return -RT_EIO;
  206. if ((oflag & RT_DEVICE_FLAG_DMA_TX) && !(dev->flag & RT_DEVICE_FLAG_DMA_TX))
  207. return -RT_EIO;
  208. if ((oflag & RT_DEVICE_FLAG_INT_RX) && !(dev->flag & RT_DEVICE_FLAG_INT_RX))
  209. return -RT_EIO;
  210. if ((oflag & RT_DEVICE_FLAG_INT_TX) && !(dev->flag & RT_DEVICE_FLAG_INT_TX))
  211. return -RT_EIO;
  212.  
  213. /* get open flags */
  214. dev->open_flag = oflag & 0xff;
  215.  
  216. /* initialize the Rx/Tx structure according to open flag */
  217. if (serial->serial_rx == RT_NULL)
  218. {
  219. if (oflag & RT_DEVICE_FLAG_DMA_RX)
  220. {
  221. /* 代码省略 */
  222. }
  223. else if (oflag & RT_DEVICE_FLAG_INT_RX)
  224. {
  225. struct rt_serial_rx_fifo* rx_fifo;
  226.  
  227. /* 创建中断接收buffer */
  228. rx_fifo = (struct rt_serial_rx_fifo*) rt_malloc (sizeof(struct rt_serial_rx_fifo) +
  229. serial->config.bufsz);
  230. RT_ASSERT(rx_fifo != RT_NULL);
  231. rx_fifo->buffer = (rt_uint8_t*) (rx_fifo + 1);
  232. rt_memset(rx_fifo->buffer, 0, serial->config.bufsz);
  233. rx_fifo->put_index = 0;
  234. rx_fifo->get_index = 0;
  235.  
  236. /* 保存指向接收buffer的指针,以便在接收中断函数rt_hw_serial_isr中使用 */
  237. serial->serial_rx = rx_fifo;
  238. dev->open_flag |= RT_DEVICE_FLAG_INT_RX;
  239. /* 调用usart.c中的stm32_control函数
  240. * 开启uart接收中断
  241. */
  242. serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX);
  243. }
  244. else
  245. {
  246. serial->serial_rx = RT_NULL;
  247. }
  248. }
  249.  
  250. if (serial->serial_tx == RT_NULL)
  251. {
  252. if (oflag & RT_DEVICE_FLAG_DMA_TX)
  253. {
  254. /* 代码省略 */
  255. }
  256. else if (oflag & RT_DEVICE_FLAG_INT_TX)
  257. {
  258. /* 代码省略 */
  259. }
  260. else
  261. {
  262. serial->serial_tx = RT_NULL;
  263. }
  264. }
  265.  
  266. return RT_EOK;
  267. }
  268.  
  269. /* 关闭设备 */
  270. static rt_err_t rt_serial_close(struct rt_device *dev)
  271. {
  272. struct rt_serial_device *serial;
  273.  
  274. RT_ASSERT(dev != RT_NULL);
  275. serial = (struct rt_serial_device *)dev;
  276.  
  277. /* 实际上只有ref_count为0时本函数才会被调用到,
  278. * 即最后一个打开此设备的应用调用rt_device_close时,本函数才会被调用
  279. * 所以下面一条语句并不起作用
  280. */
  281. if (dev->ref_count > 1) return RT_EOK;
  282.  
  283. if (dev->open_flag & RT_DEVICE_FLAG_INT_RX)
  284. {
  285. struct rt_serial_rx_fifo* rx_fifo;
  286.  
  287. rx_fifo = (struct rt_serial_rx_fifo*)serial->serial_rx;
  288. RT_ASSERT(rx_fifo != RT_NULL);
  289. /* 释放中断接收buffer */
  290. rt_free(rx_fifo);
  291. serial->serial_rx = RT_NULL;
  292. dev->open_flag &= ~RT_DEVICE_FLAG_INT_RX;
  293. /* 关闭接收中断 */
  294. serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void*)RT_DEVICE_FLAG_INT_RX);
  295. }
  296. else if (dev->open_flag & RT_DEVICE_FLAG_DMA_RX)
  297. {
  298. /* 代码省略 */
  299. }
  300.  
  301. if (dev->open_flag & RT_DEVICE_FLAG_INT_TX)
  302. {
  303. /* 代码省略 */
  304. }
  305. else if (dev->open_flag & RT_DEVICE_FLAG_DMA_TX)
  306. {
  307. /* 代码省略 */
  308. }
  309.  
  310. return RT_EOK;
  311. }
  312.  
  313. /* 从设备中读取数据 */
  314. static rt_size_t rt_serial_read (struct rt_device *dev,
  315. rt_off_t pos,
  316. void *buffer,
  317. rt_size_t size)
  318. {
  319. struct rt_serial_device *serial;
  320.  
  321. RT_ASSERT(dev != RT_NULL);
  322. if (size == 0) return 0;
  323.  
  324. serial = (struct rt_serial_device *)dev;
  325.  
  326. if (dev->open_flag & RT_DEVICE_FLAG_INT_RX)
  327. {
  328. /* 调用中断接收函数 */
  329. return _serial_int_rx(serial, buffer, size);
  330. }
  331. else if (dev->open_flag & RT_DEVICE_FLAG_DMA_RX)
  332. {
  333. return _serial_dma_rx(serial, buffer, size);
  334. }
  335.  
  336. return _serial_poll_rx(serial, buffer, size);
  337. }
  338.  
  339. /* 向设备中写入数据 */
  340. static rt_size_t rt_serial_write(struct rt_device *dev,
  341. rt_off_t pos,
  342. const void *buffer,
  343. rt_size_t size)
  344. {
  345. struct rt_serial_device *serial;
  346.  
  347. RT_ASSERT(dev != RT_NULL);
  348. if (size == 0) return 0;
  349.  
  350. serial = (struct rt_serial_device *)dev;
  351.  
  352. if (dev->open_flag & RT_DEVICE_FLAG_INT_TX)
  353. {
  354. return _serial_int_tx(serial, buffer, size);
  355. }
  356. else if (dev->open_flag & RT_DEVICE_FLAG_DMA_TX)
  357. {
  358. return _serial_dma_tx(serial, buffer, size);
  359. }
  360. else
  361. {
  362. /* 轮询模式发送 */
  363. return _serial_poll_tx(serial, buffer, size);
  364. }
  365. }
  366.  
  367. /* 设备控制操作 */
  368. static rt_err_t rt_serial_control (struct rt_device *dev,
  369. rt_uint8_t cmd,
  370. void *args)
  371. {
  372. struct rt_serial_device *serail;
  373.  
  374. RT_ASSERT(dev != RT_NULL);
  375.  
  376. /* 获得真正的串口对象 */
  377. serial = (struct rt_serial_device *)dev;
  378.  
  379. switch (cmd)
  380. {
  381. case RT_DEVICE_CTRL_SUSPEND:
  382. /* 挂起设备 */
  383. break;
  384. dev->flag |= RT_DEVICE_FLAG_SUSPENDED;
  385.  
  386. case RT_DEVICE_CTRL_RESUME:
  387. /* 唤醒设备 */
  388. dev->flag &= ~RT_DEVICE_FLAG_SUSPENDED;
  389. break;
  390. case RT_DEVICE_CTRL_CONFIG:
  391. /* 配置设备,设置波特率、数据位数等 */
  392. serial->ops->configure(serial, (struct serial_configure *)args);
  393. break;
  394.  
  395. default :
  396. /* control device */
  397. serial->ops->control(serial, cmd, args);
  398. break;
  399. }
  400.  
  401. return RT_EOK;
  402. }
  403.  
  404. /*
  405. * 向系统中注册串口设备
  406. */
  407. rt_err_t rt_hw_serial_register(struct rt_serial_device *serial,
  408. const char *name,
  409. rt_uint32_t flag,
  410. void *data)
  411. {
  412. struct rt_device *device;
  413. RT_ASSERT(serial != RT_NULL);
  414.  
  415. device = &(serial->parent);
  416.  
  417. /* 设置设备驱动类型 */
  418. device->type = RT_Device_Class_Char;
  419. device->rx_indicate = RT_NULL;
  420. device->tx_complete = RT_NULL;
  421. /* 设置设备驱动公共接口函数 */
  422. device->init = rt_serial_init;
  423. device->open = rt_serial_open;
  424. device->close = rt_serial_close;
  425. device->read = rt_serial_read;
  426. device->write = rt_serial_write;
  427. device->control = rt_serial_control;
  428. /* 在使用stm32f10x时,此处传给data的是指向stm32_uart结构体的指针 */
  429. device->user_data = data;
  430.  
  431. /* 注册一个字符设备 */
  432. return rt_device_register(device, name, flag);
  433. }
  434.  
  435. /* ISR for serial interrupt */
  436. void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
  437. {
  438. switch (event & 0xff)
  439. {
  440. /* 接收中断 */
  441. case RT_SERIAL_EVENT_RX_IND:
  442. {
  443. int ch = -1;
  444. rt_base_t level;
  445. struct rt_serial_rx_fifo* rx_fifo;
  446.  
  447. /* 获取中断接收buffer,serial->serial_rx在rt_serial_open里进行赋值 */
  448. rx_fifo = (struct rt_serial_rx_fifo*)serial->serial_rx;
  449. RT_ASSERT(rx_fifo != RT_NULL);
  450.  
  451. while (1)
  452. {
  453. /* 实际调用stm32_getc */
  454. ch = serial->ops->getc(serial);
  455. if (ch == -1) break;
  456.  
  457.  
  458. /* disable interrupt */
  459. level = rt_hw_interrupt_disable();
  460.  
  461. rx_fifo->buffer[rx_fifo->put_index] = ch;
  462. rx_fifo->put_index += 1;
  463. if (rx_fifo->put_index >= serial->config.bufsz) rx_fifo->put_index = 0;
  464.  
  465. /* if the next position is read index, discard this 'read char' */
  466. if (rx_fifo->put_index == rx_fifo->get_index)
  467. {
  468. /* 丢弃最旧的数据,buffer里能保存最多bufsz - 1个字节 */
  469. rx_fifo->get_index += 1;
  470. if (rx_fifo->get_index >= serial->config.bufsz) rx_fifo->get_index = 0;
  471. }
  472.  
  473. /* enable interrupt */
  474. rt_hw_interrupt_enable(level);
  475. }
  476.  
  477. /* 调用接收回调函数
  478. * rx_indicate在device.c文件rt_device_set_rx_indicate函数中赋值
  479. * 对于finsh在finsh_thread_entry中进行设置
  480. */
  481. if (serial->parent.rx_indicate != RT_NULL)
  482. {
  483. rt_size_t rx_length;
  484.  
  485. /* get rx length */
  486. level = rt_hw_interrupt_disable();
  487. rx_length = (rx_fifo->put_index >= rx_fifo->get_index)? (rx_fifo->put_index - rx_fifo->get_index):
  488. (serial->config.bufsz - (rx_fifo->get_index - rx_fifo->put_index));
  489. rt_hw_interrupt_enable(level);
  490.  
  491. serial->parent.rx_indicate(&serial->parent, rx_length);
  492. }
  493. break;
  494. }
  495. case RT_SERIAL_EVENT_TX_DONE:
  496. {
  497. /* 代码省略 */
  498. }
  499. case RT_SERIAL_EVENT_TX_DMADONE:
  500. {
  501. /* 代码省略 */
  502. }
  503. case RT_SERIAL_EVENT_RX_DMADONE:
  504. {
  505. /* 代码省略 */
  506. }
  507. }
  508.  
  509. }

uart驱动位于bsp/stm32f10x/drivers/usart.c中,代码如下:

  1. /* STM32 uart driver */
  2. struct stm32_uart
  3. {
  4. USART_TypeDef* uart_device;
  5. IRQn_Type irq;
  6. };
  7.  
  8. static rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
  9. {
  10. struct stm32_uart* uart;
  11. USART_InitTypeDef USART_InitStructure;
  12.  
  13. RT_ASSERT(serial != RT_NULL);
  14. RT_ASSERT(cfg != RT_NULL);
  15. /* serial->parent.user_data即device->user_data在设备注册时进行赋值 */
  16. uart = (struct stm32_uart *)serial->parent.user_data;
  17.  
  18. USART_InitStructure.USART_BaudRate = cfg->baud_rate;
  19.  
  20. if (cfg->data_bits == DATA_BITS_8){
  21. USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  22. } else if (cfg->data_bits == DATA_BITS_9) {
  23. USART_InitStructure.USART_WordLength = USART_WordLength_9b;
  24. }
  25.  
  26. if (cfg->stop_bits == STOP_BITS_1){
  27. USART_InitStructure.USART_StopBits = USART_StopBits_1;
  28. } else if (cfg->stop_bits == STOP_BITS_2){
  29. USART_InitStructure.USART_StopBits = USART_StopBits_2;
  30. }
  31.  
  32. if (cfg->parity == PARITY_NONE){
  33. USART_InitStructure.USART_Parity = USART_Parity_No;
  34. } else if (cfg->parity == PARITY_ODD) {
  35. USART_InitStructure.USART_Parity = USART_Parity_Odd;
  36. } else if (cfg->parity == PARITY_EVEN) {
  37. USART_InitStructure.USART_Parity = USART_Parity_Even;
  38. }
  39.  
  40. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  41. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  42. USART_Init(uart->uart_device, &USART_InitStructure);
  43.  
  44. /* Enable USART */
  45. USART_Cmd(uart->uart_device, ENABLE);
  46.  
  47. return RT_EOK;
  48. }
  49.  
  50. static rt_err_t stm32_control(struct rt_serial_device *serial, int cmd, void *arg)
  51. {
  52. struct stm32_uart* uart;
  53.  
  54. RT_ASSERT(serial != RT_NULL);
  55. uart = (struct stm32_uart *)serial->parent.user_data;
  56.  
  57. switch (cmd)
  58. {
  59. /* disable interrupt */
  60. case RT_DEVICE_CTRL_CLR_INT:
  61. /* disable rx irq */
  62. UART_DISABLE_IRQ(uart->irq);
  63. /* 关闭接收中断 */
  64. USART_ITConfig(uart->uart_device, USART_IT_RXNE, DISABLE);
  65. break;
  66. /* enable interrupt */
  67. case RT_DEVICE_CTRL_SET_INT:
  68. /* enable rx irq */
  69. UART_ENABLE_IRQ(uart->irq);
  70. /* 打开接收中断 */
  71. USART_ITConfig(uart->uart_device, USART_IT_RXNE, ENABLE);
  72. break;
  73. }
  74.  
  75. return RT_EOK;
  76. }
  77.  
  78. static int stm32_putc(struct rt_serial_device *serial, char c)
  79. {
  80. struct stm32_uart* uart;
  81.  
  82. RT_ASSERT(serial != RT_NULL);
  83. uart = (struct stm32_uart *)serial->parent.user_data;
  84.  
  85. uart->uart_device->DR = c;
  86. while (!(uart->uart_device->SR & USART_FLAG_TC));
  87.  
  88. return 1;
  89. }
  90.  
  91. static int stm32_getc(struct rt_serial_device *serial)
  92. {
  93. int ch;
  94. struct stm32_uart* uart;
  95.  
  96. RT_ASSERT(serial != RT_NULL);
  97. uart = (struct stm32_uart *)serial->parent.user_data;
  98.  
  99. ch = -1;
  100. if (uart->uart_device->SR & USART_FLAG_RXNE)
  101. {
  102. ch = uart->uart_device->DR & 0xff;
  103. }
  104.  
  105. return ch;
  106. }
  107.  
  108. static const struct rt_uart_ops stm32_uart_ops =
  109. {
  110. stm32_configure,
  111. stm32_control,
  112. stm32_putc,
  113. stm32_getc,
  114. };
  115.  
  116. #if defined(RT_USING_UART1)
  117. /* UART1 device driver structure */
  118. struct stm32_uart uart1 =
  119. {
  120. USART1,
  121. USART1_IRQn,
  122. };
  123. struct rt_serial_device serial1;
  124.  
  125. void USART1_IRQHandler(void)
  126. {
  127. struct stm32_uart* uart;
  128.  
  129. uart = &uart1;
  130.  
  131. /* enter interrupt */
  132. rt_interrupt_enter();
  133. /* 接收中断 Read data register not empty */
  134. if(USART_GetITStatus(uart->uart_device, USART_IT_RXNE) != RESET)
  135. {
  136. /* 调用中断处理函数,处理接收中断 */
  137. rt_hw_serial_isr(&serial1, RT_SERIAL_EVENT_RX_IND);
  138. /* clear interrupt */
  139. USART_ClearITPendingBit(uart->uart_device, USART_IT_RXNE);
  140. }
  141. /* 发送完成中断 Transmission complete */
  142. if (USART_GetITStatus(uart->uart_device, USART_IT_TC) != RESET)
  143. {
  144. /* clear interrupt */
  145. USART_ClearITPendingBit(uart->uart_device, USART_IT_TC);
  146. }
  147. /* Overrun error */
  148. if (USART_GetFlagStatus(uart->uart_device, USART_FLAG_ORE) == SET)
  149. {
  150. stm32_getc(&serial1);
  151. }
  152. /* leave interrupt */
  153. rt_interrupt_leave();
  154. }
  155. #endif
  156.  
  157. /* UART2至UART4相关代码省略 */
  158.  
  159. static void RCC_Configuration(void)
  160. {
  161. #if defined(RT_USING_UART1)
  162. /* Enable UART GPIO clocks */
  163. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  164. /* Enable UART clock */
  165. RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
  166. #endif /* RT_USING_UART1 */
  167.  
  168. /* UART2至UART4相关代码省略 */
  169. }
  170.  
  171. static void GPIO_Configuration(void)
  172. {
  173. GPIO_InitTypeDef GPIO_InitStructure;
  174.  
  175. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  176.  
  177. #if defined(RT_USING_UART1)
  178. /* Configure USART Rx/tx PIN */
  179. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  180. GPIO_InitStructure.GPIO_Pin = UART1_GPIO_RX;
  181. GPIO_Init(UART1_GPIO, &GPIO_InitStructure);
  182.  
  183. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  184. GPIO_InitStructure.GPIO_Pin = UART1_GPIO_TX;
  185. GPIO_Init(UART1_GPIO, &GPIO_InitStructure);
  186. #endif /* RT_USING_UART1 */
  187.  
  188. /* UART2至UART4相关代码省略 */
  189. }
  190.  
  191. static void NVIC_Configuration(struct stm32_uart* uart)
  192. {
  193. NVIC_InitTypeDef NVIC_InitStructure;
  194.  
  195. /* Enable the USART Interrupt */
  196. NVIC_InitStructure.NVIC_IRQChannel = uart->irq;
  197. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  198. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  199. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  200. NVIC_Init(&NVIC_InitStructure);
  201. }
  202.  
  203. void rt_hw_usart_init(void)
  204. {
  205. struct stm32_uart* uart;
  206. /* 配置默认波特率、数据位等 */
  207. struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
  208.  
  209. RCC_Configuration();
  210. GPIO_Configuration();
  211.  
  212. #if defined(RT_USING_UART1)
  213. uart = &uart1;
  214. config.baud_rate = BAUD_RATE_115200;
  215.  
  216. /* 接口函数赋值 */
  217. serial1.ops = &stm32_uart_ops;
  218. /* 配置赋值 */
  219. serial1.config = config;
  220.  
  221. NVIC_Configuration(&uart1);
  222.  
  223. /* 注册设备uart1
  224. * 第4个参数uart最终被传给device->user_data
  225. */
  226. rt_hw_serial_register(&serial1, "uart1",
  227. RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX ,
  228. uart);
  229. #endif /* RT_USING_UART1 */
  230.  
  231. /* UART2至UART4相关代码省略 */
  232. }

对于包含中断发送、接收的情况的驱动程序,以下例子给出了具体的使用代码。在这个例子中,用户线程将从两个设备上(uart1, uart2)读取数据,然后再写到uart1设备中。

  1. /*
  2. * 程序清单:串口设备操作例程
  3. *
  4. * 在这个例程中,将启动一个devt线程,然后打开串口1和2
  5. * 当串口1和2有输入时,将读取其中的输入数据然后写入到
  6. * 串口1设备中。
  7. *
  8. */
  9. #include <rtthread.h>
  10.  
  11. /* UART接收消息结构*/
  12. struct rx_msg
  13. {
  14. rt_device_t dev;
  15. rt_size_t size;
  16. };
  17. /* 用于接收消息的消息队列*/
  18. static rt_mq_t rx_mq;
  19. /* 接收线程的接收缓冲区*/
  20. static char uart_rx_buffer[64];
  21.  
  22. /* 数据到达回调函数*/
  23. rt_err_t uart_input(rt_device_t dev, rt_size_t size)
  24. {
  25. struct rx_msg msg;
  26. msg.dev = dev;
  27. msg.size = size;
  28.  
  29. /* 发送消息到消息队列中*/
  30. rt_mq_send(rx_mq, &msg, sizeof(struct rx_msg));
  31.  
  32. return RT_EOK;
  33. }
  34.  
  35. void device_thread_entry(void* parameter)
  36. {
  37. struct rx_msg msg;
  38. int count = 0;
  39. rt_device_t device, write_device;
  40. rt_err_t result = RT_EOK;
  41.  
  42. /* 查找系统中的串口1设备 */
  43. device = rt_device_find("uart1");
  44. if (device!= RT_NULL)
  45. {
  46. /* 设置回调函数及打开设备*/
  47. rt_device_set_rx_indicate(device, uart_input);
  48. rt_device_open(device, RT_DEVICE_OFLAG_RDWR|RT_DEVICE_FLAG_INT_RX);
  49. }
  50. /* 设置写设备为uart1设备 */
  51. write_device = device;
  52.  
  53. /* 查找系统中的串口2设备 */
  54. device= rt_device_find("uart2");
  55. if (device_!= RT_NULL)
  56. {
  57. /* 设置回调函数及打开设备*/
  58. rt_device_set_rx_indicate(device, uart_input);
  59. rt_device_open(device, RT_DEVICE_OFLAG_RDWR);
  60. }
  61.  
  62. while (1)
  63. {
  64. /* 从消息队列中读取消息*/
  65. result = rt_mq_recv(rx_mq, &msg, sizeof(struct rx_msg), 50);
  66. if (result == -RT_ETIMEOUT)
  67. {
  68. /* 接收超时*/
  69. rt_kprintf("timeout count:%d\n", ++count);
  70. }
  71.  
  72. /* 成功收到消息*/
  73. if (result == RT_EOK)
  74. {
  75. rt_uint32_t rx_length;
  76. rx_length = (sizeof(uart_rx_buffer) - 1) > msg.size ?
  77. msg.size : sizeof(uart_rx_buffer) - 1;
  78.  
  79. /* 读取消息*/
  80. rx_length = rt_device_read(msg.dev, 0, &uart_rx_buffer[0],
  81. rx_length);
  82. uart_rx_buffer[rx_length] = '\0';
  83.  
  84. /* 写到写设备中*/
  85. if (write_device != RT_NULL)
  86. rt_device_write(write_device, 0, &uart_rx_buffer[0],
  87. rx_length);
  88. }
  89. }
  90. }
  91.  
  92. int rt_application_init()
  93. {
  94. /* 创建devt线程*/
  95. rt_thread_t thread = rt_thread_create("devt",
  96. device_thread_entry, RT_NULL,
  97. 1024, 25, 7);
  98. /* 创建成功则启动线程*/
  99. if (thread!= RT_NULL)
  100. rt_thread_startup(thread);
  101. }

线程devt启动后,系统将先查找是否存在uart1, uart2这两个设备,如果存在则设置数据接收回调函数。在数据接收回调函数中,系统将对应的设备句柄、接收到的数据长度填充到一个消息结构体(struct rx_msg)上,然后发送到消息队列rx_mq中。devt线程在打开设备后,将在消息队列中等待消息的到来。如果消息队列是空的,devt线程将被阻塞,直到达到唤醒条件被唤醒,被唤醒的条件是devt线程收到消息或0.5秒(50 OS tick, 在RT_TICK_PER_SECOND设置为100时)内都没收到消息。可以根据rt_mq_recv函数返回值的不同,区分出devt线程是因为什么原因而被唤醒。如果devt线程是因为接收到消息而被唤醒(rt_mq_recv函数的返回值是RT_EOK),那么它将主动调用rt_device_read去读取消息,然后写入uart1设备中。

finsh使用uart设备分析

1.注册设备

我们首先要注册设备,才能用rt_device_find查找到设备。然后就可以进行初始化、打开、读取等操作。首先在各线程启动之前进行设备注册,函数调用关系如下:

  1. main ==> rt_thread_startup ==> rt_hw_board_init ==> rt_hw_usart_init ==> rt_hw_serial_register ==> rt_device_register

在函数rt_thread_startup中最后才调用了rt_system_scheduler_start各线程才开始运行。可以确定线程在查找设备时设备已经存在。

rtconfig.h中有#define RT_CONSOLE_DEVICE_NAME "uart1",注册完设备后设置了终端设备

  1. rt_hw_board_init ==> rt_console_set_device(RT_CONSOLE_DEVICE_NAME)

finsh将使用此终端设备。

2.启动finsh线程

shell.c中有代码INIT_COMPONENT_EXPORT(finsh_system_init),采用宏INIT_COMPONENT_EXPORT导出的函数将在rt_components_init函数中被调用。调用关系:

  1. rt_thread_startup ==> rt_application_init ==> rt_init_thread_entry

启动初始化线程,然后在初始化线程中启动了finsh线程:

  1. rt_init_thread_entry ==> rt_components_init ==> finsh_system_init ==> finsh_thread_entry

3.打开设备

在finsh线程中打开设备,相关代码如下:

  1. shell->device = rt_console_get_device();
  2. RT_ASSERT(shell->device);
  3. rt_device_set_rx_indicate(shell->device, finsh_rx_ind);
  4. rt_device_open(shell->device, (RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_STREAM | RT_DEVICE_FLAG_INT_RX));

如果打开时设备没有进行初始化将首先进行初始化

  1. rt_device_open ==> rt_serial_init ==> stm32_configure

stm32_configure进行了波特率等参数的配置。

然后打开设备

  1. rt_device_open ==> rt_serial_open ==> stm32_control

stm32_control中将打开接收中断。

4.接收数据

finsh采用了中断接收方式打开设备,当uart收到数据时将产生中断

  1. USART1_IRQHandler ==> rt_hw_serial_isr ==> stm32_getc

将收到的数据放到接收buffer里,然后调用回调函数finsh_rx_indfinsh_rx_ind释放信号量,finsh线程得到信号量后读取数据。

  1. finsh_thread_entry ==> rt_device_read ==> rt_serial_read ==> _serial_int_rx

_serial_int_rx函数从接收buffer中读取数据。

5.发送数据

在finsh中调用rt_kprintf函数进行输出

  1. rt_kprintf ==> rt_device_write ==> rt_serial_write ==> _serial_poll_tx ==> stm32_putc

以上即finsh中对uart设备的使用分析。