Skip to content

Commit c2f0dd8

Browse files
C++ interrupts and interrupt example
1 parent 604efb9 commit c2f0dd8

File tree

4 files changed

+116
-1
lines changed

4 files changed

+116
-1
lines changed

i2c/mpu6050_i2c/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,13 @@ pico_add_extra_outputs(mpu6050_i2c_scale_test)
2929
# enable usb output, disable uart output
3030
pico_enable_stdio_usb(mpu6050_i2c_scale_test 1)
3131
pico_enable_stdio_uart(mpu6050_i2c_scale_test 0)
32+
33+
34+
add_executable(mpu6050_i2c_irq mpu6050_i2c_irq_main.cpp)
35+
target_link_libraries(mpu6050_i2c_irq MPU6050_i2c_pico_cpp_lib)
36+
37+
# create map/bin/hex file etc.
38+
pico_add_extra_outputs(mpu6050_i2c_irq)
39+
# enable usb output, disable uart output
40+
pico_enable_stdio_usb(mpu6050_i2c_irq 1)
41+
pico_enable_stdio_uart(mpu6050_i2c_irq 0)

i2c/mpu6050_i2c/mpu6050.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,18 @@ void MPU6050::set_timing(uint8_t lowpass_filter_cfg, uint8_t sample_rate_div) {
7272
}
7373

7474
MPU6050TimingParams MPU6050::read_timing(void) {
75+
mpu6050_setbusaddr(bus_addr);
7576
mpu6050_timing_params_t accel_timing_c, gyro_timing_c;
7677
mpu6050_read_timing(&accel_timing_c, &gyro_timing_c);
7778
return MPU6050TimingParams(convert(&accel_timing_c), convert(&gyro_timing_c));
7879
}
7980

80-
81+
void MPU6050::configure_interrupt(bool active_low, bool open_drain, bool latch_pin, bool read_clear, bool enable) {
82+
mpu6050_setbusaddr(bus_addr);
83+
mpu6050_configure_interrupt(active_low, open_drain, latch_pin, read_clear, enable);
84+
}
85+
86+
uint8_t MPU6050::read_interrupt_status() {
87+
mpu6050_setbusaddr(bus_addr);
88+
return mpu6050_read_interrupt_status();
89+
}

i2c/mpu6050_i2c/mpu6050.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ class MPU6050 {
3636
bool is_connected(void);
3737
void set_timing(uint8_t lowpass_filter_cfg, uint8_t sample_rate_div);
3838
MPU6050TimingParams read_timing(void);
39+
void configure_interrupt(bool active_low, // Whether the INT pin is active low or active high
40+
bool open_drain, // Whether the INT pin is push-pull or open-drain
41+
bool latch_pin, // Whether the INT pin latches or pulses for 50us
42+
bool read_clear, // Whether interrupt status bits are cleared by reading interrupt status (default) or on any read
43+
bool enable); // Turn interrupts on or off
44+
uint8_t read_interrupt_status(); // 0 = no interrupts set, 1 = data ready
3945
private:
4046
float *accel, *gyro, temp;
4147
enum Scale accel_scale, gyro_scale;
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* MPU6050 I2C example measuring the interrupt pin and lowpass filter.
3+
*/
4+
5+
#include <stdio.h>
6+
#include <memory>
7+
#include "pico/stdlib.h"
8+
#include "pico/float.h"
9+
#include "pico/binary_info.h"
10+
#include "hardware/gpio.h"
11+
#include "mpu6050.hpp"
12+
13+
const bool USE_READ_CLEAR = true; // true => fewer reads required, eliminates a failure mode (forgetting to clear irq)
14+
const unsigned READ_TIME_MS = 8000;
15+
const uint8_t IRQ_PIN = 6;
16+
const uint8_t SAMPLE_RATE_DIVS[] = {99, 9};
17+
const uint8_t LOWPASS_FILTER_CFGS[] = {5, 1};
18+
volatile bool got_irq;
19+
20+
static std::unique_ptr<MPU6050> IMU;
21+
static float accel[3] = {0}, gyro[3] = {0}; // TODO we shouldn't need this
22+
23+
void print_SensorTimingParams(const MPU6050SensorTimingParams &params) {
24+
printf("Sample Rate: %.2f, Bandwidth: %i, Delay: %.1f\n", params.sample_rate, params.bandwidth, params.delay);
25+
}
26+
27+
void print_TimingParams(const MPU6050TimingParams &params) {
28+
printf("Accelerometer ");
29+
print_SensorTimingParams(params.accel_timing);
30+
printf("Gyroscope ");
31+
print_SensorTimingParams(params.gyro_timing);
32+
}
33+
34+
void irq_callback(uint gpio, uint32_t events) {
35+
static unsigned num_reads = 0, sample_rate_div_idx = 0, lowpass_filter_cfg_idx = 0;
36+
static float last_accel[3] = {0}, last_gyro[3] = {0};
37+
static uint64_t last_time_us = 0;
38+
static float avg_change_acc = 0, avg_change_gyro = 0;
39+
got_irq = true;
40+
if (!USE_READ_CLEAR) {
41+
IMU->read_interrupt_status();
42+
}
43+
IMU->read();
44+
float change_acc = 0, change_gyro = 0;
45+
for (int i = 0; i < 3; i++) {
46+
change_acc += (accel[i] - last_accel[i]) * (accel[i] - last_accel[i]);
47+
change_gyro += (gyro[i] - last_gyro[i]) * (gyro[i] - last_gyro[i]);
48+
last_accel[i] = accel[i];
49+
last_gyro[i] = gyro[i];
50+
}
51+
avg_change_acc += sqrtf(change_acc);
52+
avg_change_gyro += sqrtf(change_gyro);
53+
if (++num_reads > READ_TIME_MS / (SAMPLE_RATE_DIVS[sample_rate_div_idx] + 1)) {
54+
uint64_t time_us = to_us_since_boot(get_absolute_time());
55+
printf("Measured cycle rate: %f Hz\n", (1e6 * num_reads) / (time_us - last_time_us));
56+
last_time_us = time_us;
57+
printf("Average change between readings:\n\t accel: %f mm/s2 gyro: %f mrad/s\n\n",
58+
1000 * avg_change_acc / num_reads, 1000 * avg_change_gyro / num_reads);
59+
avg_change_acc = 0;
60+
avg_change_gyro = 0;
61+
num_reads = 0;
62+
if (lowpass_filter_cfg_idx == 1)
63+
sample_rate_div_idx = 1 - sample_rate_div_idx;
64+
lowpass_filter_cfg_idx = 1 - lowpass_filter_cfg_idx;
65+
IMU->set_timing(LOWPASS_FILTER_CFGS[lowpass_filter_cfg_idx], SAMPLE_RATE_DIVS[sample_rate_div_idx]);
66+
print_TimingParams(IMU->read_timing());
67+
}
68+
}
69+
70+
int main() {
71+
stdio_init_all();
72+
bi_decl(bi_1pin_with_name(IRQ_PIN, "IMU IRQ pin 1"));
73+
IMU = std::make_unique<MPU6050>(accel, gyro);
74+
IMU->reset();
75+
IMU->power(1, false, false, false);
76+
// push-pull is faster, latch allows debugging with the INT pin
77+
IMU->configure_interrupt(false, false, true, USE_READ_CLEAR, true);
78+
IMU->set_timing(LOWPASS_FILTER_CFGS[0], SAMPLE_RATE_DIVS[0]);
79+
print_TimingParams(IMU->read_timing());
80+
gpio_set_irq_enabled_with_callback(IRQ_PIN, GPIO_IRQ_LEVEL_HIGH, true, &irq_callback);
81+
while (true) {
82+
got_irq = false;
83+
sleep_ms(3000);
84+
if (!IMU->is_connected()) {
85+
printf("MPU6050 is not connected...\n");
86+
} else if (!got_irq){
87+
printf("MPU6050 is connected, but didn't trigger an interrupt\n");
88+
}
89+
}
90+
}

0 commit comments

Comments
 (0)