ESP-Hosted 入门介绍 &使用指南

ESP-Hosted 解决方案可将 ESP 板用作通信处理器,为主机添加网络和 HCI 接口。介绍了其基本功能,如 Wi-Fi、BT/BLE 功能,支持的芯片型号、主机及传输方式。还详细说明了基于 Linux 的 SDIO 通讯步骤,包括硬件连接、设备端和 host 端设置、验证及故障排除等。

ESP-Hosted 解决方案提供了将 ESP 板用作 Wi-Fi 和 Bluetooth/BLE 连接的通信处理器的方法。基本上为主机添加了一个网络接口和一个 HCI 接口,允许它与其他设备进行通信。

注:对于主机和 ESP 板之间的控制路径,ESP-Hosted 使用基于 Protobuf 的自定义实现。

1 基本功能与支持

  • Wi-Fi 功能 :802.11 b/g/n
  • BT/BLE 功能:v4.2 BR/EDR 和 BLE
  • 支持的 ESP 芯片型号:目前支持 ESP32, ESP32S2
  • 支持的主机:
    • 基于 linux 的主机 (树莓派 3 B 型,树莓派 3 型号 B+,Raspberry-Pi 4 模型 B) (支持 4.x 内核版本。 很快就会有 5.x 内核版本支持。 它实际上也适用于 5.x 内核,但有一些问题需要还待解决)
    • 基于 MCU 的主机, STM32 探索板 (STM32F469I-DISCO)
  • 支持的传输方式
    • ESP-Hosted 使用 UART, SDIO 或 SPI 总线来连接 ESP 板和主机平台。

不同的 ESP 设备支持不同的接口,下表说明了基于 Linux 主机的不同传输接口支持的不同功能。
在这里插入图片描述

下表说明了基于 MCU 主机的不同传输接口支持的不同功能。
在这里插入图片描述

2 基于 linux 的 SDIO 通讯步骤

  • 硬件连接需求

    • Raspberry-Pi model 3 Model B/B+ or Raspberry-Pi 4 model B
    • ESP32 board
    • 8-12 根 10 cm 长的跳线(短于 10 cm 长度的连接线)
  • 设备端(ESP32/ESP32S2)

  • host 端 (linux 系统)

  • 设置验证

    • 使用以下命令验证主机上是否可以看到ethsta0和ethap0接口。

       $ ifconfig -a
      
    • 使用以下命令验证 hci0 接口是否存在

       $ hciconfig
      

      如下图所示:
      在这里插入图片描述

  • 测试 Wi-Fi 和 BT/BLE 功能

    此处可参考 ESP-Hosted with Linux Host (Raspberry-Pi) 用户指南。参考如下:

在这里插入图片描述
在这里插入图片描述

在设置过程中会出现有几种情况:

  1. 出现 /lib/modules/4.14.50-v7+/build: No such file or directory.
make ARCH=arm CROSS_COMPILE= -C /lib/modules/4.14.50-v7+/build M=/tmp/rtl8812au  modules
make[1]: *** /lib/modules/4.14.50-v7+/build: No such file or directory.  Stop.
Makefile:1052: recipe for target 'modules' failed
make: *** [modules] Error 2

出现如上的情况,这是因为安装 kernel-headers 有问题导致的,这个需要重新安装,可以通过如下命令:

sudo apt-get update && sudo apt-get install --reinstall raspberrypi-bootloader raspberrypi-kernel
sudo apt-get install raspberrypi-kernel-headers
reboot

然后再运行 ./rpi_init.sh sdio,将会看到如下截图所示:

在这里插入图片描述

然后可以在 host_driver/esp32 下会有esp32_sdio.ko 生成,如下图所示:

在这里插入图片描述

  1. 如果要用蓝牙模块,需要安装 bluez 工具。可参考 Linux_based_readme
<think> 我们参考了多个引用资料,这些资料详细介绍了Linux系统中SPI驱动框架的各个组成部分及其相互关系。根据引用内容,我们可以将SPI驱动框架分为三个核心部分:SPI核心层(SPI Core)、SPI主机驱动(SPI Master Driver)和SPI设备驱动(SPI Device Driver)。下面我们将逐一介绍这三个部分,并说明它们如何协同工作。 ### 1. SPI核心层(SPI Core) SPI核心层是Linux SPI驱动框架的中间层,它提供了一系列通用的接口和函数,用于连接SPI主机驱动和SPI设备驱动。其主要功能包括: - 注册SPI总线(`spi_bus_type`)以及管理总线上的设备与驱动匹配。 - 提供SPI控制器(主机)和SPI设备驱动的注册和注销接口。 - 提供数据传输的通用函数(如`spi_sync`, `spi_async`等),供设备驱动使用。 引用[3]提到:“SPI核心层是SPI子系统的中间层,提供了一个通用的接口以便设备驱动可以与SPI主机驱动交互。” 同时,引用[2]也指出SPI核心层负责“注册SPI总线以及匹配总线与设备”。 ### 2. SPI主机驱动(SPI Master Driver) SPI主机驱动直接与硬件SPI控制器交互,负责底层的硬件操作。在Linux内核中,SPI主机驱动由`spi_master`结构体表示(引用[5])。主要职责包括: - 初始化SPI控制器硬件(如时钟、引脚等配置)。 - 实现数据传输的具体方法(如`transfer`函数)。 - 通过SPI核心层注册到系统中,以便设备驱动可以访问。 引用[1]提到:“spi_master负责管理SPI总线,为spi_device提供通信的基础。” 引用[5]进一步指出:“SPI主机驱动就是SOC的SPI控制器驱动,类似I2C驱动里面的适配器驱动。” ### 3. SPI设备驱动(SPI Device Driver) SPI设备驱动针对具体的SPI从设备(如传感器、存储器等),通过`spi_driver`结构体实现(引用[4])。主要工作包括: - 定义设备ID表(`id_table`)用于与设备匹配。 - 实现`probe`、`remove`等函数,用于设备的初始化和卸载。 - 通过SPI核心层提供的接口(如`spi_read`、`spi_write`)与设备通信。 引用[4]给出了`spi_driver`结构体的定义,并说明我们在编写设备驱动时需要实现这个结构体。 ### 4. SPI设备(SPI Device) 除了上述三个核心部分,还有一个重要的概念是SPI设备(`spi_device`),它代表一个具体的SPI从设备。在设备树(Device Tree)中描述,并在系统启动时由内核解析并创建。`spi_device`包含该设备的配置信息(如最大速度、模式等)。 ### 协同工作流程 1. **注册SPI主机驱动**:SPI控制器驱动程序(主机驱动)在初始化时,通过`spi_register_master()`函数向SPI核心层注册自己。 2. **注册SPI设备**:设备树中定义的SPI从设备会在系统启动时被内核解析,并创建对应的`spi_device`,然后注册到SPI总线上。 3. **注册SPI设备驱动**:设备驱动通过`spi_register_driver()`注册自己,其`id_table`会与已注册的`spi_device`进行匹配。 4. **匹配与探测**:当匹配成功时,设备驱动的`probe`函数被调用,完成设备初始化。 5. **数据传输**:设备驱动通过SPI核心层提供的接口(如`spi_sync_transfer()`)发起数据传输请求,该请求最终会调用主机驱动实现的`transfer`函数。 ### 开发SPI设备驱动的步骤 1. **定义`spi_driver`结构体**:设置`id_table`、`probe`、`remove`等函数。 2. **实现`probe`函数**:在`probe`函数中初始化设备,例如配置寄存器、申请资源、注册字符设备等。 3. **实现数据传输函数**:使用SPI核心层提供的API(如`spi_write_then_read()`)与设备通信。 4. **注册驱动**:在模块初始化函数中调用`spi_register_driver()`。 5. **注销驱动**:在模块退出函数中调用`spi_unregister_driver()`。 ### 示例代码片段 以下是一个简单的SPI设备驱动示例(伪代码): ```c #include <linux/spi/spi.h> static int my_spi_probe(struct spi_device *spi) { // 获取设备配置(如模式、速度等) spi->mode = SPI_MODE_0; spi->max_speed_hz = 1000000; spi_setup(spi); // 设备初始化操作 // ... return 0; } static int my_spi_remove(struct spi_device *spi) { // 清理资源 // ... return 0; } static const struct spi_device_id my_spi_id_table[] = { { "my_spi_device", 0 }, { } }; MODULE_DEVICE_TABLE(spi, my_spi_id_table); static struct spi_driver my_spi_driver = { .driver = { .name = "my_spi_driver", .owner = THIS_MODULE, }, .id_table = my_spi_id_table, .probe = my_spi_probe, .remove = my_spi_remove, }; module_spi_driver(my_spi_driver); // 自动注册和注销驱动 ``` ### 总结 Linux SPI驱动框架通过分层设计,将硬件控制(主机驱动)、设备驱动和核心层分离,提高了代码的复用性和可维护性。开发人员通常只需关注设备驱动的实现,而无需直接操作硬件控制器。 §§相关问题§§ 1. 如何在设备树中描述一个SPI设备节点? 2. SPI主机驱动中的`transfer`函数需要实现哪些功能? 3. SPI设备驱动中如何实现同步和异步数据传输? 4. 如何调试Linux SPI驱动? </think>### Linux SPI 驱动框架详解 Linux SPI 驱动采用分层架构设计,主要由三个核心组件构成: #### 1. **SPI主机控制器驱动(spi_master)** - **作用**:管理物理SPI控制器硬件 - **功能**: - 初始化SPI控制器时钟/寄存器 - 实现底层数据传输接口(如`transfer()`函数) - 提供总线访问能力 - **数据结构**: ```c struct spi_master { struct device dev; int (*transfer)(struct spi_device *spi, struct spi_message *mesg); // 其他硬件操作函数 }; ``` - **注册方式**:`spi_register_master()`[^5] #### 2. **SPI设备抽象(spi_device)** - **作用**:描述连接的SPI从设备 - **配置信息**: - 片选号(CS) - 通信模式(CPOL/CPHA) - 最大时钟频率 - **创建方式**: - 设备树描述(推荐): ```dts &spi1 { status = "okay"; sensor@0 { compatible = "vendor,spi-sensor"; reg = <0>; // 片选号 spi-max-frequency = <1000000>; }; }; ``` - 或通过`spi_new_device()`动态创建[^1] #### 3. **SPI设备驱动(spi_driver)** - **作用**:实现具体设备的功能逻辑 - **核心结构**: ```c struct spi_driver { const struct spi_device_id *id_table; int (*probe)(struct spi_device *spi); int (*remove)(struct spi_device *spi); struct device_driver driver; }; ``` - **关键操作**: - **probe()**:设备初始化,资源分配 - **remove()**:资源释放 - 实现文件操作接口(如read/write)[^4] ### 数据传输流程 1. **构造消息**: 使用`spi_message`结构封装传输请求 ```c struct spi_transfer xfer = { .tx_buf = tx_data, .rx_buf = rx_data, .len = len }; spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); ``` 2. **提交传输**: 同步传输:`spi_sync(spi, &msg)` 异步传输:`spi_async(spi, &msg)` 3. **硬件执行**: `spi_master->transfer()` 被调用,控制器处理物理信号[^5] ### 驱动开发步骤 1. **注册驱动**: ```c static struct spi_driver my_driver = { .driver = { .name = "my_spi_dev" }, .probe = my_probe, .remove = my_remove, .id_table = my_spi_ids, }; module_spi_driver(my_driver); ``` 2. **实现probe函数**: ```c static int my_probe(struct spi_device *spi) { // 1. 验证配置 spi->mode = SPI_MODE_0; spi_setup(spi); // 2. 分配设备数据 struct my_data *data = devm_kzalloc(&spi->dev, sizeof(*data), GFP_KERNEL); // 3. 初始化设备(如寄存器配置) spi_write(spi, init_seq, sizeof(init_seq)); // 4. 注册字符设备/创建sysfs节点 misc_register(&my_miscdev); } ``` 3. **实现数据传输**: ```c uint8_t read_reg(struct spi_device *spi, uint8_t reg) { uint8_t tx[2] = {reg, 0}; uint8_t rx[2]; struct spi_transfer t = { .tx_buf = tx, .rx_buf = rx, .len = 2, }; spi_sync_transfer(spi, &t, 1); return rx[1]; } ``` ### 关键API函数 | 函数 | 作用 | |------|------| | `spi_write()` | 同步写操作 | | `spi_read()` | 同步读操作 | | `spi_write_then_read()` | 先写后读组合操作 | | `spi_sync_transfer()` | 高级传输控制 | | `spi_message_init()` | 初始化消息结构 | ### 调试技巧 1. 启用SPI层调试:`echo 1 > /sys/module/spi/parameters/debug` 2. 查看注册的设备:`cat /sys/bus/spi/devices/*/uevent` 3. 使用逻辑分析仪抓取SCK/MOSI/MISO信号
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值