This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Migrating OPTIGA TRUST I2C PAL from nrf_drv_* to nrfx_twim causes nrf_pwr_mgmt_run to not return

I am currently testing Optiga Trust X using an NRF52 DK. I am using armgcc as my toolchain.

The example provided by the nRF5 SDK v17.0.0 is a great starting point and I was able to fully test the Optiga functionalities.

Now, I am integrating the Optiga Trust X libs with my product codebase. So far, I have already included the required macros in the sdk_config.h, added the files to the makefile, got a successful compilation and run the code. However, to do so, since Optiga Trust X I2C Platform Abstraction Layer (PAL) provided by Nordic uses the legacy TWI drivers and the twi manager, I needed to remove my code that uses the nrfx_twim driver. Otherwise the application of the nrfx_glue and legacy porting layer messes up compilation by defining the legacy drivers and undefining the nrfx so much that I cannot get an executable.

As far as I am aware, nrfx_twim cannot coexist with nrf_drv or nrf_twi_mngr, so I started porting the I2C NRF PAL to use only the nrfx_twim. The port was apparently successful, since the code compiles, but when running the code, it gets stuck __SEV(), on nrf_pwr_mgmt_run call, on line 361 of nrf_pwr_mgmt.c, which contains:

// Wait for an event.
__WFE();
// Clear the internal event register.
__SEV();
__WFE();

My port of the to the nrfx_twim is attached below. Please note that I am using a blocking call, but have also tested using a non-blocking call with a twim_handler and it causes the same result. The call stack is in the following image.

/**
* MIT License
*
* Copyright (c) 2018 Infineon Technologies AG
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE
*
*
* \file
*
* \brief This file implements the platform abstraction layer(pal) APIs for I2C.
*
* \addtogroup  grPAL
* @{
*/

/**********************************************************************************************************************
 * HEADER FILES
 *********************************************************************************************************************/
#include "optiga/pal/pal_i2c.h"
#include "optiga/ifx_i2c/ifx_i2c.h"
#include "pal_pin_config.h"
#include "nrfx_twim.h"
#include <stdbool.h>

/// @cond hidden

/**********************************************************************************************************************
 * MACROS
 *********************************************************************************************************************/
#define PAL_I2C_MASTER_MAX_BITRATE  (400)

/** @brief I2C driver instance */
#define TWI_INSTANCE_ID             0

/** @brief Maximal number of pending I2C transactions */
//#define MAX_PENDING_TRANSACTIONS    5

/*********************************************************************************************************************
 * LOCAL DATA
 *********************************************************************************************************************/

/* Pointer to the current pal i2c context */
static pal_i2c_t * gp_pal_i2c_current_ctx;

/** @brief Definition of TWI manager instance */
#ifndef IFX_2GO_SUPPORT
//NRF_TWI_MNGR_DEF(m_app_twi, MAX_PENDING_TRANSACTIONS, TWI_INSTANCE_ID);
const nrfx_twim_t m_app_twi = NRFX_TWIM_INSTANCE(TWI_INSTANCE_ID);
#else
const nrfx_twim_t m_app_twi = NRFX_TWIM_INSTANCE(TWI_INSTANCE_ID);

//nrf_twi_mngr_t m_app_twi;
#endif

/** @brief Definition of TWI manager transfer instance */
//static nrf_twi_mngr_transfer_t    m_transfer;

/** @brief Definition of TWI manager transaction instance */
//static nrf_twi_mngr_transaction_t m_transaction;

static bool initialized = false;

/**********************************************************************************************************************
 * LOCAL ROUTINES
 *********************************************************************************************************************/

/**
 * Pal I2C event handler function to invoke the registered upper layer callback<br>
 *
 *<b>API Details:</b>
 *  - This function implements the platform specific i2c event handling mechanism<br>
 *  - It calls the registered upper layer function after completion of the I2C read/write operations<br>
 *  - The respective event status are explained below.
 *   - #PAL_I2C_EVENT_ERROR when I2C fails due to low level failures(NACK/I2C protocol errors)
 *   - #PAL_I2C_EVENT_SUCCESS when operation is successfully completed
 *
 * \param[in] p_pal_i2c_ctx   Pointer to the pal i2c context #pal_i2c_t
 * \param[in] event           Status of the event reported after read/write completion or due to I2C errors
 *
 */
static void app_twi_callback(ret_code_t result, void * p_user_data)
{
    app_event_handler_t upper_layer_handler;
    //lint --e{611} suppress "void* function pointer is type casted to app_event_handler_t type"
    upper_layer_handler = (app_event_handler_t)gp_pal_i2c_current_ctx->upper_layer_event_handler;

    if (result == NRF_SUCCESS)
    {
        upper_layer_handler(gp_pal_i2c_current_ctx->upper_layer_ctx, PAL_I2C_EVENT_SUCCESS);
    }
    else
    {
        upper_layer_handler(gp_pal_i2c_current_ctx->upper_layer_ctx, PAL_I2C_EVENT_ERROR);
    }
}

/// @endcond

/**********************************************************************************************************************
 * API IMPLEMENTATION
 *********************************************************************************************************************/

/**
 * API to initialize the i2c master with the given context.
 * <br>
 *
 *<b>API Details:</b>
 * - The platform specific initialization of I2C master has to be implemented as part of this API, if required.<br>
 * - If the target platform does not demand explicit initialization of i2c master
 *   (Example: If the platform driver takes care of init after the reset), it would not be required to implement.<br>
 * - The implementation must take care the following scenarios depending upon the target platform selected.
 *   - The implementation must handle the acquiring and releasing of the I2C bus before initializing the I2C master to
 *     avoid interrupting the ongoing slave I2C transactions using the same I2C master.
 *   - If the I2C bus is in busy state, the API must not initialize and return #PAL_STATUS_I2C_BUSY status.
 *   - Repeated initialization must be taken care with respect to the platform requirements. (Example: Multiple users/applications
 *     sharing the same I2C master resource)
 *
 *<b>User Input:</b><br>
 * - The input #pal_i2c_t p_i2c_context must not be NULL.<br>
 *
 * \param[in] p_i2c_context   Pal i2c context to be initialized
 *
 * \retval  #PAL_STATUS_SUCCESS  Returns when the I2C master init it successfull
 * \retval  #PAL_STATUS_FAILURE  Returns when the I2C init fails.
 */
pal_status_t pal_i2c_init(const pal_i2c_t* p_i2c_context)
{
#ifndef IFX_2GO_SUPPORT
    const nrfx_twim_config_t config = {
       .scl                 = OPTIGA_PIN_I2C_SCL,
       .sda                 = OPTIGA_PIN_I2C_SDA,
       .frequency           = NRF_TWIM_FREQ_400K,
       .interrupt_priority  = NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY,
       .hold_bus_uninit     = NRFX_TWIM_DEFAULT_CONFIG_HOLD_BUS_UNINIT
    };
#else
    #include "ifx_2go_common.h"
    nrfx_twim_config_t const config = {
       .scl                = ifx_2go_pin_config()->scl,
       .sda                = ifx_2go_pin_config()->sda,
       .frequency          = NRF_TWI_FREQ_400K,
       .interrupt_priority = APP_IRQ_PRIORITY_LOWEST,
       .hold_bus_uninit     = false
    };
#endif

    if(initialized)
    {
        nrfx_twim_uninit(&m_app_twi);
    }

    // Initialize I2C driver
    if (nrfx_twim_init(&m_app_twi, &config, NULL, NULL) != NRF_SUCCESS)
    {
            return PAL_STATUS_FAILURE;
    }
    nrfx_twim_enable(&m_app_twi);

    initialized = true;
    return PAL_STATUS_SUCCESS;
}

/**
 * API to de-initialize the I2C master with the specified context.
 * <br>
 *
 *<b>API Details:</b>
 * - The platform specific de-initialization of I2C master has to be implemented as part of this API, if required.<br>
 * - If the target platform does not demand explicit de-initialization of i2c master
 *   (Example: If the platform driver takes care of init after the reset), it would not be required to implement.<br>
 * - The implementation must take care the following scenarios depending upon the target platform selected.
 *   - The implementation must handle the acquiring and releasing of the I2C bus before de-initializing the I2C master to
 *     avoid interrupting the ongoing slave I2C transactions using the same I2C master.
 *   - If the I2C bus is in busy state, the API must not de-initialize and return #PAL_STATUS_I2C_BUSY status.
 *   - This API must ensure that multiple users/applications sharing the same I2C master resource is not impacted.
 *
 *<b>User Input:</b><br>
 * - The input #pal_i2c_t p_i2c_context must not be NULL.<br>
 *
 * \param[in] p_i2c_context   I2C context to be de-initialized
 *
 * \retval  #PAL_STATUS_SUCCESS  Returns when the I2C master de-init it successfull
 * \retval  #PAL_STATUS_FAILURE  Returns when the I2C de-init fails.
 */
pal_status_t pal_i2c_deinit(const pal_i2c_t* p_i2c_context)
{
    if(initialized) {
        nrfx_twim_uninit(&m_app_twi);
    }
    initialized = false;
    return PAL_STATUS_SUCCESS;
}

/**
 * Platform abstraction layer API to write the data to I2C slave.
 * <br>
 * <br>
 * \image html pal_i2c_write.png "pal_i2c_write()" width=20cm
 *
 *
 *<b>API Details:</b>
 * - The API attempts to write if the I2C bus is free, else it returns busy status #PAL_STATUS_I2C_BUSY<br>
 * - The bus is released only after the completion of transmission or after completion of error handling.<br>
 * - The API invokes the upper layer handler with the respective event status as explained below.
 *   - #PAL_I2C_EVENT_BUSY when I2C bus in busy state
 *   - #PAL_I2C_EVENT_ERROR when API fails
 *   - #PAL_I2C_EVENT_SUCCESS when operation is successfully completed asynchronously
 *<br>
 *
 *<b>User Input:</b><br>
 * - The input #pal_i2c_t p_i2c_context must not be NULL.<br>
 * - The upper_layer_event_handler must be initialized in the p_i2c_context before invoking the API.<br>
 *
 *<b>Notes:</b><br>
 *  - Otherwise the below implementation has to be updated to handle different bitrates based on the input context.<br>
 *  - The caller of this API must take care of the guard time based on the slave's requirement.<br>
 *
 * \param[in] p_i2c_context  Pointer to the pal I2C context #pal_i2c_t
 * \param[in] p_data         Pointer to the data to be written
 * \param[in] length         Length of the data to be written
 *
 * \retval  #PAL_STATUS_SUCCESS  Returns when the I2C write is invoked successfully
 * \retval  #PAL_STATUS_FAILURE  Returns when the I2C write fails.
 * \retval  #PAL_STATUS_I2C_BUSY Returns when the I2C bus is busy.
 */
pal_status_t pal_i2c_write(pal_i2c_t* p_i2c_context,uint8_t* p_data , uint16_t length)
{
    gp_pal_i2c_current_ctx = p_i2c_context;
/*
    m_transfer.p_data    = p_data;
    m_transfer.length    = length;
    m_transfer.operation = NRF_TWI_MNGR_WRITE_OP(IFX_I2C_BASE_ADDR);
    m_transfer.flags     = 0;

    m_transaction.callback            = app_twi_callback;
    m_transaction.number_of_transfers = 1;
    m_transaction.p_required_twi_cfg  = NULL;
    m_transaction.p_transfers         = &m_transfer;
    m_transaction.p_user_data         = (void*) PAL_STATUS_SUCCESS;
*/

    nrfx_twim_xfer_desc_t tx_xfer = NRFX_TWIM_XFER_DESC_TX(IFX_I2C_BASE_ADDR, p_data, length);


    if (nrfx_twim_xfer(&m_app_twi, &tx_xfer, 0) != NRF_SUCCESS)
    {
        app_twi_callback(NRF_ERROR_BUSY, 0);
    }

    return PAL_STATUS_SUCCESS;
}

/**
 * Platform abstraction layer API to read the data from I2C slave.
 * <br>
 * <br>
 * \image html pal_i2c_read.png "pal_i2c_read()" width=20cm
 *
 *<b>API Details:</b>
 * - The API attempts to read if the I2C bus is free, else it returns busy status #PAL_STATUS_I2C_BUSY<br>
 * - The bus is released only after the completion of reception or after completion of error handling.<br>
 * - The API invokes the upper layer handler with the respective event status as explained below.
 *   - #PAL_I2C_EVENT_BUSY when I2C bus in busy state
 *   - #PAL_I2C_EVENT_ERROR when API fails
 *   - #PAL_I2C_EVENT_SUCCESS when operation is successfully completed asynchronously
 *<br>
 *
 *<b>User Input:</b><br>
 * - The input #pal_i2c_t p_i2c_context must not be NULL.<br>
 * - The upper_layer_event_handler must be initialized in the p_i2c_context before invoking the API.<br>
 *
 *<b>Notes:</b><br>
 *  - Otherwise the below implementation has to be updated to handle different bitrates based on the input context.<br>
 *  - The caller of this API must take care of the guard time based on the slave's requirement.<br>
 *
 * \param[in]  p_i2c_context  pointer to the PAL i2c context #pal_i2c_t
 * \param[in]  p_data         Pointer to the data buffer to store the read data
 * \param[in]  length         Length of the data to be read
 *
 * \retval  #PAL_STATUS_SUCCESS  Returns when the I2C read is invoked successfully
 * \retval  #PAL_STATUS_FAILURE  Returns when the I2C read fails.
 * \retval  #PAL_STATUS_I2C_BUSY Returns when the I2C bus is busy.
 */
pal_status_t pal_i2c_read(pal_i2c_t* p_i2c_context , uint8_t* p_data , uint16_t length)
{
    gp_pal_i2c_current_ctx = p_i2c_context;
/*
    m_transfer.p_data    = p_data;
    m_transfer.length    = length;
    m_transfer.operation = NRF_TWI_MNGR_READ_OP(IFX_I2C_BASE_ADDR);
    m_transfer.flags     = 0;

    m_transaction.callback            = app_twi_callback;
    m_transaction.number_of_transfers = 1;
    m_transaction.p_required_twi_cfg  = 0;
    m_transaction.p_transfers         = &m_transfer;
    m_transaction.p_user_data         = (void*) PAL_STATUS_SUCCESS;
*/
    nrfx_twim_xfer_desc_t rx_xfer = NRFX_TWIM_XFER_DESC_RX(IFX_I2C_BASE_ADDR, p_data, length);


    if (nrfx_twim_xfer(&m_app_twi, &rx_xfer, 0) != NRF_SUCCESS)
    {
        app_twi_callback(NRF_ERROR_BUSY, 0);
    }

    return PAL_STATUS_SUCCESS;
}

/**
 * Platform abstraction layer API to set the bitrate/speed(KHz) of I2C master.
 * <br>
 *
 *<b>API Details:</b>
 * - Sets the bitrate of I2C master if the I2C bus is free, else it returns busy status #PAL_STATUS_I2C_BUSY<br>
 * - The bus is released after the setting the bitrate.<br>
 * - This API must take care of setting the bitrate to I2C master's maximum supported value.
 * - Eg. In XMC4500, the maximum supported bitrate is 400 KHz. If the supplied bitrate is greater than 400KHz, the API will
 *   set the I2C master's bitrate to 400KHz.
 * - Use the #PAL_I2C_MASTER_MAX_BITRATE macro to specify the maximum supported bitrate value for the target platform.
 * - If upper_layer_event_handler is initialized, the upper layer handler is invoked with the respective event
 *   status listed below.
 *   - #PAL_I2C_EVENT_BUSY when I2C bus in busy state
 *   - #PAL_I2C_EVENT_ERROR when API fails to set the bit rate
 *   - #PAL_I2C_EVENT_SUCCESS when operation is successful
 *<br>
 *
 *<b>User Input:</b><br>
 * - The input #pal_i2c_t  p_i2c_context must not be NULL.<br>
 *
 * \param[in] p_i2c_context  Pointer to the pal i2c context
 * \param[in] bitrate        Bitrate to be used by i2c master in KHz
 *
 * \retval  #PAL_STATUS_SUCCESS  Returns when the setting of bitrate is successfully completed
 * \retval  #PAL_STATUS_FAILURE  Returns when the setting of bitrate fails.
 * \retval  #PAL_STATUS_I2C_BUSY Returns when the I2C bus is busy.
 */
pal_status_t pal_i2c_set_bitrate(const pal_i2c_t* p_i2c_context , uint16_t bitrate)
{
    // Bitrate is fixed to the maximum frequency on this platform (400K)
    return PAL_STATUS_SUCCESS;
}

#ifdef IFX_2GO_SUPPORT
pal_status_t pal_i2c_set_instance(nrfx_twim_t* twi_inst)
{
        m_app_twi = *twi_inst;
}
#endif/*IFX_2GO_SUPPORT*/

/**
* @}
*/

I have two questions:

1. Is not possible to use, on the same application, nrf_drv_ + nrf_twi_mgnr and a nrfx_twim drivers, even if the former controls the TWI0 and the latter the TWIM1, correct?

2. Why am I getting stuck on the pwr_mgmt_run routine and what can be done to fix it?

Best regards,

Pedro

  • Hi Martin,

    As far as I am aware, nrfx_twim cannot coexist with nrf_drv or nrf_twi_mngr, so I started porting the I2C NRF PAL to use only the nrfx_twim

    As far as i can see nrf_twi_mngr uses nrf_drv_twi which in turn uses nrfx_twim (if NRF_DRV_TWI_USE_TWIM is defined) 

    I needed to remove my code that uses the nrfx_twim driver. Otherwise the application of the nrfx_glue and legacy porting layer messes up compilation by defining the legacy drivers and undefining the nrfx so much that I cannot get an executable.

    What errors do you get when you have this. I believe we need to convince the glue layer to use TWOM and make  NRF_DRV_TWI_USE_TWIM set to true by satisfying its dependencies.

    Can you please attach the project, so that i can give it a quick try.

  • Hi ,

    Thank you for the quick response!

    I apologize for my long answer, but I am trying to be as detailed as possible here to reduce the number of messages exchanged.

    As far as i can see nrf_twi_mngr uses nrf_drv_twi which in turn uses nrfx_twim (if NRF_DRV_TWI_USE_TWIM is defined) 

    Yes, this is true depending on the macros you set.

    But the issue is that you cannot manually set NRF_DRV_TWI_USE_TWIM, as you said above, since the file  integration/nrfx/legacy/nrf_drv_twi.h does not check if it has been previously defined elsewhere. Also, the macro expansion performed by the full chain of #includes that allows the integration of legacy nrf_drv_* with nrfx_* is complex, poorly documented and difficult to follow, since macros are defined and undefined across multiple files. 

    What errors do you get when you have this. I believe we need to convince the glue layer to use TWOM and make  NRF_DRV_TWI_USE_TWIM set to true by satisfying its dependencies.

    I was getting linking errors on the twi_mngr. I manage it to fix it by trial and error of defining NRFX_TWI_*, TWI_* and NRFX_TWIM_* macros. It is currently building correctly with the macros:

    #define TWI_ENABLED 1
    #define TWI0_ENABLED 1
    #define TWI0_USE_EASY_DMA 1
    #define NRFX_TWI_ENABLED 1
    #define NRFX_TWI0_ENABLED 1
    #define NRF_TWI_MNGR_ENABLED 1
    #define NRFX_TWIM_ENABLED 1

    Can you please attach the project, so that i can give it a quick try.

    I cannot do this for the whole project do to privacy concerns, since the project is already in an advanced development state. I can, however, work on providing a minimal working example with only the TWI counterpart. Also, please note that to able to reproduce the error you will need an Optiga Trust X. Please advise if you want me to do this


    Regarding my initial questions:

    1. Is not possible to use, on the same application, nrf_drv_ + nrf_twi_mgnr and a nrfx_twim drivers, even if the former controls the TWI0 and the latter the TWIM1, correct?

    From your answer I conclude that due to the "magic" of the nrfx integration layer, I am, in all cases, using the nrfx_twim, because the nrf_twi_mngr, which uses nrf_drv_twi, is in fact using the nrfx_twim drivers, due to macros defined on the sdk_config.h

    Is my interpretation correct?

    2. Why am I getting stuck on the pwr_mgmt_run routine and what can be done to fix it?

    Regarding this bug, using the macros above I can compile and run the my code with one device using the twim drivers explicitly and another implicit (through nrf_twi_mngr).

    However, since they require different communication speeds, I am alternatively disabling one and enabling the other to communicate. When I try to enable the second device, I am getting a NRF_ERROR_INVALID_STATE on the TWIM driver initialization.

    A code snapshot is provided below. The error is happening on the line err_code = nrfx_twim_init(m_twi_master, &twim_config, twim_handler, NULL). Am I missing something? Please note that both initialization routines work well independently.

    ret_code_t err_code;
    
    // Optiga Trust X Initialization
    err_code = nrfx_clock_init(clock_event_handler);
    APP_ERROR_CHECK(err_code);
    nrfx_clock_lfclk_start();
    
    // Init nrf_crypto, which initializes the OPTIGA backend, and the OPTIGA host library/stack
    err_code = nrf_crypto_init();
    DEMO_ERROR_CHECK(err_code);
    NRF_LOG_INFO("Optiga Trust X Init succesfull\r\n");
    
    optiga_trust_x_test();
    
    err_code = nrf_crypto_uninit();
    DEMO_ERROR_CHECK(err_code);
    NRF_LOG_INFO("Optiga Trust X Uninit succesfull\r\n");
    
    
    // Intialize second I2C device
    #define MASTER_TWI_INST_ID     0       //!< TWI interface used as a master
    
    static const nrfx_twim_t m_twi_master = NRFX_TWIM_INSTANCE(MASTER_TWI_INST_ID);
    
    
    const nrfx_twim_config_t twim_config = {
       .scl                 = ARDUINO_SCL_PIN,
       .sda                 = ARDUINO_SDA_PIN,
       .frequency           = NRF_TWIM_FREQ_100K*8/10,  // Set to 80 kHz
       .interrupt_priority  = NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY,
       .hold_bus_uninit     = NRFX_TWIM_DEFAULT_CONFIG_HOLD_BUS_UNINIT
    };
    
    err_code = nrfx_twim_init(m_twi_master, &twim_config, twim_handler, NULL);
    APP_ERROR_CHECK(err_code);
    
    nrfx_twim_enable(m_twi_master);

    Thank you for your help

  • However, since they require different communication speeds, I am alternatively disabling one and enabling the other to communicate. When I try to enable the second device, I am getting a NRF_ERROR_INVALID_STATE on the TWIM driver initialization.

    In the meantime, I was able to fix this problem. Somehow, the nrf_twi_mngr_uninit() was leaving the TWIM peripheral on a INITIALIZED STATE. This function is called byNordics implementation of Optiga Trust X I2C pal_i2c_deinit, which on the code above is called by nrf_crypto_uninit().

    I solved it by adding:

     

    nrfx_twim_disable(&m_twi_master);
    nrfx_twim_uninit(&m_twi_master);

    after the nrf_crypto_uninit and before initializing the twim again.

  • martinspedro said:

    I solved it by adding:

    nrfx_twim_disable(&m_twi_master);
    nrfx_twim_uninit(&m_twi_master);
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    nrfx_twim_disable(&m_twi_master);
    nrfx_twim_uninit(&m_twi_master);

    after the nrf_crypto_uninit and before initializing the twim again.

    this is very strange, nrf_twi_mngr_uninit should call nrf_drv_twi_uninit ->  nrfx_twim_uninit which also should disable the twim (nrfx_twim_disable)

    I understand that the preprocessor defines around this glue wrapper between nrx and the legacy driver is making it complicated here. But I am glad that you have a workaround for this. The idea was to create a simple glue layer so that the users using legacy drivers migrate easity to the new changes. But it seems that it can be complicated in some cases to use this.

  • Hi ,

    The workaround works fine, but I shouldn't need one. I decided to invest more time and further investigate the problem.

    Doing a complete trace of the function calls, one can see that when calling nrf_crypto_init(), the call stack is:

    nrf_crypto_init()
    - optiga_backend_init()
    -- optiga_init()
    --- pal_gpio_init();
    --- pal_os_event_init();
    --- optiga_util_open_application(&optiga_comms);
    ---- optiga_comms_open()

    When calling nrf_crypto_deinit(), the call stack is only:

    nrf_crypto_deinit()
    - optiga_backend_uninit()

    because the contents of optiga_backend_uninit() are:

    /** @internal @brief Function to uninitialize OPTIGA backend - currently no implementation is required.
     */
    static ret_code_t optiga_backend_uninit(void)
    {
        // Empty implementation
        return NRF_SUCCESS;
    }

    As you can see, nothing is being done and the twi_mngr is never being uninitialized.

    Since my knowledge of the nrf_crypto is limited, I am not sure if anything needs to be unitialized. At least, Optiga's backend should be removed from the list of available backends, no? Can you please advice?

    Either way, to release the hardware peripherals being used to communicate with Optiga, this problem can be solved by rewriting this function as:

    static ret_code_t optiga_backend_uninit(void)
    {
        if(optiga_comms_close(&optiga_comms) == PAL_STATUS_SUCCESS) {
          return NRF_SUCCESS;
        }
        else {
          return NRF_ERROR_INTERNAL;
        }
        
    }

Related