forked from robido/TytoProto3Multiwii
-
Notifications
You must be signed in to change notification settings - Fork 0
/
I2C.cpp
125 lines (110 loc) · 3.53 KB
/
I2C.cpp
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
//
//
//
#include "Arduino.h"
#include "config.h"
#include "def.h"
#include "types.h"
#include "MultiWii.h"
#include "Alarms.h"
#include "EEPROM.h"
#include "IMU.h"
#include "LCD.h"
#include "I2C.h"
uint8_t rawADC[6];
static uint32_t neutralizeTime = 0;
// ************************************************************************************************************
// I2C general functions
// ************************************************************************************************************
void waitTransmissionI2C();
void i2c_init(void) {
#if defined(INTERNAL_I2C_PULLUPS)
I2C_PULLUPS_ENABLE
#else
I2C_PULLUPS_DISABLE
#endif
TWSR = 0; // no prescaler => prescaler = 1
TWBR = ((F_CPU / 400000) - 16) / 2; // set the I2C clock rate to 400kHz
TWCR = 1<<TWEN; // enable twi module, no interrupt
}
void i2c_rep_start(uint8_t address) {
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN) ; // send REPEAT START condition
waitTransmissionI2C(); // wait until transmission completed
TWDR = address; // send device address
TWCR = (1<<TWINT) | (1<<TWEN);
waitTransmissionI2C(); // wail until transmission completed
}
void i2c_stop(void) {
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
// while(TWCR & (1<<TWSTO)); // <- can produce a blocking state with some WMP clones
}
void i2c_write(uint8_t data ) {
TWDR = data; // send data to the previously addressed device
TWCR = (1<<TWINT) | (1<<TWEN);
waitTransmissionI2C();
}
uint8_t i2c_read(uint8_t ack) {
TWCR = (1<<TWINT) | (1<<TWEN) | (ack? (1<<TWEA) : 0);
waitTransmissionI2C();
uint8_t r = TWDR;
if (!ack) i2c_stop();
return r;
}
uint8_t i2c_readAck() {
return i2c_read(1);
}
uint8_t i2c_readNak(void) {
return i2c_read(0);
}
void waitTransmissionI2C() {
uint16_t count = 255;
while (!(TWCR & (1<<TWINT))) {
count--;
if (count==0) { //we are in a blocking state => we don't insist
TWCR = 0; //and we force a reset on TWINT register
neutralizeTime = micros(); //we take a timestamp here to neutralize the value during a short delay
i2c_errors_count++;
break;
}
}
}
void i2c_read_reg_to_buf(uint8_t add, uint8_t reg, uint8_t *buf, uint8_t size) {
i2c_rep_start(add<<1); // I2C write direction
i2c_write(reg); // register selection
i2c_rep_start((add<<1) | 1); // I2C read direction
uint8_t *b = buf;
while (size--) {
/* acknowledge all but the final byte */
*b++ = i2c_read(size > 0);
}
}
/* transform a series of bytes from big endian to little
endian and vice versa. */
void swap_endianness(void *buf, size_t size) {
/* we swap in-place, so we only have to
* place _one_ element on a temporary tray
*/
uint8_t tray;
uint8_t *from;
uint8_t *to;
/* keep swapping until the pointers have assed each other */
for (from = (uint8_t*)buf, to = &from[size-1]; from < to; from++, to--) {
tray = *from;
*from = *to;
*to = tray;
}
}
void i2c_getSixRawADC(uint8_t add, uint8_t reg) {
i2c_read_reg_to_buf(add, reg, rawADC, 6);
}
void i2c_writeReg(uint8_t add, uint8_t reg, uint8_t val) {
i2c_rep_start(add<<1); // I2C write direction
i2c_write(reg); // register selection
i2c_write(val); // value to write in register
i2c_stop();
}
uint8_t i2c_readReg(uint8_t add, uint8_t reg) {
uint8_t val;
i2c_read_reg_to_buf(add, reg, &val, 1);
return val;
}