From e7c9e46eb22629801237729e054e20b58ea208e7 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Sat, 28 Sep 2024 09:42:36 +0200 Subject: [PATCH] Documentation: port "Device Drivers vs. Bus Drivers and GPIO Drivers" from wiki port page from wiki: https://cwiki.apache.org/confluence/display/NUTTX/Device+Drivers+vs.+Bus+Drivers+and+GPIO+Drivers --- Documentation/components/drivers/index.rst | 3 + .../implementation/device_drivers.rst | 209 ++++++++++++++++++ Documentation/implementation/index.rst | 1 + 3 files changed, 213 insertions(+) create mode 100644 Documentation/implementation/device_drivers.rst diff --git a/Documentation/components/drivers/index.rst b/Documentation/components/drivers/index.rst index ff86a6e7aa4..b1e35e10255 100644 --- a/Documentation/components/drivers/index.rst +++ b/Documentation/components/drivers/index.rst @@ -31,6 +31,9 @@ Drivers in NuttX generally work in two distinct layers: * A "lower half" which is typically hardware-specific. This is usually implemented at the architecture or board level. +Details about drivers implementation can be found in +:doc:`../../implementation/drivers_design` and :doc:`../../implementation/device_drivers`. + Subdirectories of ``nuttx/drivers`` =================================== diff --git a/Documentation/implementation/device_drivers.rst b/Documentation/implementation/device_drivers.rst new file mode 100644 index 00000000000..526c109a0b8 --- /dev/null +++ b/Documentation/implementation/device_drivers.rst @@ -0,0 +1,209 @@ +============== +Device Drivers +============== + +Standard Device Drivers +======================= + +Device drivers should be implemented in the RTOS and used by applications. +Drivers provide access to device functionality for applications. This is a +necessary part of the modular RTOS design. In the NuttX directory structure, +share-able device drivers reside under ``drivers/`` and custom drivers reside in +the board-specific directories at ``nuttx/boards////src`` or +``nuttx/boards///drivers`` that are built into the RTOS. + +Bus Drivers +=========== + +There a many things that get called drivers in OS; NuttX makes a distinction +between device drivers and bus drivers. For example, SPI, PCI, PCMCIA, USB, +Ethernet, etc. are buses and not devices. You will never find a device driver +for a bus in the NuttX architecture. + +In most devices architectures, devices reside on a bus. A bus is a transport +layer that connects the device residing on the bus to a device driver. +The bus is managed by a bus driver. The device driver uses the facilities of +the bus driver transport layer to interact with the device. + +Consider SPI. SPI is a bus. It provides a serial bus to which many devices may +be connected. An SPI device resides on the SPI bus in the sense that is shares +the same MISO, MOSI, and clock lines with other devices on the SPI bus (but in +SPI, it will have its own dedicated chip select discrete). + +Although we typically use the same term driver to refer to both bus drivers and +device drivers, there is one big, fundamental difference: applications interact +only with devices drivers and never with bus drivers. Applications never talk +directly to PCI, PCMCIA, USB, Ethernet, nor with I2C, SPI, or GPIOs. Applications +interface through device drivers that use PCI, PCMCIA, USB, Ethernet, I2C, or SPI. +Bus drivers only exist to support the communication between the device driver and +the device on the bus. + +Back to SPI... There will never be an application accessible interface to SPI. +If your application were to use SPI directly, then you would have have embedded +a device driver in your application and would have violated the RTOS functional +partition. + +Test Drivers +============ + +It would be possible to provide character driver, such as SPI driver, that could +perform bus level accesses on behalf of an application. There are not many cases +where this would be acceptable, however. One possibility would be to support +support testing of bus drivers. +There is, an example for I2S here: ``drivers/audio/i2schar.c`` with a test case +here ``apps/examples/i2schar``. I2S is, of course, very similar to SPI. +This interface exists only for testing purposes and would probably not be +possible to build any meaningless application with it. + +The I2C Tool +------------ + +Of course, like most rules, there are lots of violations. I2C is another bus and +the the I2C "driver" is another transport similar in many ways to SPI. For I2C, +there is an application at ``apps/system/i2c`` alled the "I2C tool" that will allow +you access I2C devices from the command line. This is not really just a test tool +and not a real part of an application. + +And there is a fundamental flaw in the I2C tool: it uses NuttX internal interfaces +and violates the functional partitioning. NuttX has three build mode: (1) A flat +build where there is no enforcement of RTOS boundaries. In that flat build, +the I2C tool works fine. And (2) a kernel build mode and (3) a protected build mode. +In bothof these latter cases, the OS interfaces are strictly enforced. In the kernel +pand protected build modes, the I2C tool is not available because it cannot access +those NuttX internal interfaces. + +User Space Drivers +================== + +Above, it was stated that if your application were to use a bus directly, then you +would have have embedded a device driver in your application and would violate +the RTOS functional partition. Such device built into user applications are +referred to as user space drivers in some contexts. There is no plan or intent +to support user space drivers in NuttX. + +Communication Devices +===================== + +What about interface like CAN and UARTs? Why are those exposed as drivers when +SPI and I2C are not? + +Semantics are difficult. The general principles that are maintain in +the RTOS are clear, but sometimes applying principles in a black and white way +is not easy in a world with shades of grey. (And if the principles get in the +way of good design then the principles should change). + +In the case of true buses that support generic devices, the principle +is a good one. But there are grey areas too. + +CAN seems similar to Ethernet. Both are network interfaces of sorts. You +wouldn't interface directly with Ethernet driver because you need to go +through a network stack of some type. The OSI model prevents it. + +UARTs are communication devices. There is no RS-232 bus with devices connected +to it. Rather there are peers on the bus that you communicate with. This does not +preclude a UART from being used as a low level transfer for a device driver +(as with the driver for a wireless modules). Nor does it preclude a stack layer +like Modbus from being inserted in the path. + +CAN differs from Ethernet in that it really is a direct peer-to-peer +communication, more like a UART. Although you can support a stack like CANOPen +on CAN. Currently CAN can be used as a simple character device, or as a network +interface using SocketCAN. + +Communication devices support a fundamental peer-to-peer model. CAN and UARTs +are basically serial interfaces. But so are SPI, I2C, and USB. But those latter +serial interfaces clearly have a host/device, master/slave model associated with +them. It make perfectly good sense to think of them as buses that support device +interfaces. + +I/O Expander +============ + +An I/O expander is device that interfaces with the MCU, usually via I2C, and +provides additional discrete inputs and outputs. The same rules apply: + +* **GPIOS are Board-Specific**. Nothing in the system should now about GPIOs + except for board specific logic. GPIOs can change from board-toboard. They + can come and go. They can be replaced by GPIO expanders. Your (portable) + application should not have any knowledge about how any discrete I/O is + implemented on the board. There will never be GPIO drivers as a part of + the NuttX architecture. + +* **Common Drivers are Board-Independent**. Nor should common drivers + (like those in ``drivers/``) know anything about GPIOs. In ALL cases, + the board specific implementation in the board directories creates + a "lower half" driver and binds that "lower half" driver with an common + "upper half" driver to initialize the driver. Only the board logic has + any kind of GPIO knowledge; not the application and not the common + "upper half driver". + +* **I2C and SPI Drivers are Internal Bus Drivers**. Similarly I2C and SPI + drivers are not accessible to applications. These are NOT device drivers + but are bus drivers. They should not be accessed directly by applications. + Rather, again, the board-specific logic generates a "lower half" driver + that provides a common I2C or SPI interface and binds that with + an "upper half" driver to initialize the driver. + +None of those rules change if you use an I/O expander, things just get +more convoluted. + +Example Architecture +-------------------- + +Consider this case for some ````: + +#. A discrete joystick is implemented as set of buttons: UP, DOWN, LEFT, RIGHT, + and CENTER. The state of each the buttons is sensed as a GPIO input. + +#. The GPIO button inputs go to I2C I/O expander at say, + ``drivers/ioexpander/myexpander.c``, and finally to + +#. The discrete joystick driver "upper half" driver (``drivers/input/djoystick.c``). + +Implementation Details +---------------------- + +These should be implemented in the following, flexible, portable, layered architecture: + +#. In the end, the application would interact only with a joystick driver + interface via standard open/close/read/ioctl operations. It would receive + pjoystick information as described in ``include/nuttx/input/djoystick.h.`` + +#. The discrete joystick driver would have been initialized by logic in some + file like ``boards//xyz//src/xyz_djoystick.c`` when the system + was initialized. ``zyz_joystick.c`` would have created instance of + the ``struct djoy_lowerhalf_s`` "lower half" interface as described in + ``nuttx/include/nuttx/input/djoystick.h`` and would have passed that + interface instance to the ``drivers/input/djoystick.c`` "upper half" driver + to initialize it. + +#. As part of the creation of the ``struct djoy_lowerhalf_s`` "lower half" + interface instance, logic in ``xyz_djoystick.c`` would have done the following: + It would have created an I2C driver instance by called MCU specific I2C initialization + logic then passed this I2C driver instance to the I/O expander initialization interface + in ``drivers/ioexpander/myexpander.c`` to create the I/O expander interface instance. + + Note that the I/O expander interface should NOT be a normal character driver. + It should NOT be accessed via open/close/read/write/ioctl. Rather, it should return + an instance of a some ``struct ioexpander_s`` interface. That I/O expander interface + would be described in ``nuttx/include/ioexpander/ioexpander.h``. It is an internal + operating system interface and would never be available to application logic. + + After receiving the I/O expander interface instance, the "lower half" discrete + joystick interface would retain this internally as private data. Nothing in the + system other than this "lower half" discrete joystick driver needs to know how + the joystick is connected on board. + +#. After creating the "upper half" discrete joystick interface interface, + the "lower half" discrete joystick interface would enable interrupts from + the I/O expander device. + +#. When a key is pressed, the "lower half" discrete joystick driver would receive + an interrupt from the I/O expander. It would then interact with the I/O driver + to obtain the current discrete button depressions. The I/O expander driver would + interact with I2C to obtain those button settings. Then the discrete joystick + interface callback will be called, providing the discrete joystick "upper half" + driver with the joystick input. + +#. The "upper half" discrete joystick character driver would then return the encoded + joystick input to the application in response to a ``read()`` from application code. diff --git a/Documentation/implementation/index.rst b/Documentation/implementation/index.rst index 07891136920..05a87949672 100644 --- a/Documentation/implementation/index.rst +++ b/Documentation/implementation/index.rst @@ -7,6 +7,7 @@ Implementation Details :caption: Contents: drivers_design.rst + device_drivers.rst processes_vs_tasks.rst critical_sections.rst interrupt_controls.rst