Skip to content

Commit daf21fd

Browse files
Reorganized to use register functions and scaling
Reorganized so i2c code is in register reading and writing functions. Rewrote power functions for reset and power options. Added mpu6050 scale set functions and local scaling functions. Tested connecting, reading data and changing scale, all working.
1 parent afd1d20 commit daf21fd

File tree

1 file changed

+102
-41
lines changed

1 file changed

+102
-41
lines changed

i2c/mpu6050_i2c/mpu6050_i2c.c

Lines changed: 102 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <stdio.h>
88
#include <string.h>
9+
#include <math.h>
910
#include "pico/stdlib.h"
1011
#include "pico/binary_info.h"
1112
#include "hardware/i2c.h"
@@ -17,10 +18,8 @@
1718
inbuilt FIFO to make it more useful.
1819
1920
NOTE: Ensure the device is capable of being driven at 3.3v NOT 5v. The Pico
20-
GPIO (and therefor I2C) cannot be used at 5v.
21-
22-
You will need to use a level shifter on the I2C lines if you want to run the
23-
board at 5v.
21+
GPIO (and therefor I2C) cannot be used at 5v. You will need to use a level
22+
shifter on the I2C lines if you want to run the board at 5v.
2423
2524
Connections on Raspberry Pi Pico board, other boards may vary.
2625
@@ -30,52 +29,103 @@
3029
GND (pin 38) -> GND on MPU6050 board
3130
*/
3231

33-
// By default these devices are on bus address 0x68
34-
static int addr = 0x68;
32+
// By default these devices are on bus address 0x68
33+
static uint8_t bus_addr = 0x68;
34+
// Register addresses in the MPU6050 to read and write data to
35+
const uint8_t REG_PWR_MGMT_1 = 0x6B, REG_ACCEL_OUT = 0x3B, REG_GYRO_OUT = 0x43, REG_TEMP_OUT = 0x41,
36+
REG_SIGNAL_PATH_RESET = 0x68, REG_GYRO_CONFIG = 0x1B, REG_ACCEL_CONFIG = 0x1C;
37+
typedef enum MPU6050_Scale {MPU_FS_0, MPU_FS_1, MPU_FS_2, MPU_FS_3} MPU6050_Scale;
38+
39+
float gyro_scale_deg[] = {250. / 0x7fff, 500. / 0x7fff, 1000. / 0x7fff, 2000. / 0x7fff};
40+
float gyro_scale_rad[] = {M_PI / 180. * 250. / 0x7fff, M_PI / 180. * 500. / 0x7fff,
41+
M_PI / 180. * 1000. / 0x7fff, M_PI / 180. * 2000. / 0x7fff};
42+
float accel_scale[] = {2. / 0x7fff, 4. / 0x7fff, 8. / 0x7fff, 16. / 0x7fff};
3543

44+
45+
////////////////////////////////////////////////////lower level functions for i2c
3646
#ifdef i2c_default
37-
static void mpu6050_reset() {
38-
// Two byte reset. First byte register, second byte data
39-
// There are a load more options to set up the device in different ways that could be added here
40-
uint8_t buf[] = {0x6B, 0x00};
41-
i2c_write_blocking(i2c_default, addr, buf, 2, false);
47+
void mpu6050_writereg(uint8_t reg, uint8_t value) {
48+
// write one byte to the register reg. Send register byte then data byte.
49+
uint8_t buf[] = {reg, value};
50+
i2c_write_blocking(i2c_default, bus_addr, buf, 2, false); // False - finished with bus
4251
}
4352

44-
static void mpu6050_read_raw(int16_t accel[3], int16_t gyro[3], int16_t *temp) {
53+
void mpu6050_readreg(uint8_t reg, uint8_t *out, size_t length) {
54+
//read length 8-bit integers from the register at reg, store them in out.
55+
i2c_write_blocking(i2c_default, bus_addr, &reg, 1, true); // true to keep master control of bus
56+
i2c_read_blocking(i2c_default, bus_addr, out, length, false);
57+
}
58+
#else
59+
void mpu6050_writereg(uint8_t reg, uint8_t value) {};
60+
void mpu6050_readreg(uint8_t reg, uint8_t *out, size_t length) {};
61+
#endif
62+
63+
void mpu6050_readreg16(uint8_t reg, int16_t *out, size_t length) {
64+
//read length 16-bit from the register at reg, store them in out. Max length 32 (= 64 bytes)
4565
// For this particular device, we send the device the register we want to read
4666
// first, then subsequently read from the device. The register is auto incrementing
4767
// so we don't need to keep sending the register we want, just the first.
68+
static uint8_t buffer[64];
69+
if (length > 32) length = 32;
70+
mpu6050_readreg(reg, buffer, length * 2);
71+
for (int i = 0; i < length; i++) {
72+
out[i] = (buffer[i * 2] << 8 | buffer[(i * 2) + 1]);
73+
}
74+
}
4875

49-
uint8_t buffer[6];
76+
void mpu6050_setbusaddr(uint8_t addr) {
77+
bus_addr = addr;
78+
}
5079

51-
// Start reading acceleration registers from register 0x3B for 6 bytes
52-
uint8_t val = 0x3B;
53-
i2c_write_blocking(i2c_default, addr, &val, 1, true); // true to keep master control of bus
54-
i2c_read_blocking(i2c_default, addr, buffer, 6, false);
5580

56-
for (int i = 0; i < 3; i++) {
57-
accel[i] = (buffer[i * 2] << 8 | buffer[(i * 2) + 1]);
58-
}
81+
////////////////////////////////////////////////////higher level mpu6050 functions
82+
void mpu6050_power(uint8_t CLKSEL, bool temp_disable, bool sleep, bool cycle) {
83+
/* Set the power and clock settings. CLKSEL is clock source, see docs. Recommended CLKSEL = 1 if gyro is enabled.
84+
temp_disable disables temperature, sleep enables sleep mode, cycle wakes up only when converting. */
85+
uint8_t pwrval = (CLKSEL & 7) + ((uint8_t)temp_disable << 3)
86+
+ ((uint8_t)sleep << 6) + ((uint8_t)cycle << 5);
87+
mpu6050_writereg(REG_PWR_MGMT_1, pwrval);
88+
}
5989

60-
// Now gyro data from reg 0x43 for 6 bytes
61-
// The register is auto incrementing on each read
62-
val = 0x43;
63-
i2c_write_blocking(i2c_default, addr, &val, 1, true);
64-
i2c_read_blocking(i2c_default, addr, buffer, 6, false); // False - finished with bus
90+
void mpu6050_reset() {
91+
// Reset power management and signal path registers. MPU6050 returns to default settings.
92+
// Reset instructions come from register map doc. Includes 200ms of wait.
93+
mpu6050_writereg(REG_PWR_MGMT_1, 1 << 7); //DEVICE_RESET = 1
94+
sleep_ms(100);
95+
mpu6050_writereg(REG_SIGNAL_PATH_RESET, 7); //GYRO_RESET = ACCEL_RESET = TEMP_RESET = 1
96+
sleep_ms(100);
97+
}
6598

99+
void mpu6050_read_raw(int16_t accel[3], int16_t gyro[3], int16_t *temp) {
100+
mpu6050_readreg16(REG_ACCEL_OUT, accel, 3);
101+
mpu6050_readreg16(REG_GYRO_OUT, gyro, 3);
102+
mpu6050_readreg16(REG_TEMP_OUT, temp, 1);
103+
}
104+
105+
// set and use sensitivity
106+
void mpu6050_setscale(MPU6050_Scale accel_scale, MPU6050_Scale gyro_scale) {
107+
mpu6050_writereg(REG_GYRO_CONFIG, (uint8_t)gyro_scale << 3);
108+
mpu6050_writereg(REG_ACCEL_CONFIG, (uint8_t)accel_scale << 3);
109+
}
110+
void mpu6050_scale_accel(float *accel, int16_t *accel_raw, MPU6050_Scale scale) {
66111
for (int i = 0; i < 3; i++) {
67-
gyro[i] = (buffer[i * 2] << 8 | buffer[(i * 2) + 1]);;
112+
accel[i] = accel_raw[i] * accel_scale[scale];
68113
}
69-
70-
// Now temperature from reg 0x41 for 2 bytes
71-
// The register is auto incrementing on each read
72-
val = 0x41;
73-
i2c_write_blocking(i2c_default, addr, &val, 1, true);
74-
i2c_read_blocking(i2c_default, addr, buffer, 2, false); // False - finished with bus
75-
76-
*temp = buffer[0] << 8 | buffer[1];
77114
}
78-
#endif
115+
void mpu6050_scale_gyro_deg(float *gyro, int16_t *gyro_raw, MPU6050_Scale scale) {
116+
for (int i = 0; i < 3; i++) {
117+
gyro[i] = gyro_raw[i] * gyro_scale_deg[scale];
118+
}
119+
}
120+
void mpu6050_scale_gyro_rad(float *gyro, int16_t *gyro_raw, MPU6050_Scale scale) {
121+
for (int i = 0; i < 3; i++) {
122+
gyro[i] = gyro_raw[i] * gyro_scale_rad[scale];
123+
}
124+
}
125+
//TODO: set timing
126+
//TODO: set and read filter cutoff
127+
//TODO: read self test
128+
79129

80130
int main() {
81131
stdio_init_all();
@@ -86,7 +136,7 @@ int main() {
86136
printf("Hello, MPU6050! Reading raw data from registers...\n");
87137

88138
// This example will use I2C0 on the default SDA and SCL pins (4, 5 on a Pico)
89-
i2c_init(i2c_default, 400 * 1000);
139+
i2c_init(i2c_default, 400 * 1000); // Max bus speed 400 kHz
90140
gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C);
91141
gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C);
92142
gpio_pull_up(PICO_DEFAULT_I2C_SDA_PIN);
@@ -95,19 +145,30 @@ int main() {
95145
bi_decl(bi_2pins_with_func(PICO_DEFAULT_I2C_SDA_PIN, PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C));
96146

97147
mpu6050_reset();
148+
//setting CLKSEL = 1 gets better results than 0 if gyro is running and no sleep mode
149+
mpu6050_power(1, false, false, false);
150+
MPU6050_Scale testscale = MPU_FS_0;
151+
mpu6050_setscale(testscale, testscale);
98152

99-
int16_t acceleration[3], gyro[3], temp;
153+
int16_t accel_raw[3], gyro_raw[3], temp_raw;
154+
float acceleration[3], gyro[3];
100155

101156
while (1) {
102-
mpu6050_read_raw(acceleration, gyro, &temp);
157+
mpu6050_read_raw(accel_raw, gyro_raw, &temp_raw);
158+
//TODO time read function
103159

104160
// These are the raw numbers from the chip, so will need tweaking to be really useful.
105161
// See the datasheet for more information
106-
printf("Acc. X = %d, Y = %d, Z = %d\n", acceleration[0], acceleration[1], acceleration[2]);
107-
printf("Gyro. X = %d, Y = %d, Z = %d\n", gyro[0], gyro[1], gyro[2]);
162+
printf("Raw Acc. X = %d, Y = %d, Z = %d\n", accel_raw[0], accel_raw[1], accel_raw[2]);
163+
printf("Raw Gyro. X = %d, Y = %d, Z = %d\n", gyro_raw[0], gyro_raw[1], gyro_raw[2]);
108164
// Temperature is simple so use the datasheet calculation to get deg C.
109165
// Note this is chip temperature.
110-
printf("Temp. = %f\n", (temp / 340.0) + 36.53);
166+
printf("Temp [C] = %f \t\t Scale = %d\n", (temp_raw / 340.0) + 36.53, testscale);
167+
//include the scaling
168+
mpu6050_scale_accel(acceleration, accel_raw, testscale);
169+
mpu6050_scale_gyro_rad(gyro, gyro_raw, testscale);
170+
printf("Acc [m/s^2] X = %f, Y = %f, Z = %f\n", acceleration[0], acceleration[1], acceleration[2]);
171+
printf("Gyro [rad/s] X = %f, Y = %f, Z = %f\n", gyro[0], gyro[1], gyro[2]);
111172

112173
sleep_ms(100);
113174
}

0 commit comments

Comments
 (0)