摘 要: 在基于SH7709S處理器的系統上實現了自開發軟件,介紹了自開發軟件的原理、方法、組成與結構,分析了與上位機" title="上位機">上位機通信接口設計、在系統燒寫" title="燒寫">燒寫Flash及設置斷點等關鍵技術。
關鍵詞: 自開發 串口" title="串口">串口 ISP 斷點 人機界面 SH7709S處理器
嵌入式自開發軟件有兩大特點。一是嵌入,指嵌入在系統內部,占用系統一定的RAM和ROM資源;二是自開發功能,自身具備調試和開發功能。自開發軟件也被稱為監控程序(monitor program)。實現自開發軟件是一種廉價的仿真器替代方案,它讓用戶更加深入地理解處理器和底層硬件的工作實質。更為重要的是,它嵌入于應用系統內部,提供完全在線式的調試功能。
自開發軟件的配置如圖1所示。上位機完成程序的編輯、編譯和鏈接,由自開發軟件通過與上位機的通信接口把程序下載到應用系統中,并提供基本的調試手段。自開發軟件在功能上可以劃分為上位機通信接口、內存操作、寄存器操作、下載及執行用戶程序和斷點調試幾大部分。
1 與上位機通信接口設計
(1)底層設計
系統狀況和用戶命令都要通過與上位機的通信接口互相交換,一般用串行通信接口實現。通常使用最簡單的硬件連接和通信協議:只使用發送(TXD)、接收(RXD)和地這三根線,不使用其他握手信號線。PC端可以使用通用的串口通信軟件,如超級終端、串口助手;應用系統端的通信軟件需要自行編寫。
串口接收數據時,當數據量很大、通信速度很快時,如果處理數據包的時間過長,則無論使用查詢或中斷方式,都有可能出現接收緩沖寄存器溢出,造成數據丟失。較好的解決方法是以中斷方式接收,在內存中開辟一個環形隊列緩沖區,把程序分成兩部分實現。
如圖2所示,當接收數據中斷時,由中斷服務程序" title="中斷服務程序">中斷服務程序迅速地把數據放置到緩沖區內,再重新使接收中斷使能,準備接收下一個數據,而主程序則通過查詢緩沖區是否為空從中讀取讀據。這樣做可以盡可能地減少關閉接收中斷的時間,防止數據丟失。緩沖區的大小與通信速度和處理器的處理速度有關。通信速度越快,處理速度越慢,緩沖區應開辟得越大。反之亦然。在SH7709S系統中,傳輸速率為38 400bps,處理器運行在64MHz時鐘下,緩沖區設置為64B。
發送也可以使用中斷加發送緩沖區的方式,主程序向緩沖區寫入數據的同時打開發送中斷,發送中斷服務程序從緩沖區取得數據并發送,如果緩沖區非空,則保持發送中斷使能。但發送的情況和接收很不一樣,發送時可以主動控制發送字節的時機,在高傳輸速率下發送每一個字符的時間比較短。例如,在38 400bps的傳輸速率下,傳輸一個字符的時間大約26μs。
(2)實現printf()函數
為了便于后續程序的設計,應該實現自己的格式化輸出函數printf(),包含字符串輸出、字符輸出、十進制數輸出和十六進制數輸出功能。輸出十六進制數時,要有8位、4位和2位寬度方式,如果數據的寬度不夠,則在前面補0,使得數據對齊,以便于用戶觀察。printf函數的實現思路是,把所有數據按不同的格式先轉換成對應的ASCII碼,然后將其串成一個有結束符的字符串,再統一按照字符串輸出。要注意一點:當輸出回車符\n時,要同時輸出一個換行符\r,以符合C語言中的編程習慣。
2 下載程序及在系統Flash燒寫技術
(1)S文件格式
上位機完成編譯、鏈接,生成程序文件后,首先要通過串口把程序裝載到系統中,自開發軟件必須能夠識別主機傳送來ASCII碼的含義,即向哪個地址裝載、是否結束、有無誤碼,這就需要有一個通信協議。這里以SH7709S使用S格式文件為例說明。它是行結構的ASCII碼文件,包含了所需要的協議,主要有起始記錄(S0)、正文記錄(S1、S2、S3)和結束記錄(S7、S8、S9)三種。三種記錄如下:
S00E00004D6F6E56657232206D6F74F8
S113000000090009000900090009DF0B0002D10BF7
S9030000FC
圖3是S1類型的記錄格式,以S1開頭;接下來是一個記錄長度的字節,長度從該字節后面開始算起,一直到該行結尾;再下來是程序的裝載地址,S1、S2和S3的裝載地址長度分別是2B、3B、4B,裝載程序的地址范圍分別是0~64KB、64KB~16MB和16MB~4GB;裝載地址后面是ASCII碼表示的十六進制機器碼,最后一個字節是校驗碼,等于該記錄中的所有內容之和的反碼。S格式文件一般以S0記錄開始,S0與S1記錄類似,所不同的是機器碼部分是S格式文件的文件名。S7、S8和S9也與S1記錄類似,但沒有機器碼部分,裝載地址表示程序的起始地址,分別為3B、2B、1B。
通過串口,可以把程序下載到RAM或Flash中。RAM的讀寫速度較快,可以邊從串口下載邊裝載;Flash的操作相對較復雜,在寫入Flash時,一般是先把程序全部下載到RAM中,再集中燒寫。
(2)在系統Flash燒寫技術
Flash存儲器由于容量大、價格低、編程方便等優勢在嵌入式系統中得到了廣泛應用。出于價格、體積等方面的考慮,多數系統只配備單片普通的NAND Flash。由于同一片Flash在寫操作時一般不能讀,因而很多采用Flash作為程序存儲器的系統無法直接實現在系統燒寫(ISP)。通過編寫程序實現在線燒寫Flash,達到“程序燒寫程序”目的,這簡化了電路設計,降低了開發成本,是目前常用的開發模式。它把燒寫Flash的程序與其他程序分開,使用時把它拷貝到RAM中執行。由于大多數嵌入式系統只能執行非可重定位的程序,即只能在鏈接時指定的地址執行程序,所以這種方法遇到的最大難點就是程序的存儲地址和執行地址不一致。這里給出一種非常有效且通行的解決方法。首先,編寫獨立的燒寫Flash程序,使這部分程序不能調用其他程序,避免在寫Flash的同時讀取Flash;然后把這部分程序編譯,并鏈接到RAM中的指定地址,生成程序文件(如前文中提到的S格式文件);最后用一個在用戶主機上運行的小程序把程序文件轉換成C語言格式的數組,再在主程序中拷貝或調用。數組定義如下:
struct rom_data {
unsigned long start_address;
unsigned long data_length;
unsigned char data[4708];
};
start address是程序在RAM中執行的入口地址,data length是機器碼的字節數,在data中存儲程序的機器碼。以一個轉換后的數組為例:
const struct rom_data datastruct={
0x0dff0000,
0x0000084b,
0x2f,0x86,0x2f,0x96,0x2f,0xa6,0x2f,0xb6,0x2f,0xc6,
0x2f,0xd6,0x2f,0xe6,0x4f,0x22,
……
};
程序從地址0xdff0000開始執行,由0x84b個字節組成。燒寫Flash時,由自開發軟件把這部分程序搬運到RAM中的對應地址,再跳轉到該地址開始執行。只要了解程序文件的結構,程序文件到數組的轉換將很容易實現。Renesas公司提供了S文件格式的程序文件到數組轉換工具motice_cl,把它設定為IDE的最后一個編譯階段即可方便地生成數組。
3 實現斷點
在程序中設置斷點是調試程序的有效方法。通常,斷點只能在RAM中實現。SH7709S由于內嵌有UBC(用戶斷點控制器)單元,所以也可以在ROM中設置斷點。
(1)在RAM中設置斷點
RAM中設置斷點的思路是:在斷點處用一條軟中斷指令替換原有指令,當軟中斷發生時,將所有寄存器的值推入堆棧中。只要在軟中斷的服務程序顯示棧中對應CPU有關寄存器的內容,回到主程序,并允許修改寄存器和內存,就實現了在RAM中設置斷點。
用戶設置完斷點后,在自開發軟件中不要直接替換對應地址的指令,否則觀察寄存器或反匯編" title="反匯編">反匯編時,這段程序就被改變了。應該在用戶輸入運行程序命令后再去替代指令,在軟中斷服務程序返回前,還要遍歷每個斷點,將已經替換后的指令恢復,使用戶看不到被替換過的痕跡。
(2)使用UBC單元設置斷點
SH7709S內置兩個UBC單元,以方便在ROM或RAM設置斷點,協助用戶實現自調試功能。它實際上是一個比較中斷發生器,在程序運行時,斷點寄存器中的地址不停地與程序計數器PC比較,中斷發生的條件可以是地址相同,也可以是某一數據的讀或寫等。發生中斷后在中斷服務程序中顯示寄存器,同時把這個斷點清除,屏蔽UBC中斷,并返回到主程序,從而實現斷點功能。
實現斷點功能后就可以輕松地實現單步調試功能,實際上是在下一條指令前設置斷點。
4 編輯寄存器或內存
(1)編輯寄存器
編輯寄存器包括讀、寫和清零操作。讀寄存器并不需要每次都顯示當前寄存器的真實值(因為系統被自開發軟件控制時,這種顯示對用戶并無意義),而只需在用戶程序被打斷后顯示打斷前的真實寄存器值;寫和清零操作也不需要在用戶改變寄存器后立即改變CPU的寄存器,否則自開發軟件無法正常運行,而只需在用戶程序執行前改變。自開發軟件應該在內存中建立一個CPU寄存器的映像,用戶對寄存器的操作實際上是操作內存中的映像單元。發生斷點中斷后,在中斷服務程序里把入棧的中斷前寄存器值寫入到對應的內存映像單元,在用戶輸入運行程序命令后,先把內存映像單元的值寫入到CPU的寄存器中再運行程序。
(2)編輯內存
編輯內存包括顯示、修改和反匯編操作。一般按單字節使用十六進制顯示內存的內容,每一行顯示16個內存單元,左邊要有該段內存的起始地址,在最右邊,將這些數據對應的ASCII碼顯示出來,數值小于0x20的ASCII碼控制字符及大于0x7F的非ASCII碼字符用“.”表示,如圖4所示。
修改內存應提供按逐個內存單元和按塊填充功能。對于總線寬度為32位的系統,內存單元可以是字節、雙字和長字,修改過一個單元后,提示符應指向下一個單元,最好能設置一個鍵碼,當發現輸入值不當時,可以回退一個單元,如果輸入字符不是0~F,則自動退出,此單元無須修改時按回車繼續下一單元。填充內存是把一塊內存單元修改為同一個值,在觀察內存變化時很有用。
反匯編是將內存的內容以指令形式顯示出來。在RISC和CISC機上實現反匯編的難度不同,RISC架構的處理器指令是定長的,如SH7709S每條指令占用兩個字節,而CISC架構的處理器上指令占用的字節數從一個到四個不等,讀取時還要判斷是否讀到了正確的指令。反匯編功能需占用較多的存儲空間,因為它要建立一個對應關系,在內存中存儲一個指令表。一般情況下,指令的設計都有一定規律,設計時要仔細觀察,SH7709S的指令集可以分為n、nm和md等類型,找出規律可大大簡化程序設計。
5 人機對話界面設計
用戶主機上的串口通信軟件,如Hypertrm,只顯示接收的字符。為了在用戶輸入命令的同時把命令字符顯示到屏幕上,自開發軟件需要把接收到的字符再發送一遍。有些特殊字符要特別處理,如用戶鍵入backspace后,軟件應發送退格、空格、退格三個字符才能得到backspace鍵效果。
圖5是實現人機界面的流程圖,當用戶輸入回車符后,認為一個命令輸入完畢。命令中可能會含有一些多余的空格,要先把這些空格剔除并整定成要求的格式。有些命令需要經常執行,如單步、查看內容等。把這些命令設定為需要標記的命令,輸入一次后,再輸入回車即可重復執行。
自開發軟件可以大大方便調試和開發,它提供了所有基本的調試手段,嵌入于應用系統內部,攜帶方便,十分靈活,是仿真器的有益補充,甚至可以在一定程度上替代昂貴的仿真器。
筆者在基于SH7709S處理器的系統上成功地實現了自開發軟件,在此基礎上闡述了自開發軟件的原理和方法,介紹了自開發軟件的組成與結構,詳細分析了與上位機通信接口設計、在系統燒寫Flash和設置斷點等關鍵技術。這些內容也適用于基于不同處理器或單片機的應用及開發系統。
參考文獻
1 邵貝貝.單片機嵌入式應用的在線開發方法.北京:清華大學出版社,2004
2 Renesas Co,Ltd.SH7709s hardware manual.2003,9
3 Renesas Co,Ltd.SuperH RISC engine C/C++ Compiler,Assembler,Optimizing Linkage Editor User′s Manual.2003
4 Hitachi Europe LTD.Utility To Convert S-Record DataTo A C Structure.2003