Skip to content

Commit 8f8a368

Browse files
tidy & clarify, move demo code to i2c_main.c
1 parent c2f0dd8 commit 8f8a368

File tree

7 files changed

+126
-90
lines changed

7 files changed

+126
-90
lines changed

i2c/mpu6050_i2c/mpu6050.cpp

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,6 @@ MPU6050TimingParams::MPU6050TimingParams(const MPU6050SensorTimingParams &_accel
2121
: accel_timing(_accel_timing), gyro_timing(_gyro_timing) {}
2222

2323

24-
/*MPU6050::MPU6050() : //TODO: smart pointers
25-
chip_temp(*temp) {
26-
accel = {0., 0., 0.};
27-
gyro = {0., 0., 0.};
28-
temp = {};
29-
MPU6050(accel, gyro, temp);
30-
} */
31-
3224
MPU6050::MPU6050(float *accel_out, float *gyro_out, uint8_t addr) :
3325
chip_temp(temp), accel(accel_out), gyro(gyro_out), accel_scale(Scale_0), gyro_scale(Scale_0), bus_addr(addr) {
3426
setup_MPU6050_i2c();
@@ -61,6 +53,16 @@ void MPU6050::read(void) {
6153
mpu6050_read(accel, gyro, &temp, (MPU6050_Scale)accel_scale, (MPU6050_Scale)gyro_scale);
6254
}
6355

56+
void MPU6050::read_accel(void) {
57+
mpu6050_setbusaddr(bus_addr);
58+
mpu6050_read_accel(accel, (MPU6050_Scale)accel_scale);
59+
}
60+
61+
void MPU6050::read_gyro(void) {
62+
mpu6050_setbusaddr(bus_addr);
63+
mpu6050_read_gyro_rad(gyro, (MPU6050_Scale)gyro_scale);
64+
}
65+
6466
bool MPU6050::is_connected() {
6567
mpu6050_setbusaddr(bus_addr);
6668
return mpu6050_is_connected();
@@ -87,3 +89,11 @@ uint8_t MPU6050::read_interrupt_status() {
8789
mpu6050_setbusaddr(bus_addr);
8890
return mpu6050_read_interrupt_status();
8991
}
92+
93+
94+
float MPU6050_max_accel(MPU6050::Scale scale) {
95+
return accel_scale_vals[(int)scale];
96+
}
97+
float MPU6050_max_gyro_rad(MPU6050::Scale scale) {
98+
return gyro_scale_rad[(int)scale];
99+
}

i2c/mpu6050_i2c/mpu6050.hpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
/* class for using an MPU6050 IMU sensor on pi pico.
2-
An abstraction of pico example C code.
3-
TODO:
4-
smart ptrs for results
2+
A C++ interface to the pico example C code.
53
*/
64
#include "stdint.h"
75

@@ -22,7 +20,6 @@ class MPU6050 {
2220
public:
2321
const float &chip_temp; // [C]
2422

25-
MPU6050(); //TODO
2623
MPU6050(float *accel_out, float *gyro_out, uint8_t i2c_addr=0x68); // [m/s^2], [rad/s]
2724

2825
void power(uint8_t CLKSEL, bool temp_disable, bool sleep, bool cycle);
@@ -33,6 +30,8 @@ class MPU6050 {
3330
void setscale_accel(Scale scale); //scale 0-3 is 2g, 4g, 8g, or 16g
3431
void setscale_gyro(Scale scale); // scale 0-3 is 250, 500, 1000, or 2000 deg/s
3532
void read(void);
33+
void read_accel(void);
34+
void read_gyro(void);
3635
bool is_connected(void);
3736
void set_timing(uint8_t lowpass_filter_cfg, uint8_t sample_rate_div);
3837
MPU6050TimingParams read_timing(void);
@@ -47,3 +46,6 @@ class MPU6050 {
4746
enum Scale accel_scale, gyro_scale;
4847
uint8_t bus_addr;
4948
};
49+
50+
float MPU6050_max_accel(MPU6050::Scale scale);
51+
float MPU6050_max_gyro_rad(MPU6050::Scale scale);

i2c/mpu6050_i2c/mpu6050_i2c.c

Lines changed: 20 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,6 @@
1212
#include "hardware/i2c.h"
1313
#include "mpu6050_i2c.h"
1414

15-
/* Example code to talk to a MPU6050 MEMS accelerometer and gyroscope
16-
17-
This is taking to simple approach of simply reading registers. It's perfectly
18-
possible to link up an interrupt line and set things up to read from the
19-
inbuilt FIFO to make it more useful.
20-
21-
NOTE: Ensure the device is capable of being driven at 3.3v NOT 5v. The Pico
22-
GPIO (and therefor I2C) cannot be used at 5v. You will need to use a level
23-
shifter on the I2C lines if you want to run the board at 5v.
24-
25-
Connections on Raspberry Pi Pico board, other boards may vary.
26-
27-
GPIO PICO_DEFAULT_I2C_SDA_PIN (On Pico this is GP4 (pin 6)) -> SDA on MPU6050 board
28-
GPIO PICO_DEFAULT_I2C_SCL_PIN (On Pico this is GP5 (pin 7)) -> SCL on MPU6050 board
29-
3.3v (pin 36) -> VCC on MPU6050 board
30-
GND (pin 38) -> GND on MPU6050 board
31-
*/
3215

3316
// By default these devices are on bus address 0x68
3417
static uint8_t bus_addr = 0x68;
@@ -43,6 +26,7 @@ const float gyro_scale_rad[] = {M_PI / 180. * 250. / 0x7fff, M_PI / 180. * 500.
4326
M_PI / 180. * 1000. / 0x7fff, M_PI / 180. * 2000. / 0x7fff};
4427
const float accel_scale_vals[] = {2 * 9.81 / 0x7fff, 4 * 9.81 / 0x7fff, 8 * 9.81 / 0x7fff, 16 * 9.81 / 0x7fff};
4528

29+
// timing data, indexed with lowpass_filter_cfg
4630
const int accel_bandwidth_lookup[] = {260, 184, 94, 44, 21, 10, 5};
4731
const float accel_delay_lookup[] = {0, 2.0, 3.0, 4.9, 8.5, 13.8, 19.0};
4832
const int gyro_bandwidth_lookup[] = {256, 188, 98, 42, 20, 10, 5};
@@ -98,10 +82,12 @@ void mpu6050_reset() {
9882
sleep_ms(100);
9983
}
10084

101-
void mpu6050_read_raw(int16_t accel[3], int16_t gyro[3], int16_t *temp) {
85+
void mpu6050_read_accel_raw(int16_t accel[3]) {
10286
mpu6050_readreg16(REG_ACCEL_OUT, accel, 3);
87+
}
88+
89+
void mpu6050_read_gyro_raw(int16_t gyro[3]) {
10390
mpu6050_readreg16(REG_GYRO_OUT, gyro, 3);
104-
mpu6050_readreg16(REG_TEMP_OUT, temp, 1);
10591
}
10692

10793
void mpu6050_read(float accel[3], float gyro_rad[3], float *temp, MPU6050_Scale accel_scale, MPU6050_Scale gyro_scale) {
@@ -112,6 +98,21 @@ void mpu6050_read(float accel[3], float gyro_rad[3], float *temp, MPU6050_Scale
11298
if (temp) *temp = mpu6050_scale_temp(buffer[3]);
11399
mpu6050_scale_gyro_rad(gyro_rad, buffer + 4, gyro_scale);
114100
}
101+
void mpu6050_read_accel(float accel[3], MPU6050_Scale accel_scale) {
102+
int16_t buffer[3];
103+
mpu6050_readreg16(REG_ACCEL_OUT, buffer, 3);
104+
mpu6050_scale_accel(accel, buffer, accel_scale);
105+
}
106+
void mpu6050_read_gyro_rad(float gyro[3], MPU6050_Scale gyro_scale) {
107+
int16_t buffer[3];
108+
mpu6050_readreg16(REG_GYRO_OUT, buffer, 3);
109+
mpu6050_scale_gyro_rad(gyro, buffer, gyro_scale);
110+
}
111+
void mpu6050_read_gyro_deg(float gyro[3], MPU6050_Scale gyro_scale) {
112+
int16_t buffer[3];
113+
mpu6050_readreg16(REG_GYRO_OUT, buffer, 3);
114+
mpu6050_scale_gyro_deg(gyro, buffer, gyro_scale);
115+
}
115116

116117
// functions to set and calculate with sensitivity
117118
void mpu6050_setscale_gyro(MPU6050_Scale gyro_scale) {
@@ -208,42 +209,3 @@ bool setup_MPU6050_i2c() {
208209
return true;
209210
#endif
210211
}
211-
212-
int run_MPU6050_demo() {
213-
MPU6050_Scale testscale = MPU_FS_0;
214-
mpu6050_setscale_accel(testscale);
215-
mpu6050_setscale_gyro(testscale);
216-
217-
int16_t accel_raw[3], gyro_raw[3], temp_raw;
218-
float acceleration[3], gyro[3];
219-
220-
mpu6050_reset();
221-
//setting CLKSEL = 1 gets better results than 0 if gyro is running and no sleep mode
222-
mpu6050_power(1, false, false, false);
223-
224-
mpu6050_set_timing(5, 99); // 10 Hz
225-
226-
while (1) {
227-
while (!mpu6050_is_connected()) {
228-
printf("MPU6050 is not connected...\n");
229-
sleep_ms(1000);
230-
}
231-
uint64_t time_us = to_us_since_boot(get_absolute_time());
232-
mpu6050_read_raw(accel_raw, gyro_raw, &temp_raw);
233-
time_us = to_us_since_boot(get_absolute_time()) - time_us;
234-
235-
// These are the raw numbers from the chip
236-
printf("Raw Acc. X = %d, Y = %d, Z = %d\n", accel_raw[0], accel_raw[1], accel_raw[2]);
237-
printf("Raw Gyro. X = %d, Y = %d, Z = %d\n", gyro_raw[0], gyro_raw[1], gyro_raw[2]);
238-
// This is chip temperature.
239-
printf("Temp [C] = %f\n", mpu6050_scale_temp(temp_raw));
240-
printf("Read time: %llu us; \t\t Accel and Gyro Scale = %d\n", time_us, (int)testscale);
241-
mpu6050_scale_accel(acceleration, accel_raw, testscale);
242-
mpu6050_scale_gyro_rad(gyro, gyro_raw, testscale);
243-
printf("Acc [m/s^2] X = %f, Y = %f, Z = %f\n", acceleration[0], acceleration[1], acceleration[2]);
244-
printf("Gyro [rad/s] X = %f, Y = %f, Z = %f\n", gyro[0], gyro[1], gyro[2]);
245-
246-
sleep_ms(100);
247-
}
248-
return 0;
249-
}

i2c/mpu6050_i2c/mpu6050_i2c.h

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,9 @@ typedef struct {
1616
float sample_rate; // rate of new data loading in the register [Hz]
1717
} mpu6050_timing_params_t;
1818

19-
// lower level functions for i2c
20-
void mpu6050_writereg(uint8_t reg, uint8_t value); //write one byte to a register
21-
//read length 8-bit integers from the register at reg, store them in *out.
22-
void mpu6050_readreg(uint8_t reg, uint8_t *out, size_t length);
23-
//read length 16-bit integers from the register at reg, store them in *out. Max length 32 (= 64 bytes)
24-
void mpu6050_readreg16(uint8_t reg, int16_t *out, size_t length);
19+
bool setup_MPU6050_i2c(); //call this before using any other functions
2520
void mpu6050_setbusaddr(uint8_t addr); //set the i2c bus address for communication. MPU6050 must already have this value.
2621

27-
// higher level mpu6050 functions
2822
/* Set the power and clock settings.
2923
CLKSEL is clock source, see docs. Recommended CLKSEL = 1 if gyro is enabled.
3024
temp_disable disables temperature, sleep enables sleep mode, cycle wakes up only when converting. */
@@ -54,18 +48,20 @@ uint8_t mpu6050_read_interrupt_status(); // 0 = no interrupts set, 1 = data rea
5448
//set and use scaling. The first read() after setscale() might not have the updated scaling.
5549
void mpu6050_setscale_accel(MPU6050_Scale accel_scale);
5650
void mpu6050_setscale_gyro(MPU6050_Scale gyro_scale);
51+
extern const float gyro_scale_deg[4], gyro_scale_rad[4], accel_scale_vals[4]; // scale constants, index with MPU6050_Scale
5752
void mpu6050_scale_accel(float accel[3], int16_t accel_raw[3], MPU6050_Scale scale); //sets accel[3] in m/s^2 from accel_raw[3]
58-
void mpu6050_scale_gyro_deg(float gyro[3], int16_t gyro_raw[3], MPU6050_Scale scale); //sets gyro[3] in degrees from gyro_raw[3]
59-
void mpu6050_scale_gyro_rad(float gyro[3], int16_t gyro_raw[3], MPU6050_Scale scale); //sets gyro[3] in radians from gyro_raw[3]
53+
void mpu6050_scale_gyro_deg(float gyro[3], int16_t gyro_raw[3], MPU6050_Scale scale); //sets gyro[3] in degrees/s from gyro_raw[3]
54+
void mpu6050_scale_gyro_rad(float gyro[3], int16_t gyro_raw[3], MPU6050_Scale scale); //sets gyro[3] in radians/s from gyro_raw[3]
6055
float mpu6050_scale_temp(float temp_raw);
6156

62-
// core IMU reading functions
63-
void mpu6050_read_raw(int16_t accel[3], int16_t gyro[3], int16_t *temp); //read raw data values. Could read different samples.
64-
void mpu6050_read(float accel[3], float gyro[3], float *temp,
57+
// core sensor data reading functions
58+
void mpu6050_read_accel_raw(int16_t accel[3]);
59+
void mpu6050_read_gyro_raw(int16_t gyro[3]);
60+
void mpu6050_read(float accel[3], float gyro_rad[3], float *temp,
6561
MPU6050_Scale accel_scale, MPU6050_Scale gyro_scale); //reads all at same sample time, converts. temp can be NULL.
66-
67-
bool setup_MPU6050_i2c(); //call this before using any other functions
68-
int run_MPU6050_demo();
62+
void mpu6050_read_accel(float accel[3], MPU6050_Scale accel_scale);
63+
void mpu6050_read_gyro_rad(float gyro[3], MPU6050_Scale gyro_scale);
64+
void mpu6050_read_gyro_deg(float gyro[3], MPU6050_Scale gyro_scale);
6965

7066
#ifdef __cplusplus
7167
}

i2c/mpu6050_i2c/mpu6050_i2c_irq_main.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const uint8_t LOWPASS_FILTER_CFGS[] = {5, 1};
1818
volatile bool got_irq;
1919

2020
static std::unique_ptr<MPU6050> IMU;
21-
static float accel[3] = {0}, gyro[3] = {0}; // TODO we shouldn't need this
21+
static float accel[3] = {0}, gyro[3] = {0};
2222

2323
void print_SensorTimingParams(const MPU6050SensorTimingParams &params) {
2424
printf("Sample Rate: %.2f, Bandwidth: %i, Delay: %.1f\n", params.sample_rate, params.bandwidth, params.delay);
@@ -72,6 +72,7 @@ int main() {
7272
bi_decl(bi_1pin_with_name(IRQ_PIN, "IMU IRQ pin 1"));
7373
IMU = std::make_unique<MPU6050>(accel, gyro);
7474
IMU->reset();
75+
//setting CLKSEL = 1 gets better results than 0 if gyro is running and no sleep mode
7576
IMU->power(1, false, false, false);
7677
// push-pull is faster, latch allows debugging with the INT pin
7778
IMU->configure_interrupt(false, false, true, USE_READ_CLEAR, true);
@@ -85,6 +86,10 @@ int main() {
8586
printf("MPU6050 is not connected...\n");
8687
} else if (!got_irq){
8788
printf("MPU6050 is connected, but didn't trigger an interrupt\n");
89+
IMU->read();
90+
printf("Read accel and gyro without IRQ:\n"
91+
"%+6f %+6f %+6f | %+6f %+6f %+6f\n",
92+
accel[0], accel[1], accel[2], gyro[0], gyro[1], gyro[2]);
8893
}
8994
}
9095
}

i2c/mpu6050_i2c/mpu6050_i2c_main.c

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
/**
2-
* Boilerplate main for mpu6050 I2c example
2+
Example code to talk to a MPU6050 MEMS accelerometer and gyroscope
3+
4+
NOTE: Ensure the device is capable of being driven at 3.3v NOT 5v. The Pico
5+
GPIO (and therefor I2C) cannot be used at 5v. You will need to use a level
6+
shifter on the I2C lines if you want to run the board at 5v.
7+
8+
Connections on Raspberry Pi Pico board, other boards may vary.
9+
10+
GPIO PICO_DEFAULT_I2C_SDA_PIN (On Pico this is GP4 (pin 6)) -> SDA on MPU6050 board
11+
GPIO PICO_DEFAULT_I2C_SCL_PIN (On Pico this is GP5 (pin 7)) -> SCL on MPU6050 board
12+
3.3v (pin 36) -> VCC on MPU6050 board
13+
GND (pin 38) -> GND on MPU6050 board
314
*/
415

516
#include <stdio.h>
@@ -12,5 +23,53 @@ int main() {
1223
if (setup_MPU6050_i2c()) {
1324
printf("Hello, MPU6050! Reading raw data from registers...\n");
1425
}
15-
return run_MPU6050_demo();
26+
MPU6050_Scale testscale = MPU_FS_0;
27+
28+
float acceleration[3], gyro[3], temperature;
29+
int16_t raw_accel[3], raw_gyro[3];
30+
31+
mpu6050_reset();
32+
//setting CLKSEL = 1 gets better results than 0 if gyro is running and no sleep mode
33+
mpu6050_power(1, false, false, false);
34+
mpu6050_setscale_accel(testscale);
35+
mpu6050_setscale_gyro(testscale);
36+
mpu6050_set_timing(6, 99); // lowpass frequency = 5 Hz, sample rate = 10 Hz
37+
38+
while (1) {
39+
while (!mpu6050_is_connected()) {
40+
printf("MPU6050 is not connected...\n");
41+
sleep_ms(1000);
42+
}
43+
uint64_t time_us = to_us_since_boot(get_absolute_time());
44+
mpu6050_read_accel_raw(raw_accel);
45+
mpu6050_read_gyro_raw(raw_gyro);
46+
time_us = to_us_since_boot(get_absolute_time()) - time_us;
47+
printf("Takes %llu us to read raw accel and gyro readings separately\n"
48+
"Acc X = %d, Y = %d, Z = %d\nGyro X = %d, Y = %d, Z = %d\n",
49+
time_us, raw_accel[0], raw_accel[1], raw_accel[2],
50+
raw_gyro[0], raw_gyro[1], raw_gyro[2]);
51+
52+
time_us = to_us_since_boot(get_absolute_time());
53+
mpu6050_read_accel(acceleration, testscale);
54+
mpu6050_read_gyro_rad(gyro, testscale);
55+
time_us = to_us_since_boot(get_absolute_time()) - time_us;
56+
printf("Takes %llu us to read and scale accel and gyro readings separately\n"
57+
"Acc [m/s^2] X = %f, Y = %f, Z = %f\n"
58+
"Gyro [rad/s] X = %f, Y = %f, Z = %f\n",
59+
time_us, acceleration[0], acceleration[1], acceleration[2],
60+
gyro[0], gyro[1], gyro[2]);
61+
62+
time_us = to_us_since_boot(get_absolute_time());
63+
mpu6050_read(acceleration, gyro, &temperature, testscale, testscale);
64+
time_us = to_us_since_boot(get_absolute_time()) - time_us;
65+
printf("Takes %llu us to read and scale all together\n"
66+
"Acc [m/s^2] X = %f, Y = %f, Z = %f\n"
67+
"Gyro [rad/s] X = %f, Y = %f, Z = %f\n"
68+
"Temp [C] = %f\n----------------------\n",
69+
time_us, acceleration[0], acceleration[1], acceleration[2],
70+
gyro[0], gyro[1], gyro[2], temperature);
71+
72+
sleep_ms(1000);
73+
}
74+
return 0;
1675
}

i2c/mpu6050_i2c/mpu6050_scale_test.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,16 @@
88
#include "mpu6050.hpp"
99
#include "pico/stdlib.h"
1010

11-
const int READ_DELAY_MS = 100, READS_PER_SCALE = 50, PRINTS_PER_SCALE = 2;
11+
const uint8_t READ_DELAY_MS = 100, READS_PER_SCALE = 50, PRINTS_PER_SCALE = 3;
1212

1313
int main() {
1414
stdio_init_all();
15-
float accel[3] = {0}, gyro[3] = {0}; // TODO we shouldn't need this
15+
float accel[3] = {0}, gyro[3] = {0};
1616
MPU6050 *IMU = new MPU6050(accel, gyro);
1717
IMU->reset();
18+
//setting CLKSEL = 1 gets better results than 0 if gyro is running and no sleep mode
1819
IMU->power(1, false, false, false);
20+
IMU->set_timing(6, READ_DELAY_MS - 1); // DLPF = 5 Hz
1921
int accel_scale = 0, gyro_scale = 2;
2022
while (true) {
2123
while (!IMU->is_connected()) {

0 commit comments

Comments
 (0)