分析Zephyr ESP32 WIFI驅動的實現可以更為清晰的掌握esp32 wifi在zephyr上的使用,本文主要分析esp32的wifi驅動如何被集成進Zephyr的驅動,并不涉及esp32 wifi驅動本身API的說明。
框架
目前ESP32 wifi在zephyr上的實現框架如下圖
1. esp_private:
esp提供的wifi驅動,不開源,屬于zephyr的外部module,其API頭文件在moduleshalespressifcomponentsesp_wifiincludeesp_private內
2. adapter
esp提供的zephyr wifi適配層,對esp_private進行封裝專門為zephyr用,屬于zephyr的外部module,其代碼放在moduleshalespressifzephyradaptersrcwifi
3. esp_wifi_drv:
Zephyr中的esp32 wifi驅動,調用adapter,和L2 ethernet進行對接。明明是wifi,不封裝為L2 wifi, 而封裝為L2 ethernet,這可能是目前zephyr對L2 wifi的抽象還不完備,目前只支持offload wifi。
這部分是后文的主要分析內容,代碼在zephyrdriverswifiesp32src
4. L2 ethernet
Zephyr L2 ethernet,提供ethernet初始化/配置/收發功能, 代碼在zephyrsubsys etl2ethernet,本文不做分析
esp_wifi_drv
zephyr的esp32 wifi驅動可以分為初始化,收,發三部分來分析:
初始化
主要是完成L2的初始化,注冊入device初始化函數eth_esp32_dev_init和iface的初始化函數eth_esp32_init已經L2的發送函數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注冊后,在系統啟動時kernel的POST_KERNEL階段調用eth_esp32_dev_init,在net初始化階段調用eth_esp32_init.
eth_esp32_dev_init代碼如下,主要是調用hal中提供的一系列初始化和啟動函數,讓wifi啟動,值得注意的是當CONFIG_ESP32_WIFI_STA_AUTO=y時,zephyr驅動會自動去幫你用配置好的CONFIG_ESP32_WIFI_SSID和CONFIG_ESP32_WIFI_PASSWORD去連接Wifi。
如果沒有配置,就需要在應用代碼中直接調用esp hal的API進行連接,另外就是zephyr目前并沒有將esp32 wifi的scan/connect/disconnect做到L2 WIFI內進行管理,可以參考Zephyr網絡管理模塊分析-注冊請求機制, 這邊部分也需要在應用中直接調用esp hal的API進行管理。
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();
//安裝配置進行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;
}
網絡初始化, 完成ethernet iface注冊,并注冊數據接收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地址,設置給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);
//進行ethernet初始化
ethernet_init(iface);
//注冊接收數據的callback,當hal esp32 wifi驅動收到網絡封包后會調用eth_esp32_rx
esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, eth_esp32_rx);
}
數據接收
前面的代碼可以看到注冊的callback是eth_esp32_rx,hal esp32 wifi驅動收到網絡封包后會調用eth_esp32_rx,eth_esp32_rx會將網絡封包直接轉發給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;
}
//為封包分配內存
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;
}
//將封包數據從驅動搬運到pkt內
if (net_pkt_write(pkt, buffer, len) 《 0) {
LOG_ERR(“Failed to write pkt”);
goto pkt_unref;
}
//將封包抓發給IP層
if (net_recv_data(esp32_wifi_iface, pkt) 《 0) {
LOG_ERR(“Failed to push received data”);
goto pkt_unref;
}
//通知esp驅動封包數據已經使用完
esp_wifi_internal_free_rx_buffer(eb);
return ESP_OK;
pkt_unref:
net_pkt_unref(pkt);
return ESP_FAIL;
}
數據發送
數據發送的API在初始化時將eth_esp32_send注冊進ethernet_api的send, IP層在呼叫L2的send時會找到ethernet_send進行發送,ethernet_send調用就是eth_esp32_send
static int ethernet_send(struct net_if *iface, struct net_pkt *pkt)
{
。。。
//這里api-》send就是注冊的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進行發送
/* 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;
}
待確認
Wifi的幀結構是802.11, 其幀結構和ethernet不一樣,現在直接將hal esp32 wifi和zephyr ethernet對接,應該是esp做了相應的轉換,具體如何,待確認。
編輯:jq
-
驅動
+關注
關注
12文章
1825瀏覽量
85178 -
API
+關注
關注
2文章
1485瀏覽量
61814 -
WIFI
+關注
關注
81文章
5287瀏覽量
203282 -
ESP
+關注
關注
0文章
181瀏覽量
33885 -
開源
+關注
關注
3文章
3247瀏覽量
42402
原文標題:Zephyr ESP32 wifi驅動簡析
文章出處:【微信號:ZephyrProject,微信公眾號:ZephyrProject】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論