STM32F103_LL庫+寄存器學習筆記10 - DMA傳輸過半+DMA傳輸完成中斷實現DMA串口接收“雙緩沖“

導言


《[[STM32F103_LL庫+寄存器學習筆記09 - DMA串口接收與DMA串口發送,串口接收空閑中斷]]》上一章節完成DMA發送與接收。此時,有一個致命的問題可能會導致數據包丟失。原因是USART1接收只開啟了接收空閑中斷(IDLE),DMA在連續模式下,如果數據一直持續發送(或者數據包的大小比接收緩存區要大),將會出現數據被覆蓋,被覆蓋的數據等于丟失的數據。

實現更加健壯的串口接收程序是同時利用USART空閑中斷來判斷數據包的結束,并配合DMA半傳輸和傳輸完成中斷及時處理數據,從而避免數據溢出或被覆蓋。 總的來說就是接收空閑中斷 + DMA傳輸過半中斷 + DMA傳輸完成中斷。
方案如下:

  1. 開啟接收空閑中斷
    • 當數據傳輸過程中出現空閑(即一段數據傳輸結束后總線靜默),USART空閑中斷就會觸發。這時,立即關閉DMA,讀取DMA剩余計數器(或利用緩沖區總大小減去剩余計數得到實際接收字節數),將這部分數據交給上層處理,然后清除中斷標志并重新啟動DMA。這樣即使數據包不足一個完整緩沖區,也能準確提取數據。
  2. 開啟半傳輸和全傳輸中斷
    • 半傳輸中斷:當DMA接收到緩沖區前半部分的數據時觸發。此時可以先處理前半部分的數據,避免數據不斷寫入后覆蓋還未處理的數據。
    • 傳輸完成中斷:當DMA完成整個緩沖區的數據接收時觸發,同樣可處理后半部分數據。這種“雙緩沖”技術允許你在數據接收的同時就將已接收部分取出處理,降低丟包風險。

總的來說:

  • 對于連續且數據量較大的情況,DMA半傳輸和傳輸完成中斷能保證數據能及時被輪換處理,不會因緩沖區滿而丟失數據。
  • 對于數據量較小或者數據傳輸間有間隔的情況,空閑中斷能夠準確捕獲數據包結束時刻,防止因數據不足而不觸發DMA半/全傳輸中斷而導致數據滯留。

另外,中斷的處理必須保證簡單,盡可能保證快進快出。 所以,數據的處理必須留在主循環來做(配合高效的數據結構ringbuffer)。后續章節會介紹ringbuffer的移植與使用。
在這里插入圖片描述
以115200波特率計算(假設每字節約10位,即包括起始、數據、停止位),理論上每秒可以傳輸約11520字節,也就是每毫秒大約11.5個字節。512個字節大概需要44~46毫秒填滿。當然,這個值會依據具體的幀配置(比如數據位、停止位、校驗位)略有不同。所以,如果數據量很大(一直連續)當觸發傳輸過半中斷時,要在大概44ms內把數據搬運出去,否則會被覆蓋。
在這里插入圖片描述
效果如下所示:
在這里插入圖片描述
項目地址:https://github.com/q164129345/MCU_Develop/tree/main/stm32f103_ll_library10_usart_dma_rx_interrupt

一、代碼(LL庫)


1.1、main.c

在這里插入圖片描述
在這里插入圖片描述

1.2、usart.c

在這里插入圖片描述

1.3、stm32f1xx_it.c

在這里插入圖片描述
在這里插入圖片描述

1.4、編譯、下載

在這里插入圖片描述
如上所示,編譯通過。
在這里插入圖片描述
效果如上所示,大量發送數據包,不丟包!

二、調試傳輸過半中斷與傳輸完成中斷


調試傳輸過半中斷與傳輸完成中斷之前,先被USART1的接收空閑中斷關閉掉,從而方便你單獨調試這兩個中斷。如下所示:
在這里插入圖片描述

2.1、傳輸過半中斷

在這里插入圖片描述
如上所示,從串口助手發送512個字節到STM32F103,觸發了DMA1通道5的傳輸過半中斷。從寄存器表格看到,HTIF5確認被置1了。
在這里插入圖片描述
如上所示,代碼LL_DMA_ClearFlag_HT5(DMA1)運行完,HTIF5標志位確實被清0了。
在這里插入圖片描述
如上所示,串口助手發送512個字節給STM32F103,讓它觸發DMA1通道5的傳輸過半中斷。在中斷里將前半段512個字節讓DMA1通道4回傳給電腦的串口助手。數據傳輸數量寄存器CNDTR5從0x400(1024)變成0x200(512),寫指針指向接收緩存區的偏移512。從整個過程看來,傳輸過半中斷程序調試OK。

2.2、傳輸完成中斷

在這里插入圖片描述
如上所示,串口助手再一次發送512個字節給STM32F103后,進入傳輸完成中斷。此時,TCIF5被置1。
在這里插入圖片描述
如上所示,代碼LL_DMA_ClearFlag_TC5(DMA1)運行之后,TCIF5標志被清0。
在這里插入圖片描述
如上所示,將斷點放開后,STM32F103將第二次收到的512個字節回傳給電腦的串口助手。此時,寄存器CNDTR5從0x200(512)變回最開始的0x400(1024)。從整個過程看來,傳輸完成中斷正常!

三、寄存器梳理


3.1、啟動傳輸過半中斷、傳輸完成中斷

在這里插入圖片描述
在這里插入圖片描述
如上所示,寄存器DMA_CCR5的位2與位1置1就可以打開半傳輸中斷與傳輸完成中斷。

// 增加傳輸完成與傳輸過半中斷
DMA1_Channel5->CCR |= (1UL << 1);             // 傳輸完成中斷 (TCIE)
DMA1_Channel5->CCR |= (1UL << 2);             // 傳輸過半中斷 (HTIE)

3.2、全局中斷DMA1_Channel5_IRQHandler()里判斷傳輸過半標志與傳輸完成標志

在這里插入圖片描述
在這里插入圖片描述

void DMA1_Channel5_IRQHandler(void) {// 半傳輸中斷if (DMA1->ISR & (1UL << 18)) {DMA1->IFCR |= (1UL << 18); // 清除標志}// 傳輸完成中斷if (DMA1->ISR & (1UL << 17)) {DMA1->IFCR |= (1UL << 17); // 清除標志}// 改為if...else if,中斷運行的時間更短
}

如上所示,通過寄存器ISR判斷是否進入該中斷,接著使用寄存器IFCR來清除中斷標志位。

四、代碼(寄存器)


4.1、main.c

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

4.2、stm32f1xx_it.c

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

4.3、編譯、下載

在這里插入圖片描述

4.4、串口助手調試

在這里插入圖片描述
如上所示,效果跟LL庫一樣。

五、細節補充


5.1、當接收緩存區大小1024bytes,剛好收到一幀大小512bytes數據時,會怎樣???

當接收緩存區大小1024bytes,剛好收到一幀大小512bytes數據時,將會進入傳輸過半中斷,然后再進入接收空閑中斷。 然后,傳輸過半中斷與接收空閑中斷都有將接收緩存區復制到發送緩存區的功能,會復制兩遍數據給發送緩存區嗎?代碼處理好了,不會! 以下是接收空閑中斷里的某部分代碼。

// 根據剩余字節判斷當前正在哪個半區
// 還有,避免當數據長度剛好512字節與1024字節時,傳輸過半中斷與空閑中斷復制兩遍數據,與傳輸完成中斷與空閑中斷復制兩遍數據。
if (remaining > (RX_BUFFER_SIZE/2)) {// 還在接收前半區:接收數據量 = (1K - remaining),但肯定不足 512 字節count = RX_BUFFER_SIZE - remaining;if (count != 0) { // 避免與傳輸完成中斷沖突,多復制一次memcpy((void*)tx_buffer, (const void*)rx_buffer, count);}
} else {// 前半區已寫滿,當前在后半區:后半區接收數據量 = (RX_BUFFER_SIZE/2 - remaining)count = (RX_BUFFER_SIZE/2) - remaining;if (count != 0) { // 避免與傳輸過半中斷沖突,多復制一次memcpy((void*)tx_buffer, (const void*)(rx_buffer + RX_BUFFER_SIZE/2), count);}
}
if (count != 0) {recvd_length = count;rx_complete = 1;
}

假設RX_BUFFER_SIZE為1024,當串口助手發送512個字節時,DMA剩余計數remaining正好為512。此時remaining不大于512,所以進入else分支,計算得到count = (1024/2) - 512 = 512 - 512 = 0。因此不會再復制數據,也就避免了重復拷貝前半段數據。

當接收緩存區大小1024bytes,剛好收到一幀大小1024bytes數據時,發生順序大致如下:

  1. 當接收到前512字節時,DMA觸發半傳輸中斷,此時會調用對應中斷服務程序,將前半區(偏移0~511)的數據復制到發送緩沖區,并設置接收完成標志。
  2. 當接收到后512字節時,DMA觸發傳輸完成中斷,同樣將后半區(偏移512~1023)的數據復制到發送緩沖區(注意,如果使用同一個tx_buffer,則需要根據應用需求處理兩次復制的數據是合并還是分別處理)。
  3. 如果此時串口沒有繼續接收數據,USART1空閑中斷也可能觸發。此時,在空閑中斷處理代碼中,會先禁用DMA,然后通過下面這段代碼來計算“新增”的數據長度:
// 禁用 DMA1 通道5,防止數據繼續寫入
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_5);
uint16_t remaining = LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_5); // 獲取剩余的容量
uint16_t count = 0;
// 根據剩余字節判斷當前正在哪個半區
// 還有,避免當數據長度剛好512字節與1024字節時,傳輸過半中斷與空閑中斷復制兩遍數據,與傳輸完成中斷與空閑中斷復制兩遍數據。
if (remaining > (RX_BUFFER_SIZE/2)) {// 還在接收前半區:接收數據量 = (1K - remaining),但肯定不足 512 字節count = RX_BUFFER_SIZE - remaining;if (count != 0) { // 避免與傳輸完成中斷沖突,多復制一次memcpy((void*)tx_buffer, (const void*)rx_buffer, count);}
} else {// 前半區已寫滿,當前在后半區:后半區接收數據量 = (RX_BUFFER_SIZE/2 - remaining)count = (RX_BUFFER_SIZE/2) - remaining;if (count != 0) { // 避免與傳輸過半中斷沖突,多復制一次memcpy((void*)tx_buffer, (const void*)(rx_buffer + RX_BUFFER_SIZE/2), count);}
}
if (count != 0) {recvd_length = count;rx_complete = 1;
}
// 重新設置 DMA 傳輸長度并使能 DMA
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_5, RX_BUFFER_SIZE);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_5);

對于1024字節的情況,DMA工作在循環模式下,當完整數據傳輸完成后,DMA的計數器會重新加載為 RX_BUFFER_SIZE(即1024),因此當空閑中斷進入處理時:

  • remaining 將等于1024,
  • 如果進入第一個分支,則計算得到 count = RX_BUFFER_SIZE - remaining = 1024 - 1024 = 0,
  • 如果進入第二個分支(一般不會出現,因為remaining不小于512),同樣結果為0。
    因此,空閑中斷處理代碼不會再復制數據,也不會重復處理前半區數據。總結來說,當剛好發送1024字節時:
  • 半傳輸中斷處理了前512字節,
  • 傳輸完成中斷處理了后512字節,
  • 空閑中斷因計算出的新接收字節數為0而不再進行復制。
    這就避免了數據重復拷貝的問題!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/899309.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/899309.shtml
英文地址,請注明出處:http://en.pswp.cn/news/899309.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

李宏毅機器學習筆記06 | 魚和熊掌可以兼得的機器學習 - 內容接寶可夢

本章提要 深度學習可以在較少參數量的情況下得到比較低的loss&#xff1a; h a l l a r g min ? h ∈ H L ( h , D a l l ) h^{all}arg \min_{h \in H}L(h,D_{all}) hallargminh∈H?L(h,Dall?) 引入 如何權衡模型的復雜程度 Tradeoff of Model Complexity 理論上&#…

java八股文之JVM

1.什么是程序計數器 程序計數器是 JVM 管理線程執行的“定位器”&#xff0c;記錄每個線程當前執行的指令位置&#xff0c;確保程序流程的連續性和線程切換的準確性。線程私有的&#xff0c;每個線程一份&#xff0c;內部保存的字節碼的行號。用于記錄正在執行的字節碼指令的地…

Android設計模式之觀察者模式

一、定義&#xff1a;定義對象間一種一對多的依賴關系&#xff0c;使得每當一個對象改變狀態&#xff0c;則所有依賴于它的對象都會得到通知并被自動更新。 二、核心角色&#xff1a; Subject&#xff1a;抽象主題被觀察的角色&#xff0c;管理觀察者集合&#xff0c;提供注冊…

海康gdb流程

gdb相關 在initrun.sh文件里加入&#xff0c;注意需要在hikauto起來之前 # 設置core dump大小 ulimit -c unlimited if [ $? -eq 0 ];then echo "core dump size set success" else echo -e "\33[31m core dump size set fail\33[0m" fi echo …

springBoot統一響應類型3.3版本

前言&#xff1a; 通過實踐而發現真理&#xff0c;又通過實踐而證實真理和發展真理。從感性認識而能動地發展到理性認識&#xff0c;又從理性認識而能動地指導革命實踐&#xff0c;改造主觀世界和客觀世界。實踐、認識、再實踐、再認識&#xff0c;這種形式&#xff0c;循環往…

【空間變換】歐拉角與四元數

核心 歐拉角描述的是一種變換&#xff0c;只關注變換后的結果&#xff0c;不關注變換過程中的運動 而四元數不僅良好地表示了一種變換&#xff0c;也很好地表示了一種運動過程&#xff0c;又避免了萬向節死鎖Gimbal Lock變換順序&#xff0c;是歐拉角變換的一部分&#xff0c;…

基于Linux下的MyBash命令解釋器

項目介紹&#xff1a;?個?C語?實現的簡單shell&#xff0c;可以接受??輸?的命令并執?操作&#xff0c;?持多管道和重 定向。 mybash---打造自己的命令解釋器 目前我們Linux的系統默認的命令解釋器是bash; 命令解釋器&#xff08;也稱為命令行解釋器或shell&#xff0…

Linux常見使用場景

一、文件查看與內容操作 ?1. cat ?作用&#xff1a;查看文件內容&#xff08;一次性輸出全部內容&#xff09;。?常用選項&#xff1a; -n&#xff1a;顯示行號。-b&#xff1a;僅對非空行顯示行號。 ?示例&#xff1a; cat file.txt # 查看文件內容 cat -n fil…

Ingredient-oriented Multi-Degradation Learning for Image Restoration論文閱讀

摘要&#xff1a;重點在于關聯多個任務本質的聯系。 不同恢復任務的關聯性很重要。 揭示退化現象的內在機理聯系很有意義。 多合一的方法能在單一模型中處理多種退化問題&#xff0c;可擴展性較差。 成分導向范式挖掘不同圖像退化現象背后的物理規律或特征模式。 成分導向退化重…

禪道后臺命令執行漏洞

漏洞簡介 禪道是第一款國產的開源項目管理軟件。它集產品管理、項目管理、質量管理、文檔管理、 組織管理和事務管理于一體&#xff0c;是一款專業的研發項目管理軟件&#xff0c;完整地覆蓋了項目管理的核心流程。 禪道管理思想注重實效&#xff0c;功能完備豐富&#xff0c;…

密碼學——知識問答

目錄 1、闡述公開密鑰算法的定義&#xff0c;結合RSA算法說明公鑰密碼的基本要求。 說明公鑰與私鑰兩種密碼學并舉例與其應用 1. 公鑰密碼學&#xff08;非對稱加密&#xff09;&#xff1a; 2. 私鑰密碼學&#xff08;對稱加密&#xff09;&#xff1a; 對比公鑰與私鑰密碼…

PDF多表格結構識別與跨表語義對齊:基于對抗遷移的魯棒相似度度量模型

文章目錄 一. 項目結構二.流程分析2.1 批處理器核心代碼解析 三. 跨頁表格相似度匹配原理3.1 表頭內容相似度-特征向量歸一化3.2 表頭內容相似度-余弦相似度3.3 定時緩存清理 ocr掃描有其局限性。對于pdf文本類型這種pdfbox&#xff0c;aspose-pdf&#xff0c;spire直接提取文本…

es 3期 第27節-運用Script腳本實現復雜需求

#### 1.Elasticsearch是數據庫&#xff0c;不是普通的Java應用程序&#xff0c;傳統數據庫需要的硬件資源同樣需要&#xff0c;提升性能最有效的就是升級硬件。 #### 2.Elasticsearch是文檔型數據庫&#xff0c;不是關系型數據庫&#xff0c;不具備嚴格的ACID事務特性&#xff…

23、web前端開發之html5(四)

十二. HTML5實踐示例 前面我們詳細講解了HTML5的特點&#xff0c;包括語義化標簽、增強的表單功能、多媒體元素&#xff08;如<video>和<audio>&#xff09;、Canvas繪圖、SVG集成以及離線存儲等。以下是一些詳細的HTML5實踐示例&#xff0c;展示如何使用HTML5的新…

海思燒錄工具HITool電視盒子刷機詳解

HiTool是華為開發的一款用于海思芯片設備的刷機和調試工具&#xff0c;可對搭載海思芯片的機頂盒、智能電視等設備進行固件燒錄、參數配置等操作。以下為你詳細介紹&#xff1a; 功能用途 固件燒錄&#xff1a;這是HiTool最主要的功能之一。它能夠將下載好的適配固件文件燒錄到…

軟考中級-軟件設計師 23種設計模式(內含詳細解析)

23種設計模式 &#x1f3af; 創建型設計模式&#x1f4cc; 抽象工廠&#xff08;Abstract Factory&#xff09; 設計模式&#x1f4cc; 工廠方法&#xff08;Factory Method&#xff09;設計模式&#x1f4cc; 單例&#xff08;Singleton&#xff09;設計模式&#x1f4cc; 生成…

thinkphp8.0\swoole的websocket應用

環境&#xff1a;centOS7.9、php8.3、thinkphp8.0\think-swoole4.1 我用的官方think-swoole插件 第一步&#xff1a;根據官方文檔&#xff0c;需要安裝此擴展插件 composer require topthink/think-swoole 第二步&#xff1a;在根目錄下config文件夾下編輯swoole.php配置文…

Ubuntu服務器掛載時遇到文件系統錯誤怎么辦

在Ubuntu服務器上掛載分區時&#xff0c;如果遇到文件系統錯誤&#xff0c;通常可能是由于磁盤損壞、文件系統損壞、不正確的卸載等原因造成的。以下是詳細的排查與修復步驟&#xff1a; 一、查看錯誤信息 首先&#xff0c;嘗試手動掛載并觀察具體錯誤&#xff1a; sudo mount …

【設計模式】策略模式(Strategy Pattern)詳解

策略模式&#xff08;Strategy Pattern&#xff09;詳解 一、策略模式的定義 策略模式&#xff08;Strategy Pattern&#xff09;是一種行為型設計模式&#xff0c;它定義了一組算法&#xff0c;將每個算法封裝起來&#xff0c;并使它們可以相互替換&#xff0c;從而讓算法的…

軟考筆記5——軟件工程基礎知識

第五章節——軟件工程基礎知識 軟件工程基礎知識 第五章節——軟件工程基礎知識一、軟件工程概述1. 計算機軟件2. 軟件工程基本原理3. 軟件生命周期4. 軟件過程 二、軟件過程模型1. 瀑布模型2. 增量模型3. 演化模型&#xff08;原型模型、螺旋模型)4. 噴泉模型5. 基于構建的開發…