TWI Bluetooth transmittion problem.

Hi everyone,

I'm trying to send updated gyro and acceleration values from MPU6050 continuously by BLE function from nrf52832. I'm currently using the nrf52 development kit board to run this code. However, I'm getting a NRF_ERROR_DATA_SIZE.

This is the code:

#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "nordic_common.h"
#include "nrf.h"
#include "app_error.h"
#include "ble.h"
#include "ble_hci.h"
#include "ble_srv_common.h"
#include "ble_advdata.h"
#include "ble_advertising.h"
#include "ble_conn_params.h"
#include "nrf_sdh.h"
#include "nrf_sdh_soc.h"
#include "nrf_sdh_ble.h"
#include "app_timer.h"
#include "nrf_pwr_mgmt.h"
#include "app_util_platform.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"
#include "mpu6050.h"

#define DEVICE_NAME                     "MPU"                          
#define APP_ADV_INTERVAL                300                             
#define APP_ADV_DURATION                0                               
#define APP_BLE_CONN_CFG_TAG            1                               

#define TWI_SCL_PIN                     25                              
#define TWI_SDA_PIN                     24                              

BLE_ADVERTISING_DEF(m_advertising);                                      

static uint8_t m_adv_data[31];                                            
static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID;                  

static void advertising_start(void);

void twi_init(void) {
    ret_code_t err_code;

    const nrf_drv_twi_config_t twi_config = {
       .scl                = TWI_SCL_PIN,
       .sda                = TWI_SDA_PIN,
       .frequency          = NRF_TWI_FREQ_400K,
       .interrupt_priority = APP_IRQ_PRIORITY_HIGH,
       .clear_bus_init     = false
    };

    err_code = nrf_drv_twi_init(&m_twi, &twi_config, NULL, NULL);
    APP_ERROR_CHECK(err_code);

    nrf_drv_twi_enable(&m_twi);
}

static void on_adv_evt(ble_adv_evt_t ble_adv_evt) {
    switch (ble_adv_evt) {
        case BLE_ADV_EVT_FAST:
            NRF_LOG_INFO("Fast advertising.");
            break;
        case BLE_ADV_EVT_IDLE:
            advertising_start();
            break;
        default:
            break;
    }
}

static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context) {
    switch (p_ble_evt->header.evt_id) {
        case BLE_GAP_EVT_DISCONNECTED:
            NRF_LOG_INFO("Disconnected.");
            break;
        case BLE_GAP_EVT_CONNECTED:
            NRF_LOG_INFO("Connected.");
            m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
            break;
        default:
            break;
    }
}

static void gap_params_init(void) {
    ret_code_t err_code;
    ble_gap_conn_params_t gap_conn_params;
    ble_gap_conn_sec_mode_t sec_mode;

    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);

    err_code = sd_ble_gap_device_name_set(&sec_mode,
                                          (const uint8_t *)DEVICE_NAME,
                                          strlen(DEVICE_NAME));
    APP_ERROR_CHECK(err_code);

    memset(&gap_conn_params, 0, sizeof(gap_conn_params));

    gap_conn_params.min_conn_interval = MSEC_TO_UNITS(100, UNIT_1_25_MS);
    gap_conn_params.max_conn_interval = MSEC_TO_UNITS(200, UNIT_1_25_MS);
    gap_conn_params.slave_latency     = 0;
    gap_conn_params.conn_sup_timeout  = MSEC_TO_UNITS(4000, UNIT_10_MS);

    err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
    APP_ERROR_CHECK(err_code);
}

static void advertising_init(void) {
    ret_code_t err_code;
    ble_advdata_t advdata;

    memset(&advdata, 0, sizeof(advdata));

    advdata.name_type               = BLE_ADVDATA_FULL_NAME;
    advdata.include_appearance      = false;
    advdata.flags                   = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;

    ble_advdata_manuf_data_t manuf_data;
    manuf_data.company_identifier = 0x0059; // Nordic Semiconductor company ID
    manuf_data.data.p_data = m_adv_data;
    manuf_data.data.size = sizeof(m_adv_data);

    advdata.p_manuf_specific_data = &manuf_data;

    ble_advertising_init_t init;
    memset(&init, 0, sizeof(init));

    init.advdata = advdata;
    init.config.ble_adv_fast_enabled  = true;
    init.config.ble_adv_fast_interval = APP_ADV_INTERVAL;
    init.config.ble_adv_fast_timeout  = APP_ADV_DURATION;
    init.evt_handler = on_adv_evt;

    err_code = ble_advertising_init(&m_advertising, &init);
    APP_ERROR_CHECK(err_code);

    ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);
}

static void ble_stack_init(void) {
    ret_code_t err_code = nrf_sdh_enable_request();
    APP_ERROR_CHECK(err_code);

    uint32_t ram_start = 0x20001800;  // Adjusted RAM start
    err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_sdh_ble_enable(&ram_start);
    APP_ERROR_CHECK(err_code);
}

static void power_management_init(void) {
    ret_code_t err_code = nrf_pwr_mgmt_init();
    APP_ERROR_CHECK(err_code);
}

static void idle_state_handle(void) {
    if (NRF_LOG_PROCESS() == false) {
        nrf_pwr_mgmt_run();
    }
}

static void advertising_start(void) {
    ret_code_t err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
    APP_ERROR_CHECK(err_code);
}

int main(void) {
    int16_t accel_data[3], gyro_data[3];

    APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
    NRF_LOG_DEFAULT_BACKENDS_INIT();

    NRF_LOG_INFO("MPU6050 BLE example started.");
    NRF_LOG_FLUSH();

    twi_init();
    mpu6050_init();

    power_management_init();
    ble_stack_init();
    gap_params_init();
    advertising_init();

    advertising_start();

    while (true) {
        read_mpu6050_data(accel_data, gyro_data);

        // Send only 0.2f values of acceleration and gyro data
        float ax = accel_data[0] / 16384.0;
        float ay = accel_data[1] / 16384.0;
        float az = accel_data[2] / 16384.0;
        float gx = gyro_data[0] / 131.0;
        float gy = gyro_data[1] / 131.0;
        float gz = gyro_data[2] / 131.0;

        // Prepare advertising data (in this example, ensure it fits in 31 bytes)
        memcpy(m_adv_data, &ax, sizeof(float));
        memcpy(m_adv_data + sizeof(float), &ay, sizeof(float));
        memcpy(m_adv_data + 2 * sizeof(float), &az, sizeof(float));
        memcpy(m_adv_data + 3 * sizeof(float), &gx, sizeof(float));
        memcpy(m_adv_data + 4 * sizeof(float), &gy, sizeof(float));
        memcpy(m_adv_data + 5 * sizeof(float), &gz, sizeof(float));

        NRF_LOG_INFO("ACC: X=%0.2f, Y=%0.2f, Z=%0.2f; GYRO: X=%0.2f, Y=%0.2f, Z=%0.2f",
                     ax, ay, az, gx, gy, gz);

        advertising_start();

        nrf_delay_ms(1000);
        idle_state_handle();
    }
}

Why am I not able to send acceleration and gyro values though BLE?

Thank you so much for the help.

  • Thank you so much for your help! 

    I currently having a problem with sending ax,ay,az,gx,gy,gz values through BLE.

    This is what acceleration and gyro values that should be sent out by BLE:

    However, this is a snapshot of data that's sent through BLE. I used Wireshark to get this data:

    Frame 723682: 63 bytes on wire (504 bits), 63 bytes captured (504 bits) on interface COM8-4.2, id 0
        Section number: 1
        Interface id: 0 (COM8-4.2)
        Encapsulation type: nRF Sniffer for Bluetooth LE (186)
        Arrival Time: Jun 21, 2024 18:27:41.048745000 중부 일광 절약 시간
        UTC Arrival Time: Jun 21, 2024 23:27:41.048745000 UTC
        Epoch Arrival Time: 1719012461.048745000
        [Time shift for this packet: 0.000000000 seconds]
        [Time delta from previous captured frame: 0.000755000 seconds]
        [Time delta from previous displayed frame: 0.000755000 seconds]
        [Time since reference or first frame: 3786.864048000 seconds]
        Frame Number: 723682
        Frame Length: 63 bytes (504 bits)
        Capture Length: 63 bytes (504 bits)
        [Frame is marked: False]
        [Frame is ignored: False]
        [Protocols in frame: nordic_ble:btle:btcommon]
    nRF Sniffer for Bluetooth LE
        Board: 8
        Header Version: 3, Packet counter: 6013
            Length of payload: 56
            Protocol version: 3
            Packet counter: 6013
            Packet ID: 2
        Length of packet: 10
        Flags: 0x01
            .... ...1 = CRC: Ok
            .... ..0. = Reserved: 0
            .... .0.. = Reserved: 0
            .... 0... = Address Resolved: No
            .000 .... = PHY: LE 1M (0)
            0... .... = Reserved: 0
        Channel Index: 39
        RSSI: -51 dBm
        Event counter: 0
        Timestamp: 76326918µs
        [Packet time (start to end): 376µs]
        [Delta time (end to start): 579µs]
        [Delta time (start to start): 755µs]
    Bluetooth Low Energy Link Layer
        Access Address: 0x8e89bed6
        Packet Header: 0x2560 (PDU Type: ADV_IND, ChSel: #2, TxAdd: Random)
        Advertising Address: cc:69:fe:c9:06:21 (cc:69:fe:c9:06:21)
        Advertising Data
            Flags
                Length: 2
                Type: Flags (0x01)
                000. .... = Reserved: 0x0
                ...0 .... = Simultaneous LE and BR/EDR to Same Device Capable (Host): false (0x0)
                .... 0... = Simultaneous LE and BR/EDR to Same Device Capable (Controller): false (0x0)
                .... .1.. = BR/EDR Not Supported: true (0x1)
                .... ..1. = LE General Discoverable Mode: true (0x1)
                .... ...0 = LE Limited Discoverable Mode: false (0x0)
            Manufacturer Specific
                Length: 23
                Type: Manufacturer Specific (0xff)
                Company ID: Nordic Semiconductor ASA (0x0059)
                Data: 0024ffbd03760000000000000000000000000000
                    [Expert Info (Note/Undecoded): Undecoded]
            Device Name (shortened): MP
                Length: 3
                Type: Device Name (shortened) (0x08)
                Device Name: MP
        CRC: 0xca4899
    
    I don't think I'm sending correct acceleration and gyro values through BLE.

    This is my current code:

    #include <stdbool.h>
    #include <stdint.h>
    #include <string.h>
    #include "nordic_common.h"
    #include "nrf.h"
    #include "app_error.h"
    #include "ble.h"
    #include "ble_hci.h"
    #include "ble_srv_common.h"
    #include "ble_advdata.h"
    #include "ble_advertising.h"
    #include "ble_conn_params.h"
    #include "nrf_sdh.h"
    #include "nrf_sdh_soc.h"
    #include "nrf_sdh_ble.h"
    #include "app_timer.h"
    #include "nrf_pwr_mgmt.h"
    #include "app_util_platform.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"
    #include "mpu6050.h"
    #include <math.h>  // Include this for M_PI(pi)
    
    #define DEVICE_NAME                     "MPU"                          
    #define APP_ADV_INTERVAL                300                             
    #define APP_ADV_DURATION                0                               
    #define APP_BLE_CONN_CFG_TAG            1                               
    
    #define TWI_SCL_PIN                     25                              
    #define TWI_SDA_PIN                     24                              
    
    #define gyroSENSITIVITY                 131.0f
    #define G_CONSTANT                      9.8f
    #define accSENSITIVITY                  16384.0f
    
    BLE_ADVERTISING_DEF(m_advertising);                                      
    
    static uint8_t m_adv_data[20];                                            
    static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID;                  
    static char log_buffer[256];
    
    static void advertising_start(void);
    
    void twi_init(void) {
        ret_code_t err_code;
    
        const nrf_drv_twi_config_t twi_config = {
           .scl                = TWI_SCL_PIN,
           .sda                = TWI_SDA_PIN,
           .frequency          = NRF_TWI_FREQ_400K,
           .interrupt_priority = APP_IRQ_PRIORITY_HIGH,
           .clear_bus_init     = false
        };
    
        err_code = nrf_drv_twi_init(&m_twi, &twi_config, NULL, NULL);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_twi_enable(&m_twi);
    }
    
    static void on_adv_evt(ble_adv_evt_t ble_adv_evt) {
        switch (ble_adv_evt) {
            case BLE_ADV_EVT_FAST:
                NRF_LOG_INFO("Fast advertising.");
                break;
            case BLE_ADV_EVT_IDLE:
                advertising_start();
                break;
            default:
                break;
        }
    }
    
    static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context) {
        switch (p_ble_evt->header.evt_id) {
            case BLE_GAP_EVT_DISCONNECTED:
                NRF_LOG_INFO("Disconnected.");
                break;
            case BLE_GAP_EVT_CONNECTED:
                NRF_LOG_INFO("Connected.");
                m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
                break;
            default:
                break;
        }
    }
    
    static void gap_params_init(void) {
        ret_code_t err_code;
        ble_gap_conn_params_t gap_conn_params;
        ble_gap_conn_sec_mode_t sec_mode;
    
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
    
        err_code = sd_ble_gap_device_name_set(&sec_mode,
                                              (const uint8_t *)DEVICE_NAME,
                                              strlen(DEVICE_NAME));
        APP_ERROR_CHECK(err_code);
    
        memset(&gap_conn_params, 0, sizeof(gap_conn_params));
    
        gap_conn_params.min_conn_interval = MSEC_TO_UNITS(100, UNIT_1_25_MS);
        gap_conn_params.max_conn_interval = MSEC_TO_UNITS(200, UNIT_1_25_MS);
        gap_conn_params.slave_latency     = 0;
        gap_conn_params.conn_sup_timeout  = MSEC_TO_UNITS(4000, UNIT_10_MS);
    
        err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
        APP_ERROR_CHECK(err_code);
    }
    
    static void advertising_init(void) {
        ret_code_t err_code;
        ble_advdata_t advdata;
    
        memset(&advdata, 0, sizeof(advdata));
    
        advdata.name_type               = BLE_ADVDATA_FULL_NAME;
        advdata.include_appearance      = false;
        advdata.flags                   = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
    
        ble_advdata_manuf_data_t manuf_data;
        manuf_data.company_identifier = 0x0059; // Nordic Semiconductor company ID
        manuf_data.data.p_data = m_adv_data;
        manuf_data.data.size = sizeof(m_adv_data);
    
        advdata.p_manuf_specific_data = &manuf_data;
    
        ble_advertising_init_t init;
        memset(&init, 0, sizeof(init));
    
        init.advdata = advdata;
        init.config.ble_adv_fast_enabled  = true;
        init.config.ble_adv_fast_interval = APP_ADV_INTERVAL;
        init.config.ble_adv_fast_timeout  = APP_ADV_DURATION;
        init.evt_handler = on_adv_evt;
    
        err_code = ble_advertising_init(&m_advertising, &init);
        APP_ERROR_CHECK(err_code);
    
        ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);
    }
    
    static void ble_stack_init(void) {
        ret_code_t err_code = nrf_sdh_enable_request();
        APP_ERROR_CHECK(err_code);
    
        uint32_t ram_start = 0x20001800;  // Adjusted RAM start
        err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_sdh_ble_enable(&ram_start);
        APP_ERROR_CHECK(err_code);
    }
    
    static void power_management_init(void) {
        ret_code_t err_code = nrf_pwr_mgmt_init();
        APP_ERROR_CHECK(err_code);
    }
    
    static void idle_state_handle(void) {
        if (NRF_LOG_PROCESS() == false) {
            nrf_pwr_mgmt_run();
        }
    }
    
    static void advertising_start(void) {
        ret_code_t err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
        APP_ERROR_CHECK(err_code);
    }
    
    void update_advertising_data(void) {
        ret_code_t err_code;
        ble_advdata_t advdata;
    
        ble_advdata_manuf_data_t manuf_data;
        manuf_data.company_identifier = 0x0059;
        manuf_data.data.p_data = m_adv_data;
        manuf_data.data.size = sizeof(m_adv_data);
    
        memset(&advdata, 0, sizeof(advdata));
        advdata.name_type               = BLE_ADVDATA_FULL_NAME;
        advdata.include_appearance      = false;
        advdata.flags                   = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
        advdata.p_manuf_specific_data   = &manuf_data;
    
        err_code = ble_advertising_advdata_update(&m_advertising, &advdata, NULL);
        APP_ERROR_CHECK(err_code);
    }
    
    int main(void) {
        int16_t accel_data[3], gyro_data[3];
        float ax, ay, az, gx, gy, gz;
    
        APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    
        NRF_LOG_INFO("MPU6050 BLE example started.");
        NRF_LOG_FLUSH();
    
        twi_init();
        mpu6050_init();
    
        power_management_init();
        ble_stack_init();
        gap_params_init();
        advertising_init();
    
        advertising_start();
    
        while (true) {
            read_mpu6050_data(accel_data, gyro_data);
    
            // Log raw data for debugging
            NRF_LOG_INFO("Raw ACC: X=%d, Y=%d, Z=%d; Raw GYRO: X=%d, Y=%d, Z=%d",
                         accel_data[0], accel_data[1], accel_data[2],
                         gyro_data[0], gyro_data[1], gyro_data[2]);
    
            ax = ((float)accel_data[0] / accSENSITIVITY) * G_CONSTANT;
            ay = ((float)accel_data[1] / accSENSITIVITY) * G_CONSTANT;
            az = ((float)accel_data[2] / accSENSITIVITY) * G_CONSTANT;
            gx = ((float)gyro_data[0] / gyroSENSITIVITY) * (M_PI / 180);
            gy = ((float)gyro_data[1] / gyroSENSITIVITY) * (M_PI / 180);
            gz = ((float)gyro_data[2] / gyroSENSITIVITY) * (M_PI / 180);
    
    
            uint8_t offset = 0;
            // Directly update m_adv_data array with scaled values
            int16_t scaled_value;
    
            scaled_value = (int16_t)(ax*100);
            m_adv_data[offset++] = (scaled_value >> 8) & 0xFF;
            m_adv_data[offset++] = scaled_value & 0xFF;
    
            scaled_value = (int16_t)(ay*100);
            m_adv_data[offset++] = (scaled_value >> 8) & 0xFF;
            m_adv_data[offset++] = scaled_value & 0xFF;
    
            scaled_value = (int16_t)(az*100);
            m_adv_data[offset++] = (scaled_value >> 8) & 0xFF;
            m_adv_data[offset++] = scaled_value & 0xFF;
    
            scaled_value = (int16_t)(gx*100);
            m_adv_data[offset++] = (scaled_value >> 8) & 0xFF;
            m_adv_data[offset++] = scaled_value & 0xFF;
    
            scaled_value = (int16_t)(gy*100);
            m_adv_data[offset++] = (scaled_value >> 8) & 0xFF;
            m_adv_data[offset++] = scaled_value & 0xFF;
    
            scaled_value = (int16_t)(gz*100);
            m_adv_data[offset++] = (scaled_value >> 8) & 0xFF;
            m_adv_data[offset++] = scaled_value & 0xFF;
    
            update_advertising_data();
    
            nrf_delay_ms(1000);
            idle_state_handle();
        }
    }
    

    Thank you for helping me!

  • If you want me to test any parts of your code, then you need to zip and upload the entire application folder that you are using (the folder containing the example and configuration files, such as the SDK\examples\ble_peripheral\<your application project>

    So what do you expect the values to look like? Have you tried printing the hexadecimal values that you are feeding into your advertising data?

    NRF_LOG_RAW_INFO("m_adv_data[] = ");
    for (int i=0; i<sizeof(m_adv_data); i++)
    {
        NRF_LOG_RAW_INFO("%02x:", m_adv_data[i]);
    }
    NRF_LOG_RAW_INFO("\r\n");

    BR,
    Edvin

  • I just tried printing the m_adv_data.

    But I'm getting this issue:

    Also, I have attached zip file here. My project is under example file and the folder name is called "ble_app_template_twi(use this). go into pca10040 afterwards.3515.nRF5_SDK_17.1.0_ddde560.zip

  • Thank you for sharing the projects.

    Some few hints while developing:

    1: Open your project settings. For all project settings, select the "Common" option in the drop down menu. Then select the preprocessor definitions, and add "DEBUG" to the list:

    2: Then I also added a small function that will print out the log. call this directly before nrf_delay_ms(1000) in your main loop. Do not call it from anywhere else, as it may lead to weird behavior.

    void process_logs(void)
    {
        while (NRF_LOG_PROCESS())
        {
            // Do nothing.
        }
    }
    
    int main(void)
    {
        ...
        while (true)
        {
            ...
            process_logs();
            nrf_delay_ms(1000);
            idle_state_handle();
        }
    }

    3: Then, you can also debug your application. You can set breakpoints, and add variables to watch, to monitor their value. Note that when you are using the softdevice, and set a breakpoint that is hit, then you can't continue to step. You need to reset the application. 

    Using these three steps, I see that the casting that you are doing is not working as you expect it to. The scaled_value parameter doesn't get the value of ax*100. It is 0. 

    I don't know what you intend to do with these numbers. If you only plan to send them out and process it somewhere else, then you can just copy the values into your m_adv_data (memcpy()). If you need to find out what format you want them to be. 

    Best regards,

    Edvin

  • I don't understand how to use the debug function. Also, I don't think I understand how you store the acceleration and gyro values too.. 

    What I'm trying to do is to send out advertising data packet with gyro and acceleration values. I'm planning to gather those data through BLE. 

    How can I store them so that I can transmit 3 gyro and 3 acceleration values all together with no ram problem?

Related