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"
17
18
inbuilt FIFO to make it more useful.
18
19
19
20
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.
24
23
25
24
Connections on Raspberry Pi Pico board, other boards may vary.
26
25
30
29
GND (pin 38) -> GND on MPU6050 board
31
30
*/
32
31
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 };
35
43
44
+
45
+ ////////////////////////////////////////////////////lower level functions for i2c
36
46
#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
42
51
}
43
52
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)
45
65
// For this particular device, we send the device the register we want to read
46
66
// first, then subsequently read from the device. The register is auto incrementing
47
67
// 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
+ }
48
75
49
- uint8_t buffer [6 ];
76
+ void mpu6050_setbusaddr (uint8_t addr ) {
77
+ bus_addr = addr ;
78
+ }
50
79
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
80
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
+ }
59
89
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
+ }
65
98
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 ) {
66
111
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 ] ;
68
113
}
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
114
}
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
+
79
129
80
130
int main () {
81
131
stdio_init_all ();
@@ -86,7 +136,7 @@ int main() {
86
136
printf ("Hello, MPU6050! Reading raw data from registers...\n" );
87
137
88
138
// 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
90
140
gpio_set_function (PICO_DEFAULT_I2C_SDA_PIN , GPIO_FUNC_I2C );
91
141
gpio_set_function (PICO_DEFAULT_I2C_SCL_PIN , GPIO_FUNC_I2C );
92
142
gpio_pull_up (PICO_DEFAULT_I2C_SDA_PIN );
@@ -95,19 +145,30 @@ int main() {
95
145
bi_decl (bi_2pins_with_func (PICO_DEFAULT_I2C_SDA_PIN , PICO_DEFAULT_I2C_SCL_PIN , GPIO_FUNC_I2C ));
96
146
97
147
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 );
98
152
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 ];
100
155
101
156
while (1 ) {
102
- mpu6050_read_raw (acceleration , gyro , & temp );
157
+ mpu6050_read_raw (accel_raw , gyro_raw , & temp_raw );
158
+ //TODO time read function
103
159
104
160
// These are the raw numbers from the chip, so will need tweaking to be really useful.
105
161
// 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 ]);
108
164
// Temperature is simple so use the datasheet calculation to get deg C.
109
165
// 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 ]);
111
172
112
173
sleep_ms (100 );
113
174
}
0 commit comments