痞子衡嵌入式:淺析IAR下調試信息輸出機制之硬體UART外設

来源:https://www.cnblogs.com/henjay724/archive/2022/08/22/16614420.html
-Advertisement-
Play Games

大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家分享的是IAR下調試信息輸出機制之硬體UART外設。 在嵌入式世界里,輸出列印信息是一種非常常用的輔助調試手段,藉助列印信息,我們可以比較容易地定位和分析程式問題。在嵌入式應用設計里實現列印信息輸出的方式有很多,本系列將以 IAR 環境為例逐一 ...



  大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家分享的是IAR下調試信息輸出機制之硬體UART外設

  在嵌入式世界里,輸出列印信息是一種非常常用的輔助調試手段,藉助列印信息,我們可以比較容易地定位和分析程式問題。在嵌入式應用設計里實現列印信息輸出的方式有很多,本系列將以 IAR 環境為例逐一介紹 ARM Cortex-M 內核 MCU 下列印信息輸出方法。

  本篇是第一篇,我們先介紹最常見的輸出列印信息方式,即利用 MCU 晶元內的硬體 UART 外設。本篇其實並不是要具體介紹 UART 外設模塊使用方法,而是重點分析 IAR 下是如何聯繫 C 標準頭文件 stdio.h 定義的 printf() 函數與 UART 外設底層驅動函數的。

  • Note: 本文使用的 IAR EWARM 軟體版本是 v9.10.2。

一、列印輸出整體框圖

  首先簡介下本文介紹的列印輸出方法整體軟硬體框圖,硬體上主要是 PC 主機、MCU 目標板、一根連接線(連接線有兩種方案:一種是 RS232 串口線、另一種是 TTL 串口轉 USB 模塊板)。

  軟體上 PC 這邊需要安裝一個串口調試助手軟體,然後目標板 MCU 應用程式需要包含列印輸出相關代碼,當 MCU 程式運行起來後,驅動片內 UART 外設實現列印字元數據 (hello world.) 物理傳輸,在 PC 上串口調試助手軟體里可以看到列印信息。

  上圖裡的 MCU 應用程式是在 IAR 環境下編譯鏈接的,因此我們的重點就是 stdio.h 頭文件里的 printf() 在 IAR 下到底是如何與 UART 外設驅動函數“勾搭”起來的。

二、C 標準頭文件 stdio.h

  熟悉嵌入式工程的朋友應該都知道 stdio.h 頭文件並不在用戶工程文件夾里,無需我們手動添加該文件進工程目錄,該文件是 C 標准定義的頭文件,由工具鏈自動提供。

  stdio.h 是 C 語言為輸入輸出提供的標準庫頭文件,其前身是邁克·萊斯克 20 世紀 70 年代編寫的“可移植輸入輸出程式庫”。C 語言中的所有輸入和輸出都由抽象的位元組流來完成,對文件的訪問也通過關聯的輸入或輸出流進行。

  大部分人學 C 語言一般都是在 Visual Studio / C++ 環境下,在這個環境里 stdio.h 定義的那些函數底層實現都由 Visual Studio 軟體直接搞定,我們通常無需關心其實現細節。

  在嵌入式 IAR 環境下,這些標準 C 定義的頭文件大部分也都是可以被支持的,我們可以在如下 IAR 軟體目錄找到它們,當我們在工程代碼裡加入 #include <stdio.h> 等語句時,實際上就是添加 IAR 軟體目錄里的文件進工程編譯。

\IAR Systems\Embedded Workbench 9.10.2\arm\inc\c\stdio.h

  但是 IAR 目錄下 stdio.h 文件里定義的諸如 printf() 函數具體實現我們是需要關註的,畢竟是要編譯鏈接生成具體機器碼下載進 MCU 運行的,但是 printf() 函數原型在哪呢?我們先留個懸念。

三、UART 外設驅動函數

  說到 UART 外設驅動函數,這個大家應該再熟悉不過了。我們以恩智浦 i.MXRT1060 型號(ARM Cortex-M7 內核)為例來具體介紹,在其官方 SDK 包里有相應的 LPUART 驅動文件:

\SDK_2.11.0_EVK-MIMXRT1060\devices\MIMXRT1062\drivers\fsl_lpuart.h
\SDK_2.11.0_EVK-MIMXRT1060\devices\MIMXRT1062\drivers\fsl_lpuart.c

  這個 LPUART 驅動庫里的 LPUART_WriteBlocking() 和 LPUART_ReadBlocking() 函數可以完成用戶數據包的發送和接收,其實單純利用 LPUART_WriteBlocking() 函數也可以實現列印信息輸出,只是沒有 printf() 函數那樣包含格式化輸出的強大功能。

status_t LPUART_Init(LPUART_Type *base, const lpuart_config_t *config, uint32_t srcClock_Hz)
status_t LPUART_WriteBlocking(LPUART_Type *base, const uint8_t *data, size_t length)
status_t LPUART_ReadBlocking(LPUART_Type *base, uint8_t *data, size_t length)

四、IAR 對 C 標準 I/O 庫的支持

  IAR 顯然是對 C 標準 I/O 庫有支持的,不然我們不可能在工程里能使用 printf() 函數,只是這個支持我們如何去輕鬆發現呢?痞子衡今天教大家一個方法,就是看工程編譯鏈接後生成的 .map 文件,這個 map 文件里會列出工程里所有函數的來源。

4.1 引出底層介面 __write()

  我們以 \SDK_2.11.0_EVK-MIMXRT1060\boards\evkmimxrt1060\demo_apps\hello_world\iar 工程為例來介紹,需要簡單改造一下工程里 hello_world.c 文件里的 main() 函數,將原來代碼全部刪掉(原來的列印輸出涉及恩智浦 SDK 封裝,本文沒必要關心其實現),只要如下一句列印即可:

#include <stdio.h>
int main(void)
{
    printf("hello world.\r\n");
    while (1);
}

  然後註意工程選項里跟 Library 實現相關的如下三處設置。其中 Library 選項配置的是 runtime lib 的功能,有 Normal 和 Full 兩個選項(可按需選擇);Printf formatter 選項決定格式化輸出功能細節,分 Full、Large、Small、Tiny 四個選項(可按需選擇)。Library low-level interface implementation 選項決定低層 I/O 實現,這裡我們選 None,即由用戶來實現。

  配置好 Library 後編譯工程會發現有如下報錯,根據這個報錯我們可以猜到 dl7M_tln.a 是 IAR 編譯好的 C/C++ 庫,庫裡面實現了 printf() 函數及其所依賴的 putchar() 函數,而 puchar() 函數對外提供了底層 I/O 介面函數,這個 I/O 函數名字叫 __write(),它就是需要用戶結合晶元 UART 外設去實現的發送函數。

 Error[Li005]: no definition for "__write" [referenced from putchar.o(dl7M_tln.a)]   

  在 IAR 目錄下我們可以找到 dl7M_tln.a 文件路徑,經過測試,工程 Library 設置里 Normal 和 Full 選項其實就是選 dl7M_tln.a 還是 dl7M_tlf.a 進用戶工程去鏈接。

4.2 DLIB底層 I/O 介面設計

  找到了 __write() 函數,但是它的原型到底是什麼?我們該如何實現它?這時候需要去查萬能的 \IAR Systems\Embedded Workbench 9.10.2\arm\doc\EWARM_DevelopmentGuide.ENU 手冊,在裡面搜索 __write 字樣可以找到如下設計,原來我們在代碼里調用的 C 標準 I/O 介面均是由 IAR 底層預編譯好的 DLIB 去具體實現的,這個 DLIB 庫也留下了給用戶實現的最底層與硬體相關的介面函數。

  IAR 為 DLIB 里那些最底層的 I/O 介面函數都創建了模板源文件,在這些模板文件里我們可以找到它們的原型,所以我們在 write.c 文件里找到了 __write() 原型及其示例實現。

size_t __write(int handle, const unsigned char * buffer, size_t size)

4.3 DLIB庫 I/O 相關源碼實現

  有了 __write() 原型及示例代碼,我們很容易便能用 LPUART_WriteBlocking() 函數去實現它,將這個代碼添加進 hello_world 工程編譯,這時候就不會報錯了(當然要想真正在板子上測試列印功能,main 函數里還得加入 LPUART 初始化代碼)。

#include "fsl_lpuart.h"
size_t __write(int handle, const unsigned char *buf, size_t size)
{
    // 假設使用 LPUART1 去做輸出
    (void)LPUART_WriteBlocking(LPUART1, buf, size);

    return 0;
}

  工程編譯完成後,查看生成的 hello_world.map 文件,找到 dl7M_tln.a 部分的信息,可以看到其由很多個 .o 文件組成(功能比較豐富),這些 .o 文件都是可以在 IAR 安裝目錄下找到其源碼的。

*******************************************************************************
*** MODULE SUMMARY
***

    Module                ro code  ro data  rw data
    ------                -------  -------  -------
dl7M_tln.a: [10]
    abort.o                     6
    exit.o                      4
    low_level_init.o            4
    printf.o                   40
    putchar.o                  32
    xfail_s.o                  64                 4
    xprintfsmall_nomb.o     1'281
    xprout.o                   22
    -----------------------------------------------
    Total:                  1'453                 4

  DLIB 庫中關於 I/O 相關的源碼放在瞭如下目錄里,感興趣的可以去查看其具體實現,這裡特別提一下 formatter 文件夾下 xprintf 有很多種不同的源文件實現,其實就對應了工程選項 Printf formatter 里的不同配置。

\IAR Systems\Embedded Workbench 9.10.2\arm\src\lib\dlib\file
\IAR Systems\Embedded Workbench 9.10.2\arm\src\lib\dlib\formatters

  至此,IAR下調試信息輸出機制之硬體UART外設痞子衡便介紹完畢了,掌聲在哪裡~~~

歡迎訂閱

文章會同時發佈到我的 博客園主頁CSDN主頁知乎主頁微信公眾號 平臺上。

微信搜索"痞子衡嵌入式"或者掃描下麵二維碼,就可以在手機上第一時間看了哦。

  最後歡迎關註痞子衡個人微信公眾號【痞子衡嵌入式】,一個專註嵌入式技術的公眾號,跟著痞子衡一起玩轉嵌入式。

痞子衡嵌入式-微信二維碼 痞子衡嵌入式-微信收款二維碼 痞子衡嵌入式-支付寶收款二維碼

  衡傑(痞子衡),目前就職於恩智浦MCU系統部門,擔任嵌入式系統應用工程師。

  專欄內所有文章的轉載請註明出處:http://www.cnblogs.com/henjay724/

  與痞子衡進一步交流或咨詢業務合作請發郵件至 [email protected]

  可以關註痞子衡的Github主頁 https://github.com/JayHeng,有很多好玩的嵌入式項目。

  關於專欄文章有任何疑問請直接在博客下麵留言,痞子衡會及時回覆免費(劃重點)答疑。

  痞子衡郵箱已被私信擠爆,技術問題不推薦私信,堅持私信請先掃碼付款(5元起步)再發。



您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Java集合06 13.Map介面02 13.2Map介面常用方法 put():添加 remove():根據鍵鍵刪除映射關係 get():根據鍵獲取值 size():獲取元素個數 isEnpty():判斷個數是否為0 clear():清除 containsKey():查找鍵是否存在 例子1:Map接 ...
  • ​ 前幾天聽到朋友說自己選課事情,突發奇想想要搞這樣一個東西,但是由於各種原因只做到以下的完成度,具體的情況也會在解釋的最後留下。這個只適用於曲師大的教務系統,因為用的這個系統來進行的一個調試,對於其他的系統,思路都是一樣的,代碼也只適用於學習,請不要用以其他用途!代碼放在最後。 工具 Python ...
  • 1、前言 在執行自動化測試時,我們通常都希望能夠控制執行測試用例的順序。 在unittest框架中預設按照ACSII碼的順序載入測試用例並執行,順序為:0~9、A~Z、a~z,測試目錄、測試模塊、測試類、測試方法/測試函數都按照這個規則來載入測試用例。 在pytest測試框架中,預設從上至下執行,也 ...
  • 1. Mybatis的一級緩存 Mybatis的一級緩存是預設開啟的,你只要搭建一個Mybatis框架,就可以直接使用一級緩存。 一級緩存是SqlSession級別的,通過SqlSession查詢的數據會被緩存,下次使用同一個SqlSession查詢相同的數據,就會從緩存中直接獲取,不會從資料庫重新 ...
  • 哈嘍兄弟們,今天咱們分享一下類的定義和使用。 在Python中,類表示具有相同屬性和方法的對象的集合。在使用類時,需要先定義類,然後再創建類的實例,通過類的實例就可以訪問類中的屬性和方法了。 1、定義類 在Python中,類的定義使用class關鍵字來實現,語法如下: class ClassName ...
  • 面向對象簡介 面向過程的程式設計把電腦程式視為一系列的命令集合,即一組函數的順序執行。為了簡化程式設計,面向過程把函數繼續切分為子函數,即把大塊函數通過切割成小塊函數來降低系統的複雜度。 面向對象編程——Object Oriented Programming,簡稱OOP,是一種程式設計思想。OOP ...
  • 在使用docker-compose的過程中,很多程式都提供了健康檢查(healthcheck)的方法,通過健康檢查,應用程式能夠在確保其依賴的程式都已經啟動的前提下啟動,減少各種錯誤的發生,同時,合理設計的健康檢查也能夠提供給外界關於應用程式狀態的一些信息。 大多數docker鏡像的詳細說明中,會交 ...
  • 環境: 主機 Centos7 分區表類型 GPT 文件系統格式 xfs 雙硬碟雙系統(機械安裝centos7,固態裝win10) 上次除了擴容到50G外,就是把/dev/sda 中number 4 的分區end 接到 5分區的start 裝機時機械硬碟有一部分空間沒用,前些天擴展了一遍,遇到問題卡住 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...