-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathRafPe_STM32F407_I2C.c
217 lines (153 loc) · 5.39 KB
/
RafPe_STM32F407_I2C.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
/*
* Created on: 12 Feb 2017
* Author: rafpe
*/
#include "stm32f4xx.h"
#include "stm32f407xx.h"
#include "../inc/i2c.h"
uint8_t i2c_read(uint8_t address, uint8_t registry)
{
while(I2C1->SR2 & I2C_SR2_BUSY); // Wait for BUSY line
I2C1->CR1 |= I2C_CR1_START; // Generate START condition
while (!(I2C1->SR1 & I2C_SR1_SB)); // Wait for EV5
I2C1->DR = address<<1; // Write device address (W)
while (!(I2C1->SR1 & I2C_SR1_ADDR)); // Wait for EV6
(void)I2C1->SR2; // Read SR2
while (!(I2C1->SR1 & I2C_SR1_TXE)); // Wait for EV8_1
I2C1->DR = registry;
I2C1->CR1 |= I2C_CR1_STOP; // Generate STOP condition
I2C1->CR1 |= I2C_CR1_START; // Generate START condition
while (!(I2C1->SR1 & I2C_SR1_SB)); // Wait for EV5
I2C1->DR = (address << 1 ) | 1; // Write device address (R)
while (!(I2C1->SR1 & I2C_SR1_ADDR)); // Wait for EV6
I2C1->CR1 &= ~I2C_CR1_ACK; // No ACK
(void)I2C1->SR2; // Read SR2
while (!(I2C1->SR1 & I2C_SR1_RXNE)); // Wait for EV7_1
uint8_t value = (uint8_t)I2C1->DR; // Read value
I2C1->CR1 |= I2C_CR1_STOP; // Generate STOP condition
return value;
}
void i2c_setup_gpio(void)
{
GPIOB->MODER |= GPIO_MODER_MODER6_1 | // AF: PB6 => I2C1_SCL
GPIO_MODER_MODER7_1; // AF: PB7 => I2C1_SDA
GPIOB->OTYPER |= GPIO_OTYPER_OT_6|
GPIO_OTYPER_OT_7;
GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR6|
GPIO_OSPEEDER_OSPEEDR7;
GPIOB->PUPDR |= GPIO_PUPDR_PUPDR6_0|
GPIO_PUPDR_PUPDR7_0;
/*
* Alternate functions are configured in ARFL for PINS 0..7
* and in ARFH for PINS 8..15
* Based on DS we will select appropiate AF0..AF7
*/
GPIOB->AFR[0] |= ( 1 << 30 ) | ( 1 << 26); // P6/P7 => AF4
}
void i2c_init(void)
{
/*
* Reset I2C from lock state
*/
//I2C1->CR1 |= I2C_CR1_SWRST;
/*
* FREQ: Set frequencey based on APB1 clock
* when using HSI@16MHz this is 2MHz
*/
I2C1->CR2 &= ~(I2C_CR2_FREQ);
I2C1->CR2 |= 0b000010;
/*
* Depending on the frequency of said prescaler must be installed in
* accordance with the selected data rate.
* We choose the maximum, for standard mode - 100 kHz:
*
* 2MHz / 100 = 20 kHz;
*
*/
I2C1->CCR &= ~I2C_CCR_CCR;
I2C1->CCR |= 80;
/*
* clock period is equal to (1 / 2 MHz = 500 ns), therefore the maximum rise time:
* 1000 ns / 500 ns = 2 + 1 (plus one - a small margin) = 3
*
*/
I2C1->TRISE = 3;
/*
* Enable perifpherial at the END
*/
I2C1->CR1 = I2C_CR1_ACK|
I2C_CR1_PE; // PE : Peripherial enable
}
void i2c_read_many(uint8_t address, uint8_t registry, uint8_t * result, uint8_t length)
{
while(I2C1->SR2 & I2C_SR2_BUSY); // Wait for BUSY line
I2C1->CR1 |= I2C_CR1_START; // Generate START condition
while (!(I2C1->SR1 & I2C_SR1_SB)); // Wait for EV5
I2C1->DR = address<<1; // Write device address (W)
while (!(I2C1->SR1 & I2C_SR1_ADDR)); // Wait for EV6
(void)I2C1->SR2; // Read SR2
while (!(I2C1->SR1 & I2C_SR1_TXE)); // Wait for EV8_1
I2C1->DR = registry; // Write registry address
I2C1->CR1 |= I2C_CR1_STOP; // Generate STOP condition
I2C1->CR1 |= I2C_CR1_START; // Generate START condition
while (!(I2C1->SR1 & I2C_SR1_SB)); // Wait for EV5
I2C1->DR = (address << 1 ) | 1; // Write device address (R)
if(length==2)
{
while (!(I2C1->SR1 & I2C_SR1_ADDR)); // Wait for EV6
I2C1->CR1 &= ~I2C_CR1_ACK; // No ACK
I2C1->CR1 |= I2C_CR1_POS; // POS
(void)I2C1->SR2;
while (!(I2C1->SR1 & I2C_SR1_BTF)); // Wait for BTF
I2C1->CR1 |= I2C_CR1_STOP; // Generate STOP condition
*result++ = (uint8_t)I2C1->DR; // Read value
*result++ = (uint8_t)I2C1->DR; // Read value
}
if(length>2)
{
while (!(I2C1->SR1 & I2C_SR1_ADDR)); // Wait for EV6
(void)I2C1->SR2;
length--;
while(length--)
{
while (!(I2C1->SR1 & I2C_SR1_BTF)); // Wait for BTF
*result++ = (uint8_t)I2C1->DR; // Read value
if(length==1)
{
I2C1->CR1 &= ~I2C_CR1_ACK; // No ACK
I2C1->CR1 |= I2C_CR1_STOP; // Generate STOP condition
}
}
*result++ = (uint8_t)I2C1->DR; // Read value
}
}
void i2c_write(uint8_t address, uint8_t registry, uint8_t data)
{
I2C1->CR1 |= I2C_CR1_START; // Generate START condition
while (!(I2C1->SR1 & I2C_SR1_SB)); // Wait for EV5
I2C1->DR = address<<1; // Write device address (W)
while (!(I2C1->SR1 & I2C_SR1_ADDR)); // Wait for EV6
(void)I2C1->SR2; // Read SR2
while (!(I2C1->SR1 & I2C_SR1_TXE)); // Wait for EV8_1
I2C1->DR = registry; // Write registry address
while (!(I2C1->SR1 & I2C_SR1_BTF)); // Wait for BTF
I2C1->DR = data;
I2C1->CR1 |= I2C_CR1_STOP; // Generate STOP condition
}
void i2c_write_many(uint8_t address, uint8_t registry, uint8_t* buf, uint32_t length)
{
I2C1->CR1 |= I2C_CR1_START; // Generate START condition
while (!(I2C1->SR1 & I2C_SR1_SB)); // Wait for EV5
I2C1->DR = address<<1; // Write device address (W)
while (!(I2C1->SR1 & I2C_SR1_ADDR)); // Wait for EV6
(void) I2C1->SR2; // Read SR2
while (!(I2C1->SR1 & I2C_SR1_TXE)); // Wait for EV8_1
I2C1->DR = registry; // Write registry address
while (--length)
{
while (!(I2C1->SR1 & I2C_SR1_BTF)); // Wait for BTF
I2C1->DR = *buf++;
}
while (!(I2C1->SR1 & I2C_SR1_BTF)); // Wait for BTF
I2C1->CR1 |= I2C_CR1_STOP; // Generate STOP condition
}