精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

rt-thread 驅動篇(二) serialX 理論實現

出出 ? 來源:出出 ? 作者:出出 ? 2022-06-22 09:03 ? 次閱讀

前言

“serialX” 我起的名字,起個名字想破頭。
在前一篇文章里,大致提出了我的串口驅動框架理論。里面做了一些對串口驅動特性的幻想。也在 NUC970 芯片下通過了中斷模式的實踐驗證。但是,因為 NUC970 的 uart 自帶 fifo 。用它測試效果好,并不能真正說明驅動框架通過驗證了。

然后,緊接著筆者在 STM32F429 完成了中斷和 DMA 兩種模式。今天,我把一些測試結果和移植說明發出來,征求全網公測。

測試配置:DMA 二級緩存 32 個字節,串口收發緩存各 512 字節。

注:本串口驅動工作特性請參閱前一篇文章rt-thread 驅動篇(一) serialX 框架理論

STM32 中斷模式測試

以下是三組連續發收測試:

1. 定時間隔20ms,發送250字節數據,持續發送2600w,接收發送數據量相等

250-20ms-2600w.png

2. 定時間隔50ms,發送250字節數據,持續發送600w,接收發送數據量相等

250-50ms-600w.png

3. 定時間隔80ms,發送1000字節數據,持續發送600w,接收發送數據量相等

1000-80ms-610w.png

注:剛剛跟我們小伙伴求證了一下,串口調試助手的定時間隔是固定周期。如果是這樣的,以上測試是有意義的,如果不是,那就沒達到串口帶寬上限。

STM32 DMA模式測試

1. 讀寫測試,串口調試助手定時 10ms ,發送40字節數據,持續發送129w

dma-40-10ms-129w.png

2. 串口調試助手定時 50ms ,發送500字節數據,持續發送527w

dma-500-50ms-527w.png

3. 串口調試助手定時 40ms ,發送500字節數據,持續發送261w

dma-500-40ms-261w.png

4. 串口調試助手定時 40ms ,發送1000字節數據,持續發送262w

dma-1000-40ms-262w.png

串口調試助手上發送和接收數量不相等,接著我在代碼中添加了個斷點,單獨發送了一個字節 ‘Z’ 。

dma-1000-40ms-262w-rw.png

代碼中接收和發送數量相等,都等于串口調試助手的接收量。這個缺少的部分是串口調試助手發送失敗數量,還是串口驅動接收丟失了?

接下來,修改成中斷接收發送模式,其它不做修改進行相同的測試,也是有數量差。進一步檢查串口驅動里,接收緩存有溢出現象。應用層沒來得及把數據取走,就刪掉了最舊的數據。

接口詳解及移植說明

rtdef.h 添加幾個宏定義

添加阻塞打開相關標志

#define RT_DEVICE_OFLAG_BLOCKING        0x000           /**< blocking io mode */
#define RT_DEVICE_OFLAG_NONBLOCKING     0x004           /**< non-blocking io mode */
...

#define RT_DEVICE_CTRL_BLOCKING         0x05            /**< blocking io */

serialX.h

添加串口驅動緩存和 DMA 二級緩存大小定義(放棄使用 `RT_SERIAL_RB_BUFSZ`):

#ifndef RT_SERIAL_FIFO_BUFSZ
#define RT_SERIAL_FIFO_BUFSZ            512
#endif
#ifndef RT_SERIAL_DMA_BUFSZ
#define RT_SERIAL_DMA_BUFSZ             32
#endif

串口接收和發送使用的緩存大小是一樣的,如果想改變串口緩存大小,請修改 `RT_SERIAL_FIFO_BUFSZ` 的值。

如果想改變 DMA 二級緩存大小,請修改 `RT_SERIAL_DMA_BUFSZ` 的值。

定義一個收發通用 fifo:

struct rt_serial_fifo
{
   rt_uint32_t buf_sz;
   /* software fifo */
   rt_uint8_t *buffer;
   rt_uint16_t put_index, get_index;

   rt_bool_t is_full;
};

重新定義 `rt_serial_device` 定義:

struct rt_serial_device
{
   struct rt_device          parent;
   const struct rt_uart_ops *ops;
   struct serial_configure   config;

   void *serial_rx;   // 串口接收緩存
   void *serial_tx;   // 串口發送緩存

#ifdef RT_SERIAL_USING_DMA       // 串口收發緩存和 DMA 使用的二級緩存分開
   rt_size_t dma_idx_rx;
   rt_uint8_t serial_dma_rx[RT_SERIAL_DMA_BUFSZ]; // DMA 接收緩存
   rt_uint8_t serial_dma_tx[RT_SERIAL_DMA_BUFSZ]; // DMA 發送緩存
#endif

   cb_serial_tx _cb_tx;  // 寫過程回調函數指針
   cb_serial_rx _cb_rx;  // 讀過程回調函數指針

   struct rt_completion completion_tx;    // 發送完成
   struct rt_completion completion_rx;    // 接收到新數據
};
typedef struct rt_serial_device rt_serial_t;

串口驅動通用框架和硬件底層接口定義

struct rt_uart_ops
{
// 用于配置外設寄存器,引腳功能復用,啟用外設等等
   rt_err_t (*configure)(struct rt_serial_device *serial, struct serial_configure *cfg);
   // 用于使能禁用中斷,初始配置 DMA
   rt_err_t (*control)(struct rt_serial_device *serial, int cmd, void *arg);
// 串口外設寫數據寄存器*為空*,把數據放入寫數據寄存器。*不為空*,死等
   int (*putc)(struct rt_serial_device *serial, char c);
   // 串口外設讀數據寄存器*不為空*,讀出讀數據寄存器的值。*為空*,返回 -1
   int (*getc)(struct rt_serial_device *serial);
// 啟動發送,多數是開啟串口外設發送寄存器空中斷
   void (*start_tx)(struct rt_serial_device *serial);
// 結束發送,多數是關閉串口外設發送寄存器空中斷
   void (*stop_tx)(struct rt_serial_device *serial);

#ifdef RT_SERIAL_USING_DMA
// 判斷 DMA 是否在發送過程中,就像上一篇里筆者多次提示的,必須有效檢測 DMA 是否在發送數據中
   rt_bool_t (*is_dma_txing)(struct rt_serial_device *serial);
   // 啟動 DMA 發送
   void (*start_dma_tx)(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size);
   // 停止 DMA 發送
   void (*stop_dma_tx)(struct rt_serial_device *serial);
#endif
// 使能串口外設中斷
   void (*enable_interrupt)(struct rt_serial_device *serial);
   // 禁用串口外設中斷
   void (*disable_interrupt)(struct rt_serial_device *serial);
};

移植 serialX 到新芯片上,必須按照 `rt_uart_ops` 的定義實現上述幾個接口。函數功能不能隨意更改。

`rt_hw_serial_isr`

這個中斷只接收 `RT_SERIAL_EVENT_RX_IND` `RT_SERIAL_EVENT_RX_IND` `RT_SERIAL_EVENT_RX_DMADONE` `RT_SERIAL_EVENT_TX_DMADONE` 四種中斷狀態。

  • `RT_SERIAL_EVENT_RX_IND` 接收寄存器不空中斷
  • `RT_SERIAL_EVENT_TX_DONE` 發送寄存器空中斷,為了兼容自帶 fifo 的芯片,event 參數的高三字節代表 fifo 容量
  • `RT_SERIAL_EVENT_RX_DMADONE` 串口接收 DMA 中斷。 這個可以兼容接收半傳輸和全傳輸等多種中斷。event 參數的高三字節代表 DMA fifo 接收數據數量(1-RT_SERIAL_DMA_BUFSZ)。
  • `RT_SERIAL_EVENT_TX_DMADONE` 串口發送 DMA 中斷。這個應該保證 DMA 發送完本次 DMA 緩存中的所有數據,也就是對于 stm32 芯片是 DMA 計數達到 0。

使用注意

  • `RT_SERIAL_FIFO_BUFSZ` `RT_SERIAL_DMA_BUFSZ` 兩個的定義和實際是否合適,小數據量通信可以定義小點兒,數據量大的情況適當調整這兩個值。
  • `rt_uart_ops` 接口定義,功能實現必須匹配。
  • 阻塞模式,收發是一致的。默認是阻塞模式。想使用非阻塞模式請 open 的時候添加 `RT_DEVICE_OFLAG_NONBLOCKING` flag。
  • 使用 `RT_DEVICE_FLAG_INT` `RT_DEVICE_FLAG_DMA_RX` `RT_DEVICE_FLAG_INT_TX` `RT_DEVICE_FLAG_DMA_TX` 四個 open flag 指定收發模式,是用中斷還是 DMA。
  • **特別提醒**,非阻塞模式下,read 可能返回 0。write 返回值可能不是目標寫入 size。read/write 還可能返回 `RT_EXXX` 錯誤值。
  • **特別提醒**,阻塞模式下,read 返回值可能不是期望數據量 size。筆者也曾經提供過可靠處理流數據的方案,詳見 rt-thread 使用寶典(2022-0516更新)

使用完成量進入阻塞漏洞分析

> PS: 謝謝 @HelloBye 的及時糾正,`rt_completion` 不存在本小節描述的漏洞。各位看官可以直接跳過本小節了

串口驅動里有幾個阻塞點,進入阻塞都使用的 `rt_completion` ,如下代碼:

serial->ops->enable_interrupt(serial);
ret = rt_completion_wait(&(serial->completion_rx), RT_WAITING_FOREVER);// 或者 serial->completion_tx

首先開中斷,調用 `rt_completion_wait` 等待完成量進入阻塞。這樣是有個漏洞的,當開中斷后有個串口中斷,中斷處理函數里調用 `rt_completion_done` 是沒有任何反應的,`rt_completion_done` 直接返回退出。

進而回到原線程才執行 `rt_completion_wait`。之后,如果有第二次接收(或發送)中斷發生時才會結束上一次的阻塞。但是,第二次什么時候出現也就是個未知數了。即便前一次可能已經收全了全部想要的數據,但是會不定期阻塞下去。

解決方法有兩個:一、不用永久阻塞,換成 10ms 或者幾 ms 等待;二、用二值信號量替代。

但是?。。∥覜]有用上述方法中的任何一個進行改進,原因是:

第一種方法無疑要引入一個循環,`rt_completion_wait` 超時返回的時候循環繼續阻塞。還有就是等待時間沒有理論支持。最重要的是用循環方式補漏洞的方式不美觀。

沒使用二值信號量的原因是,rt-thread 的信號量實現沒有真正的“二值”,如果中斷已經多次 release 了,然后應用層才來一次 take,之后還可能成功 take 多次(雖然應該是要阻塞的,但是實際不阻塞,反而會循環 take 多次)。

結束語

現筆者將打碼開放出來 gitee 倉庫 [serialX]( https://gitee.com/thewon/serialX ),求全論壇公測。期待各位大佬提出各種測試方案對它蹂躪。

有問題可以在倉庫里提 [issue]( https://gitee.com/thewon/serialX/issues ) ,或者到 rt-thread 官方論壇上進行討論。

審核編輯:湯梓紅

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • STM32
    +關注

    關注

    2266

    文章

    10871

    瀏覽量

    354817
  • 中斷
    +關注

    關注

    5

    文章

    895

    瀏覽量

    41394
  • 串口驅動
    +關注

    關注

    2

    文章

    82

    瀏覽量

    18623
  • RT-Thread
    +關注

    關注

    31

    文章

    1272

    瀏覽量

    39923
收藏 人收藏

    評論

    相關推薦

    RT-Thread記錄(一、版本開發環境及配合CubeMX)

    RT-Thread 學習記錄的第一文章,RT-Thread記錄(一、RT-Thread 版本、RT-Thread Studio開發環境 及
    的頭像 發表于 06-20 00:28 ?5143次閱讀
    <b class='flag-5'>RT-Thread</b>記錄(一、版本開發環境及配合CubeMX)

    RT-Thread記錄(、RT-Thread內核啟動流程)

    在前面我們RT-Thread Studio工程基礎之上講一講RT-Thread內核啟動流程.
    的頭像 發表于 06-20 00:30 ?4965次閱讀
    <b class='flag-5'>RT-Thread</b>記錄(<b class='flag-5'>二</b>、<b class='flag-5'>RT-Thread</b>內核啟動流程)

    rt-thread 驅動(六)serialX弊端及解決方法

    serialX 作為一個非阻塞串口驅動框架,在遇到一些異常時,需要做一些特殊處理,今天,筆者帶大家來扒一扒 serialX 使用過程中需要注意哪些問題。
    的頭像 發表于 06-20 11:43 ?3437次閱讀

    RT-Thread NUC97x 移植 LVGL

    不涉及 rt-thread 驅動,但是它是 LVGL 和 rt-thread 的接口。LVGL 在 rt-thread 上運行的基石。
    發表于 07-08 09:37 ?1469次閱讀

    基于RT-Thread的SPI通訊

    驅動層的驅動。(rt-thread的設備 I/O 模型有設備管理層、設備驅動框架層、設備驅動層),我寫過一
    的頭像 發表于 08-22 09:28 ?1664次閱讀

    RT-Thread ssd1306驅動

    RT-Thread 驅動ssd1306
    的頭像 發表于 04-21 10:08 ?26.4w次閱讀
    <b class='flag-5'>RT-Thread</b> ssd1306<b class='flag-5'>驅動</b>

    【原創精選】RT-Thread征文精選技術文章合集

    軟件包)NO2 專欄作者 :出出簡介:rt-thread 研究。1. rt-thread 驅動rt-thread
    發表于 07-26 14:56

    RT-Thread編程指南

    RT-Thread編程指南——RT-Thread開發組(2015-03-31)。RT-Thread做為國內有較大影響力的開源實時操作系統,本文是RT-Thread實時操作系統的編程指南
    發表于 11-26 16:06 ?0次下載

    RT-Thread Studio驅動SD卡

    RT-Thread Studio驅動SD卡前言一、創建基本工程1、創建Bootloader2、創建項目工程、配置RT-Thread Settings三、代碼分析1.引入庫2.讀入數據
    發表于 12-27 19:13 ?20次下載
    <b class='flag-5'>RT-Thread</b> Studio<b class='flag-5'>驅動</b>SD卡

    RT-Thread全球技術大會:RT-Thread對POSIX的實現情況介紹

    RT-Thread全球技術大會:RT-Thread對POSIX的實現情況介紹 ? ? ? ? ? ? 審核編輯:彭靜
    的頭像 發表于 05-27 16:52 ?1856次閱讀
    <b class='flag-5'>RT-Thread</b>全球技術大會:<b class='flag-5'>RT-Thread</b>對POSIX的<b class='flag-5'>實現</b>情況介紹

    rt-thread 驅動(四)serialX 多架構適配

    自筆者提出 serialX 串口驅動到今天近半年了,當初只在 STM32F4 NUC970 兩個系列芯片上做過理論驗證。一個是 ARM CM4 核心架構,一個是 ARM9。這兩款芯片能完美實現
    的頭像 發表于 06-10 10:21 ?3021次閱讀

    rt-thread 驅動(五)serialX 小試牛刀

    終于來到了 serialX 的實踐,期待很久了。
    的頭像 發表于 06-16 11:29 ?4472次閱讀
    <b class='flag-5'>rt-thread</b> <b class='flag-5'>驅動</b><b class='flag-5'>篇</b>(五)<b class='flag-5'>serialX</b> 小試牛刀

    RT-Thread文檔_RT-Thread 簡介

    RT-Thread文檔_RT-Thread 簡介
    發表于 02-22 18:22 ?5次下載
    <b class='flag-5'>RT-Thread</b>文檔_<b class='flag-5'>RT-Thread</b> 簡介

    RT-Thread文檔_RT-Thread SMP 介紹與移植

    RT-Thread文檔_RT-Thread SMP 介紹與移植
    發表于 02-22 18:31 ?9次下載
    <b class='flag-5'>RT-Thread</b>文檔_<b class='flag-5'>RT-Thread</b> SMP 介紹與移植

    RT-Thread設備驅動開發指南》基礎--以先楫bsp的hwtimer設備為例

    一、概述(一)RT-Thread設備驅動RT-Thread設備驅動開發指南》書籍是RT-thread官方出品撰寫,系統講解
    的頭像 發表于 02-24 08:16 ?1430次閱讀
    《<b class='flag-5'>RT-Thread</b>設備<b class='flag-5'>驅動</b>開發指南》基礎<b class='flag-5'>篇</b>--以先楫bsp的hwtimer設備為例