Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Documentation/platforms/sim/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ The following Simulator/Emulators are supported:
network_linux
network_vpnkit
sim_gpiochip
sim_ft2232h_gpio
21 changes: 21 additions & 0 deletions Documentation/platforms/sim/sim/boards/sim/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,27 @@ fb
A simple configuration used for some basic (non-graphic) debug of the
framebuffer character drivers using ``apps/examples/fb``.

ft2232h_gpio
------------

This example requires you have a FT2232H I/O Expander board (i.e. CJMCU-2232HL)
connected to your host computer (read the "Sim FTDI GPIO Driver" documentation)
to read/write external GPIO pins.

Usage example:

.. code:: console

nsh> gpio -o 1 /dev/gpio20
Driver: /dev/gpio20
Input pin: Value=1
nsh> gpio -o 1 /dev/gpio27
Driver: /dev/gpio27
Output pin: Value=0
Writing: Value=1
Verify: Value=1
nsh>

ipforward
---------

Expand Down
209 changes: 209 additions & 0 deletions Documentation/platforms/sim/sim_ft2232h_gpio.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
=====================================
Sim FTDI GPIO Driver (Using libftdi1)
=====================================

Overview
========

The NuttX simulation (sim) already has a GPIO Chip driver that provides a mechanism use GPIO to control external devices. However that solution depends on having a driver to Linux side and that adds more overhead.

This FTDI driver allows a direct use of libftdi1 to control up to 8 GPIOs.

This driver is particularly useful for:

- Testing GPIO-based applications in a simulated environment with real hardware
- Interfacing with USB-to-GPIO adapters from NuttX simulation
- Developing and debugging GPIO drivers without dedicated embedded hardware

Host Prepare
============

Preparation required on the host side:

- Hardware module required: FT2232H module like the CJMCU-2232HL module
- A udev rule on Linux side to avoid using the FT2232H as USB/Serial:

.. code-block:: console

$ cat /etc/udev/rules.d/99-ft2232h-d2xx.rules
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", ATTRS{product}=="FTDI Device", MODE="0666"

- The libftdi1-dev installed on your system.

Architecture
============

The driver consists of two layers:

1. **NuttX Layer** (``sim_gpiochip.c``): Implements the NuttX ``ioexpander_dev_s``
interface, providing standard GPIO operations to upper-layer NuttX drivers.

2. **Host Layer** (``sim_ftdi_gpiochip.c``): Interfaces directly with libftdio1 to initialize and to provide the functions to control the GPIOs.

.. uml::

@startuml
skinparam componentStyle rectangle
skinparam defaultFontName Monospaced

[NuttX Application] as app
[GPIO Lower Half\n(gpio_lower_half)] as gpio
[sim_gpiochip.c\n(ioexpander_dev_s)] as ioex
note right of ioex : NuttX ioexpander interface
[sim_ftdi_gpiochip.c\n(host interface)] as sim
note right of sim : Linux host GPIO interface
[libftdi1] as ftdi
note right of ftdi : Linux library to control FT2232H

app --> gpio
gpio --> ioex
ioex --> sim
sim --> ftdi
@enduml

Header Files
============

- ``arch/sim/src/sim/sim_gpiochip.h``: Host GPIO chip interface definitions and function prototypes.

- ``include/nuttx/ioexpander/ioexpander.h``: Standard NuttX IO expander interface.

- ``include/nuttx/ioexpander/gpio.h``: NuttX GPIO interface definitions.

Configuration Options
=====================

The following configuration options are relevant to this driver:

- ``CONFIG_SIM_GPIOCHIP_FTDI``: Enable the FTDI/FT2232H driver support.

Supported Operations
====================

The driver supports the following GPIO operations:

Direction Control
-----------------

.. code-block:: c

int sim_gpiochip_direction(struct ioexpander_dev_s *dev,
uint8_t pin, int direction);

Set GPIO pin direction. Supported directions:

- ``IOEXPANDER_DIRECTION_IN``: Configure as input
- ``IOEXPANDER_DIRECTION_OUT``: Configure as output
- ``IOEXPANDER_DIRECTION_OUT_OPENDRAIN``: Configure as open-drain output

Read/Write Pin
--------------

.. code-block:: c

int sim_gpiochip_readpin(struct ioexpander_dev_s *dev, uint8_t pin,
bool *value);
int sim_gpiochip_writepin(struct ioexpander_dev_s *dev, uint8_t pin,
bool value);

Read or write the value of a GPIO pin.

Host Layer API
==============

The host layer (``sim_ftdi_gpiochip.c``) provides the following functions:

.. code-block:: c

/* Allocate and initialize a host GPIO chip device */
struct host_gpiochip_dev *host_gpiochip_alloc(uint8_t pins_dir);

/* Free a host GPIO chip device */
void host_gpiochip_free(struct host_gpiochip_dev *dev);

/* Set GPIO pin direction */
int host_gpiochip_direction(struct host_gpiochip_dev *dev,
uint8_t pin, bool input);

/* Read GPIO pin value */
int host_gpiochip_readpin(struct host_gpiochip_dev *dev,
uint8_t pin, bool *value);

/* Write GPIO pin value */
int host_gpiochip_writepin(struct host_gpiochip_dev *dev,
uint8_t pin, bool value);

/* Request GPIO interrupt */
int host_gpiochip_irq_request(struct host_gpiochip_dev *dev,
uint8_t pin, uint16_t cfgset);

/* Check if GPIO interrupt is active */
bool host_gpiochip_irq_active(struct host_gpiochip_dev *dev, uint8_t pin);

/* Get GPIO line information */
int host_gpiochip_get_line(struct host_gpiochip_dev *priv,
uint8_t pin, bool *input);

Linux Kernel Version Requirements
=================================

The driver uses Linux GPIO v2 ABI, which requires:

- **Linux kernel >= 6.8.0**: Full functionality with GPIO v2 API support.
- **Linux kernel < 6.8.0**: The driver compiles but provides stub implementations
that return 0 or NULL.

Usage Example
=============

Initialization
--------------

Application Usage
-----------------

After initialization, GPIO pins can be accessed through standard NuttX GPIO interface:

.. code-block:: c

#include <fcntl.h>
#include <sys/ioctl.h>
#include <nuttx/ioexpander/gpio.h>

int main(void)
{
int fd;
bool value;

/* Open GPIO device */
fd = open("/dev/gpio20", O_RD);
if (fd < 0)
{
return -1;
}

/* Read GPIO value */
ioctl(fd, GPIOC_READ, &value);
printf("GPIO value: %d\n", value);

close(fd);
return 0;
}

Files
=====

- ``arch/sim/src/sim/sim_gpiochip.c``: NuttX IO expander implementation
- ``arch/sim/src/sim/posix/sim_ftdi_gpiochip.c``: Linux host GPIO interface
- ``arch/sim/src/sim/sim_gpiochip.h``: Host GPIO chip header file

Limitations
===========

1. **Polling-based interrupts**: Due to simulation constraints, interrupts are
implemented using polling rather than true hardware interrupts.

3. **Pin count**: Limited to 8 pins of SYNBB AD0-7.

4. **Invert option**: The ``IOEXPANDER_OPTION_INVERT`` option is not yet implemented.

30 changes: 25 additions & 5 deletions arch/sim/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,7 @@ config SIM_SPIDEV_NAME
endif

config SIM_GPIOCHIP
bool "Simulated gpiochip"
bool "Support to Control External GPIO devices"
default n
depends on IOEXPANDER
---help---
Expand All @@ -709,23 +709,43 @@ choice
default SIM_GPIOCHIP_LINUX

config SIM_GPIOCHIP_LINUX
bool "Linux Gpiochip Character Dev"
bool "Linux GPIOCHIP Character Dev"
depends on HOST_LINUX
---help---
Attach a Linux Gpiochip via the character device
interface. To achieve a SPI port on Linux host, it is
recommended to use a USB<>GPIO device such as CH341A/B.

config SIM_GPIOCHIP_FTDI
bool "FTDI I/O Expander (i.e. FT2232H) as GPIOCHIP"
---help---
It is possible to use a USB FTDI FTDI to support external
devices connected to the computer. These devices could be GPIO,
I2C or SPI and NuttX on SIM will see it as a real device.

endchoice

config SIM_GPIOCHIP_NAME
string "the name of host gpiochip dev to attach to simulator"
default "/dev/gpiochip0"
depends on SIM_GPIOCHIP_LINUX
---help---
This is the name of the gpiochip device on the host implementation to
attach to the simulator driver.
This is the name of the gpiochip device on the host
implementation to attach to the simulator driver.

endif
if SIM_GPIOCHIP_FTDI

config SIM_FTDI_VID
hex "USB Vendor ID"
default 0x0403

config SIM_FTDI_PID
hex "USB Product ID"
default 0x6010

endif # SIM_FTDI

endif # SIM_GPIOCHIP

menu "Simulated UART"

Expand Down
11 changes: 10 additions & 1 deletion arch/sim/src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -262,9 +262,18 @@ ifeq ($(CONFIG_SIM_SPI_LINUX),y)
HOSTSRCS += sim_linuxspi.c
endif

ifeq ($(CONFIG_SIM_GPIOCHIP),y)
CSRCS += sim_gpiochip.c

ifeq ($(CONFIG_SIM_GPIOCHIP_LINUX),y)
HOSTSRCS += sim_linux_gpiochip.c
CSRCS += sim_gpiochip.c
endif

ifeq ($(CONFIG_SIM_GPIOCHIP_FTDI),y)
HOSTSRCS += sim_ftdi_gpiochip.c
HOSTCFLAGS += $(shell pkg-config --cflags libftdi1)
STDLIBS += $(shell pkg-config --libs libftdi1)
endif
endif

ifeq ($(CONFIG_SIM_USB_DEV),y)
Expand Down
17 changes: 15 additions & 2 deletions arch/sim/src/sim/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -270,9 +270,22 @@ if(CONFIG_SIM_SPI_LINUX)
list(APPEND HOSTSRCS sim_linuxspi.c)
endif()

if(CONFIG_SIM_GPIOCHIP_LINUX)
if(CONFIG_SIM_GPIOCHIP)
list(APPEND SRCS sim_gpiochip.c)
list(APPEND HOSTSRCS sim_linux_gpiochip.c)

if(CONFIG_SIM_GPIOCHIP_LINUX)
list(APPEND HOSTSRCS sim_linux_gpiochip.c)
endif()

if(CONFIG_SIM_GPIOCHIP_FTDI)
list(APPEND HOSTSRCS sim_ftdi_gpiochip.c)

find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBFTDI1 REQUIRED IMPORTED_TARGET libftdi1)

list(APPEND HOST_INCLUDE_DIRECTORIES ${LIBFTDI1_INCLUDE_DIRS})
list(APPEND HOST_LINK_LIBRARIES PkgConfig::LIBFTDI1)
endif()
endif()

if(CONFIG_SIM_USB_DEV)
Expand Down
Loading
Loading