-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathnrf_drv_mpu_twi.c
233 lines (174 loc) · 6.43 KB
/
nrf_drv_mpu_twi.c
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
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
/*
* The library is not extensively tested and only
* meant as a simple explanation and for inspiration.
* NO WARRANTY of ANY KIND is provided.
*/
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "nrf_drv_twi.h"
#include "nrf_drv_mpu.h"
#include "app_util_platform.h"
#include "nrf_gpio.h"
/* Pins to connect MPU. Pinout is different for nRF51 DK and nRF52 DK
* and therefore I have added a conditional statement defining different pins
* for each board. This is only for my own convenience.
*/
#if defined(BOARD_CUSTOM)
#define MPU_TWI_SCL_PIN 13
#define MPU_TWI_SDA_PIN 12
#else
#define MPU_TWI_SCL_PIN 1
#define MPU_TWI_SDA_PIN 2
#endif
#define MPU_TWI_BUFFER_SIZE 14 // 14 byte buffers will suffice to read acceleromter, gyroscope and temperature data in one transmission.
#define MPU_TWI_TIMEOUT 10000
#define MPU_ADDRESS 0x68
#define MPU_AK89XX_MAGN_ADDRESS 0x0C
static const nrf_drv_twi_t m_twi_instance = NRF_DRV_TWI_INSTANCE(0);
volatile static bool twi_tx_done = false;
volatile static bool twi_rx_done = false;
uint8_t twi_tx_buffer[MPU_TWI_BUFFER_SIZE];
static void nrf_drv_mpu_twi_event_handler(nrf_drv_twi_evt_t const * p_event, void * p_context)
{
switch(p_event->type)
{
case NRF_DRV_TWI_EVT_DONE:
switch(p_event->xfer_desc.type)
{
case NRF_DRV_TWI_XFER_TX:
twi_tx_done = true;
break;
case NRF_DRV_TWI_XFER_TXTX:
twi_tx_done = true;
break;
case NRF_DRV_TWI_XFER_RX:
twi_rx_done = true;
break;
case NRF_DRV_TWI_XFER_TXRX:
twi_rx_done = true;
break;
default:
break;
}
break;
case NRF_DRV_TWI_EVT_ADDRESS_NACK:
break;
case NRF_DRV_TWI_EVT_DATA_NACK:
break;
default:
break;
}
}
/**
* @brief TWI initialization.
* Just the usual way. Nothing special here
*/
uint32_t nrf_drv_mpu_init(void)
{
uint32_t err_code;
const nrf_drv_twi_config_t twi_mpu_config = {
.scl = MPU_TWI_SCL_PIN,
.sda = MPU_TWI_SDA_PIN,
.frequency = NRF_TWI_FREQ_400K,
.interrupt_priority = APP_IRQ_PRIORITY_HIGHEST
};
err_code = nrf_drv_twi_init(&m_twi_instance, &twi_mpu_config, nrf_drv_mpu_twi_event_handler, NULL);
if(err_code != NRF_SUCCESS && err_code != NRF_ERROR_INVALID_STATE)
{
return err_code;
}
nrf_drv_twi_enable(&m_twi_instance);
return NRF_SUCCESS;
}
// The TWI driver is not able to do two transmits without repeating the ADDRESS + Write bit byte
// Hence we need to merge the MPU register address with the buffer and then transmit all as one transmission
static void merge_register_and_data(uint8_t * new_buffer, uint8_t reg, uint8_t * p_data, uint32_t length)
{
new_buffer[0] = reg;
memcpy((new_buffer + 1), p_data, length);
}
uint32_t nrf_drv_mpu_write_registers(uint8_t reg, uint8_t * p_data, uint32_t length)
{
// This burst write function is not optimal and needs improvement.
// The new SDK 11 TWI driver is not able to do two transmits without repeating the ADDRESS + Write bit byte
uint32_t err_code;
uint32_t timeout = MPU_TWI_TIMEOUT;
// Merging MPU register address and p_data into one buffer.
merge_register_and_data(twi_tx_buffer, reg, p_data, length);
// Setting up transfer
nrf_drv_twi_xfer_desc_t xfer_desc;
xfer_desc.address = MPU_ADDRESS;
xfer_desc.type = NRF_DRV_TWI_XFER_TX;
xfer_desc.primary_length = length + 1;
xfer_desc.p_primary_buf = twi_tx_buffer;
// Transferring
err_code = nrf_drv_twi_xfer(&m_twi_instance, &xfer_desc, 0);
while((!twi_tx_done) && --timeout);
if(!timeout) return NRF_ERROR_TIMEOUT;
twi_tx_done = false;
return err_code;
}
uint32_t nrf_drv_mpu_write_single_register(uint8_t reg, uint8_t data)
{
uint32_t err_code;
uint32_t timeout = MPU_TWI_TIMEOUT;
uint8_t packet[2] = {reg, data};
err_code = nrf_drv_twi_tx(&m_twi_instance, MPU_ADDRESS, packet, 2, false);
if(err_code != NRF_SUCCESS) return err_code;
while((!twi_tx_done) && --timeout);
if(!timeout) return NRF_ERROR_TIMEOUT;
twi_tx_done = false;
return err_code;
}
uint32_t nrf_drv_mpu_read_registers(uint8_t reg, uint8_t * p_data, uint32_t length)
{
uint32_t err_code;
uint32_t timeout = MPU_TWI_TIMEOUT;
err_code = nrf_drv_twi_tx(&m_twi_instance, MPU_ADDRESS, ®, 1, false);
if(err_code != NRF_SUCCESS) return err_code;
while((!twi_tx_done) && --timeout);
if(!timeout) return NRF_ERROR_TIMEOUT;
twi_tx_done = false;
err_code = nrf_drv_twi_rx(&m_twi_instance, MPU_ADDRESS, p_data, length);
if(err_code != NRF_SUCCESS) return err_code;
timeout = MPU_TWI_TIMEOUT;
while((!twi_rx_done) && --timeout);
if(!timeout) return NRF_ERROR_TIMEOUT;
twi_rx_done = false;
return err_code;
}
#if (defined(MPU9150) || defined(MPU9255)) && (TWI_COUNT >= 1) // Magnetometer only works with TWI so check if TWI is enabled
uint32_t nrf_drv_mpu_read_magnetometer_registers(uint8_t reg, uint8_t * p_data, uint32_t length)
{
uint32_t err_code;
uint32_t timeout = MPU_TWI_TIMEOUT;
err_code = nrf_drv_twi_tx(&m_twi_instance, MPU_AK89XX_MAGN_ADDRESS, ®, 1, false);
if(err_code != NRF_SUCCESS) return err_code;
while((!twi_tx_done) && --timeout);
if(!timeout) return NRF_ERROR_TIMEOUT;
twi_tx_done = false;
err_code = nrf_drv_twi_rx(&m_twi_instance, MPU_AK89XX_MAGN_ADDRESS, p_data, length);
if(err_code != NRF_SUCCESS) return err_code;
timeout = MPU_TWI_TIMEOUT;
while((!twi_rx_done) && --timeout);
if(!timeout) return NRF_ERROR_TIMEOUT;
twi_rx_done = false;
return err_code;
}
uint32_t nrf_drv_mpu_write_magnetometer_register(uint8_t reg, uint8_t data)
{
uint32_t err_code;
uint32_t timeout = MPU_TWI_TIMEOUT;
uint8_t packet[2] = {reg, data};
err_code = nrf_drv_twi_tx(&m_twi_instance, MPU_AK89XX_MAGN_ADDRESS, packet, 2, false);
if(err_code != NRF_SUCCESS) return err_code;
while((!twi_tx_done) && --timeout);
if(!timeout) return NRF_ERROR_TIMEOUT;
twi_tx_done = false;
return err_code;
}
#endif // (defined(MPU9150) || defined(MPU9255)) && (TWI_COUNT >= 1) // Magnetometer only works with TWI so check if TWI is enabled
/**
@}
*/