-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
bus.h
executable file
·276 lines (236 loc) · 11.5 KB
/
bus.h
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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
/*
* This file is part of INAV.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Alternatively, the contents of this file may be used under the terms
* of the GNU General Public License Version 3, as described below:
*
* This file is free software: you may copy, redistribute and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include "platform.h"
#include "drivers/resource.h"
#include "drivers/bus_i2c.h"
#include "drivers/bus_spi.h"
// FIXME: Hack until we rework SPI driver
#define BUS_SPI1 SPIDEV_1
#define BUS_SPI2 SPIDEV_2
#define BUS_SPI3 SPIDEV_3
#define BUS_SPI4 SPIDEV_4
#define BUS_I2C1 I2CDEV_1
#define BUS_I2C2 I2CDEV_2
#define BUS_I2C3 I2CDEV_3
#define BUS_I2C4 I2CDEV_4
#define BUS_I2C_EMULATED I2CINVALID
#define BUS_SCRATCHPAD_MEMORY_SIZE (20)
typedef enum {
BUS_SPEED_INITIALIZATION = 0,
BUS_SPEED_SLOW = 1,
BUS_SPEED_STANDARD = 2,
BUS_SPEED_FAST = 3,
BUS_SPEED_ULTRAFAST = 4
} busSpeed_e;
typedef enum {
BUSTYPE_ANY = 0,
BUSTYPE_NONE = 0,
BUSTYPE_I2C = 1,
BUSTYPE_SPI = 2
} busType_e;
/* Ultimately all hardware descriptors will go to target definition files.
* Driver code will merely query for it's HW descriptor and initialize it */
typedef enum {
DEVHW_NONE = 0,
/* Dedicated ACC chips */
DEVHW_BMA280,
DEVHW_ADXL345,
DEVHW_MMA8452,
DEVHW_LSM303DLHC,
/* Dedicated GYRO chips */
DEVHW_L3GD20,
DEVHW_L3G4200,
/* Combined ACC/GYRO chips */
DEVHW_MPU3050,
DEVHW_MPU6000,
DEVHW_MPU6050,
DEVHW_MPU6500,
DEVHW_BMI160,
DEVHW_ICM20689,
/* Combined ACC/GYRO/MAG chips */
DEVHW_MPU9250,
/* Barometer chips */
DEVHW_BMP085,
DEVHW_BMP280,
DEVHW_MS5611,
DEVHW_MS5607,
DEVHW_LPS25H,
/* Compass chips */
DEVHW_HMC5883,
DEVHW_AK8963,
DEVHW_AK8975,
DEVHW_IST8310,
DEVHW_IST8308,
DEVHW_QMC5883,
DEVHW_MAG3110,
DEVHW_LIS3MDL,
/* OSD chips */
DEVHW_MAX7456,
/* Rangefinder modules */
DEVHW_SRF10,
DEVHW_HCSR04_I2C, // DIY-style adapter
DEVHW_VL53L0X,
/* Other hardware */
DEVHW_MS4525, // Pitot meter
DEVHW_PCA9685, // PWM output device
DEVHW_M25P16, // SPI NOR flash
DEVHW_UG2864, // I2C OLED display
} devHardwareType_e;
typedef enum {
DEVFLAGS_NONE = 0,
DEVFLAGS_USE_RAW_REGISTERS = (1 << 0), // Don't manipulate MSB for R/W selection
} deviceFlags_e;
typedef struct busDeviceDescriptor_s {
void * devicePtr;
busType_e busType;
devHardwareType_e devHwType;
uint16_t flags;
uint8_t tag;
union {
#ifdef USE_SPI
struct {
SPIDevice spiBus;
ioTag_t csnPin;
} spi;
#endif
#ifdef USE_I2C
struct {
I2CDevice i2cBus;
uint8_t address;
} i2c;
#endif
} busdev;
ioTag_t irqPin;
} busDeviceDescriptor_t;
typedef struct busDevice_s {
const busDeviceDescriptor_t * descriptorPtr;
busType_e busType; // Copy of busType to avoid additional pointer dereferencing
uint32_t flags; // Copy of flags
union {
#ifdef USE_SPI
struct {
SPIDevice spiBus; // SPI bus ID
IO_t csnPin; // IO for CS# pin
} spi;
#endif
#ifdef USE_I2C
struct {
I2CDevice i2cBus; // I2C bus ID
uint8_t address; // I2C bus device address
} i2c;
#endif
} busdev;
IO_t irqPin; // Device IRQ pin. Bus system will only assign IO_t object to this var. Initialization is up to device driver
uint32_t scratchpad[BUS_SCRATCHPAD_MEMORY_SIZE / sizeof(uint32_t)]; // Memory where device driver can store persistent data. Zeroed out when initializing the device
// for the first time. Useful when once device is shared between several sensors
// (like MPU/ICM acc-gyro sensors)
} busDevice_t;
#ifdef __APPLE__
extern const busDeviceDescriptor_t __busdev_registry_start[] __asm("section$start$__DATA$__busdev_registry");
extern const busDeviceDescriptor_t __busdev_registry_end[] __asm("section$end$__DATA$__busdev_registry");
#define BUSDEV_REGISTER_ATTRIBUTES __attribute__ ((section("__DATA,__busdev_registry"), used, aligned(4)))
#else
extern const busDeviceDescriptor_t __busdev_registry_start[];
extern const busDeviceDescriptor_t __busdev_registry_end[];
#define BUSDEV_REGISTER_ATTRIBUTES __attribute__ ((section(".busdev_registry"), used, aligned(4)))
#endif
#define BUSDEV_REGISTER_SPI_F(_name, _devHw, _spiBus, _csnPin, _irqPin, _tag, _flags) \
extern const busDeviceDescriptor_t _name ## _registry; \
static busDevice_t _name ## _memory; \
const busDeviceDescriptor_t _name ## _registry BUSDEV_REGISTER_ATTRIBUTES = { \
.devicePtr = (void *) & _name ## _memory, \
.busType = BUSTYPE_SPI, \
.devHwType = _devHw, \
.flags = _flags, \
.tag = _tag, \
.busdev.spi = { \
.spiBus = _spiBus, \
.csnPin = IO_TAG(_csnPin) \
}, \
.irqPin = IO_TAG(_irqPin) \
}; \
struct _dummy \
/**/
#define BUSDEV_REGISTER_I2C_F(_name, _devHw, _i2cBus, _devAddr, _irqPin, _tag, _flags) \
extern const busDeviceDescriptor_t _name ## _registry; \
static busDevice_t _name ## _memory; \
const busDeviceDescriptor_t _name ## _registry BUSDEV_REGISTER_ATTRIBUTES = { \
.devicePtr = (void *) & _name ## _memory, \
.busType = BUSTYPE_I2C, \
.devHwType = _devHw, \
.flags = _flags, \
.tag = _tag, \
.busdev.i2c = { \
.i2cBus = _i2cBus, \
.address = _devAddr \
}, \
.irqPin = IO_TAG(_irqPin) \
}; \
struct _dummy \
/**/
#define BUSDEV_REGISTER_SPI(_name, _devHw, _spiBus, _csnPin, _irqPin, _flags) \
BUSDEV_REGISTER_SPI_F(_name, _devHw, _spiBus, _csnPin, _irqPin, 0, _flags)
#define BUSDEV_REGISTER_SPI_TAG(_name, _devHw, _spiBus, _csnPin, _irqPin, _tag, _flags) \
BUSDEV_REGISTER_SPI_F(_name, _devHw, _spiBus, _csnPin, _irqPin, _tag, _flags)
#define BUSDEV_REGISTER_I2C(_name, _devHw, _i2cBus, _devAddr, _irqPin, _flags) \
BUSDEV_REGISTER_I2C_F(_name, _devHw, _i2cBus, _devAddr, _irqPin, 0, _flags)
#define BUSDEV_REGISTER_I2C_TAG(_name, _devHw, _i2cBus, _devAddr, _irqPin, _tag, _flags) \
BUSDEV_REGISTER_I2C_F(_name, _devHw, _i2cBus, _devAddr, _irqPin, _tag, _flags)
// busTransfer and busTransferMultiple are supported only on full-duplex SPI bus
typedef struct busTransferDescriptor_s {
uint8_t * rxBuf;
const uint8_t * txBuf;
uint32_t length;
} busTransferDescriptor_t;
/* Internal abstraction function */
bool i2cBusWriteBuffer(const busDevice_t * dev, uint8_t reg, const uint8_t * data, uint8_t length);
bool i2cBusWriteRegister(const busDevice_t * dev, uint8_t reg, uint8_t data);
bool i2cBusReadBuffer(const busDevice_t * dev, uint8_t reg, uint8_t * data, uint8_t length);
bool i2cBusReadRegister(const busDevice_t * dev, uint8_t reg, uint8_t * data);
void spiBusSetSpeed(const busDevice_t * dev, busSpeed_e speed);
bool spiBusTransferMultiple(const busDevice_t * dev, busTransferDescriptor_t * dsc, int count);
bool spiBusWriteBuffer(const busDevice_t * dev, uint8_t reg, const uint8_t * data, uint8_t length);
bool spiBusWriteRegister(const busDevice_t * dev, uint8_t reg, uint8_t data);
bool spiBusReadBuffer(const busDevice_t * dev, uint8_t reg, uint8_t * data, uint8_t length);
bool spiBusReadRegister(const busDevice_t * dev, uint8_t reg, uint8_t * data);
/* Pre-initialize all known device descriptors to make sure hardware state is consistent and known
* Initialize bus hardware */
void busInit(void);
/* Finds a device in registry. First matching device is returned. Also performs the low-level initialization of the hardware (CS line for SPI) */
busDevice_t * busDeviceInit(busType_e bus, devHardwareType_e hw, uint8_t tag, resourceOwner_e owner);
busDevice_t * busDeviceOpen(busType_e bus, devHardwareType_e hw, uint8_t tag);
void busDeviceDeInit(busDevice_t * dev);
uint32_t busDeviceReadScratchpad(const busDevice_t * dev);
void busDeviceWriteScratchpad(busDevice_t * dev, uint32_t value);
void * busDeviceGetScratchpadMemory(const busDevice_t * dev);
void busSetSpeed(const busDevice_t * dev, busSpeed_e speed);
bool busWriteBuf(const busDevice_t * busdev, uint8_t reg, const uint8_t * data, uint8_t length);
bool busReadBuf(const busDevice_t * busdev, uint8_t reg, uint8_t * data, uint8_t length);
bool busRead(const busDevice_t * busdev, uint8_t reg, uint8_t * data);
bool busWrite(const busDevice_t * busdev, uint8_t reg, uint8_t data);
bool busTransfer(const busDevice_t * dev, uint8_t * rxBuf, const uint8_t * txBuf, int length);
bool busTransferMultiple(const busDevice_t * dev, busTransferDescriptor_t * buffers, int count);