This repository has been archived by the owner on Jul 4, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
test_twi0_mpu6050.ino
199 lines (168 loc) · 6.45 KB
/
test_twi0_mpu6050.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
#define F_CPU 16000000
#include <math.h>
#define _PORTA (*(volatile unsigned char*) 0x0400)
#define _PORTA_DIR (*(volatile unsigned char*) (0x0400 + 0x00))
#define _PORTA_OUT (*(volatile unsigned char*) (0x0400 + 0x04))
#define _PORTC (*(volatile unsigned char*) 0x0440)
#define _PORTC_DIR (*(volatile unsigned char*) (0x0440 + 0x00))
#define _PORTC_OUT (*(volatile unsigned char*) (0x0440 + 0x04))
#define _PORTC_PIN2CTRL (*(volatile unsigned char*) (0x0440 + 0x12))
#define _PORTC_PIN2CTRL_PULLUPEN_bm ((unsigned char) 0b00001000)
#define _PORTC_PIN3CTRL (*(volatile unsigned char*) (0x0440 + 0x13))
#define _PORTC_PIN3CTRL_PULLUPEN_bm ((unsigned char) 0b00001000)
#define _PORTF (*(volatile unsigned char*) 0x04A0)
#define _PORTF_DIR (*(volatile unsigned char*) (0x04A0 + 0x00))
#define _PORTF_OUT (*(volatile unsigned char*) (0x04A0 + 0x04))
#define _PORTMUX (*(volatile unsigned char*) 0x05E0)
#define _PORTMUX_TWISPIROUTEA (*(volatile unsigned char*) (0x05E0 + 0x03))
#define _PORTMUX_TWI0_ALT2_bm ((unsigned char) 0b00100000)
#define _PORTMUX_TCBROUTEA (*(volatile unsigned char*) (0x05E0 + 0x05))
#define _PORTMUX_TCB1_ALT1_gc ((unsigned char) 0b00000010)
#define _PORTMUX_TCB0_ALT1_gc ((unsigned char) 0b00000001)
#define _TWI0 (*(volatile unsigned char*) 0x08A0)
#define _TWI0_MCTRLA (*(volatile unsigned char*) (0x08A0 + 0x03))
#define _TWI_ENABLE_bm ((unsigned char) 0b00000001)
#define _TWI0_MCTRLB (*(volatile unsigned char*) (0x08A0 + 0x04))
#define _TWI_ACKACT_NACK_gc ((unsigned char) 0b00000100)
#define _TWI_MCMD_RECVTRANS_gc ((unsigned char) 0b00000010)
#define _TWI_MCMD_STOP_gc ((unsigned char) 0b00000011)
#define _TWI0_MSTATUS (*(volatile unsigned char*) (0x08A0 + 0x05))
#define _TWI_RIF_bm ((unsigned char) 0b10000000)
#define _TWI_WIF_bm ((unsigned char) 0b01000000)
#define _TWI_RXACK_bm ((unsigned char) 0b00010000)
#define _TWI_ARBLOST_bm ((unsigned char) 0b00001000)
#define _TWI_BUSERR_bm ((unsigned char) 0b00000100)
#define _TWI_BUSSTATE_IDLE_gc ((unsigned char) 0b00000001)
#define _TWI0_MBAUD (*(volatile unsigned char*) (0x08A0 + 0x06))
#define _TWI0_MADDR (*(volatile unsigned char*) (0x08A0 + 0x07))
#define _TWI0_MDATA (*(volatile unsigned char*) (0x08A0 + 0x08))
#define _TWI_READ true
#define _TWI_WRITE false
#define MPU6050 0x68
#define MPU6050_ACCEL_XOUT_H 0x3b
#define MPU6050_PWR_MGMT_1 0x6b
#define MPU6050_CLOCK_PLL_XGYRO_bm 0b00000001
#define PI 3.141592
#define ALPHA 0.6
#define DT 0.2534
void _twi_init();
bool _twi_start(unsigned char device, bool read);
void _twi_stop();
bool _twi_read(unsigned char* data, bool last);
bool _twi_write(unsigned char data);
void mpu6050_init();
void mpu6050_fetch(short* raw_ax, short* raw_ay, short* raw_az, short* raw_gx, short* raw_gy, short* raw_gz);
short mpu6050_offsets[6];
float angle_gx = 0, angle_x = 0;
void setup() {
mpu6050_init();
Serial1.begin(9600);
}
void loop() {
// fetch sensor data
short raw_ax, raw_ay, raw_az, raw_gx, raw_gy, raw_gz;
mpu6050_fetch(&raw_ax, &raw_ay, &raw_az, &raw_gx, &raw_gy, &raw_gz);
// calculate angle by accel data
float ax = raw_ax - mpu6050_offsets[0];
float ay = raw_ay - mpu6050_offsets[1];
float az = raw_az - mpu6050_offsets[2];
float angle_ax = atan(ay / sqrt(ax * ax + az * az)) * (180 / PI);
float gz = ((float) (raw_gx - mpu6050_offsets[3])) / 131;
// angle_gx += gz * DT;
// complementary filter
angle_x = ALPHA * (angle_x + gz * DT) + (1 - ALPHA) * angle_ax;
Serial1.println(angle_x);
}
void _twi_init() {
_PORTMUX_TWISPIROUTEA |= _PORTMUX_TWI0_ALT2_bm; // PC2: SDA, PC3: SCL
_PORTC_PIN2CTRL |= _PORTC_PIN2CTRL_PULLUPEN_bm; // PC2: PULLUP
_PORTC_PIN3CTRL |= _PORTC_PIN3CTRL_PULLUPEN_bm; // PC3: PULLUP
unsigned int frequency = 400000; // 400kHz
unsigned short t_rise = 300; // 300ns
unsigned int baud = (F_CPU / frequency - F_CPU / 1000 / 1000 * t_rise / 1000 - 10) / 2;
_TWI0_MBAUD = (unsigned char) baud;
_TWI0_MCTRLA = _TWI_ENABLE_bm;
_TWI0_MSTATUS = _TWI_BUSSTATE_IDLE_gc;
}
bool _twi_start(unsigned char device, bool read) {
_TWI0_MADDR = device << 1 | (read ? 1 : 0);
while (!(_TWI0_MSTATUS & (_TWI_WIF_bm | _TWI_RIF_bm)))
;
if (_TWI0_MSTATUS & _TWI_ARBLOST_bm) {
while (!(_TWI0_MSTATUS & _TWI_BUSSTATE_IDLE_gc))
;
return false;
}
if (_TWI0_MSTATUS & _TWI_RXACK_bm) {
_TWI0_MCTRLB |= _TWI_MCMD_STOP_gc;
while (!(_TWI0_MSTATUS & _TWI_BUSSTATE_IDLE_gc))
;
return false;
}
return true;
}
void _twi_stop() {
_TWI0_MCTRLB |= _TWI_MCMD_STOP_gc;
while (!(_TWI0_MSTATUS & _TWI_BUSSTATE_IDLE_gc))
;
}
bool _twi_read(unsigned char* data, bool last) {
while (!(_TWI0_MSTATUS & _TWI_RIF_bm))
;
*data = _TWI0_MDATA;
if (last) {
_TWI0_MCTRLB = _TWI_ACKACT_NACK_gc; // send NACK
} else {
_TWI0_MCTRLB = _TWI_MCMD_RECVTRANS_gc; // send ACK
}
return true;
}
bool _twi_write(unsigned char data) {
_TWI0_MCTRLB = _TWI_MCMD_RECVTRANS_gc;
_TWI0_MDATA = data;
while (!(_TWI0_MSTATUS & _TWI_WIF_bm))
;
if (_TWI0_MSTATUS & (_TWI_ARBLOST_bm | _TWI_BUSERR_bm)) {
return false; // ERROR
}
return !(_TWI0_MSTATUS & _TWI_RXACK_bm); // check ACK
}
void mpu6050_init() {
_twi_init();
_twi_start(MPU6050, _TWI_WRITE);
_twi_write(MPU6050_PWR_MGMT_1); // reg address
_twi_write(0); // reg value
_twi_stop();
// init sensor offset
short sum[6] = { 0 };
for (int i = 0; i < 10; i += 1) {
short raw_ax, raw_ay, raw_az, raw_gx, raw_gy, raw_gz;
mpu6050_fetch(&raw_ax, &raw_ay, &raw_az, &raw_gx, &raw_gy, &raw_gz);
sum[0] += raw_ax;
sum[1] += raw_ay;
sum[2] += raw_az;
sum[3] += raw_gx;
sum[4] += raw_gy;
sum[5] += raw_gz;
}
for (int i = 0; i < 6; i += 1) {
mpu6050_offsets[i] = sum[i] / 10;
}
}
void mpu6050_fetch(short* raw_ax, short* raw_ay, short* raw_az, short* raw_gx, short* raw_gy, short* raw_gz) {
unsigned char buf[14];
for (int i = 0; i < 14; i += 1) {
_twi_start(MPU6050, _TWI_WRITE);
_twi_write(MPU6050_ACCEL_XOUT_H + i); // reg address
_twi_stop();
_twi_start(MPU6050, _TWI_READ);
_twi_read(&buf[i], true); // reg value
_twi_stop();
}
*raw_ax = (buf[0] << 8) | buf[1];
*raw_ay = (buf[2] << 8) | buf[3];
*raw_az = (buf[4] << 8) | buf[5];
*raw_gx = (buf[8] << 8) | buf[9];
*raw_gy = (buf[10] << 8) | buf[11];
*raw_gz = (buf[12] << 8) | buf[13];
}