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

TWI sensor NRF_DRV_TWI_EVT_ADDRESS_NACK

I'm using nRF52 DK (PCA10040) <TWI sensor> example. 

On line 139, printed result =  NRF_SUCCESS

However, the program doesn't print line 142. Instead, the code jumps to twi_handler()

And then, the code doesn't print line 191. It prints line 206: Case 22: NRF_DRV_TWI_EVT_ADDRESS_NACK

A screenshot of PuTTY is given below

My code is here: 

/**
 * Copyright (c) 2015 - 2020, 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 tw_sensor_example main.c
 * @{
 * @ingroup nrf_twi_example
 * @brief TWI Sensor Example main file.
 *
 * This file contains the source code for a sample application using TWI.
 *
 */

#include <math.h>
#include <stdio.h>
#include "boards.h"
#include "app_util_platform.h"
#include "app_error.h"
#include "nrf_drv_twi.h"
#include "nrf_delay.h"


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

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



// 

/* Common addresses definition for temperature sensor. 
 * 1) U means data type is "unsigned". Another example of data type is L, which means "long"
 * 2)  >> is the right shift operator, which means to shift the bit to the right by xxx positions.
 *     e.g. if a = 5 (0000 0101), (a<<1)=10 because (0000 1010)=10
 * 3) The prefix 0x means hexadecimal value
 *    0x21U in hex = 2*(16^1) + 1*(16^0) = 33 in decimal
 *    By seeing the datasheet of SDP3x sensor: address=0x22 when ADDR connects to 1.2K resistor
 *    That's why we define address = 0x22U here
 */
 // When ADDR connects to GND/1.2k resistor, it uses the default I2C address: 0x21/0x22 (Got this info from datasheet)
#define SENSOR_ADDR          (0x22 >> 1)  

/* Chose mode for master and slave. Use 1 bit (LSB) to indicate that 
   - If master reads data from slave, use 1
   - If master sends data to slave, use 0
   In order to set sensor as continuous mode, use register 0x3608
*/
#define continuous_mode_command1 0x36
#define continuous_mode_command2 0x24

uint16_t tempVal;
float tempC;


/* Indicates if operation on TWI has ended. */
static volatile bool m_xfer_done = false;



/* Creating a TWI master driver instance. */
static const nrf_drv_twi_t m_twi = NRF_DRV_TWI_INSTANCE(TWI_INSTANCE_ID);

/* Buffer for samples read from sensor. 
   SDP3x digital sensor outputs a 16-bits data. Since m_sample is 8-bit, so we need to use m_smaple[2] for 16-bit. 
*/
static uint8_t m_sample[2];



/**
 * @brief Function for setting mode on sensor
 */
void sensor_set_mode(void)
{
    NRF_LOG_INFO("sensor_set_mode 000\r\n");
    ret_code_t err_code;
    NRF_LOG_INFO("sensor_set_mode started\r\n");
    // Writing CONTINUOUS_MODE = 0x3608U into SDP3x configuration register. Set SDP3x sensor in continuous mode. 
    uint8_t reg0 = continuous_mode_command1;
    uint8_t reg1 = continuous_mode_command2;
    NRF_LOG_INFO("regt0 = %d , 0x%x\r\n",reg0,reg0);
    NRF_LOG_INFO("regt1 = %d , 0x%x\r\n",reg1,reg1);
    //uint16_t reg = ((reg0 << 8) | reg1);
    uint8_t reg[2] = {reg0,reg1};
    NRF_LOG_INFO("reg16bit: 0x%x %x\r\n",reg[0],reg[1]);


    /* Function for sending data to a TWI slave.       
        * @param[in] p_instance Pointer to the driver instance structure.
        * @param[in] address    Address of a specific slave device (only 7 LSB).
        * @param[in] p_data     Pointer to a transmit buffer.
        * @param[in] length     Number of bytes to send.
        * @param[in] no_stop    If set, the stop condition is not generated on the bus
        *                       after the transfer has completed successfully (allowing
        *                       for a repeated start in the next transfer).
        This function will return NRF_SUCCESS if the procedure was successful.
    */
    err_code = nrf_drv_twi_tx(&m_twi, SENSOR_ADDR, reg, sizeof(reg), false);
    APP_ERROR_CHECK(err_code);
    NRF_LOG_INFO("error code = %s\r\n",nrf_strerror_find(err_code));
    //NRF_LOG_INFO("sizeof reg = %d\r\n",sizeof(reg));
    
    NRF_LOG_INFO(" set i2c address\r\n");
    while (m_xfer_done == false);
    NRF_LOG_INFO("done1\r\n");

}






/**
 * @brief Function for handling data from temperature sensor.
 *
 * @param[in] temp          Pressure value read from sensor.
 */

__STATIC_INLINE void data_handler(uint16_t pressure_raw_data)
{
     float pressure;
     float pressure_scale = 60.0;
     pressure = pressure_raw_data / pressure_scale ;
     NRF_LOG_INFO("raw_data = %d , pressure = " NRF_LOG_FLOAT_MARKER "\r\n",pressure_raw_data,NRF_LOG_FLOAT(pressure));  
}






/**
    @brief Structure for a TWI event.

    typedef struct
    {
        nrf_drv_twi_evt_type_t  type;      ///< 3 TWI master event types (enum): DONE, address_NACK, data_NACK
        nrf_drv_twi_xfer_desc_t xfer_desc; ///< Transfer details.
    } nrf_drv_twi_evt_t;
 */
/**
 * @brief TWI events handler.
 */
void twi_handler(nrf_drv_twi_evt_t const * p_event, void * p_context)
{

     // type: TWI master event types
     // foo->bar is equivalent to (*foo).bar, i.e. it gets the member called bar from the struct that foo points to.
     switch (p_event->type)
    {
        NRF_LOG_INFO("Test222\r\n");

        case NRF_DRV_TWI_EVT_DONE:            // Transfer completed event.
            // NRF_DRV_TWI_XFER_RX: is TWI master driver transfer types (Rx transfer)
            if (p_event->xfer_desc.type == NRF_DRV_TWI_XFER_RX)
            {
                NRF_LOG_INFO("Case 11: NRF_DRV_TWI_EVT_DONE\r\n");
                
                uint16_t pressure = ((m_sample[0] << 8) | m_sample[1]);
                data_handler(pressure);
            }
            m_xfer_done = true;
            break;
        case NRF_DRV_TWI_EVT_ADDRESS_NACK:
            ///< Error event: NACK received after sending the address.
            NRF_LOG_INFO("Case 22: NRF_DRV_TWI_EVT_ADDRESS_NACK\r\n");
            break;
        case NRF_DRV_TWI_EVT_DATA_NACK:
            ///< Error event: NACK received after sending a data byte.
            NRF_LOG_INFO("Case 33: NRF_DRV_TWI_EVT_DATA_NACK\r\n");
            break;
        default:
            NRF_LOG_INFO("1 Default");
            break;
        
    }
    NRF_LOG_INFO("Test 2\r\n");
}












/**
 * @brief UART initialization.
 */
void twi_init (void)
{
    ret_code_t err_code;
    

    // Structure for the TWI master driver instance configuration.
    const nrf_drv_twi_config_t twi_lm75b_config = {
       .scl                = ARDUINO_SCL_PIN,
       .sda                = ARDUINO_SDA_PIN,
       .frequency          = NRF_DRV_TWI_FREQ_100K,     // Options: 100K, 250K, 400K
       .interrupt_priority = APP_IRQ_PRIORITY_HIGH,
       .clear_bus_init     = false
    };
    NRF_LOG_INFO("111\r\n");



    err_code = nrf_drv_twi_init(&m_twi, &twi_lm75b_config, twi_handler, NULL);
    APP_ERROR_CHECK(err_code);
    NRF_LOG_INFO("222\r\n");



    nrf_drv_twi_enable(&m_twi);
    NRF_LOG_INFO("333\r\n");
}














/**
 * @brief Function for reading data from temperature sensor.
 */
static void read_sensor_data()
{
    m_xfer_done = false;
    NRF_LOG_INFO("read_sensor_data\r\n");

    /* Read 1 byte from the specified address - skip 3 bits dedicated for fractional part of temperature. 

     * Function for reading data from a TWI slave.
     *
     * The transmission will be stopped when an error occurs. If a transfer is ongoing,
     * the function returns the error code @ref NRF_ERROR_BUSY.
     *
     * @param[in] p_instance Pointer to the driver instance structure.
     * @param[in] address    Address of a specific slave device (only 7 LSB).
     * @param[in] p_data     Pointer to a receive buffer.
     * @param[in] length     Number of bytes to be received.
     *
     * @retval NRF_SUCCESS                    If the procedure was successful.
     */
    ret_code_t err_code1 = nrf_drv_twi_rx(&m_twi, SENSOR_ADDR, &m_sample[0], sizeof(m_sample));
    ret_code_t err_code2 = nrf_drv_twi_rx(&m_twi, SENSOR_ADDR, &m_sample[1], sizeof(m_sample));
    APP_ERROR_CHECK(err_code1);
    APP_ERROR_CHECK(err_code2);
    uint16_t complete_data = ((uint16_t)m_sample[0] << 8) | m_sample[1];
    NRF_LOG_INFO("complete data = %d  \r\n",complete_data);
}








/**
 * @brief Function for main application entry.
 */
int main(void)
{
    NRF_LOG_INFO("aaa\r\n");
    APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
    NRF_LOG_INFO("bbb\r\n");
    NRF_LOG_DEFAULT_BACKENDS_INIT();

    NRF_LOG_INFO("\r\nTWI sensor example started.");
    
    NRF_LOG_INFO("444\r\n");
    twi_init();
    NRF_LOG_INFO("555\r\n");
     
    sensor_set_mode();
    NRF_LOG_INFO("666\r\n");
    NRF_LOG_FLUSH();
    // NRF_LOG_INFO("Size = %d\r\n",sizeof(m_sample));
    while (true)
    {
        NRF_LOG_INFO("777\r\n");
        nrf_delay_ms(500);
        NRF_LOG_FLUSH();
        do
        {
            NRF_LOG_INFO("888\r\n");
            NRF_LOG_FLUSH();
            nrf_delay_ms(200);
            //  Wait For Event
            __WFE();
        }while (m_xfer_done == false);
        NRF_LOG_INFO("999\r\n");
        read_sensor_data();
        NRF_LOG_INFO("000\r\n");
        NRF_LOG_FLUSH();
    }
}

/** @} */

Question: 

1) Do you know why it's not printing in sequence, please? Some printing sections seem to be skipped. 

2) Do you know how to solve "NRF_DRV_TWI_EVT_ADDRESS_NACK", please? 

  • Hi,

    1. I agree that this looks a bit strange, but I believe it is caused by the log-buffer being filled all the way up, preventing the data from being added to the log. As you can see, there is a "<i" message before the second-last <info>, which could indicate that not all logs are printed. Are you testing this with deferred logging enabled or disabled? Are you using UART or RTT transport for the log?
    2. This error indicates that no devices on the TWI bus acknowledged the address packet, which means that the address in your application is wrong, that the device is not powered correctly, or that the device is in a wrong state where it does not respond to packets. I would recommend you to first run the TWI scanner example, to make sure that the address you entered in your application is correct. The address from TWI scanner can be used directly in the application, without any shifting.

    Best regards,
    Jørgen

  • Hi, dear Jorgen. 

    I tried <TWI scanner> example. 

    - nRF52 scans Arduino UNO, device found. 

    - Arduino UNO scans SDP31 EK, device found. 

    - BUT nRF52 scans SDP31 EK, no device found. 

    Exactly the same code, any idea why, please?

    For your sentence "The address from TWI scanner can be used directly in the application, without any shifting", does that mean if I got 0x21 from <TWI scanner> example, in <TWI sensor> example, I just need to write: 

    ADDRESS 0x21

    Shouldn't l write: ADDRESS  (0x21>>1) because I2C address is 7-bits with 1 R/W bit, please? 

    Thanks

  • StevenW807 said:

    - nRF52 scans Arduino UNO, device found. 

    - Arduino UNO scans SDP31 EK, device found. 

    - BUT nRF52 scans SDP31 EK, no device found. 

    Exactly the same code, any idea why, please?

    I assume that the Arduino does not run the same FW for both tests? How is the SDP31 EK powered? Is this using 3.3V supply?

    StevenW807 said:

    For your sentence "The address from TWI scanner can be used directly in the application, without any shifting", does that mean if I got 0x21 from <TWI scanner> example, in <TWI sensor> example, I just need to write: 

    ADDRESS 0x21

    Yes, if TWI scanner reports a device found on 0x21, you should set ADDRESS 0x21 without any shift.

    StevenW807 said:
    Shouldn't l write: ADDRESS  (0x21>>1) because I2C address is 7-bits with 1 R/W bit, please? 

    No, the address field used by the TWI driver expects the lower 7 LSB address only. Some manufacturers specify the I2C address in a 8-bit format, including the R/W bit. In this case, the shift is needed to remove the R/W bit before passing the address to the TWI driver API.

  • Problem Solved! 

    The code doesn't work due to the slave device and time delay issue. The sensor I'm using requires:

    1) reset-->send continuous mode command-->read data (I didn't add reset command before)

    2) meanwhile, for each read/write command, we must add a time delay (e.g. 5 ms) after the command

    Thanks to everyone who helped me before! Cheers

Related