介紹
DS80C400包含一個提供網絡棧、內存管理和進程調度的ROM,可以靈活地用于由Java、C和8051匯編編程的應用中。SDCC為8051器件提供了一個免費、開放源碼的編譯器,并兼容DS80C400的24位尋址模式。用C編寫的復雜應用程序在Dallas Semiconductor提供的庫的幫助下,可以很容易地使用DS80C400 ROM功能創建。
本應用筆記闡述了如何使用SDCC工具來創建DS80C400應用程序。從一個HelloWorld應用程序開始,然后說明如何使用ROM庫來實現一個簡單的HTTP服務器。這里的應用程序是針對TINIm400參考模塊編寫和創建的,用于具有其它存儲器配置的設計時必須進行相應修改。
從SDCC編譯器開始
遵循以下步驟,使用SDCC編譯器來完成您的第一個DS80C400的C應用程序:
-
安裝SDCC編譯器1
- 從SDCC網站上下載最新版本SDCC編譯器的安裝文件。
- 遵循安裝文件的指示(可能是sdcc/doc/INSTALL.txt)。
-
使用你喜歡的文本編輯器創建一個新文件"main.c"。在文件中寫入以下代碼:
#include < stdio.h > void main () { printf("Hello Universe!!!!....Welcome to SDCC Tini Test Program"); while (1) { } }
一定要保存文件內容。
-
從SDCC C庫站點2中拷貝文件startup400.a51和reg400.inc (包含在啟動代碼下載中),并保存到您保存main.c文件的目錄中。此文件包含startup_code函數,將在應用程序啟動時調用該函數,從而對DS80C400芯片進行初始化。啟動代碼完成以下工作:
- 將DS80C400配置成24位連續地址模式
- 配置定時器2用來為串口產生115200的波特率
- 初始化數據存儲器
-
從SDCC C庫站點拷貝ROM initialization庫文件(從init庫文件下載的rominit.lib和rom400.h),并將其解壓縮至相同目錄下。庫文件是壓縮的,使用WinZip或gunzip/tar解壓縮包。
-
在編譯我們的"Hello Universe"應用程序之前,我們需要在一個SDCC安裝的支持文件中作一個小改動,覆蓋缺省的DS80C400支持函數并使用Dallas Semiconductor的C庫代替。進行以下改動:
- 將\\SDCC\\lib\\ds400\\libds400.lib文件重命名為\\SDCC\\lib\\ds400\\libds400.lib.old
- 建立一個名為\\SDCC\\lib\\ds400\\libds400.lib的空文件(使用touch命令或在您喜歡的文本編輯器中建立一個新文件)
-
構建"Hello Universe"應用程序...
-
要由我們的startup400.a51文件創建一個目標文件(.rel),在命令行執行以下命令:
asx8051 -losffgp startup400.a51
asx8051是SDCC工具提供的匯編器。匯編器提供的參數選項有:| Option | Purpose |
| -------- | ----------------------------------------------------- |
| l | generates a list file |
| o | generates an object file |
| s | generates a symbol file |
| ff | flag reolcatable references by mode in listing file |
| g | make undefined symbols be global |
| p | disables listing pagination |
"los"參數是必須的,因為連接器需要列表、目標和符號文件來生成可執行文件。"ff"和"p"參數生成一個可讀的列表文件。"g"參數通知匯編器在發現一個沒有定義的符號且該符號未聲明為外部變量時不報錯。
-
為了由main.c生成一個目標文件,執行以下命令:
sdcc -c -mds400 --model-flat24 --stack-10bit --no-xinit-opt main.c
sdcc為編譯器。
傳遞給編譯器的參數選項為:
Option Purpose -c compiles main.c and creates an object file -mds400 generates code for the DS80C400 processor --model-flat24 use the 24-bit contiguous memory model --stack-10bit use the 1024-byte extended stack (10 bit stack addresses) --no-xinit-opt don't initialize the external RAM memory area p disables listing pagination 注意列表中最后三個參數是雙破折號。
-
為了連接目標文件并構建可執行文件,執行以下命令:
sdcc -mds400 --model-flat24 --stack-10bit -Wl-r --xram-loc 0x10000 --xram-size 0x3fff --code-loc 0x400000 main.rel startup400.rel -l rominit.lib
這里使用的新參數為:| Option | Purpose |
| ------------- | -------------------------------------------------------------- |
| -WI | pass options through to the linker |
| --xram-loc | external RAM start address (only RAM for SDCC variable use!) |
| --xram-size | external RAM size (only RAM for SDCC variable use!) |
| --code-loc | code starting address |
| -l | include the specified libraries |
| p | disables listing pagination |
請注意xram-loc、 xram-size和code-loc參數為雙破折號。也要注意給命令指定的RAM將會用來存儲SDCC變量,不應該和init_rom函數中用來初始化DS80C400所使用的存儲器范圍沖突―此存儲器用作網絡棧和存儲器管理。
-
為了壓縮可執行文件并生成一個十六進制文件,執行以下命令:
packihx main.ihx>hellouniverse.hex
packihx命令通過將連續數據記錄累積至16個字節來壓縮可執行文件。
-
有了一個可執行文件后,我們需要將應用程序下載到TINIm400模塊中并運行它。### 將示例應用程序加載到TINIm400模塊
本節說明如何使用Maxim/Dallas Semiconductor提供的 微控制器工具包(MTK) 向TINIm400驗證模塊中加載由SDCC編譯器生成的十六進制文件。目前可用的MTK版本只支持Windows?。
如果您的開發環境不是Windows,需要使用JavaKit應用程序來下載和執行應用程序。要使用JavaKit,您必須有Java運行環境3 (版本至少為1.2)并且安裝Java Communications API ^4^ 。JavaKit工具包含在TINI軟件開發包中。寫本文的時候,發布的最新固件是固件版本1.13。運行JavaKit的指導說明可以在TINI SDK docs目錄下的Running_JavaKit.txt文件中找到。如果您在運行MTK或JavaKit時遇到技術問題,可能其他人已經遇到過類似問題并且已經發表在Dallas Semiconductor的討論區中。
最新版本的MTK應用軟件可下載。要安裝MTK,請運行安裝文件并遵照提示操作。成功安裝后,會增加一個新的菜單項: Start->All Programs->Dallas Semiconductor MTK。 MTK啟動后,會出現圖1所示的對話框。
圖1. 啟動時MTK選項
選擇選項TINI,以操作TINIm400評估板。
選擇了TINI之后,會打開MTK主窗口。從Options->Configure Serial Port菜單選項中選擇您將用來和TINIm400通訊的串口。然后,選擇Tini->Tini Options菜單項,就會出現下面的對話框。選擇DSTINIm400按鈕,配置MTK用于和TINIm400板通訊。圖2顯示了帶有DSTINIm400按鈕的對話框。
圖2. 選擇TINIm400配置選項
選擇Tini->Open COMx at xxx baud菜單選項打開串口。接著選擇Tini->Reset選項復位評估板。會出現DS80C400的加載提示:
DS80C400 Silicon Software - Copyright (C) 2002 Maxim Integrated
Detailed product information available at http://www.maximintegrated.com
Welcome to the TINI DS80C400 Auto Boot Loader 1.0.1
>
從文件菜單中選擇Load HEX File。找到我們剛剛生成的hellouniverse.hex文件并選中。一旦您的程序加載后有兩種方法運行它。因為我們將程序加載到40區,您可以輸入:
> B40
> X
要選擇40區并運行那里的代碼。您也可以輸入:
> E
這會使ROM查找可執行的代碼。它查找一個標識當前區具有可執行代碼的特定標簽。此標簽由文本'TINI'組成,其后面緊跟著當前區的號碼(或零),并位于當前區的0002h地址。SDCC編譯器在生成的匯編代碼中插入此標簽。如果打開為hellouniverse工程生成的main.asm源代碼,您會找到下面的代碼段:
.area CSEG (CODE)
interrupt_vect:
; DS80C400 IVT must be generated at runtime.
sjmp __sdcc_400boot
.ascii 'TINI' ; required signature for 400 boot loader.
.db 0 ; selected bank or zero...
__sdcc_400boot:
ljmp __sdcc_gsinit_startup
注意sjmp__sdcc_400boot語句位于40區的0000h地址。其后跟隨可執行標簽{ 'T', 'I', 'N', 'I', 0h},由于simp語句為兩個字節,因此該標簽位于地址0002處。當您鍵入'E'時,ROM從C0h區開始向下搜索可執行代碼。如果您鍵入'E'時,執行了其它的代碼,則意味著ROM在一個比您的代碼加載位置400000h更高的地址找到了一個可執行標簽。您可能需要找到此標簽的位置,并刪除那個區的內容。### 和ROM以及SDCC ROM庫接口
在高速微控制器用戶指南DS80C400補充資料中說明了在匯編語言中調用ROM函數的過程。但是,在C中調用這些ROM函數會復雜一些。必須將參數從SDCC C編譯器的規則轉換成ROM使用的規則。SDCC編譯器通過硬件堆棧、累加器和數據指針相結合的方式來傳遞參數。ROM函數采用許多不同的方式來接受參數。例如,socket函數接收存儲在一個外部RAM緩沖區中的參數。相反地,許多功能函數接收由特殊功能寄存器或直接存儲器位置傳遞的參數。為了從SDCC調用方式轉換成ROM參數方式,Dallas Semiconductor已經編寫了訪問ROM函數的庫。
在您的C程序中使用ROM函數只需包含一個頭文件并與相應的庫文件連接即可。用于SDCC編譯器的ROM庫包括:
- ROM初始化程序
- DHCP客戶端
- 進程調度
- Sockets (TCP、UDP和Multicast)
- TFTP客戶端
- 功能函數(CRC16, 隨機數)
在寫本文時,還沒有為SDCC編譯器提供包括如文件系統、郵件客戶端和HTTP服務器之類的擴展庫。請關注SDCC庫主頁上的DS80C400升級信息,我們會添加支持SDCC的庫。### 簡單應用:HTTP服務器
編寫了一個簡單的http服務器來說明如何使用一些ROM庫函數,特別是socket和進程調度庫。這個示例會偶爾通過網絡時間服務器更新它的時間,并且通過它的web服務器提供這個信息。
示例應用程序由兩個模塊組成,一個HTTP服務器和SNTP客戶端。主程序生成一個新的子任務來運行http服務器,用于處理80端口上的客戶連接。父任務每60秒會試圖通過時間服務器同步當前時間。
SNTP客戶端模塊
以下代碼段實現SNTP客戶端模塊的核心功能。
socket_handle = socket(0, SOCKET_TYPE_DATAGRAM, 0);
// set a timeout of about 2 seconds
for (i=0;i< 256;i++)
buffer[i] = 0;
buffer[0] = 0x0;
buffer[1] = 0x0;
buffer[2] = 0x8;
buffer[3] = 0x0;
setsockopt(socket_handle, 0, SO_TIMEOUT, buffer, 200);
buffer[2] = 0; //reset since we used this in call to setsockopt
buffer[0] = 0x23; // No warning/NTP Ver 4/Client
address.sin_addr[12] = TIME_NIST_GOV_IP_MSB;
address.sin_addr[13] = TIME_NIST_GOV_IP_2;
address.sin_addr[14] = TIME_NIST_GOV_IP_3;
address.sin_addr[15] = TIME_NIST_GOV_IP_LSB;
address.sin_port_high = (NTP_PORT/0x100); //higher byte of port number
address.sin_port_low = (NTP_PORT%0x100); //lower byte of port number
sendto(socket_handle, buffer, 48, 0, &address, sizeof(struct sockaddr));
recvfrom(socket_handle, buffer, 256, 0, &address, sizeof(struct sockaddr));
//SDCC uses little Endian for storing data, so reorganize the data before converting it to long
buffer[0]=buffer[43];
buffer[1]=buffer[42];
buffer[2]=buffer[41];
buffer[3]=buffer[40];
timeStamp = *(unsigned long *)(&buffer[0]);
formatTimeString(timestamp - (5 * SECONDS_PER_HOUR), "Tampa, USA",
last_time_reading_1);
formatTimeString(timeStamp - (3 * SECONDS_PER_HOUR), "Sao Paulo, Brazil",
last_time_reading_2);
formatTimeString(timeStamp + (1 * SECONDS_PER_HOUR),"Marseille, France",
last_time_reading_3);
formatTimeString(timeStamp + (5 * SECONDS_PER_HOUR) + (30 *
SECONDS_PER_MINUTE), "Bangalore, India",
last_time_reading_4);
formatTimeString(timeStamp + (8 * SECONDS_PER_HOUR), "Hsinchu, Taiwan",
last_time_reading_5);
last_reading_seconds = getTimeSeconds();
closesocket(socket_handle);