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!