Skip to content

Commit 54a91fc

Browse files
split mpu6050 lib (c and c++) from demo main, refactor mostly comments
the code that's been running with simplewalker. Also add self-test even though idk what it does.
1 parent e707c9e commit 54a91fc

File tree

6 files changed

+94
-51
lines changed

6 files changed

+94
-51
lines changed

i2c/mpu6050_i2c/CMakeLists.txt

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
1-
add_executable(mpu6050_i2c
2-
mpu6050_i2c.c
3-
)
4-
1+
add_library(MPU6050_i2c_pico_lib mpu6050_i2c.c)
2+
target_include_directories(MPU6050_i2c_pico_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
53
# pull in common dependencies and additional i2c hardware support
6-
target_link_libraries(mpu6050_i2c pico_stdlib hardware_i2c)
4+
target_link_libraries(MPU6050_i2c_pico_lib pico_stdlib hardware_i2c)
5+
6+
add_library(MPU6050_i2c_pico_cpp_lib mpu6050.cpp mpu6050_i2c.c)
7+
target_include_directories(MPU6050_i2c_pico_cpp_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
8+
target_link_libraries(MPU6050_i2c_pico_cpp_lib pico_stdlib hardware_i2c)
9+
10+
11+
add_executable(mpu6050_i2c mpu6050_i2c_main.c)
12+
target_link_libraries(mpu6050_i2c MPU6050_i2c_pico_lib)
713

814
# create map/bin/hex file etc.
915
pico_add_extra_outputs(mpu6050_i2c)
16+
# enable usb output, disable uart output
17+
pico_enable_stdio_usb(mpu6050_i2c 1)
18+
pico_enable_stdio_uart(mpu6050_i2c 0)
1019

1120
# add url via pico_set_program_url
1221
example_auto_set_url(mpu6050_i2c)

i2c/mpu6050_i2c/mpu6050.cpp

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#include "hardware/i2c.h"
44
#include "mpu6050_i2c.h"
55

6-
/*MPU6050::MPU6050() : //TODO: is there a good way to do this
6+
/*MPU6050::MPU6050() : //TODO: smart pointers
77
chip_temp(*temp) {
88
accel = {0., 0., 0.};
99
gyro = {0., 0., 0.};
@@ -15,12 +15,7 @@ MPU6050::MPU6050(float *accel_out, float *gyro_out) :
1515
accel(accel_out), gyro(gyro_out), chip_temp(temp) {
1616
accel_scale = 0;
1717
gyro_scale = 0;
18-
//I2C init
19-
i2c_init(i2c_default, 400 * 1000); // Max bus speed 400 kHz
20-
gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C);
21-
gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C);
22-
gpio_pull_up(PICO_DEFAULT_I2C_SDA_PIN);
23-
gpio_pull_up(PICO_DEFAULT_I2C_SCL_PIN);
18+
setup_MPU6050_i2c();
2419
}
2520

2621
void MPU6050::power(uint8_t CLKSEL, bool temp_disable, bool sleep, bool cycle) {

i2c/mpu6050_i2c/mpu6050.hpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
11
/* class for using an MPU6050 IMU sensor on pi pico.
2-
An abstraction of pico example C code. */
2+
An abstraction of pico example C code.
3+
TODO:
4+
smart ptrs for results
5+
C++ scale enums
6+
mpu6050_t struct in C code for storing scales and bus addr
7+
*/
38
#include "pico/stdlib.h"
49

510
class MPU6050 {
611
float *accel, *gyro, temp;
712
uint8_t accel_scale, gyro_scale;
813
public:
9-
//const float *accel, *gyro, &chip_temp; // [m/s^2], [rad/s], [C]
10-
const float &chip_temp;
11-
MPU6050(void);
12-
MPU6050(float *accel_out, float *gyro_out);
14+
const float &chip_temp; // [C]
15+
16+
MPU6050(); //TODO
17+
MPU6050(float *accel_out, float *gyro_out); // [m/s^2], [rad/s]
18+
1319
void power(uint8_t CLKSEL, bool temp_disable, bool sleep, bool cycle);
1420
void reset(void);
21+
1522
void setscale_accel(uint8_t scale_num); //scale 0-3 is 2g, 4g, 8g, or 16g
1623
void setscale_gyro(uint8_t scale_num); // scale 0-3 is 250, 500, 1000, or 2000 deg/s
1724
void read(void);

i2c/mpu6050_i2c/mpu6050_i2c.c

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,8 @@
1919
inbuilt FIFO to make it more useful.
2020
2121
NOTE: Ensure the device is capable of being driven at 3.3v NOT 5v. The Pico
22-
GPIO (and therefore I2C) cannot be used at 5v.
23-
24-
You will need to use a level shifter on the I2C lines if you want to run the
25-
board at 5v.
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.
2624
2725
Connections on Raspberry Pi Pico board, other boards may vary.
2826
@@ -41,7 +39,7 @@ const uint8_t REG_PWR_MGMT_1 = 0x6B, REG_ACCEL_OUT = 0x3B, REG_GYRO_OUT = 0x43,
4139
const float gyro_scale_deg[] = {250. / 0x7fff, 500. / 0x7fff, 1000. / 0x7fff, 2000. / 0x7fff};
4240
const float gyro_scale_rad[] = {M_PI / 180. * 250. / 0x7fff, M_PI / 180. * 500. / 0x7fff,
4341
M_PI / 180. * 1000. / 0x7fff, M_PI / 180. * 2000. / 0x7fff};
44-
const float accel_scale[] = {2 * 9.81 / 0x7fff, 4 * 9.81 / 0x7fff, 8 * 9.81 / 0x7fff, 16 * 9.81 / 0x7fff};
42+
const float accel_scale_vals[] = {2 * 9.81 / 0x7fff, 4 * 9.81 / 0x7fff, 8 * 9.81 / 0x7fff, 16 * 9.81 / 0x7fff};
4543

4644

4745
////////////////////////////////////////////////////lower level functions for i2c
@@ -53,7 +51,6 @@ void mpu6050_writereg(uint8_t reg, uint8_t value) {
5351
}
5452

5553
void mpu6050_readreg(uint8_t reg, uint8_t *out, size_t length) {
56-
//read length 8-bit integers from the register at reg, store them in out.
5754
i2c_write_blocking(i2c_default, bus_addr, &reg, 1, true); // true to keep master control of bus
5855
i2c_read_blocking(i2c_default, bus_addr, out, length, false);
5956
}
@@ -63,7 +60,6 @@ void mpu6050_readreg(uint8_t reg, uint8_t *out, size_t length) {};
6360
#endif
6461

6562
void mpu6050_readreg16(uint8_t reg, int16_t *out, size_t length) {
66-
//read length 16-bit from the register at reg, store them in out. Max length 32 (= 64 bytes)
6763
// For this particular device, we send the device the register we want to read
6864
// first, then subsequently read from the device. The register is auto incrementing
6965
// so we don't need to keep sending the register we want, just the first.
@@ -82,16 +78,13 @@ void mpu6050_setbusaddr(uint8_t addr) {
8278

8379
////////////////////////////////////////////////////higher level mpu6050 functions
8480
void mpu6050_power(uint8_t CLKSEL, bool temp_disable, bool sleep, bool cycle) {
85-
/* Set the power and clock settings. CLKSEL is clock source, see docs. Recommended CLKSEL = 1 if gyro is enabled.
86-
temp_disable disables temperature, sleep enables sleep mode, cycle wakes up only when converting. */
8781
uint8_t pwrval = (CLKSEL & 7) + ((uint8_t)temp_disable << 3)
8882
+ ((uint8_t)sleep << 6) + ((uint8_t)cycle << 5);
8983
mpu6050_writereg(REG_PWR_MGMT_1, pwrval);
9084
}
9185

9286
void mpu6050_reset() {
93-
// Reset power management and signal path registers. MPU6050 returns to default settings.
94-
// Reset instructions come from register map doc. Includes 200ms of wait.
87+
// Reset instructions come from register map doc
9588
mpu6050_writereg(REG_PWR_MGMT_1, 1 << 7); //DEVICE_RESET = 1
9689
sleep_ms(100);
9790
mpu6050_writereg(REG_SIGNAL_PATH_RESET, 7); //GYRO_RESET = ACCEL_RESET = TEMP_RESET = 1
@@ -105,14 +98,15 @@ void mpu6050_read_raw(int16_t accel[3], int16_t gyro[3], int16_t *temp) {
10598
}
10699

107100
void mpu6050_read(float accel[3], float gyro_rad[3], float *temp, MPU6050_Scale accel_scale, MPU6050_Scale gyro_scale) {
108-
int16_t buffer[7];
109-
mpu6050_readreg16(REG_ACCEL_OUT, buffer, 7); //reads all at same time
101+
// reads acceleration [m/s], gyroscope [rad], and temperature [C] in one i2c interaction
102+
int16_t buffer[7]; // 3 accel + 3 gyro + scalar temp
103+
mpu6050_readreg16(REG_ACCEL_OUT, buffer, 7);
110104
mpu6050_scale_accel(accel, buffer, accel_scale);
111105
if (temp) *temp = mpu6050_scale_temp(buffer[3]);
112106
mpu6050_scale_gyro_rad(gyro_rad, buffer + 4, gyro_scale);
113107
}
114108

115-
// set and use sensitivity
109+
// functions to set and calculate with sensitivity
116110
void mpu6050_setscale_gyro(MPU6050_Scale gyro_scale) {
117111
mpu6050_writereg(REG_GYRO_CONFIG, (uint8_t)gyro_scale << 3);
118112
}
@@ -121,7 +115,7 @@ void mpu6050_setscale_accel(MPU6050_Scale accel_scale) {
121115
}
122116
void mpu6050_scale_accel(float accel[3], int16_t accel_raw[3], MPU6050_Scale scale) {
123117
for (int i = 0; i < 3; i++) {
124-
accel[i] = accel_raw[i] * accel_scale[scale];
118+
accel[i] = accel_raw[i] * accel_scale_vals[scale];
125119
}
126120
}
127121
void mpu6050_scale_gyro_deg(float gyro[3], int16_t gyro_raw[3], MPU6050_Scale scale) {
@@ -137,21 +131,25 @@ void mpu6050_scale_gyro_rad(float gyro[3], int16_t gyro_raw[3], MPU6050_Scale sc
137131
float mpu6050_scale_temp(float temp_raw) {
138132
return (temp_raw / 340.0) + 36.53;
139133
}
134+
void mpu6050_gyro_selftest_on(void) {
135+
uint8_t regdata = 0b11100000 & ((uint8_t)MPU_FS_0 << 3);
136+
mpu6050_writereg(REG_GYRO_CONFIG, regdata);
137+
}
138+
void mpu6050_accel_selftest_on(void) {
139+
uint8_t regdata = 0b11100000 & ((uint8_t)MPU_FS_2 << 3);
140+
mpu6050_writereg(REG_ACCEL_CONFIG, regdata);
141+
}
140142

141143
//TODO: set timing
142144
//TODO: set and read filter cutoff
143-
//TODO: read self test
145+
//TODO: interrupts
144146

145-
//TODO: functional mpu test
146-
int test() {
147-
stdio_init_all();
147+
bool setup_MPU6050_i2c() {
148148
#if !defined(i2c_default) || !defined(PICO_DEFAULT_I2C_SDA_PIN) || !defined(PICO_DEFAULT_I2C_SCL_PIN)
149149
#warning i2c/mpu6050_i2c example requires a board with I2C pins
150150
puts("Default I2C pins were not defined");
151-
return 0;
151+
return false;
152152
#else
153-
printf("Hello, MPU6050! Reading raw data from registers...\n");
154-
155153
// This example will use I2C0 on the default SDA and SCL pins (4, 5 on a Pico)
156154
i2c_init(i2c_default, 400 * 1000); // Max bus speed 400 kHz
157155
gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C);
@@ -160,33 +158,39 @@ int test() {
160158
gpio_pull_up(PICO_DEFAULT_I2C_SCL_PIN);
161159
// Make the I2C pins available to picotool
162160
bi_decl(bi_2pins_with_func(PICO_DEFAULT_I2C_SDA_PIN, PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C));
161+
return true;
162+
#endif
163+
}
163164

164-
mpu6050_reset();
165-
//setting CLKSEL = 1 gets better results than 0 if gyro is running and no sleep mode
166-
mpu6050_power(1, false, false, false);
165+
int run_MPU6050_demo() {
167166
MPU6050_Scale testscale = MPU_FS_0;
168167
mpu6050_setscale_accel(testscale);
169168
mpu6050_setscale_gyro(testscale);
170169

171170
int16_t accel_raw[3], gyro_raw[3], temp_raw;
172171
float acceleration[3], gyro[3];
173172

173+
mpu6050_reset();
174+
//setting CLKSEL = 1 gets better results than 0 if gyro is running and no sleep mode
175+
mpu6050_power(1, false, false, false);
176+
174177
while (1) {
178+
uint64_t time_us = to_us_since_boot(get_absolute_time());
175179
mpu6050_read_raw(accel_raw, gyro_raw, &temp_raw);
176-
//TODO time read function
180+
time_us = to_us_since_boot(get_absolute_time()) - time_us;
177181

178182
// These are the raw numbers from the chip
179183
printf("Raw Acc. X = %d, Y = %d, Z = %d\n", accel_raw[0], accel_raw[1], accel_raw[2]);
180184
printf("Raw Gyro. X = %d, Y = %d, Z = %d\n", gyro_raw[0], gyro_raw[1], gyro_raw[2]);
181-
// Temperature is simple so use the datasheet calculation to get deg C.
182-
// Note this is chip temperature.
183-
printf("Temp [C] = %f \t\t Scale = %d\n", mpu6050_scale_temp(temp_raw), testscale);
185+
// This is chip temperature.
186+
printf("Temp [C] = %f\n", mpu6050_scale_temp(temp_raw));
187+
printf("Read time: %d us; \t\t Accel and Gyro Scale = %d\n", time_us, testscale);
184188
mpu6050_scale_accel(acceleration, accel_raw, testscale);
185189
mpu6050_scale_gyro_rad(gyro, gyro_raw, testscale);
186190
printf("Acc [m/s^2] X = %f, Y = %f, Z = %f\n", acceleration[0], acceleration[1], acceleration[2]);
187191
printf("Gyro [rad/s] X = %f, Y = %f, Z = %f\n", gyro[0], gyro[1], gyro[2]);
188192

189193
sleep_ms(100);
190194
}
191-
#endif
195+
return 0;
192196
}

i2c/mpu6050_i2c/mpu6050_i2c.h

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,23 @@ typedef enum MPU6050_Scale {MPU_FS_0, MPU_FS_1, MPU_FS_2, MPU_FS_3} MPU6050_Scal
1111

1212
// lower level functions for i2c
1313
void mpu6050_writereg(uint8_t reg, uint8_t value); //write one byte to a register
14+
//read length 8-bit integers from the register at reg, store them in *out.
1415
void mpu6050_readreg(uint8_t reg, uint8_t *out, size_t length);
16+
//read length 16-bit integers from the register at reg, store them in *out. Max length 32 (= 64 bytes)
1517
void mpu6050_readreg16(uint8_t reg, int16_t *out, size_t length);
1618
void mpu6050_setbusaddr(uint8_t addr); //set the i2c bus address for communication. MPU6050 must already have this value.
1719

1820
// higher level mpu6050 functions
19-
void mpu6050_power(uint8_t CLKSEL, bool temp_disable, bool sleep, bool cycle); /* Set the power and clock settings.
21+
/* Set the power and clock settings.
2022
CLKSEL is clock source, see docs. Recommended CLKSEL = 1 if gyro is enabled.
2123
temp_disable disables temperature, sleep enables sleep mode, cycle wakes up only when converting. */
22-
void mpu6050_reset(); // Reset power management and signal path registers. MPU6050 returns to default settings.
24+
void mpu6050_power(uint8_t CLKSEL, bool temp_disable, bool sleep, bool cycle);
25+
// Reset power management and signal path registers. MPU6050 returns to default settings. Includes 200ms of wait.
26+
void mpu6050_reset();
27+
// turn on the mpu6050's accelerometer self test. Turn it off after a few 100ms with mpu6050_setscale_accel
28+
void mpu6050_accel_selftest_on(); // TODO: find out what "self test" does
29+
// turn on the mpu6050's gyroscope self test. Turn it off after a few 100ms with mpu6050_setscale_gyro
30+
void mpu6050_gyro_selftest_on();
2331
//set and use scaling
2432
void mpu6050_setscale_accel(MPU6050_Scale accel_scale);
2533
void mpu6050_setscale_gyro(MPU6050_Scale gyro_scale);
@@ -28,9 +36,13 @@ void mpu6050_scale_gyro_deg(float gyro[3], int16_t gyro_raw[3], MPU6050_Scale sc
2836
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]
2937
float mpu6050_scale_temp(float temp_raw);
3038

31-
void mpu6050_read_raw(int16_t accel[3], int16_t gyro[3], int16_t *temp); //read raw data values. Could read different timesteps.
39+
// core IMU reading functions
40+
void mpu6050_read_raw(int16_t accel[3], int16_t gyro[3], int16_t *temp); //read raw data values. Could read different samples.
3241
void mpu6050_read(float accel[3], float gyro[3], float *temp,
33-
MPU6050_Scale accel_scale, MPU6050_Scale gyro_scale); //reads all at same timestep, converts. temp can be NULL.
42+
MPU6050_Scale accel_scale, MPU6050_Scale gyro_scale); //reads all at same sample time, converts. temp can be NULL.
43+
44+
bool setup_MPU6050_i2c(); //call this before using any other functions
45+
int run_MPU6050_demo();
3446

3547
#ifdef __cplusplus
3648
}

i2c/mpu6050_i2c/mpu6050_i2c_main.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/**
2+
* Boilerplate main for mpu6050 I2c example
3+
*/
4+
5+
#include <stdio.h>
6+
#include "pico/stdlib.h"
7+
#include "mpu6050_i2c.h"
8+
9+
10+
int main() {
11+
stdio_init_all();
12+
if (setup_MPU6050_i2c()) {
13+
printf("Hello, MPU6050! Reading raw data from registers...\n");
14+
}
15+
return run_MPU6050_demo();
16+
}

0 commit comments

Comments
 (0)