分析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,
ð_data, null, config_eth_init_priority,
ð_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做了相应的转换,具体如何,待确认。
易能电气:OEM细分行业市场取得了较大的突破
VPC3215各引脚功能的电压资料
漏电保护器的使用是防止什么
一加5什么时候上市?一加5最新消息:一加5配置、做工、售价曝光,手机界的一把手
RHA推出全球首款支持以无线连接的平板单元耳机
简析esp32的wifi驱动如何被集成进Zephyr的驱动
回顾旭宇光电2020年的发展成果
特高频局部放电检测仪的设计方案
智慧大田种植管理系统,提升农业生产质量
4D成像雷达正进入规模量产落地期
PCB设计时应该注意检查什么
SQL语句大全实例
基于MSP430F149单片机和总线技术实现智能变送器的设计
我国已进入IPv6+阶段,未来将实现真正的网随云动、万物智联
混合信号PCB布局设计的基本准则
小米MAX2发布会现场最新消息:小米MAX2发布会惊现华为Loge来个视频看个究竟
博通推出第一个802.11ac(5G WiFi)芯片系列
脑虎科技发布首款脑机接口集成式颅顶半植入医用级脑机接口产品
华硕预热高性能轻薄笔记本 realme配件全家桶曝光
基于FPGA的OLED真彩色显示设计方案