nrf_drv_twi_rx error 3

I'm trying to get the device ID of the lis3dh accelerometer on a Thingy:52

nrf_drv_twi_tx returns 3 as an error. This means NRF_ERROR_INTERNAL  --> "If an error was detected by hardware." 

I doubt that my hardware is broken... 

I used a driver template: https://github.com/STMicroelectronics/lis3dh/tree/6a82fc90cfb688686d0b344c82184c33ee844697

My code is included in this post. Line 361 is where I'm trying to get the device ID. 

Greetings

Willem

/**
 * Copyright (c) 2014 - 2021, Nordic Semiconductor ASA
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form, except as embedded into a Nordic
 *    Semiconductor ASA integrated circuit in a product or a software update for
 *    such product, must reproduce the above copyright notice, this list of
 *    conditions and the following disclaimer in the documentation and/or other
 *    materials provided with the distribution.
 *
 * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
 *    contributors may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * 4. This software, with or without modification, must only be used with a
 *    Nordic Semiconductor ASA integrated circuit.
 *
 * 5. Any software provided in binary form under this license must not be reverse
 *    engineered, decompiled, modified and/or disassembled.
 *
 * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
/** @file
 *
 * @defgroup ble_sdk_app_beacon_main main.c
 * @{
 * @ingroup ble_sdk_app_beacon
 * @brief Beacon Transmitter Sample Application main file.
 *
 * This file contains the source code for an Beacon transmitter sample application.
 */

#include <stdbool.h>
#include <stdint.h>
#include "nordic_common.h"
#include "bsp.h"
#include "nrf_soc.h"
#include "nrf_sdh.h"
#include "nrf_sdh_ble.h"
#include "ble_advdata.h"
#include "app_timer.h"
#include "nrf_pwr_mgmt.h"

#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"

#include "nrf_delay.h"
#include "lis3dh_reg.c"
//#include "nrfx_twi.h"
#include "nrf_drv_twi.h"

/* TWI instance ID. */
#define TWI_INSTANCE_ID     0

/* TWI instance. */
static const nrf_drv_twi_t m_twi = NRF_DRV_TWI_INSTANCE(TWI_INSTANCE_ID);

uint32_t acc_data= 0xDDDDDDDD; //kan een groter ding zijn = ander type //@nader hier data stekenuint32_t acc_data= 0xDDDDDDDD; //kan een groter ding zijn = ander type //@nader hier data steken

#define APP_BLE_CONN_CFG_TAG            1                                   /**< A tag identifying the SoftDevice BLE configuration. */

#define NON_CONNECTABLE_ADV_INTERVAL    MSEC_TO_UNITS(100, UNIT_0_625_MS)   /**< The advertising interval for non-connectable advertisement (100 ms). This value can vary between 100ms to 10.24s). */

#define APP_BEACON_BASE_UUID            0x1d, 0x25, 0x78, 0x0a, \
                                        0x00, 0xe0, 0x46, 0xcc, \
                                        0x8d, 0x0e, 0x5c, 0x90, \
                                        0x00, 0x00, 0xe1, 0x2d              /**< Randomly generated UUID */

#define DEAD_BEEF                       0xDEADBEEF                          /**< Value used as error code on stack dump, can be used to identify stack location on stack unwind. */

static ble_gap_adv_params_t m_adv_params;                                   /**< Parameters to be passed to the stack when starting advertising. */
static uint8_t              m_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET;  /**< Advertising handle used to identify an advertising set. */
static uint8_t              m_enc_advdata[BLE_GAP_ADV_SET_DATA_SIZE_MAX];   /**< Buffer for storing an encoded advertising set. */

static ble_uuid_t m_adv_uuids[] = {{UUID, BLE_UUID_TYPE_VENDOR_BEGIN}};     /**< Universally unique service identifiers. */

/**@brief 128-bit UUID base List. */
static const ble_uuid128_t m_base_uuid128 =
{
   .uuid128 = {
       APP_BEACON_BASE_UUID
   }
};
   
static ble_uuid_t service_uuid;

/**@brief Struct that contains pointers to the encoded advertising data. */
static ble_gap_adv_data_t m_adv_data =
{
    .adv_data =
    {
        .p_data = m_enc_advdata,
        .len    = BLE_GAP_ADV_SET_DATA_SIZE_MAX
    },
    .scan_rsp_data =
    {
        .p_data = NULL,
        .len    = 0

    }
};


/**@brief Callback function for asserts in the SoftDevice.
 *
 * @details This function will be called in case of an assert in the SoftDevice.
 *
 * @warning This handler is an example only and does not fit a final product. You need to analyze
 *          how your product is supposed to react in case of Assert.
 * @warning On assert from the SoftDevice, the system can only recover on reset.
 *
 * @param[in]   line_num   Line number of the failing ASSERT call.
 * @param[in]   file_name  File name of the failing ASSERT call.
 */
void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
{
    app_error_handler(DEAD_BEEF, line_num, p_file_name);
}


/**@brief Function for initializing the Advertising functionality.
 *
 * @details Encodes the required advertising data and passes it to the stack.
 *          Also builds a structure to be passed to the stack when starting advertising.
 */
static void advertising_init(void)
{
    uint32_t      err_code;
    ble_advdata_t advdata;

    // Build and set advertising data.
    memset(&advdata, 0, sizeof(advdata));
    
    advdata.uuids_complete.p_uuids = m_adv_uuids;
    advdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);


    // add manufacturing data (accelerometer data)
    ble_advdata_manuf_data_t manuf_data;
    manuf_data.company_identifier = 0x0000;

    //TODO iets met accelerometer driver
    
    manuf_data.data.p_data = (uint8_t *) &acc_data;
    manuf_data.data.size = sizeof(acc_data);

    advdata.p_manuf_specific_data = &manuf_data;


    // Initialize advertising parameters (used when starting advertising).
    memset(&m_adv_params, 0, sizeof(m_adv_params));

    m_adv_params.properties.type = BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED;
    m_adv_params.p_peer_addr     = NULL;    // Undirected advertisement.
    m_adv_params.filter_policy   = BLE_GAP_ADV_FP_ANY;
    m_adv_params.interval        = NON_CONNECTABLE_ADV_INTERVAL;
    m_adv_params.duration        = 0;       // Never time out.

    err_code = ble_advdata_encode(&advdata, m_adv_data.adv_data.p_data, &m_adv_data.adv_data.len);
    APP_ERROR_CHECK(err_code);

    err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &m_adv_data, &m_adv_params);
    APP_ERROR_CHECK(err_code);
}


/**@brief Function for starting advertising.
 */
static void advertising_start(void)
{
    ret_code_t err_code;

    err_code = sd_ble_gap_adv_start(m_adv_handle, APP_BLE_CONN_CFG_TAG);
    APP_ERROR_CHECK(err_code);

    err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
    APP_ERROR_CHECK(err_code);
}


/**@brief Function for initializing the BLE stack.
 *
 * @details Initializes the SoftDevice and the BLE event interrupt.
 */
static void ble_stack_init(void)
{
    ret_code_t err_code;

    err_code = nrf_sdh_enable_request();
    APP_ERROR_CHECK(err_code);

    // Configure the BLE stack using the default settings.
    // Fetch the start address of the application RAM.
    uint32_t ram_start = 0;
    err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
    APP_ERROR_CHECK(err_code);

    // Enable BLE stack.
    err_code = nrf_sdh_ble_enable(&ram_start);
    APP_ERROR_CHECK(err_code);
}


/**@brief Function for initializing logging. */
static void log_init(void)
{
    ret_code_t err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);

    NRF_LOG_DEFAULT_BACKENDS_INIT();
}


/**@brief Function for the LEDs initialization.
 *
 * @details Initializes all LEDs used by the application.
 */
/*
static void leds_init(void)
{
    bsp_board_init(BSP_INIT_LEDS);
}
*/


/**@brief Function for initializing timers. */
static void timers_init(void)
{
    ret_code_t err_code = app_timer_init();
    APP_ERROR_CHECK(err_code);
}


/**@brief Function for initializing power management.
 */
static void power_management_init(void)
{
    ret_code_t err_code;
    err_code = nrf_pwr_mgmt_init();
    APP_ERROR_CHECK(err_code);
}


/**@brief Function for handling the idle state (main loop).
 *
 * @details If there is no pending log operation, then sleep until next the next event occurs.
 */
static void idle_state_handle(void)
{
    if (NRF_LOG_PROCESS() == false)
    {
        nrf_pwr_mgmt_run();
    }
}


/*
 * @brief  Write generic device register (platform dependent)
 *
 * @param  handle    customizable argument. In this examples is used in
 *                   order to select the correct sensor bus handler.
 * @param  reg       register to write
 * @param  bufp      pointer to data to write in register reg
 * @param  len       number of consecutive register to write
 *
 */

static int32_t platform_write(void *handle, uint8_t const * reg, const uint8_t *bufp,
                              uint16_t len)
{

  return nrf_drv_twi_tx(handle, LIS3DH_I2C_ADD_L, reg, 1, false);
	
}


/*
 * @brief  Read generic device register (platform dependent)
 *
 * @param  handle    customizable argument. In this examples is used in
 *                   order to select the correct sensor bus handler.
 * @param  reg       register to read
 * @param  bufp      pointer to buffer that store the data read
 * @param  len       number of consecutive register to read
 *
 */
static int32_t platform_read(void *handle, uint8_t * reg, uint8_t *bufp,
                             uint16_t len)
{

  return nrf_drv_twi_rx(handle, LIS3DH_I2C_ADD_L, reg, sizeof(reg));

}


/*
 * @brief  platform specific delay (platform dependent)
 *
 * @param  ms        delay in ms
 *
 */
static void platform_delay(uint32_t ms)
{
  nrf_delay_ms(ms);												
}

/*
 * @brief  platform specific initialization (platform dependent)
 */

static void platform_init(void)
{

  nrf_drv_twi_enable(&m_twi);
  nrf_delay_ms(50);
  void twi_master_init(void);          //Initialize i2c
  nrf_delay_ms(50);
  
}

static void accelerometer_init(void)
{
    /* Private variables Accelerometer*/
    int16_t data_raw_acceleration[3];;
    float acceleration_mg[3];
    uint8_t whoamI = 15;
    uint32_t err = 1;
    
    /* Initialize mems driver interface */
    stmdev_ctx_t dev_ctx;
    
    dev_ctx.write_reg = (stmdev_write_ptr) platform_write;
    dev_ctx.read_reg = (stmdev_read_ptr) platform_read;
    dev_ctx.handle = (void*) &m_twi;

    /* Wait boot time and initialize platform specific hardware */
    platform_init();

    /* Wait sensor boot time */
    platform_delay(10);

    /* Check device ID */
    err = lis3dh_device_id_get(&dev_ctx, &whoamI);

    if (err != NRF_SUCCESS)
        NRF_LOG_ERROR("Device ID get error");

    if (whoamI != LIS3DH_ID) {
        while (1) {
          /* manage here device not found */
        }
     }

    /* Enable Block Data Update. */
    lis3dh_block_data_update_set(&dev_ctx, PROPERTY_ENABLE);

    /* Set Output Data Rate to 1Hz. */
    lis3dh_data_rate_set(&dev_ctx, LIS3DH_ODR_1Hz);

    /* Set full scale to 2g. */
    lis3dh_full_scale_set(&dev_ctx, LIS3DH_2g);

    /* Enable temperature sensor. */
    lis3dh_aux_adc_set(&dev_ctx, LIS3DH_AUX_ON_TEMPERATURE);

    /* Set device in continuous mode with 12 bit resol. */
    lis3dh_operating_mode_set(&dev_ctx, LIS3DH_HR_12bit);

    /* Read samples in polling mode (no int) */
    while (1) {
        lis3dh_reg_t reg;
        /* Read output only if new value available */
        lis3dh_xl_data_ready_get(&dev_ctx, &reg.byte);

        if (reg.byte) {

            /* Read accelerometer data */
            memset(data_raw_acceleration, 0x00, 3 * sizeof(int16_t));

            lis3dh_acceleration_raw_get(&dev_ctx, data_raw_acceleration);

            acceleration_mg[0] =
                lis3dh_from_fs2_hr_to_mg(data_raw_acceleration[0]);

            acceleration_mg[1] =
                lis3dh_from_fs2_hr_to_mg(data_raw_acceleration[1]);

            acceleration_mg[2] =
                lis3dh_from_fs2_hr_to_mg(data_raw_acceleration[2]);

            NRF_LOG_RAW_INFO("Acceleration [mg]:%4.2f\t%4.2f\t%4.2f\r\n",
                    acceleration_mg[0], acceleration_mg[1], acceleration_mg[2]);
        }

        //Store accelerometer data for advertisment
        ////acc_data = data_raw_acceleration;

    }
}

/**
 * @brief Function for application main entry.
 */
int main(void)
{
    
    // Initialize.

    NRF_LOG_INFO("Initializing...");

    log_init();
    timers_init();
    power_management_init();
    ble_stack_init();

    // add UUID to the BLE stack's table
    uint32_t   err_code;

    err_code = sd_ble_uuid_vs_add(&m_base_uuid128, &service_uuid.type);
    if (err_code != NRF_SUCCESS){
        NRF_LOG_ERROR("Error adding base UUID: %d", err_code);
    }

    accelerometer_init();

    advertising_init();

    // Start execution.
    NRF_LOG_INFO("Glass beacon started.");
    advertising_start();

    
   
    // Enter main loop.
    for (;;)
    {
        idle_state_handle();
    }
}


/**
 * @}
 */

Parents
  • Hi Willem

    Since this is a public post, I would just like to remind future other readers of this forum that our nRF Connect SDK has a sample for the LIS2DH: Motion Sensor Monitor, which is compatible with the LIS3DH.

    However, you told me last time that you cannot switch to the nRF Connect SDK, so let us continue to work with the nRF5 SDK here.

    Where do is the function "lis3dh_device_id_get" defined?

    Is your LIS3DH sensor an external sensor?
    If so, how is it connected? Are the SCL and SDA lines pulled up?

    Regards,
    Sigurd Hellesvik

Reply
  • Hi Willem

    Since this is a public post, I would just like to remind future other readers of this forum that our nRF Connect SDK has a sample for the LIS2DH: Motion Sensor Monitor, which is compatible with the LIS3DH.

    However, you told me last time that you cannot switch to the nRF Connect SDK, so let us continue to work with the nRF5 SDK here.

    Where do is the function "lis3dh_device_id_get" defined?

    Is your LIS3DH sensor an external sensor?
    If so, how is it connected? Are the SCL and SDA lines pulled up?

    Regards,
    Sigurd Hellesvik

Children
Related