This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Help on SensorTag accelerometer resolution prolbem

Hi all, I'd like to change the default 8-bit resolution of accelerometer in SensorTag to 12-bit. So I changed the firmware source code by setting RES bit in ACC_REG_ADDR_CTRL_REG1 (0x1B) to 1 and modified the data length. However, after I test it using BLE Device Monitor, the output values remain the same. The accelerometer seems not working after the change. I am using the latest firmware source code in BLE stack 1.4.

So anyone here can help me on this issue? Thank you in advance!!

Regards

Chunmeng

  • Update: I changed the source code to let the accelerometer on all the time, then I got all six outputs successfully. I make it by putting the code below to the HalAccSetRange function in hal_acc.c file and delete the turn on/off code in the HalAccRead function

    // Select this sensor
    HalAccSelect();
    //Turn off sensor first
    HalSensorWriteReg(ACC_REG_ADDR_CTRL_REG1, &accSensorOff, sizeof(accSensorOff));
    // Turn on sensor
    HalSensorWriteReg(ACC_REG_ADDR_CTRL_REG1, &accSensorConfig, sizeof(accSensorConfig));

    However, I am still confused why the accelerometer cannot work as the usual way (wake up - measure - sleep). Does anyone have any suggestion? I am new to this area, please point out if I made any mistakes and I will appreciate your help :)

    Thank you.

    Chunmeng

  • I think the issue lies with the power-up and start-up times. Since Vdd is not switched the power-up time is not an issue; however with a default Tilt Output Data Rate of 12.5Hz there is a start-up time from “PC1 set” to valid outputs of 81mSecs when RES=1 (ie. 12-bit mode). This may apply even when not specifically enabling the tilt timer and the delay in the supplied code is much shorter than this.

     

    I’ve added an optional 12-bit mode, where FEATURE_ADC_12BIT can be added to Project->Options->C/C++ Compiler->Preprocessor::Defined Symbols for each project, eg _A and _B if using OAD:

     

    // Optional resolution setting, use high-power (12-bit) or low-power (8-bit)

    #if defined ( FEATURE_ACC_12BIT )

      #define ACC_REG_RESOLUTION           ACC_REG_CTRL_RES

    #else

      #define ACC_REG_RESOLUTION           0

    #endif

     

    // Range +- 2G

    #define ACC_REG_CTRL_ON_2G             ( ACC_REG_CTRL_PC | ACC_REG_RESOLUTION )

    #define ACC_REG_CTRL_OFF_2G            (               0 | ACC_REG_RESOLUTION )

     

    // Range +- 4G

    #define ACC_REG_CTRL_ON_4G             ( ACC_REG_CTRL_PC | ACC_REG_CTRL_GSEL_LO | ACC_REG_RESOLUTION )

    #define ACC_REG_CTRL_OFF_4G            (               0 | ACC_REG_CTRL_GSEL_LO | ACC_REG_RESOLUTION )

     

    // Range +- 8G

    #define ACC_REG_CTRL_ON_8G             ( ACC_REG_CTRL_PC | ACC_REG_CTRL_GSEL_HI | ACC_REG_RESOLUTION )

    #define ACC_REG_CTRL_OFF_8G            (               0 | ACC_REG_CTRL_GSEL_HI | ACC_REG_RESOLUTION )

     

    The data length needs to be set, depending on the compile option:

    // Length of sensor data in bytes, 12-bit requires 2 bytes per axis

    #if defined ( FEATURE_ACC_12BIT )

      #define ACCELEROMETER_DATA_LEN 6

    #else

      #define ACCELEROMETER_DATA_LEN 3

    #endif

     

    TI also uses a local define the usage of which which needs to be checked:

    #define SENSOR_SERVICE          ACCELEROMETER_SERVICE

    #define SENSOR_DATA_LEN         ACCELEROMETER_DATA_LEN

     

    Leading to potential bugs such as here:

    // Characteristic Value: data

    #if (SENSOR_DATA_LEN == 3)

    static uint8 sensorData[SENSOR_DATA_LEN] = { 0, 0, 0};

    #elif (SENSOR_DATA_LEN == 6)

    static uint8 sensorData[SENSOR_DATA_LEN] = { 0, 0, 0, 0, 0, 0};

    #endif

     

    Compile-time asserts in C code can detect this kind of issue:

    COMPILE_ASSERT(sizeof(sensorData) == ACCELEROMETER_DATA_LEN );

     

    Using your suggestion on initialization:

     

    /**************************************************************************************************

    * @fn          HalAccSetRange

    *

    * @brief       Set the range of the accelerometer

    *

    * @param       range: HAL_ACC_RANGE_2G, HAL_ACC_RANGE_4G, HAL_ACC_RANGE_8G

    *

    * @return      None

    */

    void HalAccSetRange(uint8 range)

    {

      accRange = range;

     

      switch (accRange)

      {

      case HAL_ACC_RANGE_2G:

        accSensorConfig = ACC_REG_CTRL_ON_2G;

        accSensorOff = ACC_REG_CTRL_OFF_2G;

        break;

      case HAL_ACC_RANGE_4G:

        accSensorConfig = ACC_REG_CTRL_ON_4G;

        accSensorOff = ACC_REG_CTRL_OFF_4G;

        break;

      case HAL_ACC_RANGE_8G:

        accSensorConfig = ACC_REG_CTRL_ON_8G;

        accSensorOff = ACC_REG_CTRL_OFF_8G;

        break;

      default:

        // Should not get here

        break;

      }

    #if defined ( FEATURE_ACC_12BIT )

      // Select this sensor

      HalAccSelect();

      // Turn off sensor

      HalSensorWriteReg(ACC_REG_ADDR_CTRL_REG1, &accSensorOff, sizeof(accSensorOff));

      // Turn on sensor

      HalSensorWriteReg(ACC_REG_ADDR_CTRL_REG1, &accSensorConfig, sizeof(accSensorConfig));

    #endif

    }

     

    Keep HalAccRead() to the same as before for 8-bit mode, but changing to your suggestion plus reading 6 bytes in 16-bit mode:

     

    /**************************************************************************************************

    * @fn          HalAccRead

    *

    * @brief       Read data from the accelerometer - X, Y, Z - 6 bytes 16-bit

    *

    * @return      TRUE if valid data, FALSE if not

    */

    bool HalAccRead(uint8 *pBuf )

    {

      uint8 buf[ACCELEROMETER_DATA_LEN];

      bool success;

     

      // Select this sensor

      HalAccSelect();

     

      // Read the six registers

      success = HalSensorReadReg( ACC_REG_ADDR_XOUT_L, buf, sizeof(buf) );

      if (success)

      {

        // Result is already in LE, don't need to reverse bytes

        uint8 *pDst = pBuf, *pSrc = buf, Index;

        for (Index=0; Index < sizeof(buf); Index++)

        {

          *pDst++ = *pSrc++;

        }

      }

      return success;

    }

     

     

    I’ve added more detail to the description:

     

    /* ------------------------------------------------------------------------------------------------

     *                                         Description

     * ------------------------------------------------------------------------------------------------

     */

    // CTRL_REG1 - I2C Address: 0x1Bh

    // ==============================

    // Read/write control register that controls the main feature set

    // ===== ===== ===== ===== ===== ===== ===== =====

    // R/W   R/W   R/W   R/W   R/W   R/W   R/W   R/W  

    // ===== ===== ===== ===== ===== ===== ===== =====

    // PC1   RES   DRDYE GSEL1 GSEL0 TDTE  WUFE  TPE   Reset Value

    // Bit7  Bit6  Bit5  Bit4  Bit3  Bit2  Bit1  Bit0  00000000

    // ===== ===== ===== ===== ===== ===== ===== =====

    //

    // PC1 controls the operating mode of the KXTIK

    //    PC1 = 0 - stand-by mode

    //    PC1 = 1 - operating mode

    // RES determines the performance mode of the KXTIK. Note that to change the value

    // of this bit, the PC1 bit must first be set to 0

    //    RES = 0 - low current, 8-bit valid

    //    RES = 1 - high current, 12-bit valid

    // DRDYE enables the reporting of the availability of new acceleration data on the

    // interrupt. Note that to change the value of this bit, the PC1 bit must first be set to 0

    //    DRDYE = 0 - availability of new acceleration data not reflected on interrupt pin (11)

    //    DRDYE = 1 - availability of new acceleration data reflected on interrupt pin (11)

    // GSEL1, GSEL0 selects the acceleration range of the accelerometer outputs per Table 12.

    // Note that to change the value of this bit, the PC1 bit must first be set to 0

    // ± 2g / 4g / 8g Tri-axis Digital

    //

    //    GSEL1 GSEL0  Range

    //    ===== =====  =====

    //      0      0   +/-2g

    //      0      1   +/-4g

    //      1      0   +/-8g

    //      1      1      NA

    //    Table 12. Selected Acceleration Range

    //

    // TDTE enables the Directional TapTM function that will detect single and double tap events.

    // Note that to change the value of this bit, the PC1 bit must first be set to 0

    //    TDTE = 0 - disable

    //    TDTE = 1 - enable

    // WUFE enables the Wake Up (motion detect) function that will detect a general motion event.

    // Note that to change the value of this bit, the PC1 bit must first be set to 0

    //    WUFE = 0 - disable

    //    WUFE = 1 - enable

    // TPE enables the Tilt Position function that will detect changes in device orientation.

    // Note that to change the value of this bit, the PC1 bit must first be set to 0

    //    TPE  = 0 - disable

    //    TPE  = 1 - enable

     

    // Accelerometer Registers

    // =======================

    // 1 - Read Back Acceleration Data - 8-bit

    //   - Write 0x80 to Control Register 1 to assert PC1 (Power Control bit), set the G-range to

    //     +/-2g, and set the resolution to 8 bits

    //

    //     Register Name     Address         Value

    //         CTRL_REG1     0x1B  0001 1011 0x80 1000 0000

    //   - Acceleration data can now be read from the XOUT_H, YOUT_H, and ZOUT_H registers.

    // 2 - Read Back Acceleration Data - 16-bit

    //   - Write 0x80 to Control Register 1 to assert PC1 (Power Control bit), set the G-range to

    //     +/-2g, and set the resolution to 16 bits

    //

    //     Register Name     Address         Value

    //         CTRL_REG1     0x1B  0001 1011 0xC0 1100 0000

    //   - Acceleration data can now be read from the XOUT_L/H, YOUT_L/H, and ZOUT_L/H registers.

     

    // Free-fall Sensing

    // =================

    // When a tri-axis accelerometer is stationary, its total acceleration it measures is 1g

    // (9.8m/s2), regardless of orientation. This total acceleration can be calculated from

    // the X, Y, and Z outputs of the accelerometer using Eq. 1 below. When a tri-axis

    // accelerometer is dropped in any orientation, it is in free-fall and the measured

    // acceleration on all three axes is 0g. Therefore, the total acceleration is zero

    // as well. Total acceleration can be monitored to sense that the accelerometer has been

    // dropped, and to measure its free-fall time. Note that this signature cannot accurately

    // be observed when using a dual axis accelerometer because, when horizontally oriented,

    // the X and Y-axis outputs are the same (0g), whether the accelerometer is stationary or

    // in free-fall.

    //

    // Total Acceleration atot = root(ax^2 + ay^2 + az^2)

     

    /* ------------------------------------------------------------------------------------------------

    *                                           Constants

    * ------------------------------------------------------------------------------------------------

    */

    // Sensor I2C address

    #define HAL_KXTI9_I2C_ADDRESS          0x0F

     

    // KXTI9 register addresses

    //                                                                      I2C Address

    //      Register Name                  Addr    Register Name    * Rd/Wr Hex  Binary

    //      ===========================    ====    ================ = ===== ==== =========

    #define ACC_REG_ADDR_XOUT_HPF_L        0x00 // XOUT_HPF_L           R   0x00 0000 0000

    #define ACC_REG_ADDR_XOUT_HPF_H        0x01 // XOUT_HPF_H           R   0x01 0000 0001

    #define ACC_REG_ADDR_YOUT_HPF_L        0x02 // YOUT_HPF_L           R   0x02 0000 0010

    #define ACC_REG_ADDR_YOUT_HPF_H        0x03 // YOUT_HPF_H           R   0x03 0000 0011

    #define ACC_REG_ADDR_ZOUT_HPF_L        0x04 // ZOUT_HPF_L           R   0x04 0000 0100

    #define ACC_REG_ADDR_ZOUT_HPF_H        0x05 // ZOUT_HPF_H           R   0x05 0000 0101

    #define ACC_REG_ADDR_XOUT_L            0x06 // XOUT_L               R   0x06 0000 0110

    #define ACC_REG_ADDR_XOUT_H            0x07 // XOUT_H               R   0x07 0000 0111

    #define ACC_REG_ADDR_YOUT_L            0x08 // YOUT_L               R   0x08 0000 1000

    #define ACC_REG_ADDR_YOUT_H            0x09 // YOUT_H               R   0x09 0000 1001

    #define ACC_REG_ADDR_ZOUT_L            0x0A // ZOUT_L               R   0x0A 0000 1010

    #define ACC_REG_ADDR_ZOUT_H            0x0B // ZOUT_H               R   0x0B 0000 1011

    #define ACC_REG_ADDR_DCST_RESP         0x0C // DCST_RESP            R   0x0C 0000 1100

                                                // Not Used             -   0x0D 0000 1101

                                                // Not Used             -   0x0E 0000 1110

    #define ACC_REG_ADDR_WHO_AM_I          0x0F // WHO_AM_I             R   0x0F 0000 1111

    #define ACC_REG_ADDR_TILT_POS_CUR      0x10 // TILT_POS_CUR         R   0x10 0001 0000

    #define ACC_REG_ADDR_TILT_POS_PRE      0x11 // TILT_POS_PRE         R   0x11 0001 0001

                                                // Kionix Reserved      -   0x12 0001 0010

                                                // Kionix Reserved      -   0x13 0001 0011

                                                // Kionix Reserved      -   0x14 0001 0100

    #define ACC_REG_ADDR_INT_SRC_REG1      0x15 // INT_SRC_REG1         R   0x15 0001 0101

    #define ACC_REG_ADDR_INT_SRC_REG2      0x16 // INT_SRC_REG2         R   0x16 0001 0110

                                                // Not Used             -   0x17 0001 0111

    #define ACC_REG_ADDR_STATUS_REG        0x18 // STATUS_REG           R   0x18 0001 1000

                                                // Not Used             -   0x19 0001 1001

    #define ACC_REG_ADDR_INT_REL           0x1A // INT_REL              R   0x1A 0001 1010

    #define ACC_REG_ADDR_CTRL_REG1         0x1B // CTRL_REG1        *   R/W 0x1B 0001 1011

    #define ACC_REG_ADDR_CTRL_REG2         0x1C // CTRL_REG2        *   R/W 0x1C 0001 1100

    #define ACC_REG_ADDR_CTRL_REG3         0x1D // CTRL_REG3        *   R/W 0x1D 0001 1101

    #define ACC_REG_ADDR_INT_CTRL_REG1     0x1E // INT_CTRL_REG1    *   R/W 0x1E 0001 1110

    #define ACC_REG_ADDR_INT_CTRL_REG2     0x1F // INT_CTRL_REG2    *   R/W 0x1F 0001 1111

    #define ACC_REG_ADDR_INT_CTRL_REG3     0x20 // INT_CTRL_REG3    *   R/W 0x20 0010 0000

    #define ACC_REG_ADDR_DATA_CTRL_REG     0x21 // DATA_CTRL_REG    *   R/W 0x21 0010 0001

                                                // Not Used             -   0x22-0x27

    #define ACC_REG_ADDR_TILT_TIMER        0x28 // TILT_TIMER       *   R/W 0x28 0010 1000

    #define ACC_REG_ADDR_WUF_TIMER         0x29 // WUF_TIMER        *   R/W 0x29 0010 1001

                                                // Not Used             -   0x2A 0010 1010

    #define ACC_REG_ADDR_TDT_TIMER         0x2B // TDT_TIMER        *   R/W 0x2B 0010 1011

    #define ACC_REG_ADDR_TDT_H_THRESH      0x2C // TDT_H_THRESH     *   R/W 0x2C 0010 1100

    #define ACC_REG_ADDR_TDT_L_THRESH      0x2D // TDT_L_THRESH     *   R/W 0x2D 0010 1101

    #define ACC_REG_ADDR_TDT_TAP_TIMER     0x2E // TDT_TAP_TIMER    *   R/W 0x2E 0010 1110

    #define ACC_REG_ADDR_TDT_TOTAL_TIMER   0x2F // TDT_TOTAL_TIMER  *   R/W 0x2F 0010 1111

    #define ACC_REG_ADDR_TDT_LATENCY_TIMER 0x30 // TDT_LATENCY_TIME *   R/W 0x30 0011 0000

    #define ACC_REG_ADDR_TDT_WINDOW_TIMER  0x31 // TDT_WINDOW_TIMER *   R/W 0x31 0011 0001

    #define ACC_REG_ADDR_BUF_CTRL1         0x32 // BUF_CTRL1        *   R/W 0x32 0011 0010

    #define ACC_REG_ADDR_BUF_CTRL2         0x33 // BUF_CTRL2        *   R/W 0x33 0011 0011

    #define ACC_REG_ADDR_BUF_STATUS_REG1   0x34 // BUF_STATUS_REG1      R   0x34 0011 0100

    #define ACC_REG_ADDR_BUF_STATUS_REG2   0x35 // BUF_STATUS_REG2      R ? 0x35 0011 0101

    #define ACC_REG_ADDR_BUF_CLEAR         0x36 // BUF_CLEAR            W   0x36 0011 0110

                                                // Reserved             -   0x37-0x39

    #define ACC_REG_ADDR_SELF_TEST         0x3A // SELF_TEST            R/W 0x3A 0011 1010

                                                // Reserved             -   0x3B-0x59

    #define ACC_REG_ADDR_WUF_THRESH        0x5A // WUF_THRESH       *   R/W 0x5A 0101 1010

                                                // Reserved             -   0x5B 0101 1011

    #define ACC_REG_ADDR_TILT_ANGLE        0x5C // TILT_ANGLE       *   R/W 0x5C 0101 1100

                                                // Reserved             -   0x5D-0x5E

    #define ACC_REG_ADDR_HYST_SET          0x5F // HYST_SET         *   R/W 0x5F 0101 1111

    #define ACC_REG_ADDR_BUF_READ          0x7F // BUF_READ             R   0x7F 0111 1111

     

    // Select register valies

    #define REG_VAL_WHO_AM_I               0x08 // (data sheet says 0x04)

     

    // CTRL1 BIT MASKS

    #define ACC_REG_CTRL_PC                0x80 // Power control  '1' On    '0' Off

    #define ACC_REG_CTRL_RES               0x40 // Resolution     '1' High  '0' Low

    #define ACC_REG_CTRL_DRDYE             0x20 // Data Ready     '1' On    '0' Off

    #define ACC_REG_CTRL_GSEL_HI           0x10 // Range     '00' +/-2g    '01' +/-4g

    #define ACC_REG_CTRL_GSEL_LO           0x08 //           '10' +/-8g    '11' N/A

    #define ACC_REG_CTRL_GSEL_TDTE         0x04 // Directional Tap '1' On   '0' Off

    #define ACC_REG_CTRL_GSEL_WUFE         0x02 // Wake Up         '1' On   '0' Off

    #define ACC_REG_CTRL_GSEL_TPE          0x01 // Tilt Position   '1' On   '0' Off

  • Hmm, sorry about the formatting above. I should add that although discovery shows the accelerometer is sending 6 bytes (3 x 16-bit)  the Windows BLE application does not seem to act on that and instead displays a hard-coded value of 3 x 8-bit bytes (8-bit mode), but there is no source to the BLE so we can't change it. Instead we use a Python application reading the 2540 USB dongle as a serial COM port.

  • Thank you for detailed reply. It helps a lot!

  • Just a short notice - TI's BLE SDK v. 4.0 confusingly uses code and register descriptions for KXTI9 device, while SensorTag acually populated with KXTJ9, and this makes quite a difference - check datasheets for both devices. That source code even contains such a light-hearted comments such as:

    #define REG_VAL_WHO_AM_I               0x08 // (data sheet says 0x04)
    

    while in fact, as you can probably already guess, WHO_AM_I register is 4 for KXTI9 and 8 for KXTJ9

    So a lot of mentioned registers are just not exist in KXTJ9.

    Hopefully this will be fixed in a new BLE SDK version..

  • Chunmeng,

    Thank you for your post. I'm trying to implement a faster accelerometer data rate for a science demo that I'm working on. I tried modifying the code like you did, but I'm not having success. Would you mind sharing your hal_acc.c file? Thanks.

  • Hugh,

    Thanks for your post. I want to increase the accelerometer resolution like you showed but I'm confused how to implement your file. I can see where you've modified the hal_acc.c code for the HalAccelSetRange and HalAccelRead functions. I'm confused where you implement the FEATURE_ACC_12BIT. Do I create a separate file in the SensorTag project? 

    Thanks very much for your help.

  • In the IAR Embedded Workbench navigate from the top-level project and add the define as shown; doing this makes the define visible to all files in the project.

    Project->Options->C/C++ Compiler->Preprocessor->Defined Symbols: Add "FEATURE_ADC_12BIT"

     

  • Clifton and Chenmeng,

    I'm also trying to implement a faster accelerometer data rate.  What changes did you make to the hal_acc.c file?

    Could I see it as well?

    Thanks!