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
|
#include "gfx.h"
#undef Red
#undef Green
#undef Blue
#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, uint16_t slaveAddr, uint8_t numBytes, uint32_t mode, uint32_t request)
{
uint32_t tmpreg = 0;
// Get the current CR2 register value
tmpreg = i2c->CR2;
// Clear tmpreg specific bits
tmpreg &= (uint32_t) ~((uint32_t) (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 |= (uint32_t) (((uint32_t) slaveAddr & I2C_CR2_SADD) | (((uint32_t) numBytes << 16) & I2C_CR2_NBYTES) | (uint32_t) mode | (uint32_t) 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 &= (uint32_t) ~((uint32_t) (I2C_CR2_SADD | I2C_CR2_HEAD10R | I2C_CR2_NBYTES | I2C_CR2_RELOAD | I2C_CR2_RD_WRN));
}
bool_t 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 FALSE;
}
// 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 TRUE;
}
void i2cSend(I2C_TypeDef* i2c, uint8_t slaveAddr, uint8_t* data, uint16_t 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, uint8_t slaveAddr, uint8_t data)
{
i2cSend(i2c, slaveAddr, &data, 1);
}
void i2cWriteReg(I2C_TypeDef* i2c, uint8_t slaveAddr, uint8_t regAddr, uint8_t value)
{
uint8_t txbuf[2];
txbuf[0] = regAddr;
txbuf[1] = value;
i2cSend(i2c, slaveAddr, txbuf, 2);
}
void i2cRead(I2C_TypeDef* i2c, uint8_t slaveAddr, uint8_t* data, uint16_t 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);
}
uint8_t i2cReadByte(I2C_TypeDef* i2c, uint8_t slaveAddr, uint8_t regAddr)
{
uint8_t ret = 0xAA;
i2cSend(i2c, slaveAddr, ®Addr, 1);
i2cRead(i2c, slaveAddr, &ret, 1);
return ret;
}
uint16_t i2cReadWord(I2C_TypeDef* i2c, uint8_t slaveAddr, uint8_t regAddr)
{
uint8_t ret[2] = { 0xAA, 0xAA };
i2cSend(i2c, slaveAddr, ®Addr, 1);
i2cRead(i2c, slaveAddr, ret, 2);
return (uint16_t)((ret[0] << 8) | (ret[1] & 0x00FF));
}
|