| <!-- |
| Documentation/_templates/layout.html |
| |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. The |
| ASF licenses this file to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance with the |
| License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| License for the specific language governing permissions and limitations |
| under the License. |
| --> |
| |
| |
| |
| <!DOCTYPE html> |
| <html class="writer-html5" lang="en"> |
| <head> |
| <meta charset="utf-8" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" /> |
| |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
| <title>Device Drivers — NuttX latest documentation</title> |
| <link rel="stylesheet" type="text/css" href="../_static/pygments.css" /> |
| <link rel="stylesheet" type="text/css" href="../_static/css/theme.css" /> |
| <link rel="stylesheet" type="text/css" href="../_static/copybutton.css" /> |
| <link rel="stylesheet" type="text/css" href="../_static/design-style.1e8bd061cd6da7fc9cf755528e8ffc24.min.css" /> |
| <link rel="stylesheet" type="text/css" href="../_static/custom.css" /> |
| |
| |
| <link rel="shortcut icon" href="../_static/favicon.ico"/> |
| <script src="../_static/jquery.js"></script> |
| <script src="../_static/_sphinx_javascript_frameworks_compat.js"></script> |
| <script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script> |
| <script src="../_static/doctools.js"></script> |
| <script src="../_static/sphinx_highlight.js"></script> |
| <script src="../_static/clipboard.min.js"></script> |
| <script src="../_static/copybutton.js"></script> |
| <script src="../_static/design-tabs.js"></script> |
| <script src="../_static/js/theme.js"></script> |
| <link rel="index" title="Index" href="../genindex.html" /> |
| <link rel="search" title="Search" href="../search.html" /> |
| <link rel="next" title="Linux Processes vs NuttX Tasks" href="processes_vs_tasks.html" /> |
| <link rel="prev" title="OS Drivers Design" href="drivers_design.html" /> |
| </head> |
| |
| <body class="wy-body-for-nav"> |
| <div class="wy-grid-for-nav"> |
| <nav data-toggle="wy-nav-shift" class="wy-nav-side"> |
| <div class="wy-side-scroll"> |
| <div class="wy-side-nav-search" > |
| |
| <a href="../index.html" class="icon icon-home"> NuttX |
| |
| |
| |
| </a> |
| |
| <!-- this version selector is quite ugly, should be probably replaced by something |
| more modern --> |
| |
| <div class="version-selector"> |
| <select onchange="javascript:location.href = this.value;"> |
| |
| <option value="../../latest" selected="selected">latest</option> |
| |
| <option value="../../10.0.0" >10.0.0</option> |
| |
| <option value="../../10.0.1" >10.0.1</option> |
| |
| <option value="../../10.1.0" >10.1.0</option> |
| |
| <option value="../../10.2.0" >10.2.0</option> |
| |
| <option value="../../10.3.0" >10.3.0</option> |
| |
| <option value="../../11.0.0" >11.0.0</option> |
| |
| <option value="../../12.0.0" >12.0.0</option> |
| |
| <option value="../../12.1.0" >12.1.0</option> |
| |
| <option value="../../12.2.0" >12.2.0</option> |
| |
| <option value="../../12.2.1" >12.2.1</option> |
| |
| <option value="../../12.3.0" >12.3.0</option> |
| |
| <option value="../../12.4.0" >12.4.0</option> |
| |
| <option value="../../12.5.0" >12.5.0</option> |
| |
| <option value="../../12.5.1" >12.5.1</option> |
| |
| <option value="../../12.6.0" >12.6.0</option> |
| |
| <option value="../../12.7.0" >12.7.0</option> |
| |
| <option value="../../12.8.0" >12.8.0</option> |
| |
| <option value="../../12.9.0" >12.9.0</option> |
| |
| <option value="../../12.10.0" >12.10.0</option> |
| |
| <option value="../../12.11.0" >12.11.0</option> |
| |
| </select> |
| </div> |
| |
| |
| <div role="search"> |
| <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> |
| <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> |
| <input type="hidden" name="check_keywords" value="yes" /> |
| <input type="hidden" name="area" value="default" /> |
| </form> |
| </div> |
| |
| </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> |
| <p class="caption" role="heading"><span class="caption-text">Table of Contents</span></p> |
| <ul class="current"> |
| <li class="toctree-l1"><a class="reference internal" href="../index.html">Home</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../introduction/index.html">Introduction</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../quickstart/index.html">Getting Started</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../contributing/index.html">Contributing</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../introduction/inviolables.html">The Inviolable Principles of NuttX</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../platforms/index.html">Supported Platforms</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../components/index.html">OS Components</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../applications/index.html">Applications</a></li> |
| <li class="toctree-l1 current"><a class="reference internal" href="index.html">Implementation Details</a><ul class="current"> |
| <li class="toctree-l2"><a class="reference internal" href="drivers_design.html">OS Drivers Design</a></li> |
| <li class="toctree-l2 current"><a class="current reference internal" href="#">Device Drivers</a><ul> |
| <li class="toctree-l3"><a class="reference internal" href="#standard-device-drivers">Standard Device Drivers</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="#bus-drivers">Bus Drivers</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="#test-drivers">Test Drivers</a><ul> |
| <li class="toctree-l4"><a class="reference internal" href="#the-i2c-tool">The I2C Tool</a></li> |
| </ul> |
| </li> |
| <li class="toctree-l3"><a class="reference internal" href="#user-space-drivers">User Space Drivers</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="#communication-devices">Communication Devices</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="#i-o-expander">I/O Expander</a><ul> |
| <li class="toctree-l4"><a class="reference internal" href="#example-architecture">Example Architecture</a></li> |
| <li class="toctree-l4"><a class="reference internal" href="#implementation-details">Implementation Details</a></li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li class="toctree-l2"><a class="reference internal" href="processes_vs_tasks.html">Linux Processes vs NuttX Tasks</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="critical_sections.html">Critical Sections</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="interrupt_controls.html">Per-Thread Interrupt Controls</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="preemption_latency.html">Effects of Disabling Interrupts or Pre-Emption on Response Latency</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="bottomhalf_interrupt.html">Bottom-Half Interrupt Handlers</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="simulation.html">The NuttX Simulation</a></li> |
| </ul> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../reference/index.html">API Reference</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../faq/index.html">FAQ</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../debugging/index.html">Debugging</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../guides/index.html">Guides</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../glossary.html">Glossary</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../logos/index.html">NuttX Logos</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../_tags/tagsindex.html">Tags</a></li> |
| </ul> |
| |
| </div> |
| </div> |
| </nav> |
| |
| <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > |
| <i data-toggle="wy-nav-top" class="fa fa-bars"></i> |
| <a href="../index.html">NuttX</a> |
| </nav> |
| |
| <div class="wy-nav-content"> |
| <div class="rst-content"> |
| <div role="navigation" aria-label="Page navigation"> |
| <ul class="wy-breadcrumbs"> |
| <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> |
| <li class="breadcrumb-item"><a href="index.html">Implementation Details</a></li> |
| <li class="breadcrumb-item active">Device Drivers</li> |
| <li class="wy-breadcrumbs-aside"> |
| <a href="https://github.com/apache/nuttx/blob/master/Documentation/implementation/device_drivers.rst" class="fa fa-github"> Edit on GitHub</a> |
| </li> |
| </ul> |
| <hr/> |
| </div> |
| <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> |
| <div itemprop="articleBody"> |
| |
| <section id="device-drivers"> |
| <h1>Device Drivers<a class="headerlink" href="#device-drivers" title="Permalink to this heading"></a></h1> |
| <section id="standard-device-drivers"> |
| <h2>Standard Device Drivers<a class="headerlink" href="#standard-device-drivers" title="Permalink to this heading"></a></h2> |
| <p>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 <code class="docutils literal notranslate"><span class="pre">drivers/</span></code> and custom drivers reside in |
| the board-specific directories at <code class="docutils literal notranslate"><span class="pre">nuttx/boards/<arch>/<chip>/<board>/src</span></code> or |
| <code class="docutils literal notranslate"><span class="pre">nuttx/boards/<arch>/<chip>/drivers</span></code> that are built into the RTOS.</p> |
| </section> |
| <section id="bus-drivers"> |
| <h2>Bus Drivers<a class="headerlink" href="#bus-drivers" title="Permalink to this heading"></a></h2> |
| <p>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.</p> |
| <p>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.</p> |
| <p>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).</p> |
| <p>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.</p> |
| <p>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.</p> |
| </section> |
| <section id="test-drivers"> |
| <h2>Test Drivers<a class="headerlink" href="#test-drivers" title="Permalink to this heading"></a></h2> |
| <p>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: <code class="docutils literal notranslate"><span class="pre">drivers/audio/i2schar.c</span></code> with a test case |
| here <code class="docutils literal notranslate"><span class="pre">apps/examples/i2schar</span></code>. 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.</p> |
| <section id="the-i2c-tool"> |
| <h3>The I2C Tool<a class="headerlink" href="#the-i2c-tool" title="Permalink to this heading"></a></h3> |
| <p>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 <code class="docutils literal notranslate"><span class="pre">apps/system/i2c</span></code> called 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.</p> |
| <p>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.</p> |
| </section> |
| </section> |
| <section id="user-space-drivers"> |
| <h2>User Space Drivers<a class="headerlink" href="#user-space-drivers" title="Permalink to this heading"></a></h2> |
| <p>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.</p> |
| </section> |
| <section id="communication-devices"> |
| <h2>Communication Devices<a class="headerlink" href="#communication-devices" title="Permalink to this heading"></a></h2> |
| <p>What about interface like CAN and UARTs? Why are those exposed as drivers when |
| SPI and I2C are not?</p> |
| <p>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).</p> |
| <p>In the case of true buses that support generic devices, the principle |
| is a good one. But there are grey areas too.</p> |
| <p>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.</p> |
| <p>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.</p> |
| <p>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.</p> |
| <p>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.</p> |
| </section> |
| <section id="i-o-expander"> |
| <h2>I/O Expander<a class="headerlink" href="#i-o-expander" title="Permalink to this heading"></a></h2> |
| <p>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:</p> |
| <ul class="simple"> |
| <li><p><strong>GPIOS are Board-Specific</strong>. 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.</p></li> |
| <li><p><strong>Common Drivers are Board-Independent</strong>. Nor should common drivers |
| (like those in <code class="docutils literal notranslate"><span class="pre">drivers/</span></code>) 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”.</p></li> |
| <li><p><strong>I2C and SPI Drivers are Internal Bus Drivers</strong>. 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.</p></li> |
| </ul> |
| <p>None of those rules change if you use an I/O expander, things just get |
| more convoluted.</p> |
| <section id="example-architecture"> |
| <h3>Example Architecture<a class="headerlink" href="#example-architecture" title="Permalink to this heading"></a></h3> |
| <p>Consider this case for some <code class="docutils literal notranslate"><span class="pre"><board></span></code>:</p> |
| <ol class="arabic simple"> |
| <li><p>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.</p></li> |
| <li><p>The GPIO button inputs go to I2C I/O expander at say, |
| <code class="docutils literal notranslate"><span class="pre">drivers/ioexpander/myexpander.c</span></code>, and finally to</p></li> |
| <li><p>The discrete joystick driver “upper half” driver (<code class="docutils literal notranslate"><span class="pre">drivers/input/djoystick.c</span></code>).</p></li> |
| </ol> |
| </section> |
| <section id="implementation-details"> |
| <h3>Implementation Details<a class="headerlink" href="#implementation-details" title="Permalink to this heading"></a></h3> |
| <p>These should be implemented in the following, flexible, portable, layered architecture:</p> |
| <ol class="arabic"> |
| <li><p>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 <code class="docutils literal notranslate"><span class="pre">include/nuttx/input/djoystick.h.</span></code></p></li> |
| <li><p>The discrete joystick driver would have been initialized by logic in some |
| file like <code class="docutils literal notranslate"><span class="pre">boards/<arch>/xyz/<board>/src/xyz_djoystick.c</span></code> when the system |
| was initialized. <code class="docutils literal notranslate"><span class="pre">zyz_joystick.c</span></code> would have created instance of |
| the <code class="docutils literal notranslate"><span class="pre">struct</span> <span class="pre">djoy_lowerhalf_s</span></code> “lower half” interface as described in |
| <code class="docutils literal notranslate"><span class="pre">nuttx/include/nuttx/input/djoystick.h</span></code> and would have passed that |
| interface instance to the <code class="docutils literal notranslate"><span class="pre">drivers/input/djoystick.c</span></code> “upper half” driver |
| to initialize it.</p></li> |
| <li><p>As part of the creation of the <code class="docutils literal notranslate"><span class="pre">struct</span> <span class="pre">djoy_lowerhalf_s</span></code> “lower half” |
| interface instance, logic in <code class="docutils literal notranslate"><span class="pre">xyz_djoystick.c</span></code> 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 <code class="docutils literal notranslate"><span class="pre">drivers/ioexpander/myexpander.c</span></code> to create the I/O expander interface instance.</p> |
| <p>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 <code class="docutils literal notranslate"><span class="pre">struct</span> <span class="pre">ioexpander_s</span></code> interface. That I/O expander interface |
| would be described in <code class="docutils literal notranslate"><span class="pre">nuttx/include/ioexpander/ioexpander.h</span></code>. It is an internal |
| operating system interface and would never be available to application logic.</p> |
| <p>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.</p> |
| </li> |
| <li><p>After creating the “upper half” discrete joystick interface interface, |
| the “lower half” discrete joystick interface would enable interrupts from |
| the I/O expander device.</p></li> |
| <li><p>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.</p></li> |
| <li><p>The “upper half” discrete joystick character driver would then return the encoded |
| joystick input to the application in response to a <code class="docutils literal notranslate"><span class="pre">read()</span></code> from application code.</p></li> |
| </ol> |
| </section> |
| </section> |
| </section> |
| |
| |
| </div> |
| </div> |
| <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> |
| <a href="drivers_design.html" class="btn btn-neutral float-left" title="OS Drivers Design" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> |
| <a href="processes_vs_tasks.html" class="btn btn-neutral float-right" title="Linux Processes vs NuttX Tasks" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> |
| </div> |
| |
| <hr/> |
| |
| <div role="contentinfo"> |
| <p>© Copyright 2023, The Apache Software Foundation.</p> |
| </div> |
| |
| |
| |
| </footer> |
| </div> |
| </div> |
| </section> |
| </div> |
| <script> |
| jQuery(function () { |
| SphinxRtdTheme.Navigation.enable(true); |
| }); |
| </script> |
| |
| </body> |
| </html> |