Documentation guidelines

The nRF Connect SDK documentation is written in the following formats:

  • reStructuredText (RST) for conceptual documentation

  • Kconfig for configuration documentation

  • doxygen for API documentation

RST guidelines

See Zephyr’s Documentation Guidelines for a short introduction to RST and Zephyr documentation conventions. More information about RST is available in the reStructuredText Primer.

The nRF Connect SDK documentation follows the Zephyr style guide, with the addition of the following rules.

Title and headings

  • Keep titles and headings short and to the point.

  • Add a reference label above the title.

    For example, this page has the reference label .. _doc_styleguide:. You can see this in the RST source file of this page.

  • Do not repeat the section name in the titles of subpages, such as sample when adding a sample.

Table of contents

If your page uses sections, add the .. contents:: directive just under the page title. This will add a linked table of contents at the top of the page.

For easy navigation, do not include a table of contents if the page has a list of subpages.

Subpages

Use the .. toctree:: directive at the bottom of a page to list pages that are located further down in the hierarchy. For example, the nRF Connect SDK documentation page has a list of subpages, which includes this page you are currently reading.

For a clean structure, pages with the subpages section must not contain heading-based sections or a table of contents.

Linking

You can use different linking and inclusion methods, depending on the content you want to link to.

Replacements

If you need to repeat some information, do not duplicate the text. Use the .. |tag| replace:: replacement command to reuse the text. Whenever you use the tag in an RST document, it will be replaced with the text specified for the tag.

You can reuse the content with the tag either on one page or on multiple pages:

  • To reuse the text on one page, define the |tag| and the replacement text before the reference label and the page title.

  • To reuse the text on multiple pages, define the |tag| and the replacement text in nrf/doc/nrf/shortcuts.txt.

For example, on this page, the |gl| tag is defined for local usage and will be replaced with guidelines. This tag is not available on other pages. The page is also using the |NCS| tag that is defined in shortcuts.txt and can be used on all documentation pages in the nRF Connect SDK project.

Doxybridge

The Doxybridge Sphinx plugin provides a bridge between RST and doxygen.

The doxygen documentation is not automatically included in RST. Therefore, every group must be explicitly added to an RST file. For example, the code below adds the bluetooth_throughput group to the RST document, and includes the public members of any classes in the group.

.. doxygengroup:: bluetooth_throughput

Note

Including a group on a page does not include all its subgroups automatically. To include subgroups, add the :inner: option.

However, if subgroups are defined in separate files, you should rather list them manually on the page of the group they belong to, so that you can include information on where they are defined.

To link directly to a doxygen reference from RST, use the following C domain roles:

  • Function: :c:func:

  • Structure: :c:struct:

  • Type: :c:type:

  • Enum (the list): :c:enum:

  • Enumerator (an item): :c:enumerator:

  • Macro or define: :c:macro:

  • Structure member: :c:member:

Kconfig

To link to the Kconfig options from RST, use the :kconfig:option: domain:

:kconfig:option:`CONFIG_DEBUG`

Kconfig guidelines

The nRF Connect SDK documentation follows Zephyr’s Kconfig Style Guidelines and Kconfig - Tips and Best Practices, with the addition of the following rules.

See Zephyr’s Configuration System (Kconfig) for a short introduction to Kconfig.

Additions to file structure

In addition to the Zephyr guidelines for File Organization, observe the following guidelines in the nRF Connect SDK:

  • Always include the Nordic Semiconductor copyright header at the top of the Kconfig file in the nRF Connect SDK.

    #
    # Copyright (c) YEAR Nordic Semiconductor
    #
    # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
    #
    
  • For subsystems and libraries, include the standard logging template:

    module = MODULE_NAME
    module-str = Module description
    source "$(ZEPHYR_BASE)/subsys/logging/Kconfig.template.log_config"
    

    Place this at the end of the module’s configuration section, before the final endif.

Additions to symbol naming and structure

In addition to the Zephyr guidelines for Symbol Naming and Structure, observe the following guidelines in the nRF Connect SDK:

  • General:

    • Use title case for the first word only (except proper nouns).

    • Write clear, complete sentences ending with a period.

  • Prompts:

    • Keep prompts concise. If needed, you can add more detailed information in the help text.

    • Avoid redundant phrases like “Enable support for” - use the feature name only. Prompts starting with “Enable” are invalid and can trigger CI failures. However, you can use “Enable” in the help text to explain what the feature does.

    • Always include units in the prompt (for example, “in milliseconds” or “in bytes”). Also consider including units in the option’s symbol name (for example, MY_BUFFER_SIZE_BYTES).

    • Depending on the option status:

      • If it is experimental, add the `` [EXPERIMENTAL]`` tag to the end of the prompt (with a space before it).

      • If it is deprecated, add the `` [DEPRECATED]`` tag to the end of the prompt (with a space before it).

      • If it is informational only or an option set by sysbuild, add the `` (informative only, do not change)`` information to the end of the prompt (with a space before it).

  • help text:

    • Required for all complex configuration options. If the option is very simple (without dependencies or defaults), you can omit the help text.

    • Explain what the option does, not just repeat the prompt.

    • When the prompt includes units (for example, “in milliseconds” or “in bytes”) and the option involves conversions or calculations, include the units in the help text too.

    • For thresholds or limits, explain the implications of different values.

Symbol-specific patterns

Follow these patterns based on the Kconfig option symbol type:

bool symbols

Start help text with an imperative verb.

config MY_FEATURE
  bool "My feature"
  depends on MY_DEPENDENCY
  help
    Enable support for my feature. This feature provides...

Note

Use verbs such as Enable, Allow, Use, Set, or Control. Avoid starting with “This option…” or using third-person forms (“Enables”).

Example:

config DM_HIGH_PRECISION_CALC
	# Due to memory limitations, this functionality is not provided for nRF52832.
	bool "High-precision distance estimation"
	depends on !SOC_NRF52832
	help
	  Use a more compute-intensive algorithm for the distance estimation.
	  This feature works only with the MCPD ranging mode.
int symbols

Start the prompt and help text with a noun phrase describing the value.

config MY_BUFFER_SIZE
   int "Buffer size in bytes"
   default 256
   help
     Size of the buffer used for data processing.

Note

Use noun phrases only. Avoid starting with verbs like “Set this” or “Configure.”

Example:

config DM_INITIATOR_DELAY_US
	int "Initiator start delay"
	default 1000
	help
	  Additional Initiator Start delay time.
	  Used to adjust synchronization.
hex symbols

Start the prompt and help text with a noun phrase describing the value.

config FW_INFO_OFFSET
   hex "Firmware info location offset"
   default 0x200
   help
     Offset location of firmware information inside the current firmware image.
     Valid values are 0x0, 0x200, 0x400, 0x600, 0x800.

Note

Always provide help text explaining the meaning of values and valid ranges.

Example:

config FW_INFO_OFFSET
	hex "The location of firmware info inside this firmware"
	default 0x600 if SOC_SERIES_NRF54L
	default 0x200
	help
	  The location of firmware information inside the current firmware
	  image. Valid values are 0x0, 0x200, 0x400, 0x600, 0x800, 0xe00, and 0x1000.
	  Compatible readers of firmware information should search all possible
	  offsets. Note that all space between the vector table and this address
	  is unused.
string symbols

Start the prompt and help text with a noun phrase describing what the string represents.

config MY_VERSION_STRING
   string "Application version identifier"
   default "1.0.0"
   help
     Version string in semantic versioning format (MAJOR.MINOR.PATCH).
     Used for tracking releases and compatibility.

Example:

config LTE_LOCK_PLMN_STRING
	string "LTE PLMN lock string"
	default "00101"
	help
	  Mobile Country Code (MCC) and Mobile Network Code (MNC) values.
	  Only numeric string format supported.

Comments

  • Use comments sparingly and only when needed to explain complex dependencies or unusual configurations.

  • Add comments to endif statements for readability:

    endif # MY_FEATURE
    

Additions to naming conventions

In addition to the Zephyr guidelines for Naming Conventions, observe the following guidelines in the nRF Connect SDK:

  • Use consistent prefixes for related options (for example, SAMPLE_NAME_* or LIB_NAME_*).

  • Use descriptive option names that indicate the option’s purpose.

  • Use the prefix NCS_ (for example, NCS_SAMPLE_NAME_*) for options that are specific to a repo forked by the nRF Connect SDK (“noups”).

  • If the option is about setting a value, consider including units in the option’s symbol name (for example, MY_BUFFER_SIZE_BYTES).

Additions to configuration symbol organization

In addition to the Zephyr guidelines for Configuration Symbol Organization, observe the following guidelines in the nRF Connect SDK:

  • For Kconfig files that include new Kconfig options, use the following pattern:

    [... menu type ...]
    
    config SAMPLE_OPTION_1
        int "Option 1"
        default 100
        help
          Description of option 1.
    
    config SAMPLE_OPTION_2
        bool "Option 2"
        help
          Enable option 2 functionality.
    
    [... more config options ...]
    
    endmenu
    
    source "Kconfig.zephyr"
    
  • The opening menu type statement can have the following values:

    • menu for a new container menu to be added to the hierarchy. This menu type cannot be toggled. Use it for samples or for subsystems that are always included.

      Example of how it is rendered:

      [*] Download sample --->
          [*] Use TLS/DTLS
              (42) Security tag
      
    • menuconfig for the enabling feature, in accordance with the Zephyr guidelines. This menu type can have suboptions and can be toggled. Use it for libraries or subsystems that can be enabled or disabled.

      Example of how it is rendered:

      [*] Enhanced ShockBurst
          (32) Maximum payload size
          (8)  TX buffer length
      
    • mainmenu for the name of the top-level menu. This menu type cannot have suboptions and cannot be toggled. Use it for applications or when you want to replace the default menu naming.

      Example of how it is rendered:

      ====== Matter Lock sample application ======
          (10) Maximum number of users
          (4)  Maximum credentials per user
      
  • Symbol types (such as bool, int, hex, string) come before depends on.

  • Add the source statement for Kconfig.zephyr at the end without wrapping it in a menu.

Example:

# Config options for PPI trace sample
#
# Copyright (c) 2019 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#

mainmenu "PPI trace sample"

menu "PPI trace pins configuration"

config PPI_TRACE_PIN_RTC_COMPARE_EVT
	int "Trace pin for RTC Compare event"
	default 10 if BOARD_NRF9160DK_NRF9160 || BOARD_NRF9160DK_NRF9160_NS
	default 10 if BOARD_NRF9161DK_NRF9161 || BOARD_NRF9161DK_NRF9161_NS
	default 1 if BOARD_NRF51DK_NRF51422
	default 3
	help
	  Pin is toggled when an RTC Compare event occurs.

config PPI_TRACE_PIN_RTC_TICK_EVT
	int "Trace pin for RTC Tick event"
	default 11 if BOARD_NRF9160DK_NRF9160 || BOARD_NRF9160DK_NRF9160_NS
	default 11 if BOARD_NRF9161DK_NRF9161 || BOARD_NRF9161DK_NRF9161_NS
	default 2 if BOARD_NRF51DK_NRF51422
	default 4
	help
	  Pin is toggled when an RTC Tick event occurs.

config PPI_TRACE_PIN_LFCLOCK_STARTED_EVT
	int "Trace pin for LFCLOCK Started event"
	default 12 if BOARD_NRF9160DK_NRF9160 || BOARD_NRF9160DK_NRF9160_NS
	default 12 if BOARD_NRF9161DK_NRF9161 || BOARD_NRF9161DK_NRF9161_NS
	default 3 if BOARD_NRF51DK_NRF51422
	default 28
	help
	  Pin is toggled when an LFCLOCK Started event occurs.

config USE_BLUETOOTH_RADIO_EVENTS
	bool
	default y
	select BT
	depends on SOC_SERIES_NRF52

if USE_BLUETOOTH_RADIO_EVENTS

config PPI_TRACE_PIN_RADIO_ACTIVE
	int "Trace pin for radio activity"
	default 29
	help
	  Pin is high when the radio is active.

endif # USE_BLUETOOTH_RADIO_EVENTS

endmenu

source "Kconfig.zephyr"

Doxygen guidelines

These are the guidelines for the doxygen-based API documentation.

General documentation guidelines

  • Always write full sentences, and end them with a period.

    • Exception: Sentence fragments are acceptable for descriptions of variables, structs, and enums.

  • Ensure that all documented items belong to a correct group (see the section below).

  • Use capitalization sparingly. When in doubt, use lowercase.

  • Break the line after 100 characters.

  • Use @note only in the details section, and only when really needed for emphasis.

  • Use @warning only if an operating procedure or practice, which, if not correctly followed, could result in personal injury or loss of life.

File headers and groups

  • @file element is always required at the start of a file.

  • @brief is not needed for @file.

  • @defgroup or @addgroup usually follows @file. You can divide a file into several groups.

    • @{ must open the group, @} must close it.

  • Add @brief for every defgroup.

    • @details is optional within the defgroup.

/**
 * @file
 * @defgroup bt_gatt_pool BLE GATT attribute pool API
 * @{
 * @brief BLE GATT attribute pools.
 */

#ifdef __cplusplus
extern "C" {
#endif

#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/uuid.h>

/**
 *  @brief Register a primary service descriptor.
 *
 *  @param _svc GATT service descriptor.
 *  @param _svc_uuid_init Service UUID.
 */
#define BT_GATT_POOL_SVC_GET(_svc, _svc_uuid_init)   \
{                                                    \
   struct bt_uuid *_svc_uuid = _svc_uuid_init;       \
   bt_gatt_pool_svc_get(_svc, _svc_uuid);            \
}

[...]
/** @brief Return a CCC descriptor to the pool.
 *
 *  @param attr Attribute describing the CCC descriptor to be returned.
 */
void bt_gatt_pool_ccc_put(struct bt_gatt_attr const *attr);

#if CONFIG_BT_GATT_POOL_STATS != 0
/** @brief Print basic module statistics (containing pool size usage).
*/
void bt_gatt_pool_stats_print(void);
#endif

#ifdef __cplusplus
}
#endif

/**
 * @}
 */

Functions

  • Do not use @fn. Instead, document each function where it is defined.

  • @brief is mandatory.

    • Start the brief with the imperative form (for example “do something”).

      /** @brief Request a read operation to be executed from Secure Firmware.
      
      /** @brief Send Boot Keyboard Input Report.
      
  • @details is optional. You can introduce the additional information using @details or a blank line after @brief.

  • Use @param for every parameter.

    • Always add a parameter description. Use a sentence fragment (no verb) with a period at the end.

    • Make sure the parameter documentation within the function is consistently using the parameter type: [in], [out], or [in,out].

      * @param[out] destination Pointer to destination array where the content is
      *                         to be copied.
      * @param[in]  addr        Address to be copied from.
      * @param[in]  len         Number of bytes to copy.
      
  • If you include more than one @sa (“see also” - optional), add them like this:

    @sa first_function
    @sa second_function
    
  • Use @return or @retval instead of @returns.

    • Use @return to describe a generic return value without a specific value (for example, @return The length of ..., @return The handle). Usually, there is only one return value.

      *  @return  Initializer that sets up the pipe, length, and byte array for
      *           content of the TX data.
      
    • Use @retval for specific return values (for example, @retval true, @retval CONN_ERROR). Describe the condition for each of the return values (for example, “If the function completes successfully” or “If the connection cannot be established”).

      *  @retval 0 If the operation was successful.
      *            Otherwise, a (negative) error code is returned.
      *  @retval (-ENOTSUP) Special error code used when the UUID
      *            of the service does not match the expected UUID.
      

Here is an example of a fully defined function:

/** @brief Request a random number from the Secure Firmware.
 *
 * This function provides a True Random Number from the on-board random number generator.
 *
 * @note Currently, the RNG hardware runs each time this function is called. This
 *       consumes significant time and power.
 *
 * @param[out] output  The random number. Must be at least @p len long.
 * @param[in]  len     The length of the output array. Currently, @p len must be
 *                     144.
 * @param[out] olen    The length of the random number provided.
 *
 * @retval 0        If the operation was successful.
 * @retval -EINVAL  If @p len is invalid. Currently, @p len must be 144.
 */
 int spm_request_random_number(uint8_t *output, size_t len, size_t *olen);

Enums

Place the documentation block above the enum. The documentation for the elements inside the enum can be above them or inline.

An example with documentation preceding the documented element:

/** HID Service Protocol Mode events. */
enum hids_pm_evt {

   /** Boot mode entered. */
   HIDS_PM_EVT_BOOT_MODE_ENTERED,

   /** Report mode entered. */
   HIDS_PM_EVT_REPORT_MODE_ENTERED,
 };

An example with the documentation inline (note the less than sign < after the asterisks **):

/** @brief PDN library event. */
enum pdn_event {
        PDN_EVENT_CNEC_ESM,          /**< +CNEC ESM error code. */
        PDN_EVENT_ACTIVATED,         /**< PDN connection activated. */
        PDN_EVENT_DEACTIVATED,       /**< PDN connection deactivated. */
        PDN_EVENT_IPV6_UP,           /**< PDN has IPv6 connectivity. */
        PDN_EVENT_IPV6_DOWN,         /**< PDN has lost IPv6 connectivity. */

Structs

The documentation block must precede the documented element.

In the header file:

/** @brief Event header structure.
 *
 * @warning When an event structure is defined, application event header must be placed
 *          as the first field.
 */
struct app_event_header {

        /** Linked list node used to chain events. */
   sys_dlist_t node;

        /** Pointer to the event type object. */
   const struct event_type *type_id;
};

Note

Always add a name for the struct. Avoid using unnamed structs due to Sphinx parser issue.

References

To link to functions, enums, or structs from within doxygen itself, use the @ref keyword.

/** @brief Event header structure.
 *  Use this structure with the function @ref function_name and
 *  this structure is related to another structure, @ref structure_name.
 */

Typedefs

The documentation block must precede the documented element.

/**
 * @brief Download client asynchronous event handler.
 *
 * Through this callback, the application receives events, such as
 * download of a fragment, download completion, or errors.
 *
 * If the callback returns a non-zero value, the download stops.
 * To resume the download, use @ref download_client_start().
 *
 * @param[in] event   The event.
 *
 * @retval 0 The download continues.
 * @retval non-zero The download stops.
 */
 typedef int (*download_client_callback_t)(const struct download_client_evt *event);

Inclusion in RST files

To include the doxygen documentation in the RST files, use the .. doxygengroup:: directive and the doxygen group name.

API documentation
*****************

| Header file: :file:`include/bluetooth/gatt_dm.h`
| Source file: :file:`subsys/bluetooth/gatt_dm.c`

.. doxygengroup:: bt_gatt_dm