介紹
DS80C400包含一個(gè)提供網(wǎng)絡(luò)棧、內(nèi)存管理和進(jìn)程調(diào)度的ROM,可以靈活地用于由Java、C和8051匯編編程的應(yīng)用中。SDCC為8051器件提供了一個(gè)免費(fèi)、開放源碼的編譯器,并兼容DS80C400的24位尋址模式。用C編寫的復(fù)雜應(yīng)用程序在Dallas Semiconductor提供的庫(kù)的幫助下,可以很容易地使用DS80C400 ROM功能創(chuàng)建。
本應(yīng)用筆記闡述了如何使用SDCC工具來(lái)創(chuàng)建DS80C400應(yīng)用程序。從一個(gè)HelloWorld應(yīng)用程序開始,然后說(shuō)明如何使用ROM庫(kù)來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的HTTP服務(wù)器。這里的應(yīng)用程序是針對(duì)TINIm400參考模塊編寫和創(chuàng)建的,用于具有其它存儲(chǔ)器配置的設(shè)計(jì)時(shí)必須進(jìn)行相應(yīng)修改。
從SDCC編譯器開始
遵循以下步驟,使用SDCC編譯器來(lái)完成您的第一個(gè)DS80C400的C應(yīng)用程序:
-
安裝SDCC編譯器1
- 從SDCC網(wǎng)站上下載最新版本SDCC編譯器的安裝文件。
- 遵循安裝文件的指示(可能是sdcc/doc/INSTALL.txt)。
-
使用你喜歡的文本編輯器創(chuàng)建一個(gè)新文件"main.c"。在文件中寫入以下代碼:
#include < stdio.h > void main () { printf("Hello Universe!!!!....Welcome to SDCC Tini Test Program"); while (1) { } }
一定要保存文件內(nèi)容。
-
從SDCC C庫(kù)站點(diǎn)2中拷貝文件startup400.a51和reg400.inc (包含在啟動(dòng)代碼下載中),并保存到您保存main.c文件的目錄中。此文件包含startup_code函數(shù),將在應(yīng)用程序啟動(dòng)時(shí)調(diào)用該函數(shù),從而對(duì)DS80C400芯片進(jìn)行初始化。啟動(dòng)代碼完成以下工作:
- 將DS80C400配置成24位連續(xù)地址模式
- 配置定時(shí)器2用來(lái)為串口產(chǎn)生115200的波特率
- 初始化數(shù)據(jù)存儲(chǔ)器
-
從SDCC C庫(kù)站點(diǎn)拷貝ROM initialization庫(kù)文件(從init庫(kù)文件下載的rominit.lib和rom400.h),并將其解壓縮至相同目錄下。庫(kù)文件是壓縮的,使用WinZip或gunzip/tar解壓縮包。
-
在編譯我們的"Hello Universe"應(yīng)用程序之前,我們需要在一個(gè)SDCC安裝的支持文件中作一個(gè)小改動(dòng),覆蓋缺省的DS80C400支持函數(shù)并使用Dallas Semiconductor的C庫(kù)代替。進(jìn)行以下改動(dòng):
- 將\\SDCC\\lib\\ds400\\libds400.lib文件重命名為\\SDCC\\lib\\ds400\\libds400.lib.old
- 建立一個(gè)名為\\SDCC\\lib\\ds400\\libds400.lib的空文件(使用touch命令或在您喜歡的文本編輯器中建立一個(gè)新文件)
-
構(gòu)建"Hello Universe"應(yīng)用程序...
-
要由我們的startup400.a51文件創(chuàng)建一個(gè)目標(biāo)文件(.rel),在命令行執(zhí)行以下命令:
asx8051 -losffgp startup400.a51
asx8051是SDCC工具提供的匯編器。匯編器提供的參數(shù)選項(xiàng)有:| 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"參數(shù)是必須的,因?yàn)?a target="_blank">連接器需要列表、目標(biāo)和符號(hào)文件來(lái)生成可執(zhí)行文件。"ff"和"p"參數(shù)生成一個(gè)可讀的列表文件。"g"參數(shù)通知匯編器在發(fā)現(xiàn)一個(gè)沒有定義的符號(hào)且該符號(hào)未聲明為外部變量時(shí)不報(bào)錯(cuò)。
-
為了由main.c生成一個(gè)目標(biāo)文件,執(zhí)行以下命令:
sdcc -c -mds400 --model-flat24 --stack-10bit --no-xinit-opt main.c
sdcc為編譯器。
傳遞給編譯器的參數(shù)選項(xiàng)為:
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 注意列表中最后三個(gè)參數(shù)是雙破折號(hào)。
-
為了連接目標(biāo)文件并構(gòu)建可執(zhí)行文件,執(zhí)行以下命令:
sdcc -mds400 --model-flat24 --stack-10bit -Wl-r --xram-loc 0x10000 --xram-size 0x3fff --code-loc 0x400000 main.rel startup400.rel -l rominit.lib
這里使用的新參數(shù)為:| 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 |
請(qǐng)注意xram-loc、 xram-size和code-loc參數(shù)為雙破折號(hào)。也要注意給命令指定的RAM將會(huì)用來(lái)存儲(chǔ)SDCC變量,不應(yīng)該和init_rom函數(shù)中用來(lái)初始化DS80C400所使用的存儲(chǔ)器范圍沖突―此存儲(chǔ)器用作網(wǎng)絡(luò)棧和存儲(chǔ)器管理。
-
為了壓縮可執(zhí)行文件并生成一個(gè)十六進(jìn)制文件,執(zhí)行以下命令:
packihx main.ihx>hellouniverse.hex
packihx命令通過(guò)將連續(xù)數(shù)據(jù)記錄累積至16個(gè)字節(jié)來(lái)壓縮可執(zhí)行文件。
-
有了一個(gè)可執(zhí)行文件后,我們需要將應(yīng)用程序下載到TINIm400模塊中并運(yùn)行它。### 將示例應(yīng)用程序加載到TINIm400模塊
本節(jié)說(shuō)明如何使用Maxim/Dallas Semiconductor提供的 微控制器工具包(MTK) 向TINIm400驗(yàn)證模塊中加載由SDCC編譯器生成的十六進(jìn)制文件。目前可用的MTK版本只支持Windows?。
如果您的開發(fā)環(huán)境不是Windows,需要使用JavaKit應(yīng)用程序來(lái)下載和執(zhí)行應(yīng)用程序。要使用JavaKit,您必須有Java運(yùn)行環(huán)境3 (版本至少為1.2)并且安裝Java Communications API ^4^ 。JavaKit工具包含在TINI軟件開發(fā)包中。寫本文的時(shí)候,發(fā)布的最新固件是固件版本1.13。運(yùn)行JavaKit的指導(dǎo)說(shuō)明可以在TINI SDK docs目錄下的Running_JavaKit.txt文件中找到。如果您在運(yùn)行MTK或JavaKit時(shí)遇到技術(shù)問題,可能其他人已經(jīng)遇到過(guò)類似問題并且已經(jīng)發(fā)表在Dallas Semiconductor的討論區(qū)中。
最新版本的MTK應(yīng)用軟件可下載。要安裝MTK,請(qǐng)運(yùn)行安裝文件并遵照提示操作。成功安裝后,會(huì)增加一個(gè)新的菜單項(xiàng): Start->All Programs->Dallas Semiconductor MTK。 MTK啟動(dòng)后,會(huì)出現(xiàn)圖1所示的對(duì)話框。
圖1. 啟動(dòng)時(shí)MTK選項(xiàng)
選擇選項(xiàng)TINI,以操作TINIm400評(píng)估板。
選擇了TINI之后,會(huì)打開MTK主窗口。從Options->Configure Serial Port菜單選項(xiàng)中選擇您將用來(lái)和TINIm400通訊的串口。然后,選擇Tini->Tini Options菜單項(xiàng),就會(huì)出現(xiàn)下面的對(duì)話框。選擇DSTINIm400按鈕,配置MTK用于和TINIm400板通訊。圖2顯示了帶有DSTINIm400按鈕的對(duì)話框。
圖2. 選擇TINIm400配置選項(xiàng)
選擇Tini->Open COMx at xxx baud菜單選項(xiàng)打開串口。接著選擇Tini->Reset選項(xiàng)復(fù)位評(píng)估板。會(huì)出現(xiàn)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文件并選中。一旦您的程序加載后有兩種方法運(yùn)行它。因?yàn)槲覀儗⒊绦蚣虞d到40區(qū),您可以輸入:
> B40
> X
要選擇40區(qū)并運(yùn)行那里的代碼。您也可以輸入:
> E
這會(huì)使ROM查找可執(zhí)行的代碼。它查找一個(gè)標(biāo)識(shí)當(dāng)前區(qū)具有可執(zhí)行代碼的特定標(biāo)簽。此標(biāo)簽由文本'TINI'組成,其后面緊跟著當(dāng)前區(qū)的號(hào)碼(或零),并位于當(dāng)前區(qū)的0002h地址。SDCC編譯器在生成的匯編代碼中插入此標(biāo)簽。如果打開為hellouniverse工程生成的main.asm源代碼,您會(huì)找到下面的代碼段:
.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語(yǔ)句位于40區(qū)的0000h地址。其后跟隨可執(zhí)行標(biāo)簽{ 'T', 'I', 'N', 'I', 0h},由于simp語(yǔ)句為兩個(gè)字節(jié),因此該標(biāo)簽位于地址0002處。當(dāng)您鍵入'E'時(shí),ROM從C0h區(qū)開始向下搜索可執(zhí)行代碼。如果您鍵入'E'時(shí),執(zhí)行了其它的代碼,則意味著ROM在一個(gè)比您的代碼加載位置400000h更高的地址找到了一個(gè)可執(zhí)行標(biāo)簽。您可能需要找到此標(biāo)簽的位置,并刪除那個(gè)區(qū)的內(nèi)容。### 和ROM以及SDCC ROM庫(kù)接口
在高速微控制器用戶指南DS80C400補(bǔ)充資料中說(shuō)明了在匯編語(yǔ)言中調(diào)用ROM函數(shù)的過(guò)程。但是,在C中調(diào)用這些ROM函數(shù)會(huì)復(fù)雜一些。必須將參數(shù)從SDCC C編譯器的規(guī)則轉(zhuǎn)換成ROM使用的規(guī)則。SDCC編譯器通過(guò)硬件堆棧、累加器和數(shù)據(jù)指針相結(jié)合的方式來(lái)傳遞參數(shù)。ROM函數(shù)采用許多不同的方式來(lái)接受參數(shù)。例如,socket函數(shù)接收存儲(chǔ)在一個(gè)外部RAM緩沖區(qū)中的參數(shù)。相反地,許多功能函數(shù)接收由特殊功能寄存器或直接存儲(chǔ)器位置傳遞的參數(shù)。為了從SDCC調(diào)用方式轉(zhuǎn)換成ROM參數(shù)方式,Dallas Semiconductor已經(jīng)編寫了訪問ROM函數(shù)的庫(kù)。
在您的C程序中使用ROM函數(shù)只需包含一個(gè)頭文件并與相應(yīng)的庫(kù)文件連接即可。用于SDCC編譯器的ROM庫(kù)包括:
- ROM初始化程序
- DHCP客戶端
- 進(jìn)程調(diào)度
- Sockets (TCP、UDP和Multicast)
- TFTP客戶端
- 功能函數(shù)(CRC16, 隨機(jī)數(shù))
在寫本文時(shí),還沒有為SDCC編譯器提供包括如文件系統(tǒng)、郵件客戶端和HTTP服務(wù)器之類的擴(kuò)展庫(kù)。請(qǐng)關(guān)注SDCC庫(kù)主頁(yè)上的DS80C400升級(jí)信息,我們會(huì)添加支持SDCC的庫(kù)。### 簡(jiǎn)單應(yīng)用:HTTP服務(wù)器
編寫了一個(gè)簡(jiǎn)單的http服務(wù)器來(lái)說(shuō)明如何使用一些ROM庫(kù)函數(shù),特別是socket和進(jìn)程調(diào)度庫(kù)。這個(gè)示例會(huì)偶爾通過(guò)網(wǎng)絡(luò)時(shí)間服務(wù)器更新它的時(shí)間,并且通過(guò)它的web服務(wù)器提供這個(gè)信息。
示例應(yīng)用程序由兩個(gè)模塊組成,一個(gè)HTTP服務(wù)器和SNTP客戶端。主程序生成一個(gè)新的子任務(wù)來(lái)運(yùn)行http服務(wù)器,用于處理80端口上的客戶連接。父任務(wù)每60秒會(huì)試圖通過(guò)時(shí)間服務(wù)器同步當(dāng)前時(shí)間。
SNTP客戶端模塊
以下代碼段實(shí)現(xiàn)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);