分析Zephyr ESP32 WIFI驅(qū)動(dòng)的實(shí)現(xiàn)可以更為清晰的掌握esp32 wifi在zephyr上的使用,本文主要分析esp32的wifi驅(qū)動(dòng)如何被集成進(jìn)Zephyr的驅(qū)動(dòng),并不涉及esp32 wifi驅(qū)動(dòng)本身API的說(shuō)明。
框架
目前ESP32 wifi在zephyr上的實(shí)現(xiàn)框架如下圖
1. esp_private:
esp提供的wifi驅(qū)動(dòng),不開(kāi)源,屬于zephyr的外部module,其API頭文件在moduleshalespressifcomponentsesp_wifiincludeesp_private內(nèi)
2. adapter
esp提供的zephyr wifi適配層,對(duì)esp_private進(jìn)行封裝專(zhuān)門(mén)為zephyr用,屬于zephyr的外部module,其代碼放在moduleshalespressifzephyradaptersrcwifi
3. esp_wifi_drv:
Zephyr中的esp32 wifi驅(qū)動(dòng),調(diào)用adapter,和L2 ethernet進(jìn)行對(duì)接。明明是wifi,不封裝為L(zhǎng)2 wifi, 而封裝為L(zhǎng)2 ethernet,這可能是目前zephyr對(duì)L2 wifi的抽象還不完備,目前只支持offload wifi。
這部分是后文的主要分析內(nèi)容,代碼在zephyrdriverswifiesp32src
4. L2 ethernet
Zephyr L2 ethernet,提供ethernet初始化/配置/收發(fā)功能, 代碼在zephyrsubsys etl2ethernet,本文不做分析
esp_wifi_drv
zephyr的esp32 wifi驅(qū)動(dòng)可以分為初始化,收,發(fā)三部分來(lái)分析:
初始化
主要是完成L2的初始化,注冊(cè)入device初始化函數(shù)eth_esp32_dev_init和iface的初始化函數(shù)eth_esp32_init已經(jīng)L2的發(fā)送函數(shù)eth_esp32_send
1
2
static const struct ethernet_api eth_esp32_apis = {
.iface_api.init= eth_esp32_init,
.send = eth_esp32_send,
};
NET_DEVICE_DT_INST_DEFINE(0,
eth_esp32_dev_init, NULL,
e_data, NULL, CONFIG_ETH_INIT_PRIORITY,
e_esp32_apis, ETHERNET_L2,
NET_L2_GET_CTX_TYPE(ETHERNET_L2), NET_ETH_MTU);
使用NET_DEVICE_DT_INST_DEFINE注冊(cè)后,在系統(tǒng)啟動(dòng)時(shí)kernel的POST_KERNEL階段調(diào)用eth_esp32_dev_init,在net初始化階段調(diào)用eth_esp32_init.
eth_esp32_dev_init代碼如下,主要是調(diào)用hal中提供的一系列初始化和啟動(dòng)函數(shù),讓wifi啟動(dòng),值得注意的是當(dāng)CONFIG_ESP32_WIFI_STA_AUTO=y時(shí),zephyr驅(qū)動(dòng)會(huì)自動(dòng)去幫你用配置好的CONFIG_ESP32_WIFI_SSID和CONFIG_ESP32_WIFI_PASSWORD去連接Wifi。
如果沒(méi)有配置,就需要在應(yīng)用代碼中直接調(diào)用esp hal的API進(jìn)行連接,另外就是zephyr目前并沒(méi)有將esp32 wifi的scan/connect/disconnect做到L2 WIFI內(nèi)進(jìn)行管理,可以參考Zephyr網(wǎng)絡(luò)管理模塊分析-注冊(cè)請(qǐng)求機(jī)制, 這邊部分也需要在應(yīng)用中直接調(diào)用esp hal的API進(jìn)行管理。
static int eth_esp32_dev_init(const struct device *dev)
{
esp_timer_init();
esp_event_init();
wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT();
esp_err_t ret = esp_wifi_init(&config);
ret |= esp_supplicant_init();
ret |= esp_wifi_start();
//安裝配置進(jìn)行WIFI連接
if (IS_ENABLED(CONFIG_ESP32_WIFI_STA_AUTO)) {
wifi_config_t wifi_config = {
.sta = {
.ssid = CONFIG_ESP32_WIFI_SSID,
.password = CONFIG_ESP32_WIFI_PASSWORD,
},
};
ret = esp_wifi_set_mode(WIFI_MODE_STA);
ret |= esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config);
ret |= esp_wifi_connect();
}
if (ret != ESP_OK) {
LOG_ERR(“Connect failed”);
}
return ret;
}
網(wǎng)絡(luò)初始化, 完成ethernet iface注冊(cè),并注冊(cè)數(shù)據(jù)接收callback,
static void eth_esp32_init(struct net_if *iface)
{
const struct device *dev = net_if_get_device(iface);
struct esp32_wifi_runtime *dev_data = DEV_DATA(dev);
dev_data-》iface = iface;
esp32_wifi_iface = iface;
//從ESP32讀出MAC地址,設(shè)置給zephyr的iface
/* Start interface when we are actually connected with WiFi network */
net_if_flag_set(iface, NET_IF_NO_AUTO_START);
esp_read_mac(dev_data-》mac_addr, ESP_MAC_WIFI_STA);
/* Assign link local address. */
net_if_set_link_addr(iface,
dev_data-》mac_addr, 6, NET_LINK_ETHERNET);
//進(jìn)行ethernet初始化
ethernet_init(iface);
//注冊(cè)接收數(shù)據(jù)的callback,當(dāng)hal esp32 wifi驅(qū)動(dòng)收到網(wǎng)絡(luò)封包后會(huì)調(diào)用eth_esp32_rx
esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, eth_esp32_rx);
}
數(shù)據(jù)接收
前面的代碼可以看到注冊(cè)的callback是eth_esp32_rx,hal esp32 wifi驅(qū)動(dòng)收到網(wǎng)絡(luò)封包后會(huì)調(diào)用eth_esp32_rx,eth_esp32_rx會(huì)將網(wǎng)絡(luò)封包直接轉(zhuǎn)發(fā)給IP層
static esp_err_t eth_esp32_rx(void *buffer, uint16_t len, void *eb)
{
struct net_pkt *pkt;
if (esp32_wifi_iface == NULL) {
LOG_ERR(“network interface unavailable”);
return ESP_FAIL;
}
//為封包分配內(nèi)存
pkt = net_pkt_rx_alloc_with_buffer(esp32_wifi_iface, len,
AF_UNSPEC, 0, K_NO_WAIT);
if (!pkt) {
LOG_ERR(“Failed to get net buffer”);
return ESP_FAIL;
}
//將封包數(shù)據(jù)從驅(qū)動(dòng)搬運(yùn)到pkt內(nèi)
if (net_pkt_write(pkt, buffer, len) 《 0) {
LOG_ERR(“Failed to write pkt”);
goto pkt_unref;
}
//將封包抓發(fā)給IP層
if (net_recv_data(esp32_wifi_iface, pkt) 《 0) {
LOG_ERR(“Failed to push received data”);
goto pkt_unref;
}
//通知esp驅(qū)動(dòng)封包數(shù)據(jù)已經(jīng)使用完
esp_wifi_internal_free_rx_buffer(eb);
return ESP_OK;
pkt_unref:
net_pkt_unref(pkt);
return ESP_FAIL;
}
數(shù)據(jù)發(fā)送
數(shù)據(jù)發(fā)送的API在初始化時(shí)將eth_esp32_send注冊(cè)進(jìn)ethernet_api的send, IP層在呼叫L2的send時(shí)會(huì)找到ethernet_send進(jìn)行發(fā)送,ethernet_send調(diào)用就是eth_esp32_send
static int ethernet_send(struct net_if *iface, struct net_pkt *pkt)
{
。。。
//這里api-》send就是注冊(cè)的eth_esp32_send
ret = net_l2_send(api-》send, net_if_get_device(iface), iface, pkt);
。。。
}
static inline int net_l2_send(net_l2_send_t send_fn,
const struct device *dev,
struct net_if *iface,
struct net_pkt *pkt)
{
net_capture_pkt(iface, pkt);
return send_fn(dev, pkt);
}
static int eth_esp32_send(const struct device *dev, struct net_pkt *pkt)
{
const int pkt_len = net_pkt_get_len(pkt);
//找到frame
/* Read the packet payload */
if (net_pkt_read(pkt, DEV_DATA(dev)-》frame_buf, pkt_len) 《 0) {
return -EIO;
}
//使用hal esp32 wifi進(jìn)行發(fā)送
/* Enqueue packet for transmission */
esp_wifi_internal_tx(ESP_IF_WIFI_STA, (void *)DEV_DATA(dev)-》frame_buf, pkt_len);
LOG_DBG(“pkt sent %p len %d”, pkt, pkt_len);
return 0;
}
待確認(rèn)
Wifi的幀結(jié)構(gòu)是802.11, 其幀結(jié)構(gòu)和ethernet不一樣,現(xiàn)在直接將hal esp32 wifi和zephyr ethernet對(duì)接,應(yīng)該是esp做了相應(yīng)的轉(zhuǎn)換,具體如何,待確認(rèn)。
編輯:jq
-
驅(qū)動(dòng)
+關(guān)注
關(guān)注
12文章
1898瀏覽量
86507 -
API
+關(guān)注
關(guān)注
2文章
1559瀏覽量
63505 -
WIFI
+關(guān)注
關(guān)注
81文章
5370瀏覽量
207396 -
ESP
+關(guān)注
關(guān)注
0文章
190瀏覽量
34666 -
開(kāi)源
+關(guān)注
關(guān)注
3文章
3582瀏覽量
43452
原文標(biāo)題:Zephyr ESP32 wifi驅(qū)動(dòng)簡(jiǎn)析
文章出處:【微信號(hào):ZephyrProject,微信公眾號(hào):ZephyrProject】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
ESP32驅(qū)動(dòng)MFRC522 RFID模塊讀寫(xiě)IC卡數(shù)據(jù)

esp32用什么軟件編程
ESP32-WROOM-32E、ESP32-WROOM-32D、ESP32-WROOM-32U 有什么區(qū)別?ESP32-WROOM-32 后綴字母代表的意思是?

請(qǐng)問(wèn)ESP32的網(wǎng)口與WIFI能否共存?
如何使用espidf將esp32做成WiFi中繼?
樂(lè)鑫esp32系列在睡眠模式下保持藍(lán)牙連接的功耗測(cè)試

評(píng)論