全部產品
Search
文件中心

:樂鑫ESP32開發板移植

更新時間:Jun 30, 2024

本文介紹如何在ESP32開發板上移植C-SDK4.0,並用MQTT Demo連上阿里雲物聯網平台。

開發環境說明

為了完成移植實踐,您需要:

  • 一塊搭載ESP32的開發板。

  • USB連接線。

  • 運行Linux或者macOS的電腦。

demo使用的開發板為ESP32 Core Board V2/ESP32 DevKitC,它搭載了ESP-WROOM-32官方模組,板載USB轉串口模組(CP2102)和電源模組。

說明

我們使用的開發環境為macOS,使用其他系統的使用者也可以參考ESP32的官方入門教程完成開發環境搭建。

搭建開發環境

說明

本節僅供參考使用,您在搭建開發環境中碰到問題請聯絡開發板的供應商進行解決,然後再進行SDK的移植。建議您先閱讀樂鑫官方入門教程以加快開發環境搭建。

下面對macOS環境搭建的相關步驟做簡要說明:

  1. 安裝必要的軟體。

  2. 複製esp-idf官方倉庫。

    本次示範使用esp-idf倉庫的release/v4.2分支,如果使用其他版本可能出現版本不相容。

    cd ~
    mkdir esp && cd esp
    git clone --recursive -b release/v4.2 https://github.com/espressif/esp-idf.git
  3. 安裝工具鏈和編譯工具。

    cd esp-idf
    ./install.sh
  4. 配置環境變數。

    • 運行以下指令碼:

      . $HOME/esp/esp-idf/export.sh
    • 您也可參考以下指令碼在$HOME/.bash_profile中添加配置以快速完成環境變數配置:

      set_esp32 ()
      {
          export IDF_PATH=$HOME/esp/esp-idf
          . $HOME/esp/esp-idf/export.sh
      }
  5. 拷貝WiFi state常式到獨立目錄。

    cd ~/esp
    cp -r $IDF_PATH/examples/wifi/getting_started/station .
  6. 串連開發板。

  7. 配置工程。

    使用idf.py menuconfig配置工程,示範中使用了預設配置。

  8. 編譯、燒寫、串口監視。

    • 進入station專案路徑,使用idf.py build編譯工程。

    • 編譯完成後使用idf.py -p PORT flash命令燒寫韌體(請用實際的USB連接埠名替換PORT)。

    • 燒寫成功後可運行idf.py -p PORT monitor開啟串口列印資訊監視器。

    • 您也可使用idf.py -p PORT flash monitor連續執行這兩條命令。

    至此,您已經完成了ESP32開發環境的搭建,並完成了wifi station常式的編譯燒寫,下面我們將介紹如何移植C-SDK4.0,並成功串連阿里雲物聯網平台。

移植C-SDK4.0

移植C-SDK的過程主要包括了SDK代碼的匯入,SDK port層檔案配置和編譯系統的配置。

SDK的portfiles目錄已經包含了ESP32的portfile,因此您只需要匯入SDK源碼,配置編譯系統即可完成移植工作。

基本概念

建議提前閱讀idf編譯系統介紹以理解移植過程,您需要瞭解idf的一些基本概念:

  • project:專案目錄,僅包含了所有用於構建app的源檔案和設定檔。

  • components: 功能獨立的模組化代碼, 將會編譯成.a靜態庫並連結到app,這些模組化的組件存放在idfcomponents目錄下,您可以添加自訂component

idf的編譯系統預設使用cmakeninja組合,我們只需移入SDK代碼,編寫SDK對應的CMakeList.txt即可將SDK加入編譯。

移植思路

  • 方法一:在project目錄中引入C-SDK,將SDK源碼與您的其他app源碼共同編譯。

  • 方法二:將C-SDK作為idf自訂群組件引入到idfcomponents目錄中。

我們推薦用第二種方法,將C-SDK作為獨立組件有助於在不同專案中複用,並解除與您其他app代碼的耦合。

操作步驟

  1. 添加C-SDK自訂群組件。

    下載C-SDK4.0,將SDK複製到$IDF_PATH/components目錄下,在C-SDK目錄下添加構建檔案CMakeLists.txt,內容如下:

    set(include_dirs core core/sysdep core/utils)
    file(GLOB c_sdk_srcs
        "core/*.c"
        "core/utils/*.c"
        "core/sysdep/*.c"
        "portfiles/aiot_port/*.c"
        "external/*.c")
    idf_component_register(SRCS ${c_sdk_srcs}
                           INCLUDE_DIRS "${include_dirs}"
                           REQUIRES mbedtls)
    說明

    • 由於C-SDK依賴mbedtls庫,因此需要使用REQUIRES mbedtls引入組件依賴。

    • 由於C-SDK沒有配置項,無需配置組件Kconfig。

    • 若您需要使用SDK進階組件(如物模型,OTA),則在此CMakeLists.txt中添加組件對應的源檔案和標頭檔路徑。

  2. 移植demo程式。

    您需要下載附件posix_port.c(適配了esp32),用它將$IDF_PATH/components/C-SDK/portfiles/aiot_port目錄下的posix_port.c替換掉。

    LinkSDK與idf中都有mbedtls庫,避免引用庫衝突,修改檔案$IDF_PATH/components/C-SDK/core/sysdep/core_adapter.c,關閉CORE_ADAPTER_MBEDTLS_ENABLED宏定義。

  3. 由於idf相容posix標準,您可下載附件station_example_main.c擷取並替換原有常式下檔案station/main/station_example_main.c

    說明
    • wifi_init_sta()函數會一直等待WiFi串連成功直到重連次數達到宏EXAMPLE_ESP_MAXIMUM_RETRY定義的數值。

    • WiFi串連成功後,我們便可以調用C-SDK的API進行MQTT建連,建連成功後即可與物聯網平台進行資料收發了。

    • linkkit_main()函數包含原C-SDK的mqtt demo。

  4. 編譯、燒寫。

    • 在專案目錄下運行idf.py menuconfig,進入Example Configuration菜單。

    • 修改WiFi SSIDWiFi PasswordMaximum retry(最大重連次數)3個參數,儲存並退出配置。

    • 運行idf.py build進行編譯。

    • 編譯成功後,運行idf.py -p /dev/cu.SLAB_USBtoUART flash monitor完成燒寫並開啟串口監視器。

    說明

    如果裝置使用PSK金鑰交換則需要確保mbedTLS已經開啟PSK金鑰交換方法,同時配置PSK最大長度為64,可參考以下步驟配置:

    • 進入Component config菜單的mbedTLS子功能表,進入TLS Key Exchange Methods配置項。

    • 開啟Enable pre-shared-key ciphersuites開關。

    • 同時在mbedtls組件的CMakeLists.txt中添加set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMBEDTLS_PSK_MAX_LEN=64")

  5. 作業記錄資訊。

    ......
    I (829) phy: phy_version: 4180, cb3948e, Sep 12 2019, 16:39:13, 0, 0
    I (829) wifi: mode : sta (30:ae:a4:04:81:84)
    I (829) wifi station: wifi_init_sta finished.
    I (949) wifi: new:<11,0>, old:<1,0>, ap:<255,255>, sta:<11,0>, prof:1
    I (949) wifi: state: init -> auth (b0)
    I (969) wifi: state: auth -> assoc (0)
    I (969) wifi: state: assoc -> run (10)
    I (1129) wifi: connected with C_SDK_Test, aid = 1, channel 11, BW20, bssid = ec:26:ca:4b:68:cc
    I (1129) wifi: security type: 3, phy: bgn, rssi: -37
    I (1139) wifi: pm start, type: 1
    I (1219) wifi: AP's beacon interval = 102400 us, DTIM period = 1
    I (2129) esp_netif_handlers: sta ip: 192.168.0.100, mask: 255.255.255.0, gw: 192.168.0.1
    I (2129) wifi station: got ip:192.168.0.100
    I (2129) wifi station: connected to ap SSID:C_SDK_Test password:1234abcd
    I (2139) wifi station: Start linkkit mqtt
    [1.583][LK-0313] MQTT user calls aiot_mqtt_connect api, connect
    [1.587][LK-0317] mqtt_basic_demo&a13FNXXXXXX
    [1.590][LK-0318] 4780A5F17990D8DC4CCAD392683ED80160C4C2A1FFA649425CD0E2666A8593EB
    [1.598][LK-0319] a13FN5TplKq.mqtt_basic_demo|timestamp=2524608000000,_ss=1,_v=sdk-c-4.0.0,securemode=2,signmethod=hmacsha256,ext=1,|
    establish mbedtls connection with server(host='a13FN5TplKq.iot-as-mqtt.cn-shanghai.aliyuncs.com', port=[443])
    success to establish mbedtls connection, fd = 54(cost 29739 bytes in total, max used 44007 bytes)
    [3.493][LK-0313] MQTT connect success in 1910 ms
    AIOT_MQTTEVT_CONNECT
    [3.494][LK-0309] sub: /sys/a13FN5TplKq/mqtt_basic_demo/thing/event/+/post_reply
    [3.499][LK-0309] pub: /sys/a13FN5TplKq/mqtt_basic_demo/thing/event/property/post
    [LK-030A] > 7B 22 69 64 22 3A 22 31  22 2C 22 76 65 72 73 69 | {"id":"1","versi
    [LK-030A] > 6F 6E 22 3A 22 31 2E 30  22 2C 22 70 61 72 61 6D | on":"1.0","param
    [LK-030A] > 73 22 3A 7B 22 4C 69 67  68 74 53 77 69 74 63 68 | s":{"LightSwitch
    [LK-030A] > 22 3A 30 7D 7D                                   | ":0}}
    suback, res: -0x0000, packet id: 1, max qos: 1
    [3.573][LK-0309] pub: /sys/a13FN5TplKq/mqtt_basic_demo/thing/event/property/post_reply
    [LK-030A] < 7B 22 63 6F 64 65 22 3A  32 30 30 2C 22 64 61 74 | {"code":200,"dat
    [LK-030A] < 61 22 3A 7B 7D 2C 22 69  64 22 3A 22 31 22 2C 22 | a":{},"id":"1","
    [LK-030A] < 6D 65 73 73 61 67 65 22  3A 22 73 75 63 63 65 73 | message":"succes
    [LK-030A] < 73 22 2C 22 6D 65 74 68  6F 64 22 3A 22 74 68 69 | s","method":"thi
    [LK-030A] < 6E 67 2E 65 76 65 6E 74  2E 70 72 6F 70 65 72 74 | ng.event.propert
    [LK-030A] < 79 2E 70 6F 73 74 22 2C  22 76 65 72 73 69 6F 6E | y.post","version
    [LK-030A] < 22 3A 22 31 2E 30 22 7D                          | ":"1.0"}
    pub, qos: 0, topic: /sys/a13FNXXXXXX/mqtt_basic_demo/thing/event/property/post_reply
    pub, payload: {"code":200,"data":{},"id":"1","message":"success","method":"thing.event.property.post","version":"1.0"}
    heartbeat response
    heartbeat response
    heartbeat response
    ......
    重要

    如果您看見“aiot_mqtt_connect failed: -0x0F0F”的報錯,說明網路不通暢。建議您檢查wifi網路狀態,確認板子在接收wifi訊號的範圍內,必要時可以重試燒寫和串連。

    備忘:-0x0F0F的語義是STATE_PORT_NETWORK_CONNECT_TIMEOUT,連線逾時。