6
6
7
7
#include <stdio.h>
8
8
#include <string.h>
9
+ #include <math.h>
9
10
#include "pico/stdlib.h"
10
11
#include "pico/binary_info.h"
11
12
#include "hardware/i2c.h"
30
31
GND (pin 38) -> GND on MPU6050 board
31
32
*/
32
33
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 ;
35
40
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
36
48
#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
42
53
}
43
54
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)
45
67
// For this particular device, we send the device the register we want to read
46
68
// first, then subsequently read from the device. The register is auto incrementing
47
69
// 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
+ }
48
77
49
- uint8_t buffer [6 ];
78
+ void mpu6050_setbusaddr (uint8_t addr ) {
79
+ bus_addr = addr ;
80
+ }
50
81
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);
55
82
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
+ }
59
100
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
+ }
65
106
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 ) {
66
113
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 ] ;
68
115
}
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 ];
77
116
}
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
+
79
131
80
132
int main () {
81
133
stdio_init_all ();
@@ -87,7 +139,7 @@ int main() {
87
139
printf ("Hello, MPU6050! Reading raw data from registers...\n" );
88
140
89
141
// 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
91
143
gpio_set_function (PICO_DEFAULT_I2C_SDA_PIN , GPIO_FUNC_I2C );
92
144
gpio_set_function (PICO_DEFAULT_I2C_SCL_PIN , GPIO_FUNC_I2C );
93
145
gpio_pull_up (PICO_DEFAULT_I2C_SDA_PIN );
@@ -96,19 +148,30 @@ int main() {
96
148
bi_decl (bi_2pins_with_func (PICO_DEFAULT_I2C_SDA_PIN , PICO_DEFAULT_I2C_SCL_PIN , GPIO_FUNC_I2C ));
97
149
98
150
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 );
99
155
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 ];
101
158
102
159
while (1 ) {
103
- mpu6050_read_raw (acceleration , gyro , & temp );
160
+ mpu6050_read_raw (accel_raw , gyro_raw , & temp_raw );
161
+ //TODO time read function
104
162
105
163
// These are the raw numbers from the chip, so will need tweaking to be really useful.
106
164
// 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 ]);
109
167
// Temperature is simple so use the datasheet calculation to get deg C.
110
168
// 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 ]);
112
175
113
176
sleep_ms (100 );
114
177
}
0 commit comments