nrf52810 use with KXTJ3-1057 accelerometer

Hello all, 

I hope you are well. I am currently developing a product on the nrf52810 platform. I have a custom board and now have the BLE functional on the board. The next step is to be able to read the data from the accelerometer. I have been following the example in the SDK for the twi_sensor. I uploaded the example to my dev it (nrf52832) and it worked well. I attempted to adapt the example for use with my accelerometer in my main program however I keep running into confusing errors. I have twi and twim as well as their instances turned on in the config file, and I also have the nrfx drivers installed. Would anyone be able to help guide me though the process to setting up the accelerometer for use with the nrf52810? 

Thank you!

Parents
  • Hi,

    I uploaded the example to my dev it (nrf52832) and it worked well.

    That is good, and is a good start.

    I attempted to adapt the example for use with my accelerometer in my main program however I keep running into confusing errors.

    Can you explain which changes you did in order to adapt to your accelerometer, and what errors you are seeing? Please elaborate.

  • Hello Einar,

    Sorry for the late response. Of course, I will give you a run down of what I have done so far to adapt the twi_sensor example to my program (based on the ble_blinky example). Thus far what I have done is added the twi nrfx drivers (nrfx_twi, nrfx_twi_twim, nrfx_twim). I then copied the code from the twi_sensor example to my main, This includes the code for the addresses of registers in the accelerometer:

    //acc
    #define KXTJ3_XOUTL 0x06 //x
    #define KXTJ3_YOUTL 0x08 //y
    #define KXTJ3_ZOUTL 0x0A //z
    //---

    I haven't changed much of the other code yet, mainly because the compiler keeps telling me I have undefined references.

    I will also provide a rundown of what I am trying to accomplish with the TWI communication, mainly the start sequence and reading from the accelerometer registers:

    Writing

    1. Write to the control register of the accelerometer to start it. Master then also writes slave address and write bit to slave. LSB is set to 0 to write.

    2. slave returns acknowledgment of transmission

    Reading

    1. Master transmits register address of register it wants to read. 

    2. Slave acknowledges.

    3. Master transmits repeated start condition. Then sends 1 in LSB to begin data transfer. 

    Lastly, here is an excerpt about reading the accelerometer registers from its data sheet incase my explanation was not clear enough:

    "When reading data from a KXTJ3 8-bit register on the I2C bus, as shown in Sequence 3 on the next page, the following protocol must be observed: The Master first transmits a start condition (S) and the appropriate Slave Address (SAD) with the LSB set at ‘0’ to write. The KXTJ3 acknowledges and the Master transmits the 8-bit RA of the register it wants to read. The KXTJ3 again acknowledges, and the Master transmits a repeated start condition (Sr). After the repeated start condition, the Master addresses the KXTJ3 with a ‘1’ in the LSB (SAD+R) to read from the previously selected register. The Slave then acknowledges and transmits the data from the requested register. The Master does not acknowledge (NACK) it received the transmitted data but transmits a stop condition to end the data transfer. Note that the KXTJ3 automatically increments through its sequential registers, allowing data to be read from multiple registers following a single SAD+R command as shown below in Sequence 4. The 8-bit register data is transmitted using a left-most format, first bit shifted/clocked out being the MSB bit. If a receiver cannot transmit or receive another complete byte of data until it has performed some other function, it can hold SCL LOW to force the transmitter into a wait state. Data transfer only continues when the receiver is ready for another byte and releases SCL."

    I will admit, I am relatively confused as to how to accomplish this on the nrf52810. I would like the most simple solution as all the product has to do is periodically read from the registers of the accelerometer. A step by step guide of how to do this would be greatly appreciated. 

    Take care,

    M

  • Hi,

    epice500 said:
    the compiler keeps telling me I have undefined references.

    It is not strange that you see confusing errors when you get errors like this. You will likely only be waisting time by looking at other things while you still have important compiler warnings that are not resolved. Generally warnings should always be resolved first so that your code builds without any warnings. In this case, with undefined references you are trying to do something (like call a function which does not exist), and then your code is not doing what you want it to do.

Reply
  • Hi,

    epice500 said:
    the compiler keeps telling me I have undefined references.

    It is not strange that you see confusing errors when you get errors like this. You will likely only be waisting time by looking at other things while you still have important compiler warnings that are not resolved. Generally warnings should always be resolved first so that your code builds without any warnings. In this case, with undefined references you are trying to do something (like call a function which does not exist), and then your code is not doing what you want it to do.

Children
  • Hello Einar,

    Sorry I should clarify that the undefined errors are not in my code but are contained within the nrfx drivers, specifically the nrfx_twim_rx and nrfx_twim_tx functions in the nrf_drv_twi. I delved deeper into the driver and noticed a comment saying that these functions are now deprecated and to use nrfx_twi_xfer instead. How can I transfer over the code that works for the older functions? I will post the code that I have for writing and reading registers. Thank you!

    //------TWI------
    /* TWI instance ID. */
    #define TWI_INSTANCE_ID     0
    
    /* Common addresses definition for temperature sensor. */
    #define SLAVE_ADDR          (0x0E)
    
    /*
    #define LM75B_REG_TEMP      0x00U
    #define LM75B_REG_CONF      0x01U
    #define LM75B_REG_THYST     0x02U
    #define LM75B_REG_TOS       0x03U
    */ 
    
    //acc
    #define KXTJ3_XOUTL 0x06 //x
    #define KXTJ3_YOUTL 0x08 //y
    #define KXTJ3_ZOUTL 0x0A //z
    #define KXTJ3_CTRL 0x1B
    //---------------
    
    #define BOARD_LED                       6                         /**< Is on when device is advertising. */
    #define CONNECTED_LED                   0//BSP_BOARD_LED_1                         /**< Is on when device has connected. 
    #define LEDBUTTON_LED                   0//BSP_BOARD_LED_2                         /**< LED to be toggled with the help of the LED Button Service. 
    #define LEDBUTTON_BUTTON                0//BSP_BUTTON_0                            /**< Button that will trigger the notification event with the LED Button Service 
    
    #define DEVICE_NAME                     "AutolithDisplayDevice"                         /**< Name of device. Will be included in the advertising data. */
    #define MANUFACTURER                    "AutolithInc"
    
    
    #define APP_BLE_OBSERVER_PRIO           3                                       /**< Application's BLE observer priority. You shouldn't need to modify this value. */
    #define APP_BLE_CONN_CFG_TAG            1                                       /**< A tag identifying the SoftDevice BLE configuration. */
    
    #define APP_ADV_INTERVAL                64                                      /**< The advertising interval (in units of 0.625 ms; this value corresponds to 40 ms). */
    #define APP_ADV_DURATION                BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED   /**< The advertising time-out (in units of seconds). When set to 0, we will never time out. */
    
    
    #define MIN_CONN_INTERVAL               MSEC_TO_UNITS(100, UNIT_1_25_MS)        /**< Minimum acceptable connection interval (0.5 seconds). */
    #define MAX_CONN_INTERVAL               MSEC_TO_UNITS(200, UNIT_1_25_MS)        /**< Maximum acceptable connection interval (1 second). */
    #define SLAVE_LATENCY                   0                                       /**< Slave latency. */
    #define CONN_SUP_TIMEOUT                MSEC_TO_UNITS(4000, UNIT_10_MS)         /**< Connection supervisory time-out (4 seconds). */
    
    #define FIRST_CONN_PARAMS_UPDATE_DELAY  APP_TIMER_TICKS(20000)                  /**< Time from initiating event (connect or start of notification) to first time sd_ble_gap_conn_param_update is called (15 seconds). */
    #define NEXT_CONN_PARAMS_UPDATE_DELAY   APP_TIMER_TICKS(5000)                   /**< Time between each call to sd_ble_gap_conn_param_update after the first call (5 seconds). */
    #define MAX_CONN_PARAMS_UPDATE_COUNT    3                                       /**< Number of attempts before giving up the connection parameter negotiation. */
    
    //#define BUTTON_DETECTION_DELAY          APP_TIMER_TICKS(50)                     /**< Delay from a GPIOTE event until a button is reported as pushed (in number of timer ticks). */
    
    #define DEAD_BEEF                       0xDEADBEEF                              /**< Value used as error code on stack dump, can be used to identify stack location on stack unwind. */
    
    #define ADDRESS_WHO_AM_I          (0x0F)
    
    
    BLE_LBS_DEF(m_lbs);                                                             /**< LED Button Service instance. */
    NRF_BLE_GATT_DEF(m_gatt);                                                       /**< GATT module instance. */
    NRF_BLE_QWR_DEF(m_qwr);                                                         /**< Context for the Queued Write module.*/
    
    static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID;                        /**< Handle of the current connection. */
    
    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 uint8_t m_enc_scan_response_data[BLE_GAP_ADV_SET_DATA_SIZE_MAX];         /**< Buffer for storing an encoded scan data. */
    
    //------TWI------
    /* Indicates if operation on TWI has ended. */
    static volatile bool m_xfer_done = false;
    
    /* TWI instance. */
    static const nrf_drv_twi_t m_twi = NRF_DRV_TWI_INSTANCE(TWI_INSTANCE_ID);
    
    /* Buffer for samples read from temperature sensor. */
    static uint8_t m_sample;
    
    
    
    bool KXTJ3_register_write(uint8_t register_address, uint8_t value)
    {
        ret_code_t err_code;
        uint8_t tx_buf[sizeof(SLAVE_ADDR)+1];
    
        //write to the register address and data to transmit buffer
        tx_buf[0] = register_address;
        tx_buf[1] = value;
    
        m_xfer_done = false;
    
        err_code = nrf_drv_twi_tx(&m_twi, SLAVE_ADDR, tx_buf, sizeof(SLAVE_ADDR)+1, false);
        //err_code = nrf_drv_twi_xfer(&m_twi, )
    
        //wait for data transmission
        while (m_xfer_done == false){
            
        }
    
        if (NRF_SUCCESS != err_code)
        {
            return false;
        }
    
        return true;
    }
    
    bool KXTJ3_register_read(uint8_t register_address, uint8_t *destination, uint8_t number_of_bytes)
    {
        ret_code_t err_code;
    
        m_xfer_done = false;
    
        err_code = nrf_drv_twi_tx(&m_twi, SLAVE_ADDR, &register_address, 1, true);
    
        while (m_xfer_done == false){
    
        }
    
        if (NRF_SUCCESS != err_code){
            return false;
        }
    
        m_xfer_done = false;
    
        err_code = nrf_drv_twi_rx(&m_twi, SLAVE_ADDR, destination, number_of_bytes);
    
        while (m_xfer_done == false){}
    
        if (NRF_SUCCESS != err_code){
            return false;
        }
    
        return true;
    }
    
    bool KXTJ3_Verify_id(void)
    {
        uint8_t who_am_i;
    
        if (KXTJ3_register_read(ADDRESS_WHO_AM_I, &who_am_i, 1))
        {
            
            if (who_am_i != 0x35)
            {
                return false;
            }
            else 
            {
                return true;
            }
    
        } 
        else 
        {
            return false;
        }
    
    }
    
    bool KXTJ3_init(void)
    {
        bool transfer_succedded = true;
    
        transfer_succedded &= KXTJ3_Verify_id();
    
        if (KXTJ3_Verify_id() == false){
            return false;
        }
    
        //set registers to correct values
        (void)KXTJ3_register_write(KXTJ3_CTRL, 0x00);
    
    
        return transfer_succedded;
    }
    
    bool KXTJ3_ReadAcc(int16_t * pACC_X, int16_t * pACC_Y, int16_t * pACC_Z)
    {
        uint8_t buf[6];
        bool ret = false;
    
        if (KXTJ3_register_read(KXTJ3_XOUTL, buf, 6) == true){
            KXTJ3_register_read(KXTJ3_XOUTL, buf, 6);
    
            *pACC_X = (buf[0] << 8) | buf[1];
            if(*pACC_X & 0x8000) *pACC_X-=65536;
    
            ret = true;
        }
        return ret;
    }
    
    
    
    
    /**
     * @brief Function for handling data from temperature sensor.
     *
     * @param[in] temp          Temperature in Celsius degrees read from sensor.
     */
    __STATIC_INLINE void data_handler(uint8_t temp)
    {
        NRF_LOG_INFO("Temperature: %d Celsius degrees.", temp);
    }
    
    /**
     * @brief TWI events handler.
                 if (p_event->xfer_desc.type == NRF_DRV_TWI_XFER_RX)
                {
                    data_handler(m_sample);
                }
     */
    void twi_handler(nrf_drv_twi_evt_t const * p_event, void * p_context)
    {
        switch (p_event->type)
        {
            case NRF_DRV_TWI_EVT_DONE:
                m_xfer_done = true;
                break;
            default:
                break;
        }
    }
    
    /**
     * @brief UART initialization.
     */
    void twi_master_init (void)
    {
        ret_code_t err_code;
    
        const nrf_drv_twi_config_t twi_lm75b_config = {
           .scl                = ARDUINO_SCL_PIN,
           .sda                = ARDUINO_SDA_PIN,
           .frequency          = NRF_DRV_TWI_FREQ_100K,
           .interrupt_priority = APP_IRQ_PRIORITY_HIGH,//need to change to low priority for BLE *************
           .clear_bus_init     = false
        };
    
        err_code = nrf_drv_twi_init(&m_twi, &twi_lm75b_config, twi_handler, NULL);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_twi_enable(&m_twi);
    }
    
    //---------------

  • Hi,

    epice500 said:
    I should clarify that the undefined errors are not in my code but are contained within the nrfx drivers, specifically the nrfx_twim_rx and nrfx_twim_tx functions in the nrf_drv_twi.

    I see. As long as this is part of your project though, it is still a problem regardless of who wrote the code. If you get such errors with nRF5 SDK modules that is typically because you are missing some things in your sdk_config.h, as most C files use the preprocessor to exclude non-enabled code. If you look for instance at nrfx_twim_rx() that is implemented in <nRF5 SDK>\modules\nrfx\drivers\src\nrfx_twim.c, and you cna see for instance in line 43 (assuming SDK 17.1.0) that you have this:

    #if NRFX_CHECK(NRFX_TWIM_ENABLED)

    The corresponding #endif is at the end of the file, so if this is not true nothing is included. To make this true, you need to ensure that NRFX_TWIM_ENABLED is true. As you are using the nrf_drv API you need to set the TWI_ENABLED, TWI0_ENABLED and TWI0_USE_EASY_DMA in order to use TWIM0. This will correctly set the nrfx defines which are used by the implementation. I suggest you refer to an exmaple sdk_config.h that use TWIM for a reference (for instance <nRF5 SDK>\examples\peripheral\twi_scanner\pca10056\blank\config\sdk_config.h).

    epice500 said:
    I delved deeper into the driver and noticed a comment saying that these functions are now deprecated and to use nrfx_twi_xfer instead. How can I transfer over the code that works for the older functions?

    The working about "legacy" is a bit unfortunate. There is no problem using the nrf_drv APIs in the nRF5 SDK, and that is what is done in the examples. You just need to ensure you add the requiered files and include paths, and that you correctly configure your sdk_config.h.

Related