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
|
#include "gfx.h"
#if GFX_COMPAT_V2 && GFX_COMPAT_OLDCOLORS
#undef Red
#undef Green
#undef Blue
#endif
#include "stm32f7_i2c.h"
/*
* The CR2 register needs atomic access. Hence always use this function to setup a transfer configuration.
*/
static void _i2cConfigTransfer(I2C_TypeDef* i2c, gU16 slaveAddr, gU8 numBytes, gU32 mode, gU32 request)
{
gU32 tmpreg = 0;
// Get the current CR2 register value
tmpreg = i2c->CR2;
// Clear tmpreg specific bits
tmpreg &= (gU32) ~((gU32) (I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD | I2C_CR2_AUTOEND | I2C_CR2_RD_WRN | I2C_CR2_START | I2C_CR2_STOP));
// update tmpreg
tmpreg |= (gU32) (((gU32) slaveAddr & I2C_CR2_SADD) | (((gU32) numBytes << 16) & I2C_CR2_NBYTES) | (gU32) mode | (gU32) request);
// Update the actual CR2 contents
i2c->CR2 = tmpreg;
}
/*
* According to the STM32Cube HAL the CR2 register needs to be reset after each transaction.
*/
static void _i2cResetCr2(I2C_TypeDef* i2c)
{
i2c->CR2 &= (gU32) ~((gU32) (I2C_CR2_SADD | I2C_CR2_HEAD10R | I2C_CR2_NBYTES | I2C_CR2_RELOAD | I2C_CR2_RD_WRN));
}
gBool i2cInit(I2C_TypeDef* i2c)
{
// Enable I2Cx peripheral clock.
// Select APB1 as clock source
if (i2c == I2C1) {
RCC->DCKCFGR2 &= ~RCC_DCKCFGR2_I2C1SEL;
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
} else if (i2c == I2C2) {
RCC->DCKCFGR2 &= ~RCC_DCKCFGR2_I2C2SEL;
RCC->APB1ENR |= RCC_APB1ENR_I2C2EN;
} else if (i2c == I2C3) {
RCC->DCKCFGR2 &= ~RCC_DCKCFGR2_I2C3SEL;
RCC->APB1ENR |= RCC_APB1ENR_I2C3EN;
} else if (i2c == I2C4) {
RCC->DCKCFGR2 &= ~RCC_DCKCFGR2_I2C4SEL;
RCC->APB1ENR |= RCC_APB1ENR_I2C4EN;
} else {
return gFalse;
}
// Disable the I2Cx peripheral
i2c->CR1 &= ~I2C_CR1_PE;
while (i2c->CR1 & I2C_CR1_PE);
// Set timings. Asuming I2CCLK is 50 MHz (APB1 clock source)
i2c->TIMINGR = 0x40912732; // Discovery BSP code from ST examples
// Use 7-bit addresses
i2c->CR2 &=~ I2C_CR2_ADD10;
// Enable auto-end mode
i2c->CR2 |= I2C_CR2_AUTOEND;
// Disable the analog filter
i2c->CR1 |= I2C_CR1_ANFOFF;
// Disable NOSTRETCH
i2c->CR1 |= I2C_CR1_NOSTRETCH;
// Enable the I2Cx peripheral
i2c->CR1 |= I2C_CR1_PE;
return gTrue;
}
void i2cSend(I2C_TypeDef* i2c, gU8 slaveAddr, gU8* data, gU16 length)
{
// We are currently not able to send more than 255 bytes at once
if (length > 255) {
return;
}
// Setup the configuration
_i2cConfigTransfer(i2c, slaveAddr, length, (!I2C_CR2_RD_WRN) | I2C_CR2_AUTOEND, I2C_CR2_START);
// Transmit the whole buffer
while (length > 0) {
while (!(i2c->ISR & I2C_ISR_TXIS));
i2c->TXDR = *data++;
length--;
}
// Wait until the transfer is complete
while (!(i2c->ISR & I2C_ISR_TXE));
// Wait until the stop condition was automagically sent
while (!(i2c->ISR & I2C_ISR_STOPF));
// Reset the STOP bit
i2c->ISR &= ~I2C_ISR_STOPF;
// Reset the CR2 register
_i2cResetCr2(i2c);
}
void i2cSendByte(I2C_TypeDef* i2c, gU8 slaveAddr, gU8 data)
{
i2cSend(i2c, slaveAddr, &data, 1);
}
void i2cWriteReg(I2C_TypeDef* i2c, gU8 slaveAddr, gU8 regAddr, gU8 value)
{
gU8 txbuf[2];
txbuf[0] = regAddr;
txbuf[1] = value;
i2cSend(i2c, slaveAddr, txbuf, 2);
}
void i2cRead(I2C_TypeDef* i2c, gU8 slaveAddr, gU8* data, gU16 length)
{
int i;
// We are currently not able to read more than 255 bytes at once
if (length > 255) {
return;
}
// Setup the configuration
_i2cConfigTransfer(i2c, slaveAddr, length, I2C_CR2_RD_WRN | I2C_CR2_AUTOEND, I2C_CR2_START);
// Transmit the whole buffer
for (i = 0; i < length; i++) {
while (!(i2c->ISR & I2C_ISR_RXNE));
data[i] = i2c->RXDR;
}
// Wait until the stop condition was automagically sent
while (!(i2c->ISR & I2C_ISR_STOPF));
// Reset the STOP bit
i2c->ISR &= ~I2C_ISR_STOPF;
// Reset the CR2 register
_i2cResetCr2(i2c);
}
gU8 i2cReadByte(I2C_TypeDef* i2c, gU8 slaveAddr, gU8 regAddr)
{
gU8 ret = 0xAA;
i2cSend(i2c, slaveAddr, ®Addr, 1);
i2cRead(i2c, slaveAddr, &ret, 1);
return ret;
}
gU16 i2cReadWord(I2C_TypeDef* i2c, gU8 slaveAddr, gU8 regAddr)
{
gU8 ret[2] = { 0xAA, 0xAA };
i2cSend(i2c, slaveAddr, ®Addr, 1);
i2cRead(i2c, slaveAddr, ret, 2);
return (gU16)((ret[0] << 8) | (ret[1] & 0x00FF));
}
|