libopencm3
A free/libre/open-source firmware library for various ARM Cortex-M3 microcontrollers.
i2c_common_v2.c
Go to the documentation of this file.
1/** @addtogroup i2c_file I2C peripheral API
2 * @ingroup peripheral_apis
3 */
4
5/*
6 * This file is part of the libopencm3 project.
7 *
8 * This library is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this library. If not, see <http://www.gnu.org/licenses/>.
20 */
21
24
25/**@{*/
26
27/*---------------------------------------------------------------------------*/
28/** @brief I2C Peripheral Enable.
29 *
30 * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
31 */
32
33void i2c_peripheral_enable(uint32_t i2c)
34{
35 I2C_CR1(i2c) |= I2C_CR1_PE;
36}
37
38/*---------------------------------------------------------------------------*/
39/** @brief I2C Peripheral Disable.
40 *
41 * This must not be reset while in Master mode until a communication has
42 * finished. In Slave mode, the peripheral is disabled only after communication
43 * has ended.
44 *
45 * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
46 */
47
48void i2c_peripheral_disable(uint32_t i2c)
49{
50 I2C_CR1(i2c) &= ~I2C_CR1_PE;
51}
52
53/*---------------------------------------------------------------------------*/
54/** @brief I2C Send Start Condition.
55 *
56 * If in Master mode this will cause a restart condition to occur at the end of
57 * the current transmission. If in Slave mode, this will initiate a start
58 * condition when the current bus activity is completed.
59 *
60 * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
61 */
62
63void i2c_send_start(uint32_t i2c)
64{
65 I2C_CR2(i2c) |= I2C_CR2_START;
66}
67
68/*---------------------------------------------------------------------------*/
69/** @brief I2C Send Stop Condition.
70 *
71 * After the current byte transfer this will initiate a stop condition if in
72 * Master mode, or simply release the bus if in Slave mode.
73 *
74 * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
75 */
76
77void i2c_send_stop(uint32_t i2c)
78{
79 I2C_CR2(i2c) |= I2C_CR2_STOP;
80}
81
82/*---------------------------------------------------------------------------*/
83/** @brief I2C Clear Stop Flag.
84 *
85 * Clear the "Send Stop" flag in the I2C config register
86 *
87 * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
88 */
89void i2c_clear_stop(uint32_t i2c)
90{
91 I2C_ICR(i2c) |= I2C_ICR_STOPCF;
92}
93
94/*---------------------------------------------------------------------------*/
95/** @brief I2C Set the 7 bit Slave Address for the Peripheral.
96 *
97 * This sets an address for Slave mode operation, in 7 bit form.
98 *
99 * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
100 * @param[in] slave Unsigned int8. Slave address 0...127.
101 */
102
103void i2c_set_own_7bit_slave_address(uint32_t i2c, uint8_t slave)
104{
105 I2C_OAR1(i2c) = (uint16_t)(slave << 1);
106 I2C_OAR1(i2c) &= ~I2C_OAR1_OA1MODE;
107}
108
109/*---------------------------------------------------------------------------*/
110/** @brief I2C Set the 10 bit Slave Address for the Peripheral.
111 *
112 * This sets an address for Slave mode operation, in 10 bit form.
113 *
114 * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
115 * @param[in] slave Unsigned int16. Slave address 0...1023.
116 */
117
118void i2c_set_own_10bit_slave_address(uint32_t i2c, uint16_t slave)
119{
120 I2C_OAR1(i2c) = (uint16_t)(I2C_OAR1_OA1MODE | slave);
121}
122
123/*---------------------------------------------------------------------------*/
124/** @brief I2C Send Data.
125 *
126 * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
127 * @param[in] data Unsigned int8. Byte to send.
128 */
129
130void i2c_send_data(uint32_t i2c, uint8_t data)
131{
132 I2C_TXDR(i2c) = data;
133}
134
135/*---------------------------------------------------------------------------*/
136/** @brief I2C Get Data.
137 *
138 * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
139 */
140uint8_t i2c_get_data(uint32_t i2c)
141{
142 return I2C_RXDR(i2c) & 0xff;
143}
144
145void i2c_enable_analog_filter(uint32_t i2c)
146{
147 I2C_CR1(i2c) &= ~I2C_CR1_ANFOFF;
148}
149
151{
152 I2C_CR1(i2c) |= I2C_CR1_ANFOFF;
153}
154
155/**
156 * Set the I2C digital filter.
157 * These bits are used to configure the digital noise filter on SDA and
158 * SCL input. The digital filter will filter spikes with a length of up
159 * to dnf_setting * I2CCLK clocks
160 * @param i2c peripheral of interest
161 * @param dnf_setting 0 to disable, else 1..15 i2c clocks
162 */
163void i2c_set_digital_filter(uint32_t i2c, uint8_t dnf_setting)
164{
165 I2C_CR1(i2c) = (I2C_CR1(i2c) & ~(I2C_CR1_DNF_MASK << I2C_CR1_DNF_SHIFT)) |
166 (dnf_setting << I2C_CR1_DNF_SHIFT);
167}
168
169/* t_presc= (presc+1)*t_i2cclk */
170void i2c_set_prescaler(uint32_t i2c, uint8_t presc)
171{
172 I2C_TIMINGR(i2c) = (I2C_TIMINGR(i2c) & ~I2C_TIMINGR_PRESC_MASK) |
173 (presc << I2C_TIMINGR_PRESC_SHIFT);
174}
175
176void i2c_set_data_setup_time(uint32_t i2c, uint8_t s_time)
177{
178 I2C_TIMINGR(i2c) = (I2C_TIMINGR(i2c) & ~I2C_TIMINGR_SCLDEL_MASK) |
179 (s_time << I2C_TIMINGR_SCLDEL_SHIFT);
180}
181
182void i2c_set_data_hold_time(uint32_t i2c, uint8_t h_time)
183{
184 I2C_TIMINGR(i2c) = (I2C_TIMINGR(i2c) & ~I2C_TIMINGR_SDADEL_MASK) |
185 (h_time << I2C_TIMINGR_SDADEL_SHIFT);
186}
187
188void i2c_set_scl_high_period(uint32_t i2c, uint8_t period)
189{
190 I2C_TIMINGR(i2c) = (I2C_TIMINGR(i2c) & ~I2C_TIMINGR_SCLH_MASK) |
191 (period << I2C_TIMINGR_SCLH_SHIFT);
192}
193
194void i2c_set_scl_low_period(uint32_t i2c, uint8_t period)
195{
196 I2C_TIMINGR(i2c) = (I2C_TIMINGR(i2c) & ~I2C_TIMINGR_SCLL_MASK) |
197 (period << I2C_TIMINGR_SCLL_SHIFT);
198}
199
200void i2c_enable_stretching(uint32_t i2c)
201{
202 I2C_CR1(i2c) &= ~I2C_CR1_NOSTRETCH;
203}
204
205void i2c_disable_stretching(uint32_t i2c)
206{
208}
209
210void i2c_set_7bit_addr_mode(uint32_t i2c)
211{
212 I2C_CR2(i2c) &= ~I2C_CR2_ADD10;
213}
214
215void i2c_set_10bit_addr_mode(uint32_t i2c)
216{
217 I2C_CR2(i2c) |= I2C_CR2_ADD10;
218}
219
220void i2c_set_7bit_address(uint32_t i2c, uint8_t addr)
221{
222 I2C_CR2(i2c) = (I2C_CR2(i2c) & ~I2C_CR2_SADD_7BIT_MASK) |
223 ((addr & 0x7F) << I2C_CR2_SADD_7BIT_SHIFT);
224}
225
226void i2c_set_10bit_address(uint32_t i2c, uint16_t addr)
227{
228 I2C_CR2(i2c) = (I2C_CR2(i2c) & ~I2C_CR2_SADD_10BIT_MASK) |
229 ((addr & 0x3FF) << I2C_CR2_SADD_10BIT_SHIFT);
230}
231
233{
234 I2C_CR2(i2c) &= ~I2C_CR2_RD_WRN;
235}
236
238{
239 I2C_CR2(i2c) |= I2C_CR2_RD_WRN;
240}
241
242void i2c_set_bytes_to_transfer(uint32_t i2c, uint32_t n_bytes)
243{
244 I2C_CR2(i2c) = (I2C_CR2(i2c) & ~I2C_CR2_NBYTES_MASK) |
245 (n_bytes << I2C_CR2_NBYTES_SHIFT);
246}
247
248bool i2c_is_start(uint32_t i2c)
249{
250 return (I2C_CR2(i2c) & I2C_CR2_START);
251}
252
253void i2c_enable_autoend(uint32_t i2c)
254{
255 I2C_CR2(i2c) |= I2C_CR2_AUTOEND;
256}
257
258void i2c_disable_autoend(uint32_t i2c)
259{
260 I2C_CR2(i2c) &= ~I2C_CR2_AUTOEND;
261}
262
263bool i2c_nack(uint32_t i2c)
264{
265 return (I2C_ISR(i2c) & I2C_ISR_NACKF);
266}
267
268bool i2c_busy(uint32_t i2c)
269{
270 return (I2C_ISR(i2c) & I2C_ISR_BUSY);
271}
272
273bool i2c_transmit_int_status(uint32_t i2c)
274{
275 return (I2C_ISR(i2c) & I2C_ISR_TXIS);
276}
277
278bool i2c_transfer_complete(uint32_t i2c)
279{
280 return (I2C_ISR(i2c) & I2C_ISR_TC);
281}
282
283bool i2c_received_data(uint32_t i2c)
284{
285 return (I2C_ISR(i2c) & I2C_ISR_RXNE);
286}
287
288
289/*---------------------------------------------------------------------------*/
290/** @brief I2C Enable Interrupt
291 *
292 * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
293 * @param[in] interrupt Unsigned int32. Interrupt to enable.
294 */
295void i2c_enable_interrupt(uint32_t i2c, uint32_t interrupt)
296{
297 I2C_CR1(i2c) |= interrupt;
298}
299
300/*---------------------------------------------------------------------------*/
301/** @brief I2C Disable Interrupt
302 *
303 * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
304 * @param[in] interrupt Unsigned int32. Interrupt to disable.
305 */
306void i2c_disable_interrupt(uint32_t i2c, uint32_t interrupt)
307{
308 I2C_CR1(i2c) &= ~interrupt;
309}
310
311/*---------------------------------------------------------------------------*/
312/** @brief I2C Enable reception DMA
313 *
314 * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
315 */
316void i2c_enable_rxdma(uint32_t i2c)
317{
318 I2C_CR1(i2c) |= I2C_CR1_RXDMAEN;
319}
320
321/*---------------------------------------------------------------------------*/
322/** @brief I2C Disable reception DMA
323 *
324 * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
325 */
326void i2c_disable_rxdma(uint32_t i2c)
327{
328 I2C_CR1(i2c) &= ~I2C_CR1_RXDMAEN;
329}
330
331/*---------------------------------------------------------------------------*/
332/** @brief I2C Enable transmission DMA
333 *
334 * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
335 */
336void i2c_enable_txdma(uint32_t i2c)
337{
338 I2C_CR1(i2c) |= I2C_CR1_TXDMAEN;
339}
340
341/*---------------------------------------------------------------------------*/
342/** @brief I2C Disable transmission DMA
343 *
344 * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
345 */
346void i2c_disable_txdma(uint32_t i2c)
347{
348 I2C_CR1(i2c) &= ~I2C_CR1_TXDMAEN;
349}
350
351/**
352 * Run a write/read transaction to a given 7bit i2c address
353 * If both write & read are provided, the read will use repeated start.
354 * Both write and read are optional
355 * @param i2c peripheral of choice, eg I2C1
356 * @param addr 7 bit i2c device address
357 * @param w buffer of data to write
358 * @param wn length of w
359 * @param r destination buffer to read into
360 * @param rn number of bytes to read (r should be at least this long)
361 */
362void i2c_transfer7(uint32_t i2c, uint8_t addr, const uint8_t *w, size_t wn, uint8_t *r, size_t rn)
363{
364 /* waiting for busy is unnecessary. read the RM */
365 if (wn) {
366 i2c_set_7bit_address(i2c, addr);
369 if (rn) {
371 } else {
373 }
374 i2c_send_start(i2c);
375
376 while (wn--) {
377 bool wait = true;
378 while (wait) {
379 if (i2c_transmit_int_status(i2c)) {
380 wait = false;
381 }
382 while (i2c_nack(i2c)); /* FIXME Some error */
383 }
384 i2c_send_data(i2c, *w++);
385 }
386 /* not entirely sure this is really necessary.
387 * RM implies it will stall until it can write out the later bits
388 */
389 if (rn) {
390 while (!i2c_transfer_complete(i2c));
391 }
392 }
393
394 if (rn) {
395 /* Setting transfer properties */
396 i2c_set_7bit_address(i2c, addr);
399 /* start transfer */
400 i2c_send_start(i2c);
401 /* important to do it afterwards to do a proper repeated start! */
403
404 for (size_t i = 0; i < rn; i++) {
405 while (i2c_received_data(i2c) == 0);
406 r[i] = i2c_get_data(i2c);
407 }
408 }
409}
410
411
412/**
413 * Set the i2c communication speed.
414 * NOTE: 1MHz mode not yet implemented!
415 * Min clock speed: 8MHz for FM, 2Mhz for SM,
416 * @param i2c peripheral, eg I2C1
417 * @param speed one of the listed speed modes @ref i2c_speeds
418 * @param clock_megahz i2c peripheral clock speed in MHz. Usually, rcc_apb1_frequency / 1e6
419 */
420void i2c_set_speed(uint32_t i2c, enum i2c_speeds speed, uint32_t clock_megahz)
421{
422 int prescaler;
423 switch(speed) {
424 case i2c_speed_fmp_1m:
425 /* FIXME - add support for this mode! */
426 break;
428 /* target 8Mhz input, so tpresc = 125ns */
429 prescaler = clock_megahz / 8 - 1;
430 i2c_set_prescaler(i2c, prescaler);
431 i2c_set_scl_low_period(i2c, 10-1); // 1250ns
432 i2c_set_scl_high_period(i2c, 4-1); // 500ns
433 i2c_set_data_hold_time(i2c, 3); // 375ns
434 i2c_set_data_setup_time(i2c, 4-1); // 500ns
435 break;
436 default:
437 /* fall back to standard mode */
439 /* target 4Mhz input, so tpresc = 250ns */
440 prescaler = (clock_megahz / 4) - 1;
441 i2c_set_prescaler(i2c, prescaler);
442 i2c_set_scl_low_period(i2c, 20-1); // 5usecs
443 i2c_set_scl_high_period(i2c, 16-1); // 4usecs
444 i2c_set_data_hold_time(i2c, 2); // 0.5usecs
445 i2c_set_data_setup_time(i2c, 5-1); // 1.25usecs
446 break;
447 }
448}
449
450/**@}*/
#define I2C_CR1_DNF_MASK
DNF[3:0]: Digital noise filter.
#define I2C_ISR(i2c_base)
Definition: i2c_common_v2.h:87
#define I2C_ISR_RXNE
#define I2C_ISR_BUSY
#define I2C_CR1_NOSTRETCH
#define I2C_CR1_TXDMAEN
#define I2C_TIMINGR_SCLL_SHIFT
#define I2C_CR1(i2c_base)
Definition: i2c_common_v2.h:57
#define I2C_CR2_RD_WRN
#define I2C_CR2_STOP
#define I2C_TIMINGR_SDADEL_SHIFT
#define I2C_RXDR(i2c_base)
#define I2C_CR1_ANFOFF
#define I2C_CR2_ADD10
#define I2C_TIMINGR_PRESC_SHIFT
#define I2C_CR2_START
#define I2C_OAR1_OA1MODE
#define I2C_CR1_DNF_SHIFT
#define I2C_CR2_NBYTES_SHIFT
#define I2C_ICR(i2c_base)
Definition: i2c_common_v2.h:92
#define I2C_CR2_SADD_10BIT_SHIFT
#define I2C_CR1_RXDMAEN
#define I2C_CR1_PE
i2c_speeds
I2C speed modes.
#define I2C_OAR1(i2c_base)
Definition: i2c_common_v2.h:67
#define I2C_ISR_TXIS
#define I2C_CR2_AUTOEND
#define I2C_ICR_STOPCF
#define I2C_CR2_SADD_7BIT_SHIFT
#define I2C_ISR_TC
#define I2C_TIMINGR_SCLH_SHIFT
#define I2C_ISR_NACKF
#define I2C_TIMINGR(i2c_base)
Definition: i2c_common_v2.h:77
#define I2C_TIMINGR_SCLDEL_SHIFT
#define I2C_CR2(i2c_base)
Definition: i2c_common_v2.h:62
#define I2C_TXDR(i2c_base)
@ i2c_speed_fmp_1m
@ i2c_speed_fm_400k
@ i2c_speed_sm_100k
void i2c_disable_interrupt(uint32_t i2c, uint32_t interrupt)
I2C Disable Interrupt.
void i2c_set_7bit_address(uint32_t i2c, uint8_t addr)
void i2c_enable_analog_filter(uint32_t i2c)
void i2c_enable_interrupt(uint32_t i2c, uint32_t interrupt)
I2C Enable Interrupt.
void i2c_set_digital_filter(uint32_t i2c, uint8_t dnf_setting)
Set the I2C digital filter.
void i2c_set_10bit_addr_mode(uint32_t i2c)
void i2c_set_7bit_addr_mode(uint32_t i2c)
void i2c_disable_analog_filter(uint32_t i2c)
void i2c_set_10bit_address(uint32_t i2c, uint16_t addr)
void i2c_set_prescaler(uint32_t i2c, uint8_t presc)
void i2c_set_data_setup_time(uint32_t i2c, uint8_t s_time)
void i2c_disable_stretching(uint32_t i2c)
void i2c_send_start(uint32_t i2c)
I2C Send Start Condition.
Definition: i2c_common_v2.c:63
void i2c_peripheral_disable(uint32_t i2c)
I2C Peripheral Disable.
Definition: i2c_common_v2.c:48
void i2c_set_bytes_to_transfer(uint32_t i2c, uint32_t n_bytes)
bool i2c_is_start(uint32_t i2c)
void i2c_set_write_transfer_dir(uint32_t i2c)
bool i2c_received_data(uint32_t i2c)
void i2c_set_own_7bit_slave_address(uint32_t i2c, uint8_t slave)
I2C Set the 7 bit Slave Address for the Peripheral.
void i2c_set_scl_high_period(uint32_t i2c, uint8_t period)
void i2c_disable_autoend(uint32_t i2c)
void i2c_send_stop(uint32_t i2c)
I2C Send Stop Condition.
Definition: i2c_common_v2.c:77
void i2c_peripheral_enable(uint32_t i2c)
I2C Peripheral Enable.
Definition: i2c_common_v2.c:33
void i2c_enable_rxdma(uint32_t i2c)
I2C Enable reception DMA.
void i2c_set_data_hold_time(uint32_t i2c, uint8_t h_time)
void i2c_set_own_10bit_slave_address(uint32_t i2c, uint16_t slave)
I2C Set the 10 bit Slave Address for the Peripheral.
bool i2c_transmit_int_status(uint32_t i2c)
void i2c_disable_rxdma(uint32_t i2c)
I2C Disable reception DMA.
void i2c_enable_autoend(uint32_t i2c)
void i2c_enable_stretching(uint32_t i2c)
void i2c_set_read_transfer_dir(uint32_t i2c)
void i2c_send_data(uint32_t i2c, uint8_t data)
I2C Send Data.
uint8_t i2c_get_data(uint32_t i2c)
I2C Get Data.
void i2c_clear_stop(uint32_t i2c)
I2C Clear Stop Flag.
Definition: i2c_common_v2.c:89
bool i2c_busy(uint32_t i2c)
void i2c_set_scl_low_period(uint32_t i2c, uint8_t period)
void i2c_disable_txdma(uint32_t i2c)
I2C Disable transmission DMA.
void i2c_enable_txdma(uint32_t i2c)
I2C Enable transmission DMA.
bool i2c_transfer_complete(uint32_t i2c)
void i2c_transfer7(uint32_t i2c, uint8_t addr, const uint8_t *w, size_t wn, uint8_t *r, size_t rn)
Run a write/read transaction to a given 7bit i2c address If both write & read are provided,...
bool i2c_nack(uint32_t i2c)
void i2c_set_speed(uint32_t i2c, enum i2c_speeds speed, uint32_t clock_megahz)
Set the i2c communication speed.