前言
本文章探討在嵌入式系統中的除錯方式,除錯 (debugging)有分軟體和硬體兩種方法,在這篇文章裡面主要著重在利用硬體量測來得知軟體的錯誤。既然要探討嵌入式系統,就要先知道嵌入式系統是什麼?其實這個答案在現代已經漸漸被模糊了。比方說PDA、手機、印表機、MP3隨身聽、車載系統...等,毫無疑問的我們可以歸類為嵌入式系統,因為這些產品是為了達到特殊用途的軟體和硬體的搭配,通常硬體是一個microprocessor。這些產品有著低功耗、小尺寸、特殊規格設計等表現。但是自從Intel 推出ATOM processor,並試圖讓此X86微處理器應用在手持裝置和小筆電等用途以後,個人電腦與嵌入式的定義就越來越模糊了。
但是不論如何,效能的最佳化,驅動程式的正確使用,在硬體的除錯來說,其實有著許多共同的特點。軟體的除錯方式,也由於除錯軟體的功能強化,越來越多本來在PC上面的除錯器應用在SoC上面。本文會在大部分時間,探討一些常用的硬體除錯方式,並舉作者在開發過程中的實例來說明,最後會列舉一些軟體除錯器以供參考。
硬體量測原理與常用量測方式:
電表:
又有稱為萬用電表和三用電表,之所以稱為三用電表是因為主要是用來量測電流、電壓、電阻等元件特性,當然也有可以量測溫度、電容、電感等增強功能的高級電表。那對一個程式設計師而言,我們主要是需要判斷目前開發元件、開發版上面的供電是否正常(電壓量測),電流耗流是否正確(電流量測),元件是否有短路的現象(電阻量測),這是我們比較在意的量測,畢竟那與程式的正常執行與否最息息相關。
示波器:
高速示波器的原理主要是利用類比輸入電路(Analog input),和類比數位轉換器(Analog Digital inverter)所組成。類比輸入電路會將類比訊號經過放大、縮小(scale),濾波(Filter)、再經過ADC做採樣(sampling)並且數位化轉換,成為我們所需要的數位資料,接著我們解釋一些常見的名詞以及跟量測的關係。
圖1:高速示波器的原理
示波器的頻寬(Bandwidth)講的是類比訊號經過類比輸入電路振幅減少至-3db的能力,而取樣頻率(Sampling Frequency)則是由大名鼎鼎的奈奎斯特理論(Nyquist Theorem)所決定。一般來說,數位示波器的頻寬必須比所測的訊號頻寬高三到五倍。取樣頻率和頻寬並不直接相關,取樣頻率指的是類比訊號經過輸入電路整形以後,在做ADC數位化採樣時的速度。而數位訊號處理中最重要的理論之一,奈奎斯特準則告訴我們,取樣速度必須大於兩倍的受測物訊號最高頻率。所以若受測物訊號是5MHz,那示波器必須有10MHz的能力才能無誤的重建類比訊號的波形。
邏輯分析儀:
當我們需要除錯的訊號是16/32 bit bus signal時,使用示波器來量測,已經是變成不可能任務了。當我們需要除錯的訊號,並非在前一兩筆資料傳輸時才會發生的錯誤,而是隨機的(因為還不知道是什麼原因造成,所以感覺上是隨機的),我們需要抓取大筆資料來分析,示波器也是不可能辦到的,這時候我們需要更強大的邏輯(數位訊號:TTL/CMOS)分析工具,我們採用邏輯分析儀(Logic Analyzer)。
邏輯分析儀的原理並不難,可以把他想像成是一個多通道(32/64 channel etc...)和一位元垂直分析率的示波器。主要是利用硬體上的比較器來完成。
圖2、3 邏輯分析儀的原理解釋圖
從圖二可得知,待測物波形和臨界電壓經過一比較器之後,得到圖三的比較器結果,並且顯示在邏輯分析儀上,臨界電壓通常是TTL/CMOS level,或是可以自定義的電壓臨界值。當超過臨界值時,比較器判斷為邏輯1,反之則為邏輯0。下一節我們將用兩個實際的案例,告訴大家示波器和邏輯分析儀的使用時機。
JTAG(Joint Test Action Group)與ICE(in-circuit emulation):
當我們所需查知的bug是與作業系統核心(Windows、Linux、eCos...)有極大相關時,這時候我們需要可以攔截並查知作業系統核心(Kernel)和應用程式到底發生什麼樣的問題時,我們必須借用JTAG和ICE的強大功能,其實在無作業系統底下的韌體Firmware Debugging,也必須使用這類儀器。JTAG和ICE的原理乃是根據IEEE1149.1的規範,在SoC晶片電路內設計邊境掃描電路(Bondary Scan)以及相關暫存器,並預留四五根接腳作為測試存取埠(Test Access Port)。這樣開發主機便可以透過ICE/JTAG送出訊號(單步執行、設定中斷等..)給SoC矽晶片,並觀察和設定暫存器的變化。
圖4:一般JTAG連接方式
JTAG/ICE 雖然功能強大,但是價錢相對昂貴。並且需要對SoC矽晶片做除錯,您必須了解各暫存器的資料和JTAG介面的詳細資料,通常製造商是不願意分享的,您必須簽署NDA(保密條款)。並且在目前大部分的開發版上面,各家廠商都已附上完善的BSP,所以做暫存器的單步執行顯得比較不必要,當然如果您是半導體開發商,這就變得很需要了。在本文我們不會細談此除錯器,將以常見的示波器和邏輯分析儀為主。
實際開發的量測狀況:
I2C介面的驅動程式開發:
在這個例子裡面,我們來探討I2C驅動程式在嵌入式系統中的除錯方式。首先我們必須先了解I2C的訊號規格(Bus Spec)。
I2C是由飛利浦在1980年代發展出來的一種低成本的兩線傳輸方式,主要用在許多低速的IO週邊,比方說感測器、EEPROM、觸碰螢幕控制晶片、AD/DA等低速元件。此元件的設計方式通常是由一個主控端(Master)來控制多個副控制端(Slave)。主要傳送資料的腳位為SDA,並搭配時脈訊號SCL。下圖是bus timing diagram:
圖5、6:I2C資料寫入方式與時序關係圖(取自ST24C02 datasheet)
我們將利用這兩個timing diagram來做除錯的依據,這也是所有驅動程式除錯的基本方式,搞懂你的datasheet所記載的訊號規範,讓你避掉許多除錯的時間。
在實際的case中,我的嵌入式平台Master端I2C訊號是1.8V位準,但是我的slave端元件卻是3.3V位準,透過示波器(圖7),我了解這個基本錯誤,並修改線路。
圖7:I2C電壓位準量測
修改之後發現Slave端元件無法正確控制,程式一值呼叫remote IO error!透過示波器發現,在送device address的時候,就送出error ACK:
圖8:I2C Slave address設置錯誤
透過圖8發現是程式的slave address與硬體定義位址發生不匹配,修改程式以後回報正確,並從示波器(圖9)中看到完全正確的波形,ACK回報為0,表示正確。
圖9:正確的I2C寫入時序關係圖
我們在看看用LA(邏輯分析儀),所看到的情況:
圖10:正確的I2C時序關係圖在邏輯分析儀上的呈現
我們可以在邏輯正確與否上面有更清楚的判斷,前提是我們已經確定電壓位準以及雜訊上面做過錯誤可能性排除了,這件事情我們在第一階段已經使用示波器來判斷。
SPI介面觸碰螢幕驅動程式開發:
開發裝置:嵌入式設備Omap3 beagle_board公版,作業系統andorid 2.3.X,kernel版本2.6.37,修改驅動程式touch-screen controller ADS7846,錯誤現象:觸碰螢幕無任何反應。
在除錯之前,我們必須先研讀ads7846此元件的datasheet,我們發現他是SPI bus spec的介面,SPI是四線串列匯流排,為主從結構(Master/Slave)。四條線分別為SCLK(串列時脈,由Master發出)、MOSI(Master Output;Slave Input)、MISO(Master Input;Slave Output)、CS(Chip Select,通常為Active-Low)。下圖為SPI架構的傳輸方式和Timing Diagram。
圖11:SPI Bus資料傳輸方式
圖12:SPI Bus時序關係圖(取自ADS7846 datasheet)
接著我們研究Linux 驅動程式底下對SPI Bus的控制方法:
主要由4條線所組成的SPI bus,在linux底下的驅動程式流程為:1.先向系統要求一IRQ中斷號(硬體必須連結至處理器GPIO)。2.四線SPI必須在開機過程中被初始化。3.驅動程式由IRQ取得一handler,並在中斷發生時,送出SPI 訊號傳輸,ADS7846開始做ADC電壓轉換。4.將轉換後的資料透過device event 向user space層發出訊息。
示波器驗證:
1.檢查中斷訊號是否正確發生:
圖13:中斷訊號線正常動作(Active Low)
發現中斷訊號有正確發生,所以硬體連接與系統GPIO,產生正確連結。
2.檢查SPI BUS是否初始化成功
圖14:SPI Bus初始化無訊息
發現SPI BUS一開始並無初始化,所以trace硬體初始化相關程式碼,發現果然2.6.37核心無初始化ads7846所需的SPI signals,加入相關初始化程式碼後再觀察。
圖15 開機正常初始化的SPI 訊號線
3.發現中斷發生時,ADS7846並無正確動作,檢查程式碼發現相關SPI 註冊並未成功,加入相關程式碼做修改並且測試。
圖16:中斷時無正確動作
圖17:中斷發生時,SPI Bus正確傳輸訊號
4.最後透過user space的應用程式來抓取event 所傳上來的資料,並且校正座標。因為校正方式並非本文章重點,所以在此略過。
眼尖的讀者,應該有發現,我們剛剛用示波器有幾個缺點。第一個,我們的通道不夠多。SPI BUS總共四條線,並且加上中斷訊號線,一共有五條線,但是示波器的通道只有四個。第二,能量測的時間不夠長,如果想要看細微的邏輯變化和時脈的關係,示波器顯然是不夠力的。我們再用LA來量看看吧。
圖18:完整的SPI Bus傳輸訊號
是不是跟Datasheet上面的Timing Diagram很像,這表示我們正確的驅動此IC了。
軟體除錯工具簡介:
1.使用GNU tools GDB除錯:
GDB debugger是公認Linux系統上最強大的除錯器,您可以使用gdb在嵌入式與非嵌入式的Linux作業系統中,gdb主要包含gdb除錯器和gdb伺服器(gdb server),可以利用gdb伺服器做遠端目標版應用程式的除錯,遠端介面可以使用TCP/IP或是序列傳輸介面,端看需求來選擇。這樣的好處可以讓目標版上面不需安裝龐大的除錯器軟體,可以透過伺服器程式和含除錯資訊的二元檔來傳輸除錯資訊。gdb可以設定中斷點、變數變化、檢視堆疊(backstrace)等。您也可以加入DDD套件來使原本只有command-line的除錯方式變成圖形化,這樣除錯更加直觀。
2.使用Strace來做單行程追蹤:
當除錯涉及應用程式之間和核心的互動時,gdb的功能是不夠的,這時候我們需要追蹤應用程式和核心互動的關係,strace是一個利用ptrace()系統呼叫來擷取應用程式所做的全部系統呼叫的除錯器。我們可以把所有系統呼叫調用寫入一個文件檔後,以利我們之後的分析。
3.列印除錯資訊printf/printk等degbug message:
這是最簡單的方式,但是很多工程師會告訴你這是最有效的,有效與否端賴你對應用程式的了解。使用printf來列印出我們想得知的資訊,並利用夾擊法慢慢的逼近問題的核心,通常是讓我們可以很快的找出問題所在。
結論:
正確且快速的除錯方式,一直都是工程師所竭力追求的技術,甚至於優秀的工程師,已經達到藝術的地步。善用經驗可以節省許多寶貴時間,程式的錯誤是發生在硬體還是軟體,也需要每個軟體工程師應該去研究的,這樣子軟硬體工程師的合作將會更加完善。在此希望本文能對入門的工程師有所裨益。
(本文作者任職於資策會智慧網通系統研究所)