Draft lite V1.0
EZ-LINK平臺開發手冊
1 平臺簡介
1.1 PCB設計
1.2 SDK架構
1.3 源碼目錄
2 開發環境
2.1 配置文件
2.2 庫文件
2.3 IDE配置
2.4 編程框架
2.5 燒錄Flash
2.6 調試
3 IOT接口
3.1 系統服務
3.2 硬件服務
3.3 WIFI
3.4 Bluetooth
3.5 GSM
3.6 GPS
縮略詞:
BCPU
Baseband CPU
BTCPU
Bluetooth CPU
XCPU
System CPU
BSS
Basic Service Set
BSSID
BSS ID
COS
Common Operating System
1 平臺簡介 EZ-Link是RDA物聯網應用集成開發平臺,該平臺包括SDK開發包,Eclipse集成開發環境,調試工具和燒錄工具。SDK開發包提供了在EZ-Link平臺進行物聯網開發必需的模塊和標準API接口,同時通過對硬件層抽象,提供對RDA物聯網系列芯片的全面支持。 RDA物聯網系列芯片即有獨立藍牙、WIFI芯片,也有在SoC上集成Wi-Fi、Bluetooth和GSM功能的組合芯片,并提供包括UART/ADC/I2S在內的硬件接口。 RDA特有的共存技術使用戶可以獨立或并行使用Wi-Fi及藍牙功能。 本文闡述EZ-Link平臺SDK的主要功能和使用方法。本文所描述SDK為精簡版,該版本針對物聯網設備開發周期短、市場反應敏感等特點,對EZ-Link SDK進行了一系列優化升級,以幫助客戶提高開發效率。用戶僅需要了解必要的接口,然后通過SDK提供的豐富示例代碼,簡單修改甚至零修改就可以實現一款完整的物聯網應用。 1.1 PCB設計請參考各芯片數據手冊。
1.2 SDK架構EZ-Link SDK具有模塊化、可擴展的架構和清晰的層次結構,靈活的SDK架構為產品定制提供軟件支撐,用戶可以根據不同市場需求和變化,進行快速調整。
EZ-Link SDK的架構如下,每一部分將會在下面具體描述。
除了APP應用層需要客戶完成,其余模塊將由RDA統一打包發布給客戶。 圖1-1 EZ-Link SDK架構
最底層為硬件層,包括芯片和外設硬件。
第二層為硬件抽象層,該層隱藏底層硬件細節,為上層驅動提供統一接口,為實現不同芯片間平滑切換提供軟件支持。
第三層為驅動和操作系統層。RDA在RTOS之上又提供了一層瘦COS層,該COS層封裝了核心操作系統接口如任務調度,并發處理等,為服務層提供統一接口。COS層為用戶提供兩方面便利:用戶可以隨心所欲選擇自己偏好的操作系統;用戶可以移植已有的應用程序,復用代碼,提高代碼利用效率,加速開發進度。
第四層為服務層,服務層應用程序類似windows服務程序或linux deamon程序,這些程序長時間執行,為上層用戶和應用提供特定的服務,如http,GPS服務等。上層用戶可以通過標準接口使用服務層程序提供的服務,如多媒體應用程序可以通過GUI接口顯示播放界面,同時可以通過media服務進行音頻數據解碼和播放。服務層應用程序通常為操作系統的任務(task),該任務直接調用COS接口以降低與RTOS的耦合。 服務層應用程序十分豐富,可以滿足當前主流的物聯網應用。良好的可擴展架構使用戶可以添加更多自有服務程序或第三方應用程序,滿足客戶特殊的產品需求。 該層同時提供精簡的IOT API,通過精簡IOT API,用戶可以快速開發一款簡單的物聯網應用,如智能水杯等。
最高層為應用程序層,用戶通常工作在本層。應用程序層通過調用服務層接口進行軟件開發。
EZ-Link各層之間以松散的方式耦合,各層提供的接口和實現分離,層內關注實現,層間關注接口。除此之外,EZ-Link SDK同樣遵循模塊化設計原則,方便用戶對產品特性進行裁剪以適應客戶需求,發揮用戶平臺、硬件資源的最大效率:
| RDA 芯片為本SDK設計參照的核心,芯片類型決定系統的CPU硬件架構、IO接口、總線等特性,進而影響服務層提供的服務、產品特性和源碼編譯等。芯片模塊化使用戶在無需修改上層軟件的情況下,根據需求選擇適當的芯片 | | 目前市面上嵌入式實時操作系統種類繁多,用戶可以根據自己的偏好和使用習慣選擇操作系統而不影響其他應用 | | 用戶通常有更換外設的需求,驅動模塊化正是滿足該項需求 | | 服務層模塊化,有效減少各個子模塊之間耦合,方便用戶刪減與特定產品無關服務,添加新服務 |
本SDK支持多種RDA芯片。豐富的IO接口方便連接各種外設 硬件抽象層為上層驅動提供統一接口,方便驅動程序移植 驅動模塊包括:GPIO,、UART、flash、LCD等 強大的實時操作系統: - 支持多任務處理
- 定時器管理
- 支持并發訪問控制鎖和任務間同步信號量
- 任務間通信機制
- 動態內存管理和glibc兼容的內存操作接口
提供對RTOS封裝,可針對不同RTOS進行適配,使服務層和應用層程序擺脫對操作系統依賴 EZ-Link將系統功能抽象成模塊化的服務,并提供標準的服務接口,極大簡化編程過程。針對物聯網特點,EZ-Link提供豐富的網絡協議,方便不同設備商之間的智能設備互聯互通: - 支持AllSeen協議
- 支持lwIP協議棧和http等應用層協議,方便擴展互聯網應用
- 多媒體功能,音頻、視頻等
- GPS定位服務
- 支持DLNA協議
- GSM/GPRS服務
- 硬件層服務,主要針對GPIO、UART等串行總線接口
- OS服務,主要封裝定時器、內存操作、調試等接口
簡易IOT接口,簡化編程,快速生成IOT應用,實現簡單IOT產品 相對簡單應用程序層,實現更復雜的物聯網應用
1.3 源碼目錄SDK源碼目錄結構如下,各個目錄將會在下面詳細描述。
圖1-2 EZ-Link SDK源碼目錄結構 圖中各目錄模塊說明如下:
| | | | | RDA IOT平臺代碼,其下包括:chip、edrv、 rtos、 service等子目錄,子目錄會在下面依次說明 | | 平臺芯片相關代碼,包括:boot loader,hal層,寄存器地址定義和rom代碼。通常用戶無需修改rom代碼 | | 包括外設驅動和芯片內驅動,外設驅動包括:LCD,FM等;芯片內部驅動為內部總線驅動,如GPIO,UART等 | | | | | | | 網絡服務,提供http,lwna,tcp/ip操作接口 | | | | | | | | | | | | | | | | | | 影子目錄,該目錄在編譯時由編譯腳本生成,用來存放編譯過程中生成的臨時文件 | | | | Lod文件、Ramrun文件和其他GDB相關asm及map文件 |
表1-1 EZ-LINK SDK目錄結構描述
2 開發環境EZ-LINK選用windows操作系統作主機(HOST),在windows系統中搭建交叉編譯環境。 2.1 配置文件模塊化的設計為用戶定制產品提供了便利。通常定制產品通過修改配置文件來完成。配置文件在target目錄,EZ-LINK配置文件主要涉及以下幾個:
| | | | | 對target.def信息的集中處理,通常不需要用戶修改 | | | | 用戶功能宏頭文件,控制用戶APP特性 文件存在./target/include | | 硬件線路板配置 文件存在./target/include | | |
表2-1 配置文件
產品定義配置文件target.def包含下面一些選項,各選項精確的函數請參考配置文件說明注釋: | | | | | | | | | | | | | | | | | | | | | 定義WIFI 32K時鐘管腳,TCP/IP支持,SDIO,GPIO,SDMMC接口支持,DLNA接口支持,WIFI音箱支持 | | | | | | | | | | | | | | | | | | | CT_OPT:優化編譯空間 WITHOUT_WERROR:告警是否停止編譯 | | |
表2-2 產品配置文件選項 2.2 庫文件EZ-Link開發平臺庫文件統一放置在./platform/lib/chip_name目錄。用戶開發程序時引用的頭文件放置在各模塊./inlcude目錄。
庫文件分為release和debug兩個版本,通過文件名區分。debug版本包含調試信息,并可以使用GDB工具進行單步調試,調試信息可以通過串口打印到控制臺;release版本不包含調試信息。正式發布的產品bin文件應當鏈接release版本庫以減少bin文件體積,提高運行速度。
2.3 IDE配置EZ-LINK SDK選擇Eclipse作為集成開發環境,SDK編譯工具鏈統一集成在Eclipse中。
| Eclipse和JRE(Jave Run Environment)選用32位版本,可以兼容64和32位操作系統 |
- 下載EZ-LINK集成開發工具包,其中包含JRE安裝程序和Eclipe軟件
- 安裝JRE,安裝過程始終選擇默認安裝選項
- Eclipse無需安裝,直接解壓運行
Eclipse成功運行說明集成開發環境工作正常,下一步通過Eclipse配置編譯工具,導入SDK庫文件和源碼。
打開Eclipse, 選擇菜單“File/New”, 然后選擇“RDA Project”。項目配置窗口如下,自定義工程名,選擇項目代碼路徑: 圖2-1 創建項目
項目基礎代碼由RDA提供,用戶可以在基礎代碼之上實現自己特有的功能和應用。 文檔中示例工程名為“iot”,選擇代碼路徑后單擊“Finish”按鈕,生成工程如下:  圖2-2 項目瀏覽器
在“Project Explorer”中點擊右鍵,選擇“Properties”,進入“Properties”窗口,選擇“C/C++ Build”,然后選擇“RDA Project”,配置目標: 圖2-3 項目配置
在“Project Explorer”中點擊右鍵,選擇“RDA Tools”,然后可以看到兩個編譯選項:
圖2-4 編譯項目
在“Project Explorer”中展開根目錄 iot,選擇模塊,在模塊上點擊右鍵,選擇“RDA Tools”,然后可以看到如下兩個選項:
圖2-5 編譯模塊
2.4 編程框架對EZ-LINK開發平臺而言,短短數十行代碼就可以完成一個簡單的物聯網應用,如智能LED燈等。簡單物聯網應用編程框架有兩部分組成:
- init()函數,負責資源初始化
- loop()函數,持續監聽系統事件,并處理。loop函數不間斷運行直至系統關機
圖2-6 用戶代碼結構
include目錄存放用戶頭文件,如果用戶無自定義頭文件,該目錄可以為空,或者直接刪除。
src目錄存放用戶源文件。源文件中實現init()和loop(),用戶在init()中實現初始化代碼,在loop()中處理外設如WIFI模塊產生的事件。源文件結構參考示例代碼。
makefile文件具有固定格式,簡單易用。模塊makefile甚至無需修改就可以正確編譯用戶代碼,將用戶代碼與系統庫文件一起編譯鏈接生成可燒錄的flash二進制文件。
## ----------------------------------------------------------- ## ## Don't touch the next line unless you know what you're doing.## ## ----------------------------------------------------------- ## include ${SOFT_WORKDIR}/env/compilation/compilevars.mk
# Name of the module LOCAL_NAME := apps/ap_customer
# list all modules APIs that are neccessary to compile this module LOCAL_API_DEPENDS := \ platform \ platform/service \ ## ----------------------------------------------------------- ## ## List all your sources here ## ## ----------------------------------------------------------- ## include src/make.srcs
## ----------------------------------------------------------- ## ## Do Not touch below this line ## ## ----------------------------------------------------------- ## include ${SOFT_WORKDIR}/env/compilation/compilerules.mk |
2.5 燒錄Flash
燒錄BIN文件使用USB轉串口線,RDA提供的開發包中包含USB轉串口驅動程序,點擊安裝。驅動安裝成功后,依次查看windows“控制面板”->“設備管理”->“端口”,在“端口”選項下,有如下所示USB-to-Serial端口,說明安裝成功:
圖2-7 安裝串口驅動
在Eclipse菜單項選擇“windows”,然后選擇“Preference”,選擇“C/C++”,然后選擇“RDA Tools”。在“Serial Setting”中選擇串口和正確的Baudrate。
圖2-8 串口配置
燒錄相關按鈕在Eclipse工具欄,如下圖示。 自左向右分別是:
連接UART COM口:藍線連接HST_RXD,白線連接HST_TXD,黑線接地。 啟動Eclipse,點擊工具欄“Connect Target”,連接成功后,點擊“Down Flash”,選擇Lod文件,點擊“Download”: 圖2-9 下載選項
| Flash Programmer File文件由build flash產生 System Lod File文件由build image產生,參考2.3 IDE配置
|
2.6 調試串口打印trace是最為常見的調試手段。EZ-LINK trace按模塊分類,模塊內按重要性分為不同等級。
通過宏開關,可以選擇編譯時是否包含特定模塊trace。
通過Eclipse工具,可以選擇運行時是否輸出特定模塊和該模塊特定級別的trace。設置步驟如下:
在Eclipse菜單欄選擇“windows”,然后選擇“Preference”,選擇“C/C++”,然后選擇“RDA Tools”,最后單擊“Trace Mask”按鈕,彈出如下對話框。
圖2-10 配置Trace
“Select Module”選擇trace模塊,16個level控制trace輸出級別。
3 IOT接口3.1 系統服務3.1.1 內存頭文件:iot_base.h 3.1.1.1 iot_Malloc | | | PVOID iot_Malloc(UINT32 size) | |
| | | | | |
|
| 3.1.1.2 iot_Free3.1.2 Trace頭文件iot_base.h 3.1.2.1 iot_Printf | |
| iotPrintf("led status = %d ", ledOn); | | VOID iot_Printf(INT8* fmt,...) | |
| | | | | |
|
| 3.1.3 延時3.1.3.1 iot_DelayMs | | | VOID iot_delayMs(UIN32 ms) | |
| | | | | |
|
| 3.1.3.2 iot_DelaySeconds | | | VOID iot_DelaySeconds( UINT32 seconds) | |
| | | | | |
|
| 3.2 硬件服務3.2.1 UART3.2.1.1 uart_Open | | | VOID uart_Open(UINT8 id, UINT32 baudrate) | |
| | | | | | | | |
|
| 3.2.1.2 uart_Close | | | VOID uart_Close(UINT8 id); | |
| | |
| | |
|
| 3.2.1.3 uart_Write | | | UINT32 uart_Write(UINT8 id, CHAR ch); | |
| | | | | | | | | | |
| | | | 3.2.1.4 uart_Read | | | UINT32 uart_Read(UINT8 id, CHAR* buff) | |
| | | | | | | | | | |
| | | | 3.2.2 GPIO3.2.2.1 gpio_Open | | | VOID gpio_Open(UINT8 port, UINT8 direction) | |
| | | | | | | | |
|
| 3.2.2.2 gpio_Close | | | VOID gpio_Close(UINT8 port) | |
| | | | | |
|
| 3.2.2.3 gpio_Write | | | VOID gpio_Write(UINT8 port, UINT8 data) | |
| | | | | | | | |
|
| 3.2.2.4 gpio_Read | | | UINT32 gpio_Read(UINT8 port) | |
| | | | | |
|
| 3.2.2.5 示例程序簡單物聯網應用:智能LED燈,通過WIFI無線控制LED燈開關。現實生活中,可以減少裝修布線,減輕對墻體破壞等。
// app_led.c #include “hal_gpio.h” #include “tcpip_sockets.h”
static struct sockaddr_in ledSckAddr; static INT8 ledSckServer; static INT8 ledSckClient = 0; ///Only accept 1 byte data(0 or 1), ok for turn on/off the LED #define MAX_RECV_BUFF 1 #define LED_SCK_PORT 5050 #define MAX_LED_CONNECTION 1
VOID init(VOID) { struct sockaddr_in clientAddr; HAL_GPIO_GPIO_ID_T ledGpioId; HAL_GPIO_DIRECTION_T direction;
///Use the tenth GPIO port ledGpioId = HAL_GPIO_10; direction = HAL_GPIO_DIRECTION_OUTPUT; ///Must open the GPIO before use it gpio_Open(ledGpioId, direction);
ledSckServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); memset(&ledSckAddr,0, sizeof(struct sockaddr_in));
ledSckAddr.sin_family=AF_INET; ledSckAddr.sin_addr.s_addr=htonl(INADDR_ANY); ledSckAddr.sin_port=htons(LED_SCK_PORT);
if(-1 == bind(ledSckServer, (struct sockaddr *)(& ledSckAddr),sizeof(sockaddr_in))) { return ; } }
VOID loop(VOID) { INT8 readLen = 0; UINT8 ledOn; /// If no connection, waiting for connect if (ledSckClient <= 0) { if(-1 == listen(ledSckServer, MAX_LED_CONNECTION)) { return ; } addrSize = sizeof(struct sockaddr_in); ledSckClient = accept(ledSckServer, (struct sockaddr *)(&clientAddr), &addrSize); if(-1 == ledSckClient) { return ; } } readLen = read(ledSckClient, &ledOn, MAX_REV_BUF_SIZE); if (readLen > 0) { if (0 == ledOn || 1 == ledOn) gpio_Write(ledGpioId, ledOn); } } | 3.3 WIFI3.3.1 編程接口頭文件:iot_wifi.h 3.3.1.1 iot_Connect | | | INT32 iot_Connect(const char *addr, INT16 portno) | |
| | | | | | | | |
| |
| |
| | 3.3.1.2 iot_Send | | | INT32 iot_Send(INT32 sockfd, const INT8* buffer, UINT32 len) | |
| | | | | | | | | | | |
|
| 3.3.1.3 iot_Recv | | | INT32 iot_Recv(INT32 sockfd, INT8 *buffer, UINT32 len) | |
| | | | | | | | | | | |
|
| 3.3.1.4 iot_Close | | | INT32 iot_Close(INT32 sockfd) | |
| | | | |
|
|
| 3.3.2 示例程序#include "iot_wifi.h" // Source device id allocated by oneNet #define SRC_DEV "777" // Destination device id allocated by oneNet #define DST_DEV "778" // API key allocated by oneNet #define API_KEY "your api key" // Data stream name, created on oneNet #define DATA_STREAM "your data stream" #define MAX_RESP_BUF 32
// ============================================================================ // Loop forever // Send temperature value to cloud application whenever changed // @return void // ============================================================================ VOID loop() { // Server information for connection INT8 *server_ip = "183.230.40.39"; INT8 *port = "876"; INT8 *src_dev = SRC_DEV; INT8 *dst_dev = DST_DEV; INT8 *src_api_key = API_KEY; INT8 *data_stream = DATA_STREAM; DOUBLE temperature = 0.0; INT sock, ret; EdpPacket *pkg = NULL; INT8 buffer[MAX_RESP_BUF] = { 0 }; SaveDataType data_type = kTypeSimpleJsonWithoutTime;
recv_buf = NewBuffer(); // Connect to server sock = iot_Connect(server_ip, atoi(port)); if (sock < 0) { iot_Printf("Error connect cloud server. \n"); return; } // Build connect package follow oneNet EDP protocol pkg = PacketConnect1(src_dev, src_api_key); if (pkg == NULL) { iot_Printf("Build connect pkg failed.\n"); return; } // Send connection request pkg to cloud server ret = iot_Send(sock, (const char*)pkg->_data, pkg->_write_pos); DeleteBuffer(&pkg); while (1) { Temperature = user_poll_current_temperature(); // Build save data pkg follow oneNet EDP protocol pkg =PacketSavedataDouble(data_type,dst_dev,data_stream,temperature,0, NULL); if (pkg == NULL) { iot_Printf("Build data failed.\n"); return; } // Send temperature value pkg to clould server iot_Send(sock, (const char*)pkg->_data, pkg->_write_pos); DeleteBuffer(&pkg); iot_DelayMs(2000); } // Close socket iot_Close(sock); return; } | 3.4 Bluetooth3.4.1 編程接口頭文件:iot_bt.h 3.4.1.1 bt_Open3.4.1.2 bt_Close3.4.1.3 bt_SetLocalName | | | VOID bt_SetLocalName(UINT8* name) | |
| | | | | | |
| 3.4.1.4 bt_SetVisible | | | VOID bt_SetVisable(UINT8 visable); | |
| | | | | | |
| 3.4.1.5 bt_ScanDevice | | | UINT32 bt_ScanDevice(UINT32 timeout) | |
| | | | | |
|
| 3.4.1.6 bt_BoneDevice | | | UINT32 bt_BondDevice( t_bdaddr device_addr, UINT32 timeout ) | |
| | | | | |
| 3.4.1.7 bt_GetBonedDevice | | | BOOL bt_GetBonedDevice(UINT32 index, rdabt_device_t_app *device); | |
| | | | | | | | | | |
| | | | 3.4.1.8 bt_SppConnect | | | BOOL bt_SppConnect(t_bdaddr device_addr, UINT8 timeout); | |
| | | | | | | | | | |
| | | | 3.4.1.9 bt_SppDisconnect | | | VOID bt_SppDisconnect(VOID) | |
| | |
| | |
|
| 3.4.1.10 bt_SppSend | | | INT32 bt_SppSend(UINT8* buf, UINT32 size) | |
| | | | | | | | | | |
| | | | 3.4.1.11 bt_SppRecv | | | INT32 bt_SppRecv(UINT32 timeout, UINT8 *buf) | |
| | | | | | | | | | |
| | | | 3.4.1.12 bt_SppAccept | | | BOOL bt_SppAccept(UINT32 timeout) | |
| | | | | | | |
| | | | 3.4.2 示例程序簡單物聯網應用:智能插座,通過藍牙無線控制插座的開關。
// app_smart_plug.c
#include “bt_types.h” #include “hal_gpio.h”
static HAL_GPIO_GPIO_ID_T plugGpioId;
VOID init(VOID) { HAL_GPIO_DIRECTION_T direction;
// Use the fifth GPIO port plugGpioId = HAL_GPIO_15; direction = HAL_GPIO_DIRECTION_OUTPUT; // Must open the GPIO before use it gpio_Open(plugGpioId, direction ); bt_Open(VOID); }
VOID loop(VOID) { t_DataBuf btData;
memcpy(&btData, 0, sizeof(t_DataBuf)); // Return only when data available or error bt_SppRecv(&btData); if (btData.len > 0) { if (0 == (*btData.buff) || 1 == (*btData.buff) ) { gpio_Write(plugGpioId, *btData.buff); } } } |
全部資料51hei下載地址(含源碼與手冊):
http://www.zg4o1577.cn/bbs/dpj-135991-1.html
|