Skip to content

Commit

Permalink
doc: devicetree: edits to driving gpio guide
Browse files Browse the repository at this point in the history
Edited the Driving the GPIO pins directly guide for style.
Fixed some style issues in the nordic,gpio-pins.yaml.
Added a generic page about adding drivers.
NCSDK-24813.

Signed-off-by: Grzegorz Ferenc <[email protected]>
  • Loading branch information
greg-fer committed Dec 11, 2024
1 parent 852345e commit 695d659
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 24 deletions.
90 changes: 90 additions & 0 deletions doc/nrf/app_dev/config_and_build/hardware/add_new_driver.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
.. _add_new_driver:

Adding new drivers
##################

.. contents::
:local:
:depth: 2

Adding drivers to your embedded project allows you to add support for additional hardware components and extend functionalities of your application.

To add a new driver to an application in the |NCS|, complete the following steps:

.. rst-class:: numbered-step

Create a devicetree binding
***************************

In most of the cases you want to make it possible to configure some properties of your driver instance.
For example, a sensor may need to allow configuring used GPIO pins or communication interface.

A driver instance can be made configurable through a devicetree node that is compatible with a specific binding.
The devicetree bindings provide structure for the devicetree by declaring requirements for the content of devicetree nodes.
The :ref:`compatible <zephyr:dt-bindings-compatible>` property defines compatibility of a devicetree node with a devicetree binding.

You can create a devicetree binding YAML file for your driver in the :file:`dts/bindings` directory of your project.
If applicable, you can also use one of the existing DTS bindings available in the |NCS| or Zephyr.
For implementation examples, see :file:`nrf/dts/bindings` and :file:`zephyr/dts/bindings` directories.
See also :ref:`zephyr:devicetree` documentation for more information about devicetree.

For more information about devicetree bindings, read the :ref:`documentation about them in Zephyr <zephyr:dt-binding-compat>`.

.. rst-class:: numbered-step

Create the driver files
***********************

First, create the files that will implement driver and expose driver APIs.
As a reference, you can check the |NCS| :ref:`drivers`, whose code is located at :file:`nrf/drivers`.

You will need the following files:

* :file:`CMakeLists.txt` - This file adds your driver sources to the build as a Zephyr library.
See :ref:`app_build_system` for more information about the build system.
* :file:`Kconfig` - This file will include all custom Kconfig options for your driver, including the Kconfig option to enable and disable the driver.
See Zephyr's :ref:`zephyr:kconfig` for more information.
* Driver's source files - These files will include the code for your driver, such as :ref:`zephyr:device_struct`, device definition through the :c:macro:`DEVICE_DT_DEFINE` macro, and other elements.
If possible, your driver should expose a generic API to simplify integrating the driver in user application.
For example, the driver could expose sensor driver API (:c:struct:`sensor_driver_api`).
See :file:`nrf/drivers/sensor/paw3212/paw3212.c` for an example.
See also Zephyr's :ref:`zephyr:device_model_api` for more information, in particular the "Subsystems and API structures" section.

.. rst-class:: numbered-step

Include the driver in your application
**************************************

To enable the driver in your application's configuration, complete the following steps:

1. Enable the necessary Kconfig options in the application's :file:`prj.conf` file.
This includes the Kconfig option you defined for enabling and disabling the driver.
See :ref:`configuring_kconfig` for information about how to enable Kconfig options.
#. Create or modify a devicetree overlay file for your board to add the necessary devicetree node for your custom driver.
This step is crucial for connecting the driver to the specific hardware on your board.
For information about how to create or modify devicetree files, see :ref:`configuring_devicetree`.
#. Include the appropriate header file for your custom driver in your application code and use the driver APIs in the application.
If your driver exposes a generic API (for example, :ref:`sensor driver API <zephyr:sensor>`), you can use generic headers defined for the API.

DevAcademy courses
******************

`Nordic Developer Academy`_ contains introductory courses to the |NCS| and Zephyr.
See the following course lessons to get started with driver development:

* `Lesson 6 – Serial communication (I2C)`_ in `nRF Connect SDK Fundamentals course`_ describes how to communicate with a sensor connected over I2C using I2C APIs.
* `Lesson 5 – Serial Peripheral Interface (SPI)`_ in `nRF Connect SDK Intermediate course`_ describes how to communicate with sensors over SPI in Zephyr.
* `Lesson 7 - Device driver model`_ in `nRF Connect SDK Intermediate course`_ describes how to start with adding your own sensor driver in the Exercise 1.

Related documentation
*********************

The :ref:`nrf_desktop` application describes how to :ref:`add a new motion sensor to the project <porting_guide_adding_sensor>`.

Implementation examples
***********************

Check the driver implementation examples at the following paths:

* |NCS|: :ref:`drivers`, with code located at :file:`nrf/drivers`.
* Zephyr: :ref:`zephyr:driver-samples`, with code located at :file:`zephyr/samples/drivers`.
5 changes: 5 additions & 0 deletions doc/nrf/app_dev/config_and_build/hardware/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,14 @@ The following guides provide information about configuring specific aspects of h
Read them together with Zephyr's :ref:`zephyr:hardware_support` and :ref:`zephyr:dt-guide` guides, and the official `Devicetree Specification`_.
In particular, :ref:`zephyr:set-devicetree-overlays` explains how the base devicetree files are selected.

.. note::
If you want to go through dedicated training related to some of the topics covered here, enroll in the courses in the `Nordic Developer Academy`_.
For example, `nRF Connect SDK Fundamentals course`_ describes devicetree in `Lesson 2 <Lesson 2 - Reading buttons and controlling LEDs_>`_.

.. toctree::
:maxdepth: 1
:caption: Subpages:

add_new_driver
pin_control
use_gpio_pin_directly
61 changes: 43 additions & 18 deletions doc/nrf/app_dev/config_and_build/hardware/use_gpio_pin_directly.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,36 @@ Driving a GPIO pin directly
:local:
:depth: 2

This user guide shows how to drive a GPIO pin directly.
In the development phase of an embedded project, it can be used to collect execution timings or as a debugging tool.
This user guide shows how to control a GPIO pin directly using GPIO driver APIs.
In the development phase of an embedded project, you can use this configuration to set the pin state using software, without any intermediary circuitry or additional hardware components.
You can use this solution to collect execution timings, or as a debugging tool.

Declaring the GPIO pin
**********************
The following configuration can be copied manually into the devicetree overlay files.
You can also use the `Devicetree Visual Editor <How to work with Devicetree Visual Editor_>`_ (either in GUI or text mode) in the |nRFVSC| to apply it.

To declare a GPIO pin node, use a DTS node with ``nordic,gpio-pins`` compatible set in the :term:`devicetree <Devicetree>`.
If your application does not use the same GPIO instance as used by the node, enable the GPIO port instance required by the GPIO driver.
.. rst-class:: numbered-step

This DTS content can be introduced in the DTS of your board, application, or overlay file.
Pins defined this way can be accessed using devicetree macros.
Define the compatible DTS node
******************************

The following snippet shows the declaration of a GPIO pin node for **Pin 2** of **GPIO0**.
The node is labeled as ``user-dbg-pin``.
Additionally, the ``gpio0`` instance and ``gpiote0`` are enabled, so the GPIO driver can be built and executed.
You need to define a new GPIO pin devicetree node for the pin.
The devicetree node needs to be compatible with the GPIO devicetree binding.
GPIO APIs use the devicetree node to refer to the specified GPIO pin.

If you work with a Nordic Semiconductor device, you can use the binding definition in :file:`dts/bindings/gpio`.

See Zephyr's documentation about :ref:`zephyr:devicetree` and :ref:`zephyr:gpio_api` for more information.

.. rst-class:: numbered-step

Configure the GPIO pin through DTS
**********************************

To declare a GPIO pin node, create a DTS node in the DTS of your board or application's DTS overlay.
Pins defined this way can be accessed using :ref:`GPIO devicetree APIs<zephyr:gpio_api>`.

Make sure that GPIO ports used by the GPIO pins are enabled.
The following snippet shows the declaration of a GPIO pin node called ``user_dbg_pin``:

.. code-block:: c
Expand All @@ -41,8 +56,18 @@ Additionally, the ``gpio0`` instance and ``gpiote0`` are enabled, so the GPIO dr
status = "okay";
};
Using the pin in your application
*********************************
In this snippet:

* The node is labelled as ``user-dbg-pin``.
* ``compatible`` specifies the binding definition to be used (``nordic,gpio-pins`` from :file:`dts/bindings/gpio`).
* ``gpios`` specifies which pin node is being used (**Pin 2** of **GPIO0**).
* ``status`` enables the pin node when it is set to ``"okay"``.
* Additionally, the ``gpio0`` instance and ``gpiote0`` are enabled, so the GPIO driver can be built and executed.

.. rst-class:: numbered-step

Include the pin in your application
***********************************

To let your application access the declared pins, use the following devicetree macros:

Expand All @@ -54,15 +79,15 @@ To let your application access the declared pins, use the following devicetree m
static const struct gpio_dt_spec pin_dbg =
GPIO_DT_SPEC_GET_OR(DT_NODELABEL(user_dbg_pin), gpios, {0});
#. Make sure your application initializes the pin:
#. Make sure your application initializes the pin using the :c:func:`gpio_pin_configure_dt` function:

.. code-block:: c
if (pin_dbg.port) {
gpio_pin_configure_dt(&pin_dbg, GPIO_OUTPUT_INACTIVE);
}
#. To let your application drive the pin, add the following code where needed:
#. Add the following code where needed to let your application drive the pin using the :c:func:`gpio_pin_set_dt` function:

.. code-block:: c
Expand All @@ -83,7 +108,8 @@ This is an easy way to disable this debugging infrastructure.
Declaring multiple pins
***********************

Multiple pins can be declared in one GPIO property as well.
You can also declare multiple pins in one GPIO property.
See the following code snippet:

.. code-block:: c
Expand All @@ -96,8 +122,7 @@ Multiple pins can be declared in one GPIO property as well.
};
};
To initialize the defined GPIO pin structures, use the ``GPIO_DT_SPEC_INST_GET_BY_IDX_OR()`` macro.

To initialize the defined GPIO pin structures, use the :c:macro:`GPIO_DT_SPEC_INST_GET_BY_IDX_OR` macro:

.. code-block:: c
Expand Down
4 changes: 4 additions & 0 deletions doc/nrf/links.txt
Original file line number Diff line number Diff line change
Expand Up @@ -908,9 +908,13 @@

.. _`nRF Connect SDK Fundamentals course`: https://academy.nordicsemi.com/courses/nrf-connect-sdk-fundamentals/
.. _`Installing nRF Connect SDK and VS Code`: https://academy.nordicsemi.com/courses/nrf-connect-sdk-fundamentals/lessons/lesson-1-nrf-connect-sdk-introduction/topic/exercise-1-1/
.. _`Lesson 2 - Reading buttons and controlling LEDs`: https://academy.nordicsemi.com/courses/nrf-connect-sdk-fundamentals/lessons/lesson-2-reading-buttons-and-controlling-leds/
.. _`Lesson 6 – Serial communication (I2C)`: https://academy.nordicsemi.com/courses/nrf-connect-sdk-fundamentals/lessons/lesson-6-serial-com-i2c/topic/i2c-driver/

.. _`nRF Connect SDK Intermediate course`: https://academy.nordicsemi.com/courses/nrf-connect-sdk-intermediate/
.. _`Lesson 2 - Debugging and troubleshooting`: https://academy.nordicsemi.com/courses/nrf-connect-sdk-intermediate/lessons/lesson-2-debugging/
.. _`Lesson 5 – Serial Peripheral Interface (SPI)`: https://academy.nordicsemi.com/courses/nrf-connect-sdk-intermediate/lessons/lesson-5-serial-peripheral-interface-spi/
.. _`Lesson 7 - Device driver model`: https://academy.nordicsemi.com/courses/nrf-connect-sdk-intermediate/lessons/lesson-7-device-driver-model/

.. _`Cellular IoT Fundamentals course`: https://academy.nordicsemi.com/courses/cellular-iot-fundamentals/
.. _`Power saving techniques`: https://academy.nordicsemi.com/courses/cellular-iot-fundamentals/lessons/lesson-1-cellular-fundamentals/topic/lesson-1-power-saving-techniques/
Expand Down
12 changes: 6 additions & 6 deletions dts/bindings/gpio/nordic,gpio-pins.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause

description: |
This allows to define the pin of the GPIO to be owned by the domain.
It does not provide any specyfic driver.
Its function is to allow us to use two functionalities:
This binding allows to assign a GPIO to the domain.
It does not provide any specific driver.
The binding enables the following functionalities:
1. Generate the right UICR marking the domain to own the selected pin.
2. Access to pins by the macros from zephyr/devicetree/gpio.h file
increasing the hardware abstraction this way.
- Add an entry in UICR that marks the domain to own the selected pin.
- Allow access to pins using the macros from the `zephyr/devicetree/gpio.h` file,
which increases the hardware abstraction.
compatible: "nordic,gpio-pins"

Expand Down

0 comments on commit 695d659

Please sign in to comment.