Hi all, I am going through the beginner course and am using the MPU-6050 over I2C. I am able to communicate with the board where I get the WHO_AM_I. I can also read from the sensor's accel registers. However, when trying to incorporate what I have learned about interrupts, I can't seem to get it right.
I hooked up pin 25 on my nRF52DK evaluation board to the INT pin on the MPU-6050's breakout board. I am using this datasheet to configure the interrupt and FIFO registers. I think I am doing everything I need to in the enable_fifo and enable_interrupt functions, but I must be missing something. Basically, I am getting no interrupts triggered from the sensor so my callback never gets called. I did try testing it by connecting pin 25 to VDD and it did in fact trigger.
Here is my code:
/* * Copyright (c) 2016 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #include <zephyr/kernel.h> #include <zephyr/device.h> #include <zephyr/devicetree.h> // #include <zephyr/drivers/uart.h> #include <zephyr/drivers/gpio.h> /* STEP 3 - Include the header file of the I2C API */ #include <zephyr/drivers/i2c.h> /* STEP 4.1 - Include the header file of printk() */ #include <zephyr/sys/printk.h> #include "i2c_regs.h" /* 1000 msec = 1 sec */ #define SLEEP_TIME_MS 1000 static const struct i2c_dt_spec dev_i2c = I2C_DT_SPEC_GET(I2C0_NODE); static const struct gpio_dt_spec int_pin = GPIO_DT_SPEC_GET(INT_PIN, gpios); static struct gpio_callback cb_data; static sensor_regs sr = { .fifo_count_h = I2C_FIFO_COUNT_H, .fifo_count_l = I2C_FIFO_COUNT_L, .fifo_rw = I2C_FIFO_RW_REG, .int_clear = I2C_INT_STATUS}; void read_from_fifo(const struct device *dev, struct gpio_callback *cb, uint32_t pins) { /* STEP 10 - Read from sensor */ printk("INT!\n\r"); uint8_t buf[3] = {0}; // 1. get fifo count int res = i2c_write_read_dt(&dev_i2c, &sr.fifo_count_h, 1, &buf, 1); if (res == 0) { res = i2c_write_read_dt(&dev_i2c, &sr.fifo_count_l, 1, &buf[1], 1); if (res == 0) { uint16_t bytes_to_read = (uint16_t)buf[0] << 8 | buf[1]; printk("bytes to read: %d\n\r", bytes_to_read); // 2. burst read that amount uint8_t sensor_data[bytes_to_read]; res = i2c_write_read_dt(&dev_i2c, &sr.fifo_rw, 1, &sensor_data, bytes_to_read); if (res == 0) { printk("no idea what i am printing here: %x\n\r", sensor_data[0]); } else { printk("something dumb happened in when reading from fifo\n\r"); } } else { printk("something dumb happened in int low byte\n\r"); } } else { printk("something dumb happened in int high byte\n\r"); } // clear the int: res = i2c_write_read_dt(&dev_i2c, &sr.int_clear, 1, &buf[2], 1); if (res == 0) { printk("int cleared %x\n\r", buf[2]); } else { printk("failed to clear int code: %d\n\r", res); } /////////////////////////////////////////////////////////// approach 2: read directly from sensor regs without fifo // uint8_t reg[2] = {I2C_READ_X_HIGH, I2C_READ_X_LOW}; // int res = i2c_write_read_dt(&dev_i2c, ®[0], 1, &buf, 1); // if (res == 0) // { // int res = i2c_write_read_dt(&dev_i2c, ®[1], 1, &buf[1], 1); // if (res == 0) // { // printk("High x: %x and low: %x\n\r", buf[0], buf[1]); // } // else // { // printk("LOW byte x error %d\n\r", res); // } // } // else // { // printk("high byte x error %d\n\r", res); // } ////////////////////////////////////approach 3: just read int status reg to see what kind of int? // uint8_t reg[1] = {I2C_INT_STATUS}; // int res = i2c_write_read_dt(&dev_i2c, ®, 1, &buf, 1); // if (res == 0){ // printk("int status: %x\n\r", buf[0]); // }else{ // printk("dead %d \n\r", res); // } printk("leaving now\n\r"); } int enable_interrupts() { uint8_t sensor_config_regs[2] = {0}; int res; sensor_config_regs[0] = I2C_INT_EN; sensor_config_regs[1] = 0x1; // enable data ready interrupt printk("Enabling INT \n\r"); res = i2c_write_dt(&dev_i2c, sensor_config_regs, 2); if (res != 0) { printk("could not enable INT!\n\r"); // maybe replace w log? return -1; } sensor_config_regs[0] = I2C_INT_REG; // sensor_config_regs[1] = 0x20; // 00110000 - enable int latch, clear on any read OR 0x20 for int latch with clear on status read only sensor_config_regs[1] = 0x40; // 0100 0000 - enable int latch, clear on any read, open drain instead of push pull printk("writing INT config\n\r"); res = i2c_write_dt(&dev_i2c, sensor_config_regs, 2); if (res != 0) { printk("could not enable interrupts!\n\r"); // maybe replace w log? return -1; } return 0; } int enablefifo() { uint8_t sensor_config_regs[2] = {0}; int res; sensor_config_regs[0] = I2C_FIFO_EN_REG; sensor_config_regs[1] = 0x80; // 10000000 - enable fifo, nothing else. printk("enabling fifo\n\r"); res = i2c_write_dt(&dev_i2c, sensor_config_regs, 2); if (res != 0) { printk("could not enable fifo!\n\r"); // maybe replace w log? return -1; } sensor_config_regs[0] = I2C_FIFO_DATA_EN_REG; sensor_config_regs[1] = 0x8; // 00001000: ACCEL_XOUT_H, ACCEL_XOUT_L,ACCEL_YOUT_H, ACCEL_YOUT_L, ACCEL_ZOUT_H, and ACCEL_ZOUT_L (Registers 59 to 64) to be written into the FIFO buffer. printk("writing FIFO config\n\r"); res = i2c_write_dt(&dev_i2c, sensor_config_regs, 2); if (res != 0) { printk("could not enable accel data in fifo!\n\r"); // maybe replace w log? return -1; } return 0; } int main(void) { printk("peeps\n\r"); /* STEP 7 - Retrieve the API-specific device structure and make sure that the device is * ready to use */ if (!device_is_ready(dev_i2c.bus)) { printk("I2C bus %s not ready\n\r", dev_i2c.bus->name); return -1; } if (!device_is_ready(int_pin.port)) { printk("gpio pin %d not ready\n\r", int_pin.pin); return -1; } int res = gpio_pin_configure_dt(&int_pin, GPIO_INPUT); if (res < 0) { return -1; } uint8_t value; uint8_t setup_buf[3] = {0}; // uint8_t sensor_config_regs[2] = {I2C_PWR_MGMT_REG, 0x0}; // 0x80 if 10000000 ( reset on, sleep and everything else off, last 0 is clock select - internal) printk("Waking processor. (writing to powermanagement register.)\n\r"); value = 0x0; res = i2c_reg_write_byte_dt(&dev_i2c, I2C_PWR_MGMT_REG, value); if (res != 0) { printk("could not power on device\n\r"); // maybe replace w log? return -1; } printk("reading who_am_i: "); uint8_t sensor_config_regs[2] = {I2C_WHO_AM_I, 0}; i2c_write_read_dt(&dev_i2c, &sensor_config_regs, 1, &setup_buf[0], 1); if (setup_buf[0] != I2C_ADDR) { printk("expecting 0x68 and got: %x\n\r", setup_buf[0]); return -1; } else { printk("0x%02hhX == 0x%02hhX\n\r", I2C_ADDR, setup_buf[0]); } if (enable_interrupts() != 0){ return -1; } if (enablefifo() !=0){ return -1; } printk("devices are ready. Registering interrupt callback\n\r"); res = gpio_pin_interrupt_configure_dt(&int_pin, GPIO_INT_EDGE_TO_ACTIVE); gpio_init_callback(&cb_data, read_from_fifo, BIT(int_pin.pin)); gpio_add_callback(int_pin.port, &cb_data); printk("configured, lets loop!\n\r"); while (1) { k_msleep(SLEEP_TIME_MS); } }
My header file:
#include <zephyr/kernel.h> #define I2C_ADDR 0x68 //7 bit addr: 1101000, where last bit is tied to ground via AD0 #define I2C_PWR_MGMT_REG 0x6B #define I2C_INT_REG 0x37 #define I2C_INT_EN 0x38 #define I2C_INT_STATUS 0x3A //used to clear int by reading #define I2C_FIFO_EN_REG 0x6A #define I2C_FIFO_DATA_EN_REG 0x23 #define I2C_FIFO_COUNT_H 0x72 #define I2C_FIFO_COUNT_L 0x73 #define I2C_FIFO_RW_REG 0x74 #define I2C_WHO_AM_I 0x75 #define I2C_READ_X_HIGH 0x3B #define I2C_READ_X_LOW 0x3C #define I2C_READ_Y_HIGH 0x3D #define I2C_READ_Y_LOW 0x3E #define I2C_READ_Z_HIGH 0x3F #define I2C_READ_Z_LOW 0x40 /* STEP 6 - Get the node identifier of the sensor */ #define I2C0_NODE DT_NODELABEL(mysensor) #define INT_PIN DT_NODELABEL(intpin) int enablefifo(void); int enable_interrupts(void); typedef struct { uint8_t fifo_count_h; uint8_t fifo_count_l; uint8_t fifo_rw; uint8_t int_clear; }sensor_regs;
Here is my overlay file:
&i2c0 { mysensor: mysensor@68{ compatible = "i2c-device"; status = "okay"; reg = < 0x68 >; }; }; / { userpin { compatible = "gpio-keys"; intpin: intpini2c { gpios = <&gpio0 25 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>; label = "Pin tied to INT pin output from I2C sensor."; }; }; };
Any help would be appreciated!