Skip to content

Commit 27fad17

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 da4e50d commit 27fad17

File tree

1 file changed

+100
-37
lines changed

1 file changed

+100
-37
lines changed

i2c/mpu6050_i2c/mpu6050_i2c.c

Lines changed: 100 additions & 37 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"
@@ -30,52 +31,103 @@
3031
GND (pin 38) -> GND on MPU6050 board
3132
*/
3233

33-
// By default these devices are on bus address 0x68
34-
static int addr = 0x68;
34+
// By default these devices are on bus address 0x68
35+
static uint8_t bus_addr = 0x68;
36+
// Register addresses in the MPU6050 to read and write data to
37+
const uint8_t REG_PWR_MGMT_1 = 0x6B, REG_ACCEL_OUT = 0x3B, REG_GYRO_OUT = 0x43, REG_TEMP_OUT = 0x41,
38+
REG_SIGNAL_PATH_RESET = 0x68, REG_GYRO_CONFIG = 0x1B, REG_ACCEL_CONFIG = 0x1C;
39+
typedef enum MPU6050_Scale {MPU_FS_0, MPU_FS_1, MPU_FS_2, MPU_FS_3} MPU6050_Scale;
3540

41+
float gyro_scale_deg[] = {250. / 0x7fff, 500. / 0x7fff, 1000. / 0x7fff, 2000. / 0x7fff};
42+
float gyro_scale_rad[] = {M_PI / 180. * 250. / 0x7fff, M_PI / 180. * 500. / 0x7fff,
43+
M_PI / 180. * 1000. / 0x7fff, M_PI / 180. * 2000. / 0x7fff};
44+
float accel_scale[] = {2. / 0x7fff, 4. / 0x7fff, 8. / 0x7fff, 16. / 0x7fff};
45+
46+
47+
////////////////////////////////////////////////////lower level functions for i2c
3648
#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, 0x80};
41-
i2c_write_blocking(i2c_default, addr, buf, 2, false);
49+
void mpu6050_writereg(uint8_t reg, uint8_t value) {
50+
// write one byte to the register reg. Send register byte then data byte.
51+
uint8_t buf[] = {reg, value};
52+
i2c_write_blocking(i2c_default, bus_addr, buf, 2, false); // False - finished with bus
4253
}
4354

44-
static void mpu6050_read_raw(int16_t accel[3], int16_t gyro[3], int16_t *temp) {
55+
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.
57+
i2c_write_blocking(i2c_default, bus_addr, &reg, 1, true); // true to keep master control of bus
58+
i2c_read_blocking(i2c_default, bus_addr, out, length, false);
59+
}
60+
#else
61+
void mpu6050_writereg(uint8_t reg, uint8_t value) {};
62+
void mpu6050_readreg(uint8_t reg, uint8_t *out, size_t length) {};
63+
#endif
64+
65+
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)
4567
// For this particular device, we send the device the register we want to read
4668
// first, then subsequently read from the device. The register is auto incrementing
4769
// so we don't need to keep sending the register we want, just the first.
70+
static uint8_t buffer[64];
71+
if (length > 32) length = 32;
72+
mpu6050_readreg(reg, buffer, length * 2);
73+
for (int i = 0; i < length; i++) {
74+
out[i] = (buffer[i * 2] << 8 | buffer[(i * 2) + 1]);
75+
}
76+
}
4877

49-
uint8_t buffer[6];
78+
void mpu6050_setbusaddr(uint8_t addr) {
79+
bus_addr = addr;
80+
}
5081

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);
5582

56-
for (int i = 0; i < 3; i++) {
57-
accel[i] = (buffer[i * 2] << 8 | buffer[(i * 2) + 1]);
58-
}
83+
////////////////////////////////////////////////////higher level mpu6050 functions
84+
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. */
87+
uint8_t pwrval = (CLKSEL & 7) + ((uint8_t)temp_disable << 3)
88+
+ ((uint8_t)sleep << 6) + ((uint8_t)cycle << 5);
89+
mpu6050_writereg(REG_PWR_MGMT_1, pwrval);
90+
}
91+
92+
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.
95+
mpu6050_writereg(REG_PWR_MGMT_1, 1 << 7); //DEVICE_RESET = 1
96+
sleep_ms(100);
97+
mpu6050_writereg(REG_SIGNAL_PATH_RESET, 7); //GYRO_RESET = ACCEL_RESET = TEMP_RESET = 1
98+
sleep_ms(100);
99+
}
59100

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
101+
void mpu6050_read_raw(int16_t accel[3], int16_t gyro[3], int16_t *temp) {
102+
mpu6050_readreg16(REG_ACCEL_OUT, accel, 3);
103+
mpu6050_readreg16(REG_GYRO_OUT, gyro, 3);
104+
mpu6050_readreg16(REG_TEMP_OUT, temp, 1);
105+
}
65106

107+
// set and use sensitivity
108+
void mpu6050_setscale(MPU6050_Scale accel_scale, MPU6050_Scale gyro_scale) {
109+
mpu6050_writereg(REG_GYRO_CONFIG, (uint8_t)gyro_scale << 3);
110+
mpu6050_writereg(REG_ACCEL_CONFIG, (uint8_t)accel_scale << 3);
111+
}
112+
void mpu6050_scale_accel(float *accel, int16_t *accel_raw, MPU6050_Scale scale) {
66113
for (int i = 0; i < 3; i++) {
67-
gyro[i] = (buffer[i * 2] << 8 | buffer[(i * 2) + 1]);;
114+
accel[i] = accel_raw[i] * accel_scale[scale];
68115
}
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];
77116
}
78-
#endif
117+
void mpu6050_scale_gyro_deg(float *gyro, int16_t *gyro_raw, MPU6050_Scale scale) {
118+
for (int i = 0; i < 3; i++) {
119+
gyro[i] = gyro_raw[i] * gyro_scale_deg[scale];
120+
}
121+
}
122+
void mpu6050_scale_gyro_rad(float *gyro, int16_t *gyro_raw, MPU6050_Scale scale) {
123+
for (int i = 0; i < 3; i++) {
124+
gyro[i] = gyro_raw[i] * gyro_scale_rad[scale];
125+
}
126+
}
127+
//TODO: set timing
128+
//TODO: set and read filter cutoff
129+
//TODO: read self test
130+
79131

80132
int main() {
81133
stdio_init_all();
@@ -87,7 +139,7 @@ int main() {
87139
printf("Hello, MPU6050! Reading raw data from registers...\n");
88140

89141
// This example will use I2C0 on the default SDA and SCL pins (4, 5 on a Pico)
90-
i2c_init(i2c_default, 400 * 1000);
142+
i2c_init(i2c_default, 400 * 1000); // Max bus speed 400 kHz
91143
gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C);
92144
gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C);
93145
gpio_pull_up(PICO_DEFAULT_I2C_SDA_PIN);
@@ -96,19 +148,30 @@ int main() {
96148
bi_decl(bi_2pins_with_func(PICO_DEFAULT_I2C_SDA_PIN, PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C));
97149

98150
mpu6050_reset();
151+
//setting CLKSEL = 1 gets better results than 0 if gyro is running and no sleep mode
152+
mpu6050_power(1, false, false, false);
153+
MPU6050_Scale testscale = MPU_FS_0;
154+
mpu6050_setscale(testscale, testscale);
99155

100-
int16_t acceleration[3], gyro[3], temp;
156+
int16_t accel_raw[3], gyro_raw[3], temp_raw;
157+
float acceleration[3], gyro[3];
101158

102159
while (1) {
103-
mpu6050_read_raw(acceleration, gyro, &temp);
160+
mpu6050_read_raw(accel_raw, gyro_raw, &temp_raw);
161+
//TODO time read function
104162

105163
// These are the raw numbers from the chip, so will need tweaking to be really useful.
106164
// See the datasheet for more information
107-
printf("Acc. X = %d, Y = %d, Z = %d\n", acceleration[0], acceleration[1], acceleration[2]);
108-
printf("Gyro. X = %d, Y = %d, Z = %d\n", gyro[0], gyro[1], gyro[2]);
165+
printf("Raw Acc. X = %d, Y = %d, Z = %d\n", accel_raw[0], accel_raw[1], accel_raw[2]);
166+
printf("Raw Gyro. X = %d, Y = %d, Z = %d\n", gyro_raw[0], gyro_raw[1], gyro_raw[2]);
109167
// Temperature is simple so use the datasheet calculation to get deg C.
110168
// Note this is chip temperature.
111-
printf("Temp. = %f\n", (temp / 340.0) + 36.53);
169+
printf("Temp [C] = %f \t\t Scale = %d\n", (temp_raw / 340.0) + 36.53, testscale);
170+
//include the scaling
171+
mpu6050_scale_accel(acceleration, accel_raw, testscale);
172+
mpu6050_scale_gyro_rad(gyro, gyro_raw, testscale);
173+
printf("Acc [m/s^2] X = %f, Y = %f, Z = %f\n", acceleration[0], acceleration[1], acceleration[2]);
174+
printf("Gyro [rad/s] X = %f, Y = %f, Z = %f\n", gyro[0], gyro[1], gyro[2]);
112175

113176
sleep_ms(100);
114177
}

0 commit comments

Comments
 (0)