Documentation library

nRF5 SDK v15.0.0
Migration guide

Table of Contents

If you built an application based on nRF5 SDK v14.2.0, complete the actions listed in the following sections to migrate your application to nRF5 SDK v15.0.0.

Note that this migration guide does not list all changes, but it covers the most important changes that require you to update your code. See the release notes for further information on changes that were made in this release.

Bluetooth low energy (BLE)

Advertising module (ble_advertising)

Advertising Extensions using the Advertising module

When initializing the advertising module (ble_adv_modes_config_t), a different bandwidth can be selected for the primary and secondary PHY (ble_adv_primary_phyble_adv_secondary_phy). Accepted values are (BLE_GAP_PHY_1MBPS, BLE_GAP_PHY_2MBPS, and BLE_GAP_PHY_CODED). The ble_adv_extended_enabled parameter must be set to true if your application is to use extended advertising.

Action: Make sure ble_adv_extended_enabled = false; to preserve advertising functionality similar to older SDKs.

Directed advertising defines renamed



The same applies for the events, now named BLE_ADV_EVT_DIRECTED_HIGH_DUTY and BLE_ADV_EVT_DIRECTED. Note that High Duty directed advertising cannot be used together with extended advertising.

Action: When initializing or handling events from the Advertising module, make sure you are referring to the correct directed mode.

Advertising and Scan Response Data Encoder (ble_advdata)

The function ble_advdata_set() has been deprecated. The reason is because sd_ble_gap_adv_data_set() has been removed from the SoftDevice API. Instead, you can use ble_advdata_encode() before calling the SoftDevice function sd_ble_gap_adv_set_configure.

You may need to call ble_advdata_encode() twice, because ble_advdata_set() might have both advertising data and scan response data as input. The function ble_advdata_encode() only encodes one at a time.

Advertising parameters are now part of sd_ble_gap_adv_set_configure() instead of sd_ble_gap_adv_start().

For some examples, we have moved the setting of advertising parameters so they are set together with advertising data.

Action: Replace calls to ble_advdata_set() with ble_advdata_encode(). Call sd_ble_gap_adv_set_configure() before calling sd_ble_gap_adv_start().

Multilink support for selected services

Affects the following BLE service modules:

  • ble_hids
  • ble_nus
  • ble_ias
  • ble_bas

Declaring service instance with a modified macro

This affects ble_hids, ble_nus, and ble_ias modules.





Action: Add missing parameters to the macro.

Initializing service instance

This affects only the ble_hids module.


ble_hids_inp_rep_init_t     inp_rep_array[INPUT_REPORT_COUNT];
ble_hids_outp_rep_init_t    outp_rep_array[OUTPUT_REPORT_COUNT];
ble_hids_feature_rep_init_t feat_rep_array[FEATURE_REPORT_COUNT];


static ble_hids_inp_rep_init_t     inp_rep_array[INPUT_REPORT_COUNT];
static ble_hids_outp_rep_init_t    outp_rep_array[OUTPUT_REPORT_COUNT];
static ble_hids_feature_rep_init_t feat_rep_array[FEATURE_REPORT_COUNT];

Action: Declare initialization structures for Input/Output/Feature Reports as static.

Additional parameter required

Some functions from the service module API require an additional parameter - connection handle. This affects ble_hids, ble_nus, and ble_bas modules.


ret_code_t err_code;
uint8_t    battery_level;
battery_level = (uint8_t)sensorsim_measure(&m_battery_sim_state, &m_battery_sim_cfg);
err_code = ble_bas_battery_level_update(&m_bas, battery_level);


ret_code_t err_code;
uint8_t    battery_level;
battery_level = (uint8_t)sensorsim_measure(&m_battery_sim_state, &m_battery_sim_cfg);
err_code = ble_bas_battery_level_update(&m_bas, battery_level, m_conn_handle);

Action: Pass an additional parameter (connection handle) when calling service module API functions.

BLE Connection State

ble_conn_state has gained a dependency on nrf_atflags (components/libraries/atomic_flags).

Peer Manager


Note the new dependecy in ble_conn_state.

Some error return codes have changed. The affected APIs are pm_conn_secure, pm_peer_data_store(), pm_peer_ranks_get(), and pm_peer_rank_highest().


Backwards Compatibility

All interfaces to the Secure DFU Bootloaders over the DFU protocol and through Supervisor Calls or flash pages are backwards compatible with previous versions of the Secure DFU.

Note that the value 0 as the first element in the sd-req array in the init packet has gained a special meaning in this version of the DFU, because of the support for SoftDevice independent updates. Additionally, the SV Calls to set name and bonding data have gained a new error return code for when the data cannot be written because of write protection.


Some of the files used by the bootloader and DFU have changed names. For example, dfu_public_key.c is now located in examples/dfu folder, while dfu_req_handling.c has been renamed to nrf_dfu_req_handler.c and moved to components/libraries/bootloader/dfu. See bootloader example projects for details.

Compiler definitions

The bootloaders are no longer dependent on the SoftDevice to be present, unless the transport (only BLE for now) requires it. This has brought some changes to the meaning of some compiler definitions.

SOFTDEVICE_PRESENT is no longer in use in the bootloader code, as this can no longer be known at compile time. BLE_STACK_SUPPORT_REQD is used in the bootloader code to specify whether the SoftDevice is required for DFU operation.

Configuration parameters

Old configuration parameters with file names in parentheses existed only as #defines in that file.

Old config name New config name
(new config) NRF_DFU_BLE_BUFFERS_OVERRIDE (only for BLE transport)
(new config) NRF_DFU_BLE_BUFFERS (only for BLE transport)
(new config) NRF_DFU_SERIAL_USB_RX_BUFFERS (only for USB transport)
(new config) NRF_DFU_SERIAL_UART_USES_HWFC (only for UART transport)
(new config) NRF_DFU_SERIAL_UART_RX_BUFFERS (only for UART transport)

For sane defaults and documentation for new configuration parameters, see the sdk_config.h file in SDK v15.0.0 bootloader examples.

Cryptography in DFU

Previously, all secure bootloader examples used the µECC library for implementation of cryptographic routines. The examples for nRF52832 still use µECC, but nrf_crypto now also supports other software backends, like a library written for Nordic Semiconductor by Oberon (nrf_oberon). Size limitations have prevented the examples from being ported, but if you are willing to take a possible size hit, the backend can be changed (see below). The examples for nRF52840 now all use the CryptoCell hardware present on that chip, instead of µECC.

For more information about changes to nrf_crypto, see Crypto.

Porting from µECC to nrf_oberon

  1. In sdk_config.h, set the following defines:
  2. Remove these files from the build:
    • nrf_sw_backend_hash.c
    • micro_ecc_backend_ecc.c
    • micro_ecc_backend_ecdh.c
    • micro_ecc_backend_ecdsa.c
    • sha256.c
    • micro_ecc_lib_nrf52.a
  3. Add these files to the build:
    • external\nrf_oberon\lib\nrf52\liboberon_2.0.4.a or external\nrf_oberon\lib\nrf52\oberon_short_wchar_2.0.4.lib
    • components\libraries\crypto\backend\oberon\oberon_backend_ecc.c
    • components\libraries\crypto\backend\oberon\oberon_backend_ecdsa.c
    • components\libraries\crypto\backend\oberon\oberon_backend_hash.c
  4. Add these paths to the include paths:
    • external\nrf_oberon\include
    • external\nrf_cc310\include
  5. In dfu_public_key.c:
    • Remove 'const' from the declaration of 'pk'.
  6. In nrf_dfu_validation.c:
    • Add #include "nrf_crypto_shared.h"
    • Remove 'const' from the extern declaration of 'pk'.
    • Add function calls to swap the endianness of the public key and signature.
  7. If necessary, move the start address of the bootloader to accomodate the increase in size. Typically 1 or 2 extra pages are needed (pages are 0x1000 long).
    For a debug bootloader, SES will not be able to detect that the bootloader is too large, see Known Issues in Release notes. Production bootloader is not affected.

DFU (nrf_dfu.h)

If you are using the API in nrf_dfu.h directly, i.e. not using the provided nrf_bootloader.c files, you will find that a few things have changed.

Refactoring from DFU to bootloader

The bootloader code has been restructured, and some functionality has been moved from the DFU to the bootloader.

The DFU has started sending events (nrf_dfu_evt_type_t in nrf_dfu_types.h) to allow the user to take action.

  • The DFU code will no longer reset the chip after DFU. This is done in the bootloader as a response to the event NRF_DFU_EVT_DFU_COMPLETED.
  • The inactivity timer has been moved to the bootloader (nrf_bootloader_dfu_timers.h). The timer is reset on receiving the event NRF_DFU_EVT_OBJECT_RECEIVED.
  • LEDs are now manipulated only by the main file. This happens as a response to a number of events, see the implementation of dfu_observer() in the main file of a bootloader example for details.
  • The dfu_continue functionality, previously in nrf_dfu_utils, has been moved into the bootloader and is now called Firmware Activation (nrf_bootloader_fw_activation.h).
  • nrf_dfu_enter_check() and nrf_dfu_button_enter_check() have been moved to nrf_bootloader.c.


This function has been stripped of most functionality, and should now only be called when DFU is requested, i.e. after the enter checks.

The signature of nrf_dfu_init() has been changed to take an event observer (for nrf_dfu_evt_type_t events).

uint32_t nrf_dfu_init(nrf_dfu_observer_t observer);

Note that NRF_DFU_SCHED_EVENT_DATA_SIZE must now be considered when calculating the app_scheduler queue element size.

Request handling

DFU requests are now handled asynchronously.

The result of a request and its response are no longer returned directly by nrf_dfu_req_handler_on_req(), instead they are returned via a callback to the function specified in nrf_dfu_request::callback::response. The signature of nrf_dfu_req_handler_on_req() was modified to accomodate these changes. If you are not using the bootloader, then you should take care of initializing the scheduler before initializing nrf_dfu_req_handler.

If you do not use either the bootloader or nrf_dfu, then you should handle the new DFU events (nrf_dfu_evt_type_t) received through the callback specified via the "observer" param in nrf_dfu_req_handler_init() to implement the desired behavior on DFU progress, start, completion etc.

The buffers used to store incoming firmware images were moved from dfu_req_handling.c to the transports. The transports provide a pointer to these buffers to nrf_dfu_req_handler.c as part of a write request (nrf_dfu_request::write::p_data). When the buffer is written to flash, the nrf_dfu_request::callback::write callback is invoked and the buffer can be freed by the transport.

The values of nrf_dfu_req_op_t (now nrf_dfu_op_t) have been aligned to match the serialized opcode values used between the DFU host and the device. Note that this change does not break or affect backward compatibility.

Several datatypes have changed:

Old type name New type name Comment
nrf_dfu_req_op_t nrf_dfu_op_t Fields have changed
nrf_dfu_req_t nrf_dfu_request_t Fields have changed
nrf_dfu_res_t nrf_dfu_response_t Fields have changed
nrf_dfu_res_code_t nrf_dfu_result_t -


IN direction setup data handling

The driver no longer automatically acknowledges the IN direction setup transfer.

The shortcut set inside the driver when the last setup data IN transfer was prepared was removed. It means that now the higher layer must take care of calling nrf_drv_usbd_setup_clear for both directions of setup transfer.

Global class instance definitions and descriptor generating macros

Descriptor generation has been overhauled, and therefore class instance macros have been changed.



#define CDC_ACM_INTERFACES_CONFIG()                 \
                            CDC_ACM_COMM_EPIN,      \
                            CDC_ACM_DATA_INTERFACE, \
                            CDC_ACM_DATA_EPIN,      \
static const uint8_t m_cdc_acm_class_descriptors[] = {



Action: Remove the old definition of CDC_ACM_INTERFACES_CONFIG() and m_cdc_acm_class_descriptors[] and pass the values directly to the APP_USBD_CDC_ACM_GLOBAL_DEF macro. An additional parameter to specify the CDC protocol has been added.

HID mouse





Action: Add APP_USBD_HID_SUBCLASS_BOOT as the last parameter if the device can be used as a boot device or APP_USBD_HID_SUBCLASS_NONE if it cannot.

HID keyboard





Action: Add APP_USBD_HID_SUBCLASS_BOOT as the last parameter if the device can be used as a boot device or APP_USBD_HID_SUBCLASS_NONE if it cannot.

HID generic


static const uint8_t m_hid_generic_rep_descriptor[] = APP_USBD_HID_MOUSE_REPORT_DSC_BUTTON(2);
static const uint8_t m_hid_generic_class_descriptors[] ={


static const app_usbd_hid_subclass_desc_t * reps[] = {&mouse_desc};

Action: Remove m_hid_generic_rep_descriptor and m_hid_generic_class_descriptors definition. Replace them with  APP_USBD_HID_GENERIC_SUBCLASS_REPORT_DESC macro and reports table. Pass parameters directly to the APP_USBD_HID_GENERIC_GLOBAL_DEF macro.



#define HP_AUDIO_CONTROL_DSC_LIST() (                                                                           \
        APP_USBD_AUDIO_FEATURE_UNIT_DSC(2, 1, HP_FEATURE_CONTROLS())                                            \
static const uint8_t m_hp_audio_class_descriptors[] = {



Action: Remove definitions of HP_AUDIO_CONTROL_DSC_LIST and m_hp_audio_class_descriptors. Create each descriptor using appropriate macro and pass the descriptors directly to the APP_USBD_AUDIO_GLOBAL_DEF macro. Last 4 new parameters are: streaming delay, format tag, endpoint size, and streaming type.

get_descriptors class method

The get_descriptors class method has been replaced with feed_descriptors with different parameters.


const void * (* get_descriptors)(app_usbd_class_inst_t const * const p_inst,
                                                            size_t * p_size);


bool (* feed_descriptors)(app_usbd_class_descriptor_ctx_t  * p_ctx,
                          app_usbd_class_inst_t const      * p_inst,
                          uint8_t                          * p_buff,
                          size_t                             max_size);

Action: Replace get_descriptors with feed_descriptors, adding a pointer to a buffer. Use a while loop to iterate through all descriptors. Before calling feed_descriptors, the app_usbd_class_descriptor_ctx_t variable must be defined and initialized using APP_USBD_CLASS_DESCRIPTOR_INIT.

Function class_get_descriptors has different parameters and return value.


const void * app_usbd_class_descriptor_find(app_usbd_class_inst_t const * const p_cinst,
                                            uint8_t  desc_type,
                                            uint8_t  desc_index,
                                            size_t * p_desc_len)


                                          uint8_t                             desc_type,
                                          uint8_t                             desc_index,
                                          uint8_t                           * p_desc,
                                          size_t                            * p_desc_len)

Action: Add a pointer to the descriptor (p_desc) to the function call.

Added double buffering for CDC ACM

app_usbd_cdc_acm_read now specifies the number of bytes to read. Use app_usbd_cdc_acm_read_any to retain previous usage.

Action: Replace  app_usbd_cdc_acm_read with app_usbd_cdc_acm_read_any.


app_usbd_cdc_acm_read(&m_app_cdc_acm, m_rx_buffer, sizeof(m_rx_buffer));


app_usbd_cdc_acm_read_any(&m_app_cdc_acm, m_rx_buffer, sizeof(m_rx_buffer));

USB power events moved to main event queue

usbd_user_ev_handler is now also used for processing power events. Events are mapped as follows:

APP_USBD_PROCESS_POWER_EVENTS can be set to 0 to disable this feature.

Action: Add handling of aforementioned events in usbd_user_ev_handler, for example:

       if (!nrf_drv_usbd_is_enabled())

Remove power driver initialization (nrf_drv_power_init), power_usb_event_handler definition, and the appending event handler (nrf_drv_power_usbevt_init) from the application.

Replace them with enabling power events after appending the last class:

ret = app_usbd_class_append(last_class_to_append);
    NRF_LOG_INFO("No USB power detection enabled\r\nStarting USB now");

Updated configuration parameters names

Renamed the following parameters:


Old New


Old New

Action: Change old names to new ones.

Renamed setup_device_req_std

Renamed setup_device_req_std to setup_device_req_std_handler.


static ret_code_t setup_device_req_std(app_usbd_class_inst_t const * const p_inst,
                                       app_usbd_setup_evt_t const * const  p_setup_ev)


static ret_code_t setup_device_req_std_handler(app_usbd_class_inst_t const * const p_inst,
                                               app_usbd_setup_evt_t const * const  p_setup_ev)

Action: Call setup_device_req_std_handler instead of setup_device_req_std.


APP_USBD_CONFIG_MAX_POWER is now used in bMaxPower in configuration descriptor. Default value is 500.

Action: It might be necessary to define it.

app_usbd_init() does not initialize the clock now

Clock initialization has been removed from app_usbd_init().

Action: Call nrf_drv_clock_init() before app_usbd_init().

Added SOF compression and interrupt handling

Various ways of handling SOF have been implemented. To keep using the normal handling, APP_USBD_CONFIG_SOF_HANDLING_MODE must be set to "Normal queue".





nrf_crypto has gone through extensive changes from version 14.x. A lot of the new APIs that are added in nrf_crypto APIs in nRF5 SDK v15.0.0 are not mentioned in this migration guide. To get information about the new APIs, see the respective API documentation sections in the infocenter: Cryptography library.


This configuration has changed from SDK version 14.x.

The nrf_crypto frontend/backend system relies on configuration of sdk_config.h. Multiple backends are supported and in some cases multiple backends can be used at the same time (to ensure that all required cryptographic routines are supported).

This configuration chapter assumes that an sdk_config.h file containing all required configurations is present. If this requirement is not met, it might lead to compile warnings and/or errors. Copy a valid sdk_config.h from any of the nrf_crypto examples to use as a starting point.

Enabling nrf_crypto in sdk_config.h

Enable nrf_crypto by setting the NRF_CRYPTO_ENABLED define to 1 in sdk_config.h.

Enabling one or more nrf_crypto backends

Select one or more backends appropriate to your nRF device and use case, and enable by setting one or more defines in the following table to 1:

Define Description
NRF_CRYPTO_BACKEND_CC310_BL_ENABLED nRF52840 only, hardware-accelerated for SDFU
NRF_CRYPTO_BACKEND_CC310_ENABLED nRF52840 only, hardware accelerated
NRF_CRYPTO_BACKEND_MBEDTLS_ENABLED mbed TLS, requires memory management
NRF_CRYPTO_BACKEND_NRF_HW_RNG_ENABLED RNG seed for nRF52832 and nRF52810 use cases

Note that multiple backends can be enabled at the same time, as long as the features supported by multiple backends are not duplicated. For details on configuring multiple backends, see Configuring nrf_crypto frontend and backends.

Disabling unneccessary functionality

It is possible to optimize code and RAM size by disabling unused functionality. Do this by disabling unused AES modes, ECC curves etc. in the enabled backends in the sdk_config.h file.

nrf_crypto initialization

Initialization of nrf_crypto is similar to previous versions of the nrf_crypto API. 

Calling nrf_crypto_init is required before nrf_crypto APIs can be used like for previous versions of the nRF5 SDKs. Initializing nrf_crypto:

ret_code_t err_code;
// Initialize nrf_crypto
err_code = nrf_crypto_init();
// nrf_crypto APIs are now ready to be used

nrf_crypto error codes

There is a new range allocated to nrf_crypto related errors. The following is a detailed description of the common error codes shared by all nrf_crypto APIs. All nrf_crypto error codes use the same base NRF_ERROR_CRYPTO_ERR_BASE (0x8500).

Error code Value Description
NRF_ERROR_CRYPTO_NOT_INITIALIZED 0x8500nrf_crypto_init was not called prior to this crypto function.
NRF_ERROR_CRYPTO_CONTEXT_NULL 0x8501A null pointer was provided for the context structure.
NRF_ERROR_CRYPTO_CONTEXT_NOT_INITIALIZED 0x8502The context was not initialized prior to this call or it was corrupted.
NRF_ERROR_CRYPTO_FEATURE_UNAVAILABLE 0x8503The function was called with a feature that is unavailable.
NRF_ERROR_CRYPTO_BUSY 0x8504The function could not be called because the crypto backend was busy.
NRF_ERROR_CRYPTO_INPUT_NULL 0x8510One or more of the input arguments for this function were NULL.
NRF_ERROR_CRYPTO_INPUT_LENGTH 0x8511The length of one or more of the input arguments was invalid.
NRF_ERROR_CRYPTO_OUTPUT_NULL 0x8513One or more of the output arguments for this function were NULL.
NRF_ERROR_CRYPTO_OUTPUT_LENGTH 0x8514The length of one or more output arguments was too small.
NRF_ERROR_CRYPTO_ALLOC_FAILED 0x8515A required memory allocation failed.
NRF_ERROR_CRYPTO_INTERNAL 0x8516An internal error occurred when calling this function.
NRF_ERROR_CRYPTO_INVALID_PARAM 0x8517Invalid combination of input parameters.
NRF_ERROR_CRYPTO_KEY_SIZE 0x8518Size of the key is not supported by the chosen backend.
NRF_ERROR_CRYPTO_STACK_OVERFLOW 0x8519Stack overflow detected.

Some of these error codes are only observed in nRF52840 devices when using the CC310 hardware accelerated cryptographic engine as backend to nrf_crypto:

nrf_crypto variable declarations

The types used in input/output in nrf_crypto are different from the previous versions of nRF5 SDK.

Previously, versions of nrf_crypto used macro calls to allocate variables used in nrf_crypto operations. These macros have been removed and replaced by regular structure types like context structures and/or special types for holding key material and other input or output parameters.

Macros used to create variables (as value-length types) that are no longer valid in nrf_crypto:

Macro Description
NRF_CRYPTO_ECC_PRIVATE_KEY_CREATE Macro to create a private key.
NRF_CRYPTO_ECC_PUBLIC_KEY_CREATE Macro to create a public key.
NRF_CRYPTO_ECC_PRIVATE_RAW_KEY_SIZE Macro to calculate the required size for a private key given type.
NRF_CRYPTO_ECC_PUBLIC_RAW_KEY_SIZE Macro to calculate the required size for a public key given type.
NRF_CRYPTO_ECC_PRIVATE_KEY_RAW_CREATE Macro to create a raw private key.
NRF_CRYPTO_ECC_PRIVATE_KEY_RAW_CREATE_FROM_ARRAY Macro to create a raw private key given buffer as input.
NRF_CRYPTO_ECC_PUBLIC_KEY_RAW_CREATE Macro to create a raw public key.
NRF_CRYPTO_ECC_PUBLIC_KEY_RAW_CREATE_FROM_ARRAY Macro to create a raw public key given buffer as input.
NRF_CRYPTO_HASH_CONTEXT_CREATE Macro to create a hash context structure as buffer.
NRF_CRYPTO_HASH_CREATE Macro to create a hash digest and backing buffer.
NRF_CRYPTO_HASH_CREATE_FROM_ARRAY Macro to create a hash digest given buffer as input.
NRF_CRYPTO_ECDSA_SIGNATURE_INSTANCE_CREATE_FROM_INPUT Macro to create an ECDSA signature given buffer as input.

Since these macros are no longer valid, use the types in the following chapters.

New structure types for ECC operations (ECDH and ECDSA):

Type Description
nrf_crypto_ecdh_context_t Context structure used for ECDH operation.
nrf_crypto_ecdsa_sign_context_t Context structure used for ECDSA signing.
nrf_crypto_ecdsa_verify_context_t Context structure used for ECDSA verification.
nrf_crypto_ecc_private_key_t ECC Private key provided for ECDH calculation or ECDSA signing.
nrf_crypto_ecc_public_key_t ECC Public key provided for ECDH calculation or ECDSA verification.
nrf_crypto_ecdsa_signature_t ECDSA signature (all types).

Note that the content of the context structure is dependent on a parameter given during the API calls and the enabled backend. These types should be seen as opaque types.

New structure types for hash operations

Type Description
nrf_crypto_hash_context_t Context structure used for hash calculation.
nrf_crypto_hash_sha256_digest_t Hash digest structure.

Note that the content of the context structure is dependent on the parameter given during the API calls and the enabled backend. These types should be seen as opaque types.

Structure types used for context information and input and output parameters are structurally provided as unions, where the nrf_crypto frontend APIs accepts input/output types sized to the largest requirements in the configured backends and in specific modes, ECC curve types etc. The size of the context structures may differ quite a lot dependent on what backend is used and what features are enabled in the backends. See the Sizes of the types defined by nrf_crypto for details on the structure sizes used in nrf_crypto APIs.

value_length inputs

nrf_crypto in nRF5 SDK v14.x had APIs which took value length structures for inputs. This is no longer the case in nRF5 SDK v15.0.0.

Some input/output parameters are given in pairs consisting of a pointer to a buffer and a length specifier. If the output does not use the whole allocated buffer, some APIs will update the length specifier to reflect the actual size of the result.

The following is an example of a function call that uses length specifiers in API calls:

ret_code_t                                 err_code;
static nrf_crypto_hash_context_t           hash_context;
static nrf_crypto_hash_sha256_digest_t     hash_digest;
size_t                                     digest_size = sizeof(hash_digest);
err_code = nrf_crypto_hash_calculate(&hash_context,

Note that the digest_size is taken in as a pointer to a size_t type. digest_size will be updated to reflect that a SHA-256 digest has been calculated when this API is called, regardless if the hash_digest size provided in the API call is larger.

Automatic memory allocation

nrf_crypto APIs support automatic memory allocation (optional). This is different from nRF5 SDK version 14.x nrf_crypto APIs.

Some APIs will allow sending in a NULL pointer as an argument, in which case NRF_CRYPTO_ALLOC will be used to allocate memory for variables used during the nrf_crypto operation. See the API documentation for the Cryptography library frontends for information on memory requirements for the the input/output variables.

A common use case for sending NULL as an input parameter is for context structures used in calculations, like in the following example:

ret_code_t err_code;
// A structure of type nrf_crypto_hmac_context_t will be allocated and
// freed automatically during this call (NULL in input)
    NULL,                           // Context pointer is NULL
    &g_nrf_crypto_hmac_sha256_info, // Pointer to global info structure.
    m_digest,                       // Pointer to digest (result) buffer.
    &digest_len,                    // Updated during call.
    m_key,                          // Pointer to key buffer.
    sizeof(m_key),                  // Length of key.
    m_data,                         // Pointer to input data buffer.
    sizeof(m_data));                // Length of input data.

It is recommended to use static variables for parameters used in the nrf_crypto calls if this is a possibility. This ensures that there will be denial of service while trying to execute nrf_crypto API calls due to limitations in shared resources.

nrf_crypto automatic memory management

This is a new feature compared to nRF5 SDK version 14.x.

By default, nrf_crypto is configured to use stack allocation through functionality available in alloca for dynamic memory allocation. This memory is normally allocated on the stack at the beginning of a function call and freed at the end. It is not possible to use stack allocation for variables that are intended to have extended lifetime outside of the API call. If this is a requirement, use the C dynamic memory or nRF5 SDK Memory Manager in this case.

To control the memory management, edit NRF_CRYPTO_ALLOCATOR in sdk_config to a number from 0 to 4 according to the following table:

Configuration Value Description
Default configuration 0 Uses stack allocation (alloca), except IAR which uses nRF5 SDK Memory Manager.
User macros 1 User-provided macros for NRF_CRYPTO_ALLOC and NRF_CRYPTO_FREE.
Stack allocation (Alloca) 2 Uses stack allocation, not usable for IAR projects!
C dynamic memory 3 Heap based allocation (using malloc).
nRF5 SDK Memory Manager 4 Dynamic memory allocation. Requires extra configuration.

Note that the nRF5 SDK Memory Manager (mem_manager) requires additional configuration parameters in sdk_config.h and a call to initialize it by running  prior to using the nrf_crypto APIs. The correct configuration for using the nRF5 SDK Memory Manager is outside of the scope of this guide. For details about the nRF5 SDK Memory Manager module, see Memory Manager. For specific information on the required sizes of buffers in mem_manager for ECC, ECDSA, and ECDH use cases, see Memory management in mbed TLS.

Memory management in mbed TLS backend

If mbed TLS is configured to be the nrf_crypto backend, there might be some requirements to configure memory management. This is because mbed TLS APIs rely on dynamic memory management for some of the APIs. Information about which APIs require dynamic memory allocation is outside of the scope of this migration guide. Refer to mbed TLS documentation for details on memory requirements.

Memory management in IAR builds

The C runtime library in IAR (version 7.x and 8.x) does not provide the alloca functionality. This means that stack allocated memory management is not available for nrf_crypto APIs. Therefore, backends that require dynamic memory management must be configured to either use C dynamic memory or Memory Manager.

nrf_crypto endianness changed to big-endian

Previous versions of nrf_crypto were assumed input data to be little-endian or big-endian based on the configuration parameters in the APIs. This option is removed from nrf_crypto in SDK v15.0.0.

All nrf_crypto APIs now assume big-endian input/output to reflect the cryptographic algorithm standards.

Note that BLE standard assumes data for LESC to be in little-endian format. The same is the case for the Nordic proprietary Secure DFU and the PC tool used to generate FW upgrade packets (nrfutil). The micro-ecc runtime library compiled through nRF5 SDKs is using little-endian.

little-endian support in SDFU

The Nordic proprietary Secure DFU assumes little-endian types (public key, signature, and hash digest). To conform to this, there are some added sdk_config.h parameters to make the nrf_crypto APIs support little-endian input/output.

These sdk_config.h parameters are only provided as a convenience to porting from existing solutions and to keep the code size down in Secure DFU.

Configuration parameters to enable little-endian support in SDFU use- cases:

Config Description
NRF_CRYPTO_BACKEND_MICRO_ECC_LITTLE_ENDIAN_ENABLED For SDFU+nRF52832: Enable this to use nrf_crypto_ecdsa_verify with little-endian keys, hash, and signature input.
NRF_CRYPTO_BACKEND_NRF_SW_HASH_LITTLE_ENDIAN_DIGEST_ENABLED For SDFU+nRF52832: Enable this to use nrf_crypto_hash with little-endian digest.
NRF_CRYPTO_BACKEND_CC310_BL_HASH_LITTLE_ENDIAN_DIGEST_ENABLED For SDFU+nRF52840: Enable this to use nrf_crypto_hash with little-endian digest.
NRF_CRYPTO_BACKEND_CC310_BL_ECC_LITTLE_ENDIAN_ENABLED For SDFU+nRF52840: Enable this to use nrf_crypto_ecdsa_verify with little-endian keys, hash, and signature input.

Note that these changes will only be available for the micro-ecc and nrf_cc310_bl backends. This is solely for use with Secure DFU. If little-endian input/output is required outside of this, use any of the conversion functions mentioned in the following section.

Endian conversion functions

There are some convenience functions that can be used to change endianness of input and output parameters like ECC public/private keys, ECDSA signatures, ECDH shared secrets, and hash digests. 

The functions are available by adding the following include #include "nrf_crypto_shared.h", and calling the following APIs:

Function Description Usage
nrf_crypto_internal_swap_endian Swap byte order in buffer with copy. Swap hash digest, private keys, and ECDH shared secret.
nrf_crypto_internal_swap_endian_in_place Swap byte order in buffer in-place. Swap hash digest, private keys, and ECDH shared secret.
nrf_crypto_internal_double_swap_endian Swap byte order for pairs with copy. Public keys [X,Y], Signatures [R,S].
nrf_crypto_internal_double_swap_endian_in_place Swap byte order for pairs in-place. Public keys [X,Y], Signatures [R,S].

Note that ECC Public keys and ECDSA signatures are buffers that contain two parts. Both parts must be swapped individually. For an ECC public key which is a point [X,Y], both X and Y must be swapped individually. For a ECDSA signature [R, S], both R and S must be swapped individually.

nrf_crypto API changes

nrf_crypto APIs have changed since SDK version v14.x. Key to the changes is the use of info structures to select the mode of operation.

Every example assumes that nrf_crypto is included with #include "nrf_crypto.h" and that the correct backend has been configured according to the migration guide.

SHA-256 hash calculation

The following code shows how to calculate hash.

// Assumption: message with message_size is to be hashed
ret_code_t                              err_code;
static nrf_crypto_hash_context_t        hash_context;
static nrf_crypto_hash_sha256_digest_t  digest
size_t digest_size = sizeof(digest);
// Initialize nrf_crypto
err_code = nrf_crypto_init();
// Calculate the hash digest
err_code = nrf_crypto_hash_calculate(&hash_context,
The hash digest is in big-endian format in nrf_crypto. This has changed in nRF5 SDK version v15.0.0.

ECDH shared secret calculation

The following code shows how to calculate a shared secret.

// Assumption: ECDH shared secret and private/public keys is in big-endian format.
// Assumption: remote public key already received in RAW format (public_key_raw)
// Assumption: local private key stored in RAW format (private_key_raw)
static nrf_crypto_ecc_private_key_t     private_key;
static nrf_crypto_ecc_public_key_t      public_key;
static nrf_crypto_ecdh_context_t        ecdh_context;
static nrf_crypto_ecdh_shared_secret_t  shared_secret;
size_t shared_secret_size = sizeof(shared_secret);
// Initialize nrf_crypto
err_code = nrf_crypto_init();
// Convert raw local private key to format used in backend
// Convert raw remote public key to format used in backend
// Calculate the shared secret
err_code = nrf_crypto_ecdh_compute(&ecdh_context,
// The shared secret is now calculated
// The shared_secret_size variable will be updated with the actual size of the shared secret.
For BLE LESC use cases, it is necessary to change the endianness of the public key and ECDH shared secret to little-endian for use in SoftDevice APIs.

ECDSA verify

The following code shows how to verify an ECDSA signature.

// Assumption: Signature and public key is in big-endian format.
// Assumption: Public key is stored in RAW format (public_key_raw)
// Assumption: Signature is received from remote (signature, signature_size)
// Assumption: hash has been calculated (hash_digest, digest_size)
static nrf_crypto_ecc_public_key_t          public_key;
static nrf_crypto_ecdsa_verify_context_t    verify_context;
// Convert the public key from raw format
// Verify the hash digest using ECDSA
err_code = nrf_crypto_ecdsa_verify(&verify_context,
// If code reaches here, the signature was verified
For the Nordic Proprietary Secure DFU, it is neccesary to change endianness for the public key and signature to little-endian, as described in this migration guide.



Almost all hardware drivers were moved to a new module called "nrfx" that is also available as a separate entity at the following location: In SDK v15.0.0, the "nrfx" module is located in the "modules/nrfx" folder.

Because of this change, the drivers API has been moved to a new consistent namespace that uses prefixes "nrfx_" for functions and type names, and "NRFX_" for macros and enumeration values. To provide compatibility with existing applications based on nRF5 SDK v14.2.0, a special legacy layer is provided. It is located in the "integration/nrfx/legacy" folder and it performs required translation of the former drivers API and configuration settings to their new implementations.

For new applications, it is strongly recommended to use the new API directly, since the legacy layer will be deprecated and eventually removed in future SDK releases. For existing applications the migration to the new API in most cases will be quite simple and require only:

  • renaming used functions and types from nrf_drv_* to nrfx_*,
  • renaming used macros from NRF_DRV_* to NRFX_*,
  • replacing old configuration options contained in "sdk_config.h" with their new versions by adding NRFX_ prefix to their names.

There are a few exceptions though:

  • passing NULL instead of a pointer to a driver configuration structure is no longer supported, it concerns the following drivers:
    • nrfx_comp
    • nrfx_i2s
    • nrfx_pdm
    • nrfx_qdec
    • nrfx_wdt
  • combined drivers for peripherals with EasyDMA and without were split into two separate parts for respective peripherals:
    • nrf_drv_twi to nrfx_twi and nrfx_twim
    • nrf_drv_spi to nrfx_spi and nrfx_spim
    • nrf_drv_uart to nrfx_uart and nrfx_uarte
  • drivers containing SoftDevice dependent code were replaced with simpler versions without this dependency, and the SoftDevice related code from them is now kept only in the legacy layer, this concerns:
    • nrf_drv_clock (replaced by nrfx_clock)
    • nrf_drv_power (replaced by nrfx_power)
    • nrf_drv_rng (replaced by nrfx_rng)

Other changes in drivers APIs

  • I2S Buffers are now passed in a dedicated structure (renamed in the legacy layer to "nrf_drv_i2s_buffers_t"):
    typedef struct
    uint32_t * p_rx_buffer;
    uint32_t const * p_tx_buffer;
    Therefore, code that starts a transfer must be updated from:
    err_code = nrf_drv_i2s_start(buffer_rx, buffer_tx, WORDS_IN_BUFFER, 0);
    nrf_drv_i2s_buffers_t const initial_buffers = {
    .p_rx_buffer = buffer_rx,
    .p_tx_buffer = buffer_tx,
    err_code = nrf_drv_i2s_start(&initial_buffers, WORDS_IN_BUFFER, 0);
    , and the provided buffers are no longer divided into two parts of equal size, from which one is in use by the peripheral and the other is provided to the application via a call to the data handler. Instead, the driver asks the application to provide buffers to be used in the next part of the transfer by calling the data handler called with the NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED flag set in the status parameter. After the driver finishes using the buffers, it passes them back to the application via the p_released parameter of the data handler. See nrfx_i2s documentation for detailed information.



Inline functions from nrf_atomic.h are moved to nrf_atomic.c which must now be included in the project.

nrf_balloc, nrf_queue, nrf_atfifo

Instances of the objects are now created in a custom memory section. For Segger Embedded Studio and ARM GCC, linker files must define these sections (see provided generic linker scripts).


Root commands: cli_stats, colors, and echo are now called: cli stats, cli colors, and cli echo respectively.

Function nrf_cli_uninit can return NRF_ERROR_BUSY. In such case, nrf_cli_process is called first before calling nrf_cli_uninit again.


nrf_spi_mngr_perform() has a new parameter (p_config) with SPI configuration. If p_config is NULL, the default configuration is used.


nrf_twi_mngr_perform() has a new parameter (p_config) with TWI configuration. If p_config is NULL, the default configuration is used.


Enabling dynamic changes of the TX_POWER and MAX_TX_ATTEMPTS in Gazell stack is followed by changes in the Gazell API.

For the TX_POWER, function API has not been changed, but from now on there is no need to disable Gazell stack before changing this parameter. The nrf_gzll_set_tx_power function will not set NRF_GZLL_ERROR_CODE_ATTEMPTED_TO_CONFIGURE_WHEN_ENABLED error as it has done in previous stack versions.

For the TX_ATTEMPTS_NUM, function API has been changed and does not return Boolean result, as it will always succeed.


bool nrf_gzll_set_max_tx_attempts(uint16_t max_tx_attempts);


void nrf_gzll_set_max_tx_attempts(uint16_t max_tx_attempts);