ARM的Semihosting技術(轉)


Semihosting技術將應用程序中的IO請求通過一定的通道傳送到主機(host),由主機上的資源響應應用程序的IO請求, 而不是像在主機上執行本地應用程序一樣,由應用程序所在的計算機響應應用程序IO請求, 也就是將目標板的輸入/輸出請求從應用程序代碼傳遞到遠程運行調試器的主機的一種機制。 簡單來說,目標開發板上通常不會有輸入/輸出這些外設,開發板運行的代碼想要將結果打印出來, 或者獲得用戶的輸入,可以通過請求遠程主機IO設備來實現,如:顯示器,鍵盤等。 目標開發板執行代碼中加入對輸入/輸出設備進行訪問函數,如:printf,scanf等, 這些函數並不是目標開發板的庫函數,而是遠程主機交叉編譯器中帶有的庫函數,這些庫函數被編譯時,編譯成一條軟件中斷指令。 當目標開發板上電運行之后,執行到請求訪問輸入/輸出設備指令時,產生特定中斷號的軟件中斷SWI, 與開發板相連的調試器會先截獲目標板SWI請求,由於開發板程序中也可能存在用戶自定義軟件中斷, 為了區分二者,調試器會根據SWI的軟中斷號來判斷是不是semihosting模式IO請求, 如果是,則取出R0寄存器里代表的具體請求號,然后使用遠程主機來響應目標板具體IO請求, 而不是開發板本身去處理setmihosting請求。 semihosting僅僅是一種調試手段,它的工作原理就是利用調試器捕捉目標環境運行過程中產生SWI中斷, 然后向遠程主機調試環境發送對應的調試信息。 也就是說目標開發板通過特定的軟件中斷指令,借用了遠程主機的輸入輸出設備實現IO請求的訪問。

Semihosting半主機調試模式,只能使用在開發板和調試主機通過仿真器連接的情況下, 也就是說脫離了主機調試環境上述代碼不能正常運行。 目標開發板上執行的IO實際上是交給了遠程主機來處理實現,正是因為如此,這種方式只適合在調試模式下, 真正的嵌入式系統不可能依賴於主機實現IO處理的,嵌入式系統要想獨立出來實現IO請求的處理, 這就需要將輸入輸出庫函數的底層相關硬件實現重定向。

使用ITM機制實現調試,實現printf與scanf, ITM是ARM在推出semihosting之后推出的新一代調試機制。

ITM機制要求使用SWD方式接口,並需要連接SWO線。

 

半主機是用於 ARM 目標的一種機制,可將來自應用程序代碼的輸入/輸出請求傳送至運行調試器的主機。 例如,使用此機制可以啟用 C 庫中的函數,如 printf() 和 scanf(),來使用主機的屏幕和鍵盤,而不是在目標系統上配備屏幕和鍵盤。

這種機制很有用,因為開發時使用的硬件通常沒有最終系統的所有輸入和輸出設備。 半主機可讓主機來提供這些設備。

 

半主機是通過一組定義好的軟件指令(如 SVC)來實現的,這些指令通過程序控制生成異常。 應用程序調用相應的半主機調用,然后調試代理處理該異常。 調試代理提供與主機之間的必需通信。

 

半主機接口對 ARM 公司提供的所有調試代理都是通用的。 在無需移植的情況下使用 RealView ARMulator® ISS、指令集系統模型 (ISSM)、實時系統模型 (RTSM)、RealView ICE 或 RealMonitor 時,會執行半主機操作。

 

標准庫使用半主機模式,半主機是通過一組定義好的軟件指令 (如 SVC)SVC 指令 (以前稱為 SWI 指令)來實現的,這些指令通過程序控制生成異常。 應用程序調用相應的半主機調用,然后調試代理處理該異常。調試代理(這里的調試代理是仿真器)提供與主機之間的必需通信。也就是說使用半主機模式必須使用仿真器調試。

 

ARMv7 之前的 ARM 處理器使用 SVC 指令 (以前稱為 SWI 指令)進行半主機調

 

用。 但是,如果要為 ARMv6-M 或 ARMv7-M (如 Cortex™-M1 或 Cortex-M3 處

 

理器)進行編譯,請使用 BKPT 指令來實現半主機。
 
簡單的來說,半主機模式就是通過仿真器實現開發板在電腦上的輸入和輸出。和半主機模式功能相同的是ITM調試機制。 有關ITM調試機制可以參考這里http://www.douban.com/note/248637026/
      
 上面介紹的半主機和ITM功能相當,他們都是調試機制,開發板均借助仿真器與電腦連接,實現單片機利用主機的屏幕鍵盤的輸入輸出。
這兩種機制的運行均需要仿真器,否則無法運行。
   
    開發式一般單片機需要獨立運行,開發者應去掉仿真器,把printf函數通過單片機的外設來實現,例如通過開發板的串口,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) //不使用半主機模式 //標准庫需要的支持函數 struct __FILE { int handle; }; FILE __stdout; //定義_sys_exit()以避免使用半主機模式 _sys_exit(int x) { x = x; } //重定義fputc函數 int fputc(int ch, FILE *f) { USART_SendData(USART1,ch); while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET); return ch; } 
關於 microlib
microlib 是缺省 C 庫的備選庫。 它用於必須在極少量內存環境下運行的深層嵌入式應用程序。 這些應用程序不在操作系統中運行。microlib 不會嘗試成為符合標准的 ISO C 庫。
microlib 進行了高度優化以使代碼變得很小。 它的功能比缺省 C 庫少,並且根本不具備某些 ISO C 特性。某些庫函數的運行速度也比較慢,例如,memcpy()。上面給出了正確的方法,我在測試的過程中發現方法二中注釋掉#pragma import(__use_no_semihosting) 程序依然運行正確,這個很讓人費解,是否是keil本身就沒有半主機模式???????以下是測試現象
1、假如程序中有printf等函數,如果使用微庫或者禁用半主機,沒有重定義fputc函數,程序可以運行,但不知道結果打印到主機的哪個地方去了。
2、假如程序中有printf等函數,既沒有禁用半主機也沒有重定義fputc函數,程序將一直停在中斷處,如下圖,結論:如果用了庫函數而沒有勾選微庫,則不能夠進行在線仿真。
 3、若程序中假如程序中有fopen、fread等函數,重定義fputc函數,既沒有禁用半主機也沒有重定義fopen、fread這些函數,編譯會報錯:
Error: L6200E: Symbol __stdout multiply defined (by stdio_streams.o and usart.o).為什么是重復定義,還未搞清楚。打開微庫就不會報錯,但是其實也是存在問題,這些函數也並未實現其功能。
 

大部分資料都是禁用了半主機模式,沒有使用過半主機模式借助主機的鍵盤輸入參數,看了很多資料,都是講半主機的,但講的內容太淺顯,

我沒有學會使用半主機,更多的是學會了禁用半主機模式,我們好像忽略了半主機模式的意義。另外,我們可以查到的大部分資料講解的大同小異,它們更多的告訴我們正確的步驟,而不是讓我們從源頭了解一個問題,當然,大部分人看重的是實用,問題解決了,也就不再去思考背后的原理。最有效最直接最權威的資料是mdk官方給出的資料,但是資料內容太多,看起來太多,不易懂,大部分人沒有看下去的欲望。我們應該讓使用手冊看起來更直觀,更易懂,更方便查閱,更高效地查閱。

 

 

      在keil5中,不管是否使用Semihosting,使用printf,scanf,fopen,fread等都需要自己填充底層函數,以printf為例,需要補充定義fputc(Keil是否不支持Host-semi機制,即不支持直接在IDE打印字符串?)

特別注意:在keil中串口打印窗口和邏輯分析窗口僅在軟件仿真的時候可用,而MDK5對STM32F4的軟件仿真,基本上不支持(故本教程直接沒有對軟件仿真進行介紹了),所以,基本上這兩個窗口用不着。但是對STM32F1的軟件仿真,MDK5是支持的,在F1開發的時候,可以用到。所以基於STM32F4的軟件仿真在keil5中很少用到。

 

 

     在IAR中,選擇Semihosting后,不用自己實現填充printf,scanf,fopen,fread等底層函數,就可以在terminal I/O界面實現prrint,scanf等的測試,可以在工程目錄下實現文件操作。

 

疑問研究后的結論:

      使用keil在半主機模式下,若是使用printf、 fopen等庫函數庫函數調用,會進入半主機模式,發生軟件異常,若此時有半主機調試環境的支持(RealView ISS、ISSM、RealView ICE 和 RealMonitor)進而通過調試器與主機進行交互,則可以進入半主機模式。但是本人使用的是JLINK V9調試器,此調試器應該是不支持半主機的調試。所以程序會進入一個錯誤的BKPT 0xAB狀態。得出結論:並不是keil5完全不支持半主機調試,是需要完全具備半主機調試的所有軟硬件平台條件后才可以用半主機來調試代碼。所以,大多數情況下,需要使用相關宏(#pragma import(__use_no_semihosting))和重定義底層IO函數的方法來避免使用半主機。

 

參考鏈接:

http://www.eeworld.com.cn/mcu/article_2016122632650.html

以及keil5的官方幫助文檔。

 

 另外:IAR、KEIL都可以使用ITM跟蹤調試功能,可參考下面鏈接

https://www.jianshu.com/p/0255097f594e

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM