ARM的Semihosting技術(shù)
ARM的Semihosting技術(shù)(轉(zhuǎn))
Semihosting技術(shù)將應(yīng)用程序中的IO請求通過一定的通道傳送到主機(host),由主機上的資源響應(yīng)應(yīng)用程序的IO請求, 而不是像在主機上執(zhí)行本地應(yīng)用程序一樣,由應(yīng)用程序所在的計算機響應(yīng)應(yīng)用程序IO請求, 也就是將目標板的輸入/輸出請求從應(yīng)用程序代碼傳遞到遠程運行調(diào)試器的主機的一種機制。 簡單來說,目標開發(fā)板上通常不會有輸入/輸出這些外設(shè),開發(fā)板運行的代碼想要將結(jié)果打印出來, 或者獲得用戶的輸入,可以通過請求遠程主機IO設(shè)備來實現(xiàn),如:顯示器,鍵盤等。 目標開發(fā)板執(zhí)行代碼中加入對輸入/輸出設(shè)備進行訪問函數(shù),如:printf,scanf等, 這些函數(shù)并不是目標開發(fā)板的庫函數(shù),而是遠程主機交叉編譯器中帶有的庫函數(shù),這些庫函數(shù)被編譯時,編譯成一條軟件中斷指令。 當目標開發(fā)板上電運行之后,執(zhí)行到請求訪問輸入/輸出設(shè)備指令時,產(chǎn)生特定中斷號的軟件中斷SWI, 與開發(fā)板相連的調(diào)試器會先截獲目標板SWI請求,由于開發(fā)板程序中也可能存在用戶自定義軟件中斷, 為了區(qū)分二者,調(diào)試器會根據(jù)SWI的軟中斷號來判斷是不是semihosting模式IO請求, 如果是,則取出R0寄存器里代表的具體請求號,然后使用遠程主機來響應(yīng)目標板具體IO請求, 而不是開發(fā)板本身去處理setmihosting請求。 semihosting僅僅是一種調(diào)試手段,它的工作原理就是利用調(diào)試器捕捉目標環(huán)境運行過程中產(chǎn)生SWI中斷, 然后向遠程主機調(diào)試環(huán)境發(fā)送對應(yīng)的調(diào)試信息。 也就是說目標開發(fā)板通過特定的軟件中斷指令,借用了遠程主機的輸入輸出設(shè)備實現(xiàn)IO請求的訪問。
Semihosting半主機調(diào)試模式,只能使用在開發(fā)板和調(diào)試主機通過仿真器連接的情況下, 也就是說脫離了主機調(diào)試環(huán)境上述代碼不能正常運行。 目標開發(fā)板上執(zhí)行的IO實際上是交給了遠程主機來處理實現(xiàn),正是因為如此,這種方式只適合在調(diào)試模式下, 真正的嵌入式系統(tǒng)不可能依賴于主機實現(xiàn)IO處理的,嵌入式系統(tǒng)要想獨立出來實現(xiàn)IO請求的處理, 這就需要將輸入輸出庫函數(shù)的底層相關(guān)硬件實現(xiàn)重定向。
使用ITM機制實現(xiàn)調(diào)試,實現(xiàn)printf與scanf, ITM是ARM在推出semihosting之后推出的新一代調(diào)試機制。
ITM機制要求使用SWD方式接口,并需要連接SWO線。
半主機是用于 ARM 目標的一種機制,可將來自應(yīng)用程序代碼的輸入/輸出請求傳送至運行調(diào)試器的主機。 例如,使用此機制可以啟用 C 庫中的函數(shù),如 printf() 和 scanf(),來使用主機的屏幕和鍵盤,而不是在目標系統(tǒng)上配備屏幕和鍵盤。
這種機制很有用,因為開發(fā)時使用的硬件通常沒有最終系統(tǒng)的所有輸入和輸出設(shè)備。 半主機可讓主機來提供這些設(shè)備。
半主機是通過一組定義好的軟件指令(如 SVC)來實現(xiàn)的,這些指令通過程序控制生成異常。 應(yīng)用程序調(diào)用相應(yīng)的半主機調(diào)用,然后調(diào)試代理處理該異常。 調(diào)試代理提供與主機之間的必需通信。
半主機接口對 ARM 公司提供的所有調(diào)試代理都是通用的。 在無需移植的情況下使用 RealView ARMulator? ISS、指令集系統(tǒng)模型 (ISSM)、實時系統(tǒng)模型 (RTSM)、RealView ICE 或 RealMonitor 時,會執(zhí)行半主機操作。
標準庫使用半主機模式,半主機是通過一組定義好的軟件指令 (如 SVC)SVC 指令 (以前稱為 SWI 指令)來實現(xiàn)的,這些指令通過程序控制生成異常。 應(yīng)用程序調(diào)用相應(yīng)的半主機調(diào)用,然后調(diào)試代理處理該異常。調(diào)試代理(這里的調(diào)試代理是仿真器)提供與主機之間的必需通信。也就是說使用半主機模式必須使用仿真器調(diào)試。
ARMv7 之前的 ARM 處理器使用 SVC 指令 (以前稱為 SWI 指令)進行半主機調(diào)
用。 但是,如果要為 ARMv6-M 或 ARMv7-M (如 Cortex?-M1 或 Cortex-M3 處
理器)進行編譯,請使用 BKPT 指令來實現(xiàn)半主機。 簡單的來說,半主機模式就是通過仿真器實現(xiàn)開發(fā)板在電腦上的輸入和輸出。和半主機模式功能相同的是ITM調(diào)試機制。 有關(guān)ITM調(diào)試機制可以參考這里http://www.douban.com/note/248637026/ 上面介紹的半主機和ITM功能相當,他們都是調(diào)試機制,開發(fā)板均借助仿真器與電腦連接,實現(xiàn)單片機利用主機的屏幕鍵盤的輸入輸出。這兩種機制的運行均需要仿真器,否則無法運行。 開發(fā)式一般單片機需要獨立運行,開發(fā)者應(yīng)去掉仿真器,把printf函數(shù)通過單片機的外設(shè)來實現(xiàn),例如通過開發(fā)板的串口,lcd或者sd卡。
MDK中通常使用以下兩種方法:方法1.使用微庫,因為使用微庫的話,不會使用半主機模式.int fputc(int ch, FILE *f){ while((USART1->SR&0X40)==0); USART1->DR = (u8) ch; return ch; } 方法2.仍然使用標準庫,在主程序添加下面代碼:
#pragma import(__use_no_semihosting) //不使用半主機模式 //標準庫需要的支持函數(shù) struct __FILE { int handle; }; FILE __stdout; //定義_sys_exit()以避免使用半主機模式 _sys_exit(int x) { x = x; } //重定義fputc函數(shù) int fputc(int ch, FILE *f) { USART_SendData(USART1,ch); while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET); return ch; }
關(guān)于 microlibmicrolib 是缺省 C 庫的備選庫。 它用于必須在極少量內(nèi)存環(huán)境下運行的深層嵌入式應(yīng)用程序。 這些應(yīng)用程序不在操作系統(tǒng)中運行。microlib 不會嘗試成為符合標準的 ISO C 庫。microlib 進行了高度優(yōu)化以使代碼變得很小。 它的功能比缺省 C 庫少,并且根本不具備某些 ISO C 特性。某些庫函數(shù)的運行速度也比較慢,例如,memcpy()。上面給出了正確的方法,我在測試的過程中發(fā)現(xiàn)方法二中注釋掉#pragma import(__use_no_semihosting) 程序依然運行正確,這個很讓人費解,是否是keil本身就沒有半主機模式???????以下是測試現(xiàn)象1、假如程序中有printf等函數(shù),如果使用微庫或者禁用半主機,沒有重定義fputc函數(shù),程序可以運行,但不知道結(jié)果打印到主機的哪個地方去了。2、假如程序中有printf等函數(shù),既沒有禁用半主機也沒有重定義fputc函數(shù),程序?qū)⒁恢蓖T谥袛嗵帲缦聢D,結(jié)論:如果用了庫函數(shù)而沒有勾選微庫,則不能夠進行在線仿真。 3、若程序中假如程序中有fopen、fread等函數(shù),重定義fputc函數(shù),既沒有禁用半主機也沒有重定義fopen、fread這些函數(shù),編譯會報錯:Error: L6200E: Symbol __stdout multiply defined (by stdio_streams.o and usart.o).為什么是重復(fù)定義,還未搞清楚。打開微庫就不會報錯,但是其實也是存在問題,這些函數(shù)也并未實現(xiàn)其功能。
大部分資料都是禁用了半主機模式,沒有使用過半主機模式借助主機的鍵盤輸入?yún)?shù),看了很多資料,都是講半主機的,但講的內(nèi)容太淺顯,
我沒有學(xué)會使用半主機,更多的是學(xué)會了禁用半主機模式,我們好像忽略了半主機模式的意義。另外,我們可以查到的大部分資料講解的大同小異,它們更多的告訴我們正確的步驟,而不是讓我們從源頭了解一個問題,當然,大部分人看重的是實用,問題解決了,也就不再去思考背后的原理。最有效最直接最權(quán)威的資料是mdk官方給出的資料,但是資料內(nèi)容太多,看起來太多,不易懂,大部分人沒有看下去的欲望。我們應(yīng)該讓使用手冊看起來更直觀,更易懂,更方便查閱,更高效地查閱。
在keil5中,不管是否使用Semihosting,使用printf,scanf,fopen,fread等都需要自己填充底層函數(shù),以printf為例,需要補充定義fputc(Keil是否不支持Host-semi機制,即不支持直接在IDE打印字符串?)
特別注意:在keil中串口打印窗口和邏輯分析窗口僅在軟件仿真的時候可用,而MDK5對STM32F4的軟件仿真,基本上不支持(故本教程直接沒有對軟件仿真進行介紹了),所以,基本上這兩個窗口用不著。但是對STM32F1的軟件仿真,MDK5是支持的,在F1開發(fā)的時候,可以用到。所以基于STM32F4的軟件仿真在keil5中很少用到。
在IAR中,選擇Semihosting后,不用自己實現(xiàn)填充printf,scanf,fopen,fread等底層函數(shù),就可以在terminal I/O界面實現(xiàn)prrint,scanf等的測試,可以在工程目錄下實現(xiàn)文件操作。
疑問研究后的結(jié)論:
使用keil在半主機模式下,若是使用printf、 fopen等庫函數(shù)庫函數(shù)調(diào)用,會進入半主機模式,發(fā)生軟件異常,若此時有半主機調(diào)試環(huán)境的支持(RealView ISS、ISSM、RealView ICE 和 RealMonitor)進而通過調(diào)試器與主機進行交互,則可以進入半主機模式。但是本人使用的是JLINK V9調(diào)試器,此調(diào)試器應(yīng)該是不支持半主機的調(diào)試。所以程序會進入一個錯誤的BKPT 0xAB狀態(tài)。得出結(jié)論:并不是keil5完全不支持半主機調(diào)試,是需要完全具備半主機調(diào)試的所有軟硬件平臺條件后才可以用半主機來調(diào)試代碼。所以,大多數(shù)情況下,需要使用相關(guān)宏(#pragma import(__use_no_semihosting))和重定義底層IO函數(shù)的方法來避免使用半主機。
參考鏈接:
http://www.eeworld.com.cn/mcu/article_2016122632650.html
以及keil5的官方幫助文檔。
另外:IAR、KEIL都可以使用ITM跟蹤調(diào)試功能,可參考下面鏈接
https://www.jianshu.com/p/0255097f594e
*博客內(nèi)容為網(wǎng)友個人發(fā)布,僅代表博主個人觀點,如有侵權(quán)請聯(lián)系工作人員刪除。