ESP-HOSTED-Linux Setup

August 26, 2026 · View on GitHub

1 Setup Introduction

1. Software setup

  • This section briefly explains software setup required for esp hosted device and host. Esp hosted device setup is divided into two parts
    • Host software setup This section provides information about installation of required packages for host device
    • ESP Quick start guide This section briefly explains ESP-Hosted setup. One can refer this guide to quickly prepare and test ESP-Hosted solution
    • ESP Comprehensive guide This section provides in depth information about ESP-Hosted setup, available customization options etc. Use Quick start guide for easy setup or Comprehensive guide for customizable setup.

1.1 Host software setup

Make sure that host machine is equipped with following:

  • Linux Kernel Setup

    • We recommend full version Raspbian install on Raspberry-Pi to ensure easy driver compilation.
    • Please make sure to use kernel version v4.19 and above. Prior kernel versions may work, but are not tested.
    • Kernel headers are required for driver compilation. Please install them as:
      $ sudo apt update
      $ sudo apt install raspberrypi-kernel-headers
      
    • Verify that kernel headers are installed properly by running following command. Failure of this command indicates that kernel headers are not installed correctly. In such case, follow https://github.com/RPi-Distro/rpi-source/wiki and run rpi-source to get current kernel headers. Alternatively upgrade/downgrade kernel and reinstall kernel headers.
      $ ls /lib/modules/$(uname -r)/build/
      
  • Following tools are required on Raspberry-Pi:

    • Git
    • Raspi-gpio utility
    • bluetooth
    • bluez
    • bluez-tools
    • rfkill
    • bluez-firmware
    • pi-bluetooth
      $ sudo apt install git raspi-gpio bluetooth bluez bluez-tools rfkill bluez-firmware pi-bluetooth
      
    • We suggest latest stable bluez version to be used. Any other bluetooth stack instead of bluez also could be used.
  • More transport layer specific host software setup can be found here Transport layer configuration

1.2 ESP Quick Start Guide

  • With the help of this guide, one can easily setup and start using ESP-Hosted solution with Raspberry-Pi as a host.
  • This section makes use of pre-built ESP firmware release binaries and default configuration.
  • Pre-built ESP firmware binaries are available on releases.
  • Please download the latest release.
  • Windows user can use ESP Flash Programming Tool to flash the pre-built ESP binaries.
  • Linux or Mac users can use esptool.py to flash the pre-built ESP binaries. To install, please run:
    $ pip install esptool
    
  • Please browse to desired ESP chipset directory
    $ tar xvf ESP-HOSTED-Linux-release_1.x.y.tgz
    $ cd ESP-HOSTED-Linux-release_1.x.y/
    $ cd <esp_chipset>
    $ cd <transport_layer>
    
  • here,
    • For SDIO
      • <esp_chipset> can be esp32.
      • <transport_layer> can be sdio_only or sdio+uart
    • For SPI
      • <esp_chipset> can be esp32, esp32c3, esp32s3,esp32c2.
      • <transport_layer> can be spi_only or spi+uart
  • Run the flashing command from flashing_cmd.txt file.
  • Follow these steps to setup required configurations for desired transport layer Transport layer configuration

1.3 ESP Comprehensive guide

  • FOR linux based systems.
  • Install the ESP-IDF using script

Caution

This command will revert all your local changes. Stash the changes if still needed.

```sh
$ cd esp/esp_driver
$ ./setup.sh
```
  • This will clone the required esp-idf repository and will setup it up for esp hosted firmware
  • Set-Up the esp firmware build environment using
    $ cd esp/esp_driver/esp-idf
    $ . ./esp-idf/export.sh
    # Optionally, You can add alias for this command in ~/.bashrc for later use
    
  • To build, flash and monitor firmware
    $ cd esp/esp_driver/network_adapter
    $ `idf.py set-target <chip_name>` to set target
    $ `idf.py build` to compile new firmware
    $ `idf.py monitor` to monitor serial output
    

Caution

This command will revert all your local changes. Stash the changes if still needed.

  • Setup compiling environment by running export.ps1 in esp/esp_driver/esp-idf directory
  • To build, flash and monitor firmware

    $ cd esp/esp_driver/network_adapter
    $ `idf.py set-target <chip_name>` to set target
    $ `idf.py build` to compile new firmware
    $ `idf.py monitor` to monitor serial output
    
  • Once the environment is ready for esp firmware to be built follow these steps to setup required configurations for desired transport layer Transport layer configuration

2. Transport layer configuration

  • This section will provide all required configuration to be made for required desired transport layer.
  • Hardware requirements
    1. 8-12 jumper wires of length < 10cm.
    2. ESP32, ESP32 C3, ESP32 S3, ESP32 C2 board.
    3. Raspberry-Pi 3 model B/B+ or Raspberry-Pi 4 model B
  • This is section is divided into following transport layers.
    1. SPI configuration Wi-Fi and Bluetooth over SPI
    2. SDIO configuration Wifi and bluetooth over SDIO
    3. SDIO or SPI + Uart configuration Wi-Fi over SDIO and Bluetooth over UART

2.1 SPI configuration

Wi-Fi and Bluetooth over SPI

Supported TargetsESP32ESP32-S2ESP32-S3ESP32-C2ESP32-C3ESP32-C5ESP32-C6/C61
  • Hardware setup
    • In this setup, ESP board acts as a SPI peripheral and provides Wi-Fi capabilities to host. Please connect ESP board to Raspberry-Pi with jumper cables as mentioned below. Please use short jumper cables to ensure signal integrity. Raspberry Pi should be powered with correct incoming power rating. ESP can be powered through PC using micro-USB/USB-C cable.

    • Pin Connections

      Raspberry-Pi PinESP32ESP32-S2/S3ESP32-C2/C3/C5/C6ESP32-C61Function
      24IO15IO10IO10IO8CS0
      23IO14IO12IO6IO6SCLK
      21IO12IO13IO2IO2MISO
      19IO13IO11IO7IO7MOSI
      25GNDGNDGNDGNDGround
      15IO2IO2IO3IO3Handshake
      13IO4IO4IO4IO4Data Ready
      31ENRSTRSTRSTESP32 Reset
    • Raspberry-Pi pinout can be found here!

    • Optionally, Add external pull-up of min 10k Ohm on CS line just to prevent bus floating

    • In case of ESP32-S3, For avoidance of doubt, You can power using UART port

  • Raspberry-Pi Setup
    • The SPI master driver is disabled by default on Raspberry-Pi OS. To enable it add following commands in /boot/config.txt file
      dtparam=spi=on
      dtoverlay=disable-bt
      
    • In addition, below options are set as the SPI clock frequency in analyzer is observed to be smaller than expected clock. This is RaspberryPi specific issue.
      core_freq=250
      core_freq_min=250
      
    • Please reboot Raspberry-Pi after changing this file.
  • Setting up the environment and getting started
    • Host environment setup
      • Execute following commands in root directory of cloned ESP-Hosted repository on Raspberry-Pi
        $ cd host/
        $ bash rpi_init.sh spi <ap_support>
        
      • add ap_support if you want to use interface as access point.
      • This script compiles and loads host driver on Raspberry-Pi. It also creates network interface wlanX which is used as a control interface for Wi-Fi on ESP peripheral

      • Follow these steps to Manually load the Kernel Module

    • For esp firmware if you are using ESP Quick start guide
      • Please flash the required binaries using with command mentioned in flashing_cmd.txt within desired transport configuration folder as explained in ESP Quick start guide.
      • Use minicom or any similar terminal emulator with baud rate 115200 to fetch esp side logs on UART
        $ minicom -D <serial_port>
        
      • serial_port is device where ESP chipset is detected. For example, /dev/ttyUSB0
    • For esp firmware if you are using ESP Comprehensive guide.
      • Set up the esp-idf environment as mentioned in ESP Comprehensive guide
      • To configure slave chip set environment
        $ cd esp/esp_driver/network_adapter
        $ rm -rf sdkconfig build
        $ idf.py set-target <esp_chipset>
        
      • For SPI, <esp_chipset> could be one of esp32, esp32s2, esp32s3, esp32c2, esp32c3, esp32c6, esp32c61.
      • Execute following command to configure the project
        $ idf.py menuconfig
        
      • This will open project configuration window. To select SPI transport interface, navigate to Example Configuration -> Transport layer -> SPI interface -> select and exit from menuconfig.
      • For ESP32-C3, select chip revision in addition. Navigate to Component config → ESP32C3-Specific → Minimum Supported ESP32-C3 Revision and select chip version of ESP32-C3.
      • Use below command to compile and flash the project. Replace <serial_port> with ESP peripheral's serial port.
        $ idf.py -p <serial_port> build flash
        
      • Collect the firmware log using
        $ idf.py -p <serial_port> monitor
        
  • Checking the Setup
    • On successful flashing and host driver installation, you should see following entry in ESP log:
      [   77.877892] Features supported are:
      [   77.877901]   * WLAN
      [   77.877906]   * BT/BLE
      [   77.877911]     - HCI over SPI
      [   77.877916]     - BLE
      
  • Once the one of ESP-HOSTED-Linux mode is set-up, proceed to how to use Wi-Fi and Bluetooth over this setup

2.2 SDIO configuration

Wi-Fi and Bluetooth over SDIO

Supported TargetsESP32ESP32-C5ESP32-C6/C61
  • Hardware setup

    • In this setup, ESP board acts as a SDIO peripheral and provides Wi-Fi capabilities to host. Please connect ESP board to Raspberry-Pi with jumper cables as mentioned below. Raspberry Pi should be powered with correct incoming power rating. ESP can be powered through PC using micro-USB/USB-C cable.

    • Pin connections

      Raspberry-Pi PinESP32 PinESP32-C6 PinESP32-C5ESP32-C61 PinFunction
      13IO13+pull-upIO23+pull-upIO13+pull-upIO23+pull-upDAT3
      15IO14IO19IO9IO26CLK
      16IO15+pull-upIO18+pull-upIO10+pull-upIO25+pull-upCMD
      18IO2+pull-upIO20+pull-upIO8+pull-upIO27+pull-upDAT0
      22IO4+pull-upIO21+pull-upIO7+pull-upIO28+pull-upDAT1
      31ENESP ResetESP ResetESP ResetReset
      37IO12+pull-upIO22+pull-upIO14+pull-upIO22+pull-upDAT2
      39GNDGNDGNDGNDGND
    • Raspberry-Pi pinout can be found here!

    • As SDIO faces signal integrity issues over jumper wires, we strongly recommend to Design PCB boards with above connections. If that is not possible. Use good quality extremely small (smaller than 5cm) jumper wires, all equal length. Join all possible grounds interconnected to lower noise. Add at least, 10k Ohm external pull-up resistors on 5 lines: CMD, DAT0-4. We use 51k Ohm resistors in our set-up.

  • Raspberry-Pi Setup

    • By default, the SDIO pins of Raspberry-pi are not configured and are internally used for built-in Wi -Fi interface. Please enable SDIO pins by appending following line to /boot/config.txt file
      dtoverlay=sdio,poll_once=off
      dtoverlay=disable-bt
      
    • Please reboot Raspberry-Pi after changing this file.
  • Setting up the environment and getting started

    • Host environment setup
      • Execute following commands in root directory of cloned ESP-Hosted repository on Raspberry-Pi
        $ cd host/
        $ bash rpi_init.sh sdio <ap_support>
        
      • add ap_support if you want to use interface as access point.
      • This script compiles and loads host driver on Raspberry-Pi. It also creates network interface wlanX which is used for Wi-Fi in host.

      • Follow these steps to Manually load the Kernel Module

    • For esp firmware if you are using ESP Quick start guide
      • Please flash the required binaries using with command mentioned in flashing_cmd.txt within desired transport configuration folder as explained in ESP Quick start guide.
      • Use minicom or any similar terminal emulator with baud rate 115200 to fetch esp side logs on UART
        $ minicom -D <serial_port>
        
      • serial_port is device where ESP chipset is detected. For example, /dev/ttyUSB0
    • For esp firmware if you are using ESP Comprehensive guide.
      • Set up the esp-idf environment as mentioned in ESP Comprehensive guide
      • To configure slave chip set environment
        $ cd esp/esp_driver/network_adapter
        $ rm -rf sdkconfig build
        $ idf.py set-target <esp_chipset>
        
      • For SDIO, <esp_chipset> could be esp32, esp32c5, esp32c6, esp32c61.
      • Execute following command to configure the project
        $ idf.py menuconfig
        
      • This will open project configuration window. To select SDIO transport interface, navigate to Example Configuration -> Transport layer -> SDIO interface -> select and exit from menuconfig.
      • Use below command to compile and flash the project. Replace <serial_port> with ESP peripheral's serial port.
        $ idf.py -p <serial_port> build flash
        
      • Collect the firmware log using
        $ idf.py -p <serial_port> monitor
        
  • Checking the Setup

    • On successful flashing and host driver installation, you should see following entry in ESP log:
      [   77.877892] Features supported are:
      [   77.877901]   * WLAN
      [   77.877906]   * BT/BLE
      [   77.877911]     - HCI over SDIO
      [   77.877916]     - BT/BLE dual mode
      
  • Once the one of ESP-HOSTED-Linux mode is set-up, proceed to how to use Wi-Fi and Bluetooth over this setup

2.3 SDIO or SPI and Uart configuration

Wi-Fi over SDIO/SPI and Bluetooth over UART

Supported ChipsetsESP32ESP32-C2ESP32-C3ESP32-S3ESP32-C5ESP32-C6ESP32-C61
4 line UART supportedyesnoyesyesnonono
2 line UART supportedyesyesyesyesyesyesyes
  • In this section, ESP chipset provides a way to run Bluetooth/BLE over UART interface.

  • This section is divided in two parts

  • Wi-fi over SPI and Bluetooth over UART

    • Supported targets ESP32, ESP32S3, ESP32C3, ESP32C2, ESP32C5, ESP32C6, ESP32C61
    • Please follows these steps first to setup esp device in SPI mode SPI configuration
  • Wi-fi over SDIO and Bluetooth over UART

    • Supported targets ESP32, ESP32C5, ESP32C6, ESP32C61
    • Please follows these steps first to setup esp device in SDIO mode SDIO configuration
  • Hardware Uart setup

    • Pin Connections

    • Four line setup

      Raspberry-Pi Pin FunctionRaspberry-Pi PinESP32ESP32-S3ESP32-C3ESP32 Pin Function
      RX10IO5IO17IO5TX
      TX8IO18IO18IO18RX
      CTS36IO19IO19IO19RTS
      RTS11IO23IO20IO8CTS
    • Two line setup

      Raspberry-Pi Pin FunctionRaspberry-Pi PinESP32-C2ESP32-C5ESP32-C6ESP32-C61ESP Function
      RX10IO5IO23IO5IO13TX
      TX8IO18IO24IO12IO12RX
    • Raspberry-Pi pinout can be found here!

    • In case you wish to reduce number of hardware lines, you may consider SPI_only or SDIO_only transports, where Wi-Fi and Bluetooth traffic is multiplexed on same bus and no need of extra UART pins. UART pin numbers are configurable. If you want to switch from 4 line UART mode to 2 lines, hardware flow control need to be turned off.

    • Use good quality small (smaller than 10cm) jumper wires, all equal length

  • Raspberry-Pi Setup

    • By default, the UART pins on Raspberry-Pi are in disabled state. In order to enable UART and setup it for bluetooth connection, follow below steps.
      1. Enable UART pins and disable in built bluetooth on Raspberry-Pi by appending following lines to /boot/config.txt file
        enable_uart=1
        dtoverlay=disable-bt
        
      2. Remove following from /boot/cmdline.txt. Leave everything else untouched.
        console=serial0,115200
        
        e.g. If /boot/cmdline.txt is as below:
        $ cat /boot/cmdline.txt
        dwc_otg.lpm_enable=0 console=tty1 console=serial0,115200 root=PARTUUID=5c2c80d1-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles spidev.bufsiz=32768
        
        Then after removal of above mentioned arguments, it should look as below:
        $ cat /boot/cmdline.txt
        dwc_otg.lpm_enable=0 console=tty1 root=PARTUUID=5c2c80d1-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles spidev.bufsiz=32768
        
      3. Disable hciuart on Raspberry-Pi
        $ sudo systemctl disable hciuart
        
    • Please reboot Raspberry-Pi after changing this file.
  • Setting up the environment and getting started

    • Host environment setup
      • Execute following commands in root directory of cloned ESP-Hosted repository on Raspberry-Pi
        $ cd host/
        $ bash rpi_init.sh <transport> <bt_over_uart> <ap_support>
        
      • transport can take value sdio or spi. Defaults to sdio
      • bt_over_uart can take value btuart or btuart_2pins.
      • add ap_support if you want to use interface as access point.
      • :warning: Note:
      • For ESP32-C2, 2 pin UART (TX & RX only) is supported. So btuart_2pins should be used for ESP32-C2.
      • For other chipsets, btuart should be used, where 4 pin UART (TX, RX, CTS, RTS) is used.
    • For esp firmware if you are using ESP Quick start guide
      • Please flash the required binaries using with command mentioned in flashing_cmd.txt within desired transport configuration folder as explained in ESP Quick start guide.
      • Use minicom or any similar terminal emulator with baud rate 115200 to fetch esp side logs on UART
        $ minicom -D <serial_port>
        
      • serial_port is device where ESP chipset is detected. For example, /dev/ttyUSB0
    • For esp firmware if you are using ESP Comprehensive guide.
      • Set up the esp-idf environment as mentioned in ESP Comprehensive guide

      • To configure slave chip set environment

        $ cd esp/esp_driver/network_adapter
        $ rm -rf sdkconfig build
        $ idf.py set-target <esp_chipset>
        
      • For SDIO, <esp_chipset> could be esp32, esp32c5, esp32c6, esp32c61. For SPI, it could be esp32, esp32s2, esp32s3, esp32c2, esp32c3, esp32c5, esp32c6, esp32c61.

      • Execute following command to configure the project

        $ idf.py menuconfig
        
      • Set ESP-Hosted transport

        • ESP32
          • Select transport either SDIO or SPI
          • Navigate to Example Configuration -> Transport layer select SDIO interface or SPI interface, whichever expected
        • ESP32-C3/S3
          • SPI is automatically selected. Nothing to be done, skip to next step
      • Set Bluetooth over UART

        • ESP32 / ESP32-C3/S3
          • navigate to Component config -> Bluetooth -> Bluetooth controller -> HCI mode, select UART(H4)
      • Set UART baud rate

        • Default HCI over baud rate is 921600. In case need to change,
        • ESP32
          • Navigate and change using Component config -> Bluetooth -> Bluetooth controller -> HCI UART(H4) Options -> UART Baudrate for HCI
        • ESP32-C3/S3
          • Navigate and change using Component config -> Example Configuration -> UART Baudrate for HCI
      • Additional settings

        • ESP32-C3
          • Select chip revision in addition. Navigate to Component config → ESP32C3-Specific → Minimum Supported ESP32-C3 Revision and select chip version of ESP32-C3.
      • Build and flash the project. Replace <serial_port> with ESP peripheral's serial port.

        $ idf.py -p <serial_port> build flash
        
  • Post Setup

    • After setting up host and loading ESP firmware, execute below command to create hci0 interface

      $ sudo hciattach -s <baud_rate> /dev/serial0 any <baud_rate> flow
      
    • <baud_rate> should match UART baud rate while flashing ESP peripheral (Default: 921600)

    • For ESP32

      • Check CONFIG_BT_HCI_UART_BAUDRATE parameter in esp/esp_driver/network_adapter/sdkconfig
      • Alternatively baud rate could be located using idf.py menuconfig at, Component config -> Bluetooth -> Bluetooth controller -> HCI UART(H4) Options -> UART Baudrate for HCI
    • For ESP32-C3/S3

      • Check CONFIG_EXAMPLE_HCI_UART_BAUDRATE parameter in esp/esp_driver/network_adapter/sdkconfig
      • Alternatively baud rate could be located using idf.py menuconfig at, Component config -> Example Configuration -> UART Baudrate for HCI
    • Check if UART is setup correctly

      $ hciconfig
      

      Should list the hci interface with bus as 'UART' and interface should be 'UP'

  • Points to note

    • Restart HCI on every reloading of kernel module
    • Remove and reattach HCI over UART
      $ hciconfig -a
      $ sudo killall hciattach
      $ sudo hciattach -s <baud_rate> /dev/serial0 any <baud_rate> flow
      $ hciconfig -a
      
    • <baud_rate> should match UART baud rate while flashing ESP peripheral
  • Once the one of ESP-HOSTED-Linux mode is set-up, proceed to how to use Wi-Fi and Bluetooth over this setup

3. Troubleshoot Setup Problems

After following above steps, the host software should be loaded fine. Boot-up event from ESP should already would have sent and Host should have received it.

If Boot-up event is not received in host dmesg as sample log above, please try following:

  • Please check your connections to be firm
  • Try with smaller wires
  • Check correct Pull-Ups are in place
  • If using different host than Raspberry-Pi, please check porting guide
  • Check Troubleshoot Guide for further details

4. Points to note

  • This solution is tested BR/EDR(Classic BT) 4.2 and BLE 4.2 functionalities with BlueZ 5.43+.
  • We suggest to use the latest stable BlueZ release.

5. Ota support

  • Over-The-Air (OTA) allows hosts to transport the new firmware to ESP device and update the device.
  • To update the firmware using the OTA please follow the commands on host.
    $ cd host/
    $ ./rpi_init.sh <transport> ota_file="/path/to/ota_file"
    

6. Manually loading and unloading the Kernel Module

Once the kernel modules esp32_sdio.ko or esp32_spi.ko are built, they can be found in host/. You may manually load or unload these modules as needed.


Module Parameters

ParameterDescription
resetpinGPIO pin used to reset the ESP peripheral
clockspeedClock frequency in MHz (max 50 for SDIO, 40 for SPI)
raw_tp_modeEnables raw throughput mode to measure transport performance
ota_filePath to the firmware binary for updating the ESP

Notes:

  • resetpin is mandatory.

  • clockspeed is optional. If omitted:

    • SDIO defaults to 25–50 MHz as per device tree.
    • SPI defaults to 10 MHz.
    • Ensure value is ≤50 MHz for SDIO, and does not exceed the device tree setting.
  • raw_tp_mode is optional and intended only for testing the transport layer throughput. It bypasses the protocol stack and sends raw DAPA frames directly between the host and ESP. Useful for stress testing or evaluating performance limits:

    • rawtp_host_to_esp: Sends frames from Host → ESP.
    • rawtp_esp_to_host: Sends frames from ESP → Host.
  • ota_file is optional. When specified, it triggers a firmware update on the ESP. After a successful update, the ESP reboots and reconnects automatically.


Loading the Module

For SDIO:

$ sudo insmod host/esp32_sdio.ko resetpin=6

For SPI:

$ sudo insmod host/esp32_spi.ko resetpin=6

You can also pass optional parameters:

$ sudo insmod esp32_sdio.ko resetpin=6 clockspeed=40 ota_file=/path/to/firmware.bin

Unloading the Module

For SDIO:

$ sudo rmmod esp32_sdio

For SPI:

$ sudo rmmod esp32_spi