Skip to content

Conversation

@ytarkhan
Copy link

Description

This PR introduces GPIO host control support to the esp_hosted component.
It allows the host side to configure and control GPIOs on the ESP slave device via a new API set.

Motivation:

Enables host applications to configure and use ESP GPIOs without modifying slave firmware.

Adds flexibility for integration scenarios where remote GPIO access is needed.

The feature is optional and disabled by default.

There are GPIO pin guards, to avoid accidental conflicts with transport pins.

Testing

I verified the changes using a setup with an ESP32-C6 (slave) and an ESP32-P4 (host):

The ESP32-P4 continuously sent commands to toggle a GPIO pin on the C6, and the pin responded correctly.

I tested configuring a pin that is reserved for SDIO transport between the P4 and C6. The C6 correctly returned an error, preventing misuse of transport pins and ensuring communication was not disrupted.

I also built and flashed the project with CONFIG_ESP_HOSTED_ENABLE_GPIO_RPC disabled. In this case, the project compiled and ran normally, but host GPIO control commands were handled as unknown commands, confirming the feature is fully optional and non-intrusive.


Checklist

Before submitting a Pull Request, please ensure the following:

  • 🚨 This PR does not introduce breaking changes.
  • All CI checks (GH Actions) pass.
  • Documentation is updated as needed.
  • Tests are updated or added as necessary.
  • Code is well-commented, especially in complex areas.
  • Git history is clean — commits are squashed to the minimum necessary.

@espressif-bot espressif-bot added the Status: Opened Issue is new label Aug 29, 2025
@github-actions github-actions bot changed the title Feature/gpio host control Feature/gpio host control (EHM-101) Aug 29, 2025
@ytarkhan ytarkhan marked this pull request as ready for review August 29, 2025 14:05
@mantriyogesh
Copy link
Collaborator

Hello @ytarkhan ,

We appreciate your time and efforts for this PR.

@SohKamYung-Espressif can you please review?

@SohKamYung-Espressif
Copy link
Collaborator

SohKamYung-Espressif commented Sep 1, 2025

Hi, @ytarkhan

I will give more detailed feedback via comments on the code.

@mantriyogesh Just to check: should other GPIO APIs also be added, as listed on https://github.com/espressif/esp-idf/blob/2044fba6/components/esp_driver_gpio/include/driver/gpio.h ? These include features to enable/disable pull-up/pull-down, set output drive, etc.

They can be added in the future in another commit.

The structure for gpio_config_t also includes this:

#if SOC_GPIO_SUPPORT_PIN_HYS_FILTER
    gpio_hys_ctrl_mode_t hys_ctrl_mode;       /*!< GPIO hysteresis: hysteresis filter on slope input    */
#endif

I think it is not required for general GPIO support.

For portability, I think driver/gpio.h should need to be copied for non ESP based hosts, like STM32.

Copy link
Collaborator

@SohKamYung-Espressif SohKamYung-Espressif left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ytarkhan @mantriyogesh Take a look at the code comments.

RPC_REQ_COPY_STR(p_c->dhcp_gw, p_a->dhcp_gw, 64);
RPC_REQ_COPY_STR(p_c->dns_ip, p_a->dns_ip, 64);
break;
} case RPC_ID__Req_GpioConfig: {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The spacing for case RPC_ID__Req_GpioConfig does not look correct.

Comment on lines 631 to 635
} case RPC_ID__Req_GpioResetPin: {
RPC_ALLOC_ASSIGN(RpcReqGpioReset, req_gpio_reset,
rpc__req__gpio_reset__init);
req_payload->gpio_num = app_req->u.gpio_num;
break;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The spacing for the code here and elsewhere does not match the already committed code.

In general, ESP-Hosted-MCU uses tabs for code indentation instead of spaces. You can check the .editorconfig for details on our spacing requirements.

https://github.com/espressif/esp-hosted-mcu/blob/main/.editorconfig

CMakeLists.txt Outdated
Comment on lines 73 to 74
list(APPEND srcs "${host_dir}/port/esp/freertos/src/port_esp_hosted_host_gpio.c")

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As with the co-processor, a compilation define can be added on the host side to only compile GPIO related code if needed.

Add this to the top level Kconfig, below config ESP_HOSTED_ENABLE_ITWT:

	config ESP_HOSTED_ENABLE_GPIO_CONTROL
		bool "Enable GPIO control on co-processor"
		default n
		help
			Enable RPC methods that allow the HOST MCU to configure and control GPIOs
			on the co-processor. Leave disabled unless you really need it.
			GPIO requests that target pins used by the active transport will be rejected.

This is then used to enable code compilation of the GPIO code:

  1. Modify CMakeLists.txt to conditionally compile GPIO related code:
	if(CONFIG_ESP_HOSTED_ENABLE_GPIO_CONTROL)
		list(APPEND srcs "${host_dir}/port/esp/freertos/src/port_esp_hosted_host_gpio.c")
    endif()
  1. Add a config option at the bottom of host/port/esp/freertos/include/port_esp_hosted_host_config.h:
#if CONFIG_ESP_HOSTED_ENABLE_GPIO_CONTROL
#define H_ENABLE_GPIO_CONTROL 1
#else
#define H_ENABLE_GPIO_CONTROL 0
#endif
  1. Surround GPIO related code with #if H_ENABLE_GPIO_CONTROL ... #endif

Comment on lines 12 to 13
#ifdef ESP_PLATFORM
// OTA API for ESP-IDF
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not required for Hosted GPIO API, which is generic.

ESP_PLATFORM was required for OTA related code as it used other parts of ESP-IDF for its implementation, which is not the case for GPIO control: the APIs for GPIO control as self-contained.


#endif

#endif /*__ESP_HOSTED_OTA_H__*/
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#endif /* __ESP_HOSTED_GPIO_H__ */

Copy link
Collaborator

@SohKamYung-Espressif SohKamYung-Espressif left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One more comment.

Comment on lines 39 to 42
add_pin(&mask, CONFIG_ESP_SPI_HSPI_GPIO_MOSI);
add_pin(&mask, CONFIG_ESP_SPI_HSPI_GPIO_MISO);
add_pin(&mask, CONFIG_ESP_SPI_HSPI_GPIO_CLK);
add_pin(&mask, CONFIG_ESP_SPI_HSPI_GPIO_CS);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessary to add these pins. The slave Kconfig.projbuild will set ESP_SPI_GPIO_xxx to ESP_SPI_HSPI_GPIO_xxx or ESP_SPI_VSPI_GPIO_xxx depending on the value of SPI_VSPI

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SohKamYung-Espressif The idea is that these pins are transport pins. The host should not be allowed to change the slave's transport pin GPIO configuration remotely.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The section in full:

#ifdef CONFIG_ESP_SPI_HOST_INTERFACE
    add_pin(&mask, CONFIG_ESP_SPI_GPIO_MOSI);
    add_pin(&mask, CONFIG_ESP_SPI_GPIO_MISO);
    add_pin(&mask, CONFIG_ESP_SPI_GPIO_CLK);
    add_pin(&mask, CONFIG_ESP_SPI_GPIO_CS);
    add_pin(&mask, CONFIG_ESP_SPI_GPIO_HANDSHAKE);
    add_pin(&mask, CONFIG_ESP_SPI_GPIO_DATA_READY);
    add_pin(&mask, CONFIG_ESP_SPI_GPIO_RESET);

    add_pin(&mask, CONFIG_ESP_SPI_HSPI_GPIO_MOSI);
    add_pin(&mask, CONFIG_ESP_SPI_HSPI_GPIO_MISO);
    add_pin(&mask, CONFIG_ESP_SPI_HSPI_GPIO_CLK);
    add_pin(&mask, CONFIG_ESP_SPI_HSPI_GPIO_CS);

add_pin(&mask, CONFIG_ESP_SPI_GPIO_MOSI) will do the same as add_pin(&mask, CONFIG_ESP_SPI_HSPI_GPIO_MOSI) etc., so I think the second part with _HSPI_ can be removed.

Copy link
Collaborator

@mantriyogesh mantriyogesh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for all your efforts and time @ytarkhan .

There are two ways to resolve the comments.

  1. We can use your base commit and add a new commit to incorporate the comments.
  2. You can resolve the comments in your PR and we merge on completion.

For small changes we use option (2) . However, the comments added involve little big change. so we can also got got option (1). Please suggest what option you wish to go to.

Essentially, there are two main comments:

  1. To wrap the code at host under feature flag, and route the Kconfig through https://github.com/espressif/esp-hosted-mcu/blob/main/host/port/esp/freertos/include/port_esp_hosted_host_config.h to generic MACROs, which helps to keep the host code portable. Ensure this flag is set to No by default, as this is a feature which user can use as they need. possibly host side example can be crafted to enable this option through sdkconfig.defaults in that new host example.

  2. Some of these APIs are already existing at

    /* 37 */ int (*_h_config_gpio)(void* gpio_port, uint32_t gpio_num, uint32_t mode);
    /* 38 */ int (*_h_config_gpio_as_interrupt)(void* gpio_port, uint32_t gpio_num, uint32_t intr_type, void (*gpio_isr_handler)(void* arg), void *arg);
    /* 39 */ int (*_h_teardown_gpio_interrupt)(void* gpio_port, uint32_t gpio_num);
    /* 39 */ int (*_h_read_gpio)(void* gpio_port, uint32_t gpio_num);
    /* 40 */ int (*_h_write_gpio)(void* gpio_port, uint32_t gpio_num, uint32_t value);
    /* 40 */ int (*_h_pull_gpio)(void* gpio_port, uint32_t gpio_num, uint32_t pull_value, uint32_t enable);
    /* 41 */ int (*_h_hold_gpio)(void* gpio_port, uint32_t gpio_num, uint32_t hold_value);
    . These are mandatory in nature, as some extra GPIOs needs to be set for some transports at host. Considering this, you can cross check existing APIs and do not duplicate those with new names.

Please let us know how to proceed as per your comfortability. We totally understand the code base is new for you and we can also add commit on top to make it aligned with the review comments.

Comment on lines +1 to +7
/* APIs to do control GPIOs of the co-processor
*
* Note: This API is platform dependent
*
* Source for the API should be in host/port/<platform>/...
*
*/
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to update the licence alike other files.

Copy link
Collaborator

@SohKamYung-Espressif SohKamYung-Espressif Sep 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ytarkhan ESP-Hosted-MCU uses pre-commit to check and update the copyright info on files. See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/contribute/install-pre-commit-hook.html to install pre-commit and set up with ESP-Hosted-MCU.

This can also be done later using option (1), where we add a new commit on top of yours to tidy things up.

#include "esp_hosted_rpc.pb-c.h"
#include "esp_wifi.h"
#include "esp_wifi_types.h"
#include "driver/gpio.h"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current file is generic file. But

#include "driver/gpio.h"

make it depend upon esp-idf. we can refer and re-use and ammend the GPIO APIs as below:

/* 37 */ int (*_h_config_gpio)(void* gpio_port, uint32_t gpio_num, uint32_t mode);
/* 38 */ int (*_h_config_gpio_as_interrupt)(void* gpio_port, uint32_t gpio_num, uint32_t intr_type, void (*gpio_isr_handler)(void* arg), void *arg);
/* 39 */ int (*_h_teardown_gpio_interrupt)(void* gpio_port, uint32_t gpio_num);
/* 39 */ int (*_h_read_gpio)(void* gpio_port, uint32_t gpio_num);
/* 40 */ int (*_h_write_gpio)(void* gpio_port, uint32_t gpio_num, uint32_t value);
/* 40 */ int (*_h_pull_gpio)(void* gpio_port, uint32_t gpio_num, uint32_t pull_value, uint32_t enable);
/* 41 */ int (*_h_hold_gpio)(void* gpio_port, uint32_t gpio_num, uint32_t hold_value);

return rpc_gpio_set_level(gpio_num, level);
}

int esp_hosted_gpio_get_level(gpio_num_t gpio_num)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try to return error code as esp_err_t always. Any values returned can be passed as arguments by reference.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Original API is

int gpio_get_level(gpio_num_t gpio_num)

So, keep esp_hosted_gpio_get_level() in the same format, or change to return esp_err_t?


/** Includes **/
#include "esp_wifi.h"
#include "driver/gpio.h"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines 110 to 116
esp_err_t rpc_gpio_config(const gpio_config_t *pGPIOConfig);
esp_err_t rpc_gpio_reset_pin(gpio_num_t gpio_num);
esp_err_t rpc_gpio_set_level(gpio_num_t gpio_num, uint32_t level);
int rpc_gpio_get_level(gpio_num_t gpio_num, int *level);
esp_err_t rpc_gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode);
esp_err_t rpc_gpio_input_enable(gpio_num_t gpio_num);
esp_err_t rpc_gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Should be wrapped under the feature flag for GPIO. This would help us to lower the code size at host. the feature flag should be by default set to 'n'
  2. gpio_num_t etc direct esp-idf structures should not be used. hosted should define the structures, independent of esp-idf at host, so that it is perfectly portable code.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similar to CONFIG_ESP_HOSTED_ENABLE_GPIO_RPC, we can introduce H_ENABLE_GPIO_RPC and hook it through https://github.com/espressif/esp-hosted-mcu/blob/main/host/port/esp/freertos/include/port_esp_hosted_host_config.h

We know it is extra effort to route like this. but this ensures that user using non esp host, still can control the configuration through the their own ported header files. Kconfig may not be supported by non-esp hosts. so thisis hook file to translate new Kconfig at host's CONFIG_ESP_HOSTED_ENABLE_GPIO_RPC parameter is translated to H_ENABLE_GPIO_RPC

Comment on lines 39 to 42
add_pin(&mask, CONFIG_ESP_SPI_HSPI_GPIO_MOSI);
add_pin(&mask, CONFIG_ESP_SPI_HSPI_GPIO_MISO);
add_pin(&mask, CONFIG_ESP_SPI_HSPI_GPIO_CLK);
add_pin(&mask, CONFIG_ESP_SPI_HSPI_GPIO_CS);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SohKamYung-Espressif The idea is that these pins are transport pins. The host should not be allowed to change the slave's transport pin GPIO configuration remotely.

}
#endif // CONFIG_SOC_WIFI_HE_SUPPORT

#if CONFIG_ESP_HOSTED_ENABLE_GPIO_RPC
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similar to slave, please add guard for host side code as well.

@ytarkhan
Copy link
Author

ytarkhan commented Sep 2, 2025

Thank you for all your efforts and time @ytarkhan .

There are two ways to resolve the comments.

  1. We can use your base commit and add a new commit to incorporate the comments.
  2. You can resolve the comments in your PR and we merge on completion.

For small changes we use option (2) . However, the comments added involve little big change. so we can also got got option (1). Please suggest what option you wish to go to.

Essentially, there are two main comments:

  1. To wrap the code at host under feature flag, and route the Kconfig through https://github.com/espressif/esp-hosted-mcu/blob/main/host/port/esp/freertos/include/port_esp_hosted_host_config.h to generic MACROs, which helps to keep the host code portable. Ensure this flag is set to No by default, as this is a feature which user can use as they need. possibly host side example can be crafted to enable this option through sdkconfig.defaults in that new host example.
  2. Some of these APIs are already existing at
    /* 37 */ int (*_h_config_gpio)(void* gpio_port, uint32_t gpio_num, uint32_t mode);
    /* 38 */ int (*_h_config_gpio_as_interrupt)(void* gpio_port, uint32_t gpio_num, uint32_t intr_type, void (*gpio_isr_handler)(void* arg), void *arg);
    /* 39 */ int (*_h_teardown_gpio_interrupt)(void* gpio_port, uint32_t gpio_num);
    /* 39 */ int (*_h_read_gpio)(void* gpio_port, uint32_t gpio_num);
    /* 40 */ int (*_h_write_gpio)(void* gpio_port, uint32_t gpio_num, uint32_t value);
    /* 40 */ int (*_h_pull_gpio)(void* gpio_port, uint32_t gpio_num, uint32_t pull_value, uint32_t enable);
    /* 41 */ int (*_h_hold_gpio)(void* gpio_port, uint32_t gpio_num, uint32_t hold_value);

    . These are mandatory in nature, as some extra GPIOs needs to be set for some transports at host. Considering this, you can cross check existing APIs and do not duplicate those with new names.

Please let us know how to proceed as per your comfortability. We totally understand the code base is new for you and we can also add commit on top to make it aligned with the review comments.

Thank you for the detailed feedback, @mantriyogesh.

In the meantime, I made a couple of quick fixes — rebuilt with proto-c 1.4.1 and removed some unnecessary whitespace.

That said, I believe option (1) is the most practical way forward. I’m glad we could contribute, and I’m looking forward to making more contributions in the future.

@sicanins
Copy link

sicanins commented Oct 3, 2025

Hi @mantriyogesh, is there a timeline for this? We soon need to move to release builds here.. @ytarkhan

@sicanins
Copy link

Hi @mantriyogesh,
in order to prepare to use the new ota feature we had to merge the code again.

Most of the requested changes should be implemented, please have a look.

I am not really clear what you mean by the os_abstractions. Aren't they only relevant for the host?

The code is not yet tested, we will do it tomorrow.

Thanks!

@mantriyogesh
Copy link
Collaborator

Hi @mantriyogesh, is there a timeline for this? We soon need to move to release builds here.. @ytarkhan

Sorry, we are busy in other tasks right now. I will try to push this by Mid Nov. would that be fine?
Please state if urgent, then i will have to stall something and pick this.

I am not really clear what you mean by the os_abstractions. Aren't they only relevant for the host?

Let me check this and get back.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Status: Opened Issue is new

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants