Reading MPU6050 via Interrupts on NRF52840 and Bluetooth Connectivity Issue

I have successfully implemented an interrupt-driven method to read data from the MPU6050 sensor on the NRF52840, and it functions as expected. However, I encounter an issue where I am unable to establish a Bluetooth connection while the interrupt-based reading is active. I am working with the nrf connect sdk v2.6.1 and have configured the peripheral_uart example.

After I deleted that line, the Bluetooth connection became normal: 

mpu_read_n_reg(info, ACCEL_XOUT_H, info->sensor_data.raw_data, 14);

static void mpu6050_thread(void *p1, void *p2, void *p3)
{
	ARG_UNUSED(p2);
	ARG_UNUSED(p3);

	int ret = 0;
    uint16_t tmp[7];
	mpu6050_info_t *info = p1;
    struct sensor_value val[7];

	while (1) {
        
		k_sem_take(&info->gpio_sem, K_FOREVER);
		data_cnt++;
		
		mpu_read_n_reg(info, ACCEL_XOUT_H, info->sensor_data.raw_data, 14);
			
		gpio_pin_interrupt_configure_dt(info->int_gpio, 
		    GPIO_INT_EDGE_TO_ACTIVE);

		info->sensor_data.accel_x = sys_be16_to_cpu(info->sensor_data.raw_data[0]);
		info->sensor_data.accel_y = sys_be16_to_cpu(info->sensor_data.raw_data[1]);
		info->sensor_data.accel_z = sys_be16_to_cpu(info->sensor_data.raw_data[2]);
		info->sensor_data.temp = sys_be16_to_cpu(info->sensor_data.raw_data[3]);
		info->sensor_data.gyro_x = sys_be16_to_cpu(info->sensor_data.raw_data[4]);
		info->sensor_data.gyro_y = sys_be16_to_cpu(info->sensor_data.raw_data[5]);
		info->sensor_data.gyro_z = sys_be16_to_cpu(info->sensor_data.raw_data[6]);

		
	}
}

MPU6050 CONFIG:

static const uint8_t mpu6050_init_cmd[11][2] = {
    {PWR_MGMT_1, 0x80}, // PWR_MGMT_1, DEVICE_RESET  
    // need wait 
    {PWR_MGMT_1, 0x00}, // cleat SLEEP
    {GYRO_CONFIG, 0x18}, // Gyroscope Full Scale Range = ± 2000 °/s
    {ACCEL_CONFIG, 0x00}, // Accelerometer Full Scale Range = ± 2g 
    {INT_ENABLE, 0x01}, // Interrupt Enable.  DATA_RDY_EN
    {USER_CTRL, 0x00}, // User Control.auxiliary I2C are logically driven by the primary I2C bus
    {FIFO_EN, 0x00}, // FIFO Enable.disenable  
    {SMPLRT_DIV, 99}, // Sample Rate Divider.Sample Rate = 1KHz / (1 + 99)  
    {CONFIG, 0x23}, // EXT_SYNC_SET = GYRO_ZOUT_L[0]; Bandwidth = 3
    {PWR_MGMT_1, 0x01}, // Power Management 1.PLL with X axis gyroscope reference
    {PWR_MGMT_2, 0x00}  // Power Management 2
};

  • hello, I have tried all methods, but still cannot interrupt the reading of MPU6050 data while using Bluetooth to transmit sensor data to the app.I can't find the corresponding routine in the routine you sent me. Have you ever encountered a similar situation or someone successfully achieved Bluetooth transmission + interrupt reading sensor.

  • can you send your project to see what is blocking you from doing so?

    please mentions specifics like the ncs version you or using, or any sensor / overlay etc.

  • mpu6050.c

    static const uint8_t mpu6050_init_cmd[11][2] = {
        {PWR_MGMT_1, 0x80}, // PWR_MGMT_1, DEVICE_RESET  
        // need wait
        {PWR_MGMT_1, 0x00}, // cleat SLEEP
        {GYRO_CONFIG, 0x18}, // Gyroscope Full Scale Range = ± 2000 °/s
        {ACCEL_CONFIG, 0x00}, // Accelerometer Full Scale Range = ± 2g
        {INT_ENABLE, 0x01}, // Interrupt Enable.  DATA_RDY_EN
        {USER_CTRL, 0x00}, // User Control.auxiliary I2C are logically driven by the primary I2C bus
        {FIFO_EN, 0x00}, // FIFO Enable.disenable  
        {SMPLRT_DIV, 99}, // Sample Rate Divider.Sample Rate = 1KHz / (1 + 9)  
        {CONFIG, 0x23}, // EXT_SYNC_SET = GYRO_ZOUT_L[0]; Bandwidth = 3
        {PWR_MGMT_1, 0x01}, // Power Management 1.PLL with X axis gyroscope reference
        {PWR_MGMT_2, 0x00}  // Power Management 2
    };
     
    mpu6050_info_t mpu6050_dev = {
        .i2c = I2C_DT_SPEC_GET(DT_NODELABEL(mpu6050)),  
        .int_gpio = GPIO_DT_SPEC_GET(DT_NODELABEL(mpu6050), int_gpios),
    };
    
    static void mpu6050_gpio_callback(const struct device *dev,
                      struct gpio_callback *cb, uint32_t pins)
    {
        mpu6050_info_t *info = CONTAINER_OF(cb, mpu6050_info_t, gpio_cb);
     
        ARG_UNUSED(pins);
        gpio_pin_interrupt_configure_dt(&info->int_gpio, GPIO_INT_DISABLE);
        k_sem_give(&info->gpio_sem);
    
    }
    
    void mpu_read_reg(mpu6050_info_t *dev, uint8_t reg_addr, uint8_t *data)
    {
        i2c_reg_read_byte_dt(&dev->i2c, reg_addr, data);
    }
     
    
    void mpu_write_reg(mpu6050_info_t *dev, uint8_t reg_addr, uint8_t data)
    {
        i2c_reg_write_byte_dt(&dev->i2c, reg_addr, data);
    }
     
    void mpu_read_n_reg(mpu6050_info_t *dev, uint8_t start_reg, uint8_t* data, uint32_t len)
    {
        i2c_burst_read_dt(&dev->i2c, start_reg, data, len);
    }
    
    int mpu6050_init_interrupt(mpu6050_info_t *info)
    {
        if (!gpio_is_ready_dt(&info->int_gpio)) {
            LOG_ERR("GPIO device not ready");
            return -ENODEV;
        }
     
        gpio_pin_configure_dt(&info->int_gpio, GPIO_INPUT);
     
        gpio_init_callback(&info->gpio_cb,
                   mpu6050_gpio_callback,
                   BIT(info->int_gpio.pin));
     
        if (gpio_add_callback(info->int_gpio.port, &info->gpio_cb) < 0) {
            LOG_ERR("Failed to set gpio callback");
            return -EIO;
        }
     
    #if defined(MPU6050_TRIGGER_OWN_THREAD)
        k_sem_init(&info->gpio_sem, 0, K_SEM_MAX_LIMIT);
     
        k_thread_create(&info->thread, info->thread_stack,
                MPU6050_THREAD_STACK_SIZE,
                mpu6050_thread, &mpu6050_dev,
                NULL, NULL, K_PRIO_COOP(MPU6050_THREAD_PRIORITY),
                0, K_NO_WAIT);
    #elif defined(MPU6050_TRIGGER_GLOBAL_THREAD)
        info->work.handler = mpu6050_work_cb;
    #endif
     
        gpio_pin_interrupt_configure_dt(&info->int_gpio,
                        GPIO_INT_EDGE_FALLING);
     
        return 0;
    }
    
    static void mpu6050_thread(void *p1, void *p2, void *p3)
    {
        ARG_UNUSED(p2);
        ARG_UNUSED(p3);
     
        uint16_t tmp[7];
        mpu6050_info_t *info = p1;
        // struct sensor_value val[7];
     
        while (1) {
            //等待接收
            k_sem_take(&info->gpio_sem, K_FOREVER);
     
            //读取数据
            mpu_read_n_reg(info, ACCEL_XOUT_H, (uint8_t*)tmp, 14);
           
            //开中断
            gpio_pin_interrupt_configure_dt(&info->int_gpio,
                GPIO_INT_EDGE_FALLING);
     
            info->sensor_data.accel_x = sys_be16_to_cpu(tmp[0]);
            info->sensor_data.accel_y = sys_be16_to_cpu(tmp[1]);
            info->sensor_data.accel_z = sys_be16_to_cpu(tmp[2]);
            info->sensor_data.temp = sys_be16_to_cpu(tmp[3]);
            info->sensor_data.gyro_x = sys_be16_to_cpu(tmp[4]);
            info->sensor_data.gyro_y = sys_be16_to_cpu(tmp[5]);
            info->sensor_data.gyro_z = sys_be16_to_cpu(tmp[6]);
     
            //for(int i=0; i<7; i++) printk("%x ", tmp[i]);
            //printk("\r\n");
            // k_sleep(K_MSEC(100));
        }
    }
    
    int mpu6050_init(void)
    {
        int ret;
        int i=0;
        uint8_t tmp, id;
     
        mpu6050_dev.sensor_data.accel_sensitivity_shift = 14;   // 14 - bit(4,3)
        mpu6050_dev.sensor_data.gyro_sensitivity_x10 = mpu6050_gyro_sensitivity_x10[3];
       
        if (!device_is_ready(mpu6050_dev.i2c.bus)) {
            LOG_ERR("Bus device is not ready");
            return -ENODEV;
        }
       
        /* check chip ID */
        if (i2c_reg_read_byte_dt(&mpu6050_dev.i2c, MPU6050_REG_CHIP_ID, &id) < 0) {
            LOG_ERR("Failed to read chip ID.");
            return -EIO;
        }
    
        if ((id != MPU6050_CHIP_ID) && (id != MPU9250_CHIP_ID) && (id != MPU6880_CHIP_ID)) {
            LOG_ERR("Invalid chip ID.");
            return -EINVAL;
        }
    
    
    #ifdef  MPU6050_INT_ENABLE
        ret = mpu6050_init_interrupt(&mpu6050_dev);
        if(ret) LOG_ERR("mpu6050_init_interrupt ERROR %X", ret);
    #endif
     
        for (i=0; i < 11; i++){
            mpu_write_reg(&mpu6050_dev, mpu6050_init_cmd[i][0], mpu6050_init_cmd[i][1]);
            if (i == 0)
                k_sleep(K_MSEC(500));
        }
       
        for(i=0; i<11; i++){
            mpu_read_reg(&mpu6050_dev, mpu6050_init_cmd[i][0], &tmp);
            printk("tmp %02X\n\r", tmp);
        }
    
        return 0;
    }

  • app.overlay
    / {
        chosen {
            nordic,nus-uart = &uart0;
        };
    };
    
    &i2c1 {
        status = "okay";
        // clock-frequency = <400000>;
        mpu6050: mpu6050@68 {
            compatible = "invensense,mpu6050";
            reg = <0x68>; // I2C 地址
            int-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>;
        };
    };
     
    //配置i2c1
    &i2c1_default {
        group1 {
            psels = <NRF_PSEL(TWIM_SDA, 0, 31)>, <NRF_PSEL(TWIM_SCL, 0, 30)>;
        };
    };
    main.c
    
    int main(void)
    {
        int blink_status = 0;
        int err = 0;
    
        configure_gpio();
    
        uart_init();
    
        ble_init();
    
        mpu6050_init();
    
        for (;;) {
            dk_set_led(RUN_STATUS_LED, (++blink_status) % 2);
            k_sleep(K_MSEC(RUN_LED_BLINK_INTERVAL));
        }
    }
    
    void ble_write_thread(void)
    {
        static uint8_t tmp[5] = "1234";
        k_sem_take(&ble_init_ok, K_FOREVER);
       
        for (;;) {
            if(current_conn){
                // indicate_send(current_conn, tmp, 5);
                bt_custom_send(current_conn, (uint8_t*)&mpu6050_dev.sensor_data.temp, 2);
            }
            tmp[0] ++;
            k_sleep(K_MSEC(RUN_LED_BLINK_INTERVAL));
        }
    }
    
    K_THREAD_DEFINE(ble_write_thread_id, BT_THREAD_STACKSIZE, ble_write_thread, NULL, NULL,
            NULL, BT_THREAD_PRIORITY, 0, 0);
    
    
  • I use nrf connect sdk v2.6.1. when I delete the mpu_read_n_reg() in mpu6050_thread, the ble can be connected.

Related