source: rtems/c/src/lib/libbsp/arm/stm32f4/i2c/i2c.c @ 78c9fe8

5
Last change on this file since 78c9fe8 was 8a3e8c1, checked in by Sebastian Huber <sebastian.huber@…>, on Oct 10, 2014 at 8:39:09 AM

bsp/stm32f4: Fix warning

  • Property mode set to 100644
File size: 7.6 KB
Line 
1/*
2 * Copyright (c) 2013 Christian Mauderer.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Obere Lagerstr. 30
6 *  82178 Puchheim
7 *  Germany
8 *  <rtems@embedded-brains.de>
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.org/license/LICENSE.
13 */
14
15/* The I2C-module can not run with libi2c. The reason for this is, that libi2c
16 * needs a possibility to generate a stop condition separately. This controller
17 * wants to generate the condition automatically when sending or receiving data.
18 */
19
20#include <bsp.h>
21#include <bsp/i2c.h>
22#include <bsp/rcc.h>
23#include <bsp/irq.h>
24#include <bsp/irq-generic.h>
25#include <assert.h>
26
27#define RTEMS_STATUS_CHECKS_USE_PRINTK
28
29#include <rtems/status-checks.h>
30
31#define STM32F4_I2C_INITIAL_BITRATE 100000
32
33#define I2C_RW_BIT 0x1
34
35stm32f4_rcc_index i2c_rcc_index [] = {
36  STM32F4_RCC_I2C1,
37  STM32F4_RCC_I2C2,
38};
39
40static stm32f4_rcc_index i2c_get_rcc_index(stm32f4_i2c_bus_entry *e)
41{
42  return i2c_rcc_index [e->index];
43}
44
45static uint32_t i2c_get_pclk(stm32f4_i2c_bus_entry *e)
46{
47  return STM32F4_PCLK1;
48}
49
50rtems_status_code stm32f4_i2c_set_bitrate(
51  stm32f4_i2c_bus_entry *e,
52  uint32_t br
53)
54{
55  volatile stm32f4_i2c *regs = e->regs;
56  uint32_t ccr;
57  uint32_t trise;
58  uint32_t pclk = i2c_get_pclk(e);
59
60  /* Make sure, that the module is disabled */
61  if((regs->cr1 & STM32F4_I2C_CR1_PE) != 0)
62  {
63    return RTEMS_RESOURCE_IN_USE;
64  }
65
66  /* Configure clock control register and rise time register */
67  ccr = regs->ccr;
68  trise = regs->trise;
69
70  if(br <= 100000)
71  {
72    uint32_t ccr_val = pclk / (2 * br);
73    /* according to datasheet, the rise time for standard mode is 1us -> 1MHz */
74    uint32_t trise_val = pclk / 1000000 + 1;
75    trise = STM32F4_I2C_TRISE_SET(trise, trise_val);
76
77    if(ccr_val > STM32F4_I2C_CCR_CCR_MAX)
78    {
79      return RTEMS_INVALID_NUMBER;
80    }
81
82    /* standard mode */
83    ccr &= ~STM32F4_I2C_CCR_FS;
84    ccr = STM32F4_I2C_CCR_CCR_SET(ccr, ccr_val);
85  }
86  else
87  {
88    /* FIXME: Implement speeds 100kHz < f <= 400kHz (fast mode) */
89    return RTEMS_NOT_IMPLEMENTED;
90  }
91
92  regs->ccr = ccr;
93  regs->trise = trise;
94
95  return RTEMS_SUCCESSFUL;
96}
97
98static void stm32f4_i2c_handler(void *arg)
99{
100  /* This handler implements the suggested read method from stm32f103xx
101   * reference manual if the handler is not the one with the highest priority */
102  stm32f4_i2c_bus_entry *e = arg;
103  volatile stm32f4_i2c *regs = e->regs;
104  uint32_t sr1 = regs->sr1;
105  uint8_t *data = e->data;
106  uint8_t *last = e->last;
107  bool read = e->read;
108  bool wake_task = false;
109  uint32_t cr1;
110
111  if(sr1 & STM32F4_I2C_SR1_SB) {
112    /* Start condition sent. */
113    regs->dr = e->addr_with_rw;
114  }
115
116  if(read) {
117    size_t len = e->len;
118
119    if(len == 1) {
120      /* special case for one single byte */
121      if(sr1 & STM32F4_I2C_SR1_ADDR) {
122        cr1 = regs->cr1;
123        cr1 &= ~STM32F4_I2C_CR1_ACK;
124        regs->cr1 = cr1;
125
126        /* Read sr2 to clear flag */
127        regs->sr2;
128
129        cr1 = regs->cr1;
130        cr1 |= STM32F4_I2C_CR1_STOP;
131        regs->cr1 = cr1;
132      } else if(sr1 & STM32F4_I2C_SR1_RxNE) {
133        *data = regs->dr;
134        wake_task = true;
135      }
136    } else if (len == 2) {
137      /* special case for two bytes */
138      if(sr1 & STM32F4_I2C_SR1_ADDR) {
139        /* Read sr2 to clear flag */
140        regs->sr2;
141
142        cr1 = regs->cr1;
143        cr1 &= ~STM32F4_I2C_CR1_ACK;
144        regs->cr1 = cr1;
145      } else if(sr1 & STM32F4_I2C_SR1_BTF) {
146        cr1 = regs->cr1;
147        cr1 |= STM32F4_I2C_CR1_STOP;
148        regs->cr1 = cr1;
149
150        *data = regs->dr;
151        ++data;
152        *data = regs->dr;
153        wake_task = true;
154      }
155    } else {
156      /* more than two bytes */
157      if(sr1 & STM32F4_I2C_SR1_ADDR) {
158        /* Read sr2 to clear flag */
159        regs->sr2;
160      } else if(sr1 & STM32F4_I2C_SR1_BTF && data == last - 2) {
161        cr1 = regs->cr1;
162        cr1 &= ~STM32F4_I2C_CR1_ACK;
163        regs->cr1 = cr1;
164
165        *data = regs->dr;
166        ++data;
167
168        cr1 = regs->cr1;
169        cr1 |= STM32F4_I2C_CR1_STOP;
170        regs->cr1 = cr1;
171
172        *data = regs->dr;
173        ++data;
174      } else if((sr1 & STM32F4_I2C_SR1_RxNE) && (data != last - 2)) {
175        *data = regs->dr;
176
177        if(data == last) {
178          wake_task = true;
179        } else {
180          ++data;
181        }
182      }
183    }
184  } else /* write */ {
185    if(sr1 & STM32F4_I2C_SR1_ADDR) {
186      /* Address sent */
187      regs->sr2;
188    }
189
190    if((sr1 & (STM32F4_I2C_SR1_ADDR | STM32F4_I2C_SR1_TxE)) && (data <= last)) {
191      regs->dr = *data;
192      ++data;
193    } else if(sr1 & STM32F4_I2C_SR1_BTF) {
194      uint32_t cr1 = regs->cr1;
195      cr1 |= STM32F4_I2C_CR1_STOP;
196      regs->cr1 = cr1;
197      wake_task = true;
198    }
199  }
200
201  e->data = data;
202
203  if(wake_task) {
204    bsp_interrupt_vector_disable(e->vector);
205    rtems_event_transient_send(e->task_id);
206  }
207}
208
209static rtems_status_code i2c_wait_done(stm32f4_i2c_bus_entry *e)
210{
211  bsp_interrupt_vector_enable(e->vector);
212  e->task_id = rtems_task_self();
213  return rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
214}
215
216rtems_status_code stm32f4_i2c_init(stm32f4_i2c_bus_entry *e)
217{
218  rtems_status_code sc = RTEMS_SUCCESSFUL;
219  volatile stm32f4_i2c *regs = e->regs;
220  stm32f4_rcc_index rcc_index = i2c_get_rcc_index(e);
221  uint32_t pclk = i2c_get_pclk(e);
222  uint32_t cr1 = 0;
223  uint32_t cr2 = 0;
224
225  assert(pclk >= 2000000);
226
227  /* Create mutex */
228  sc = rtems_semaphore_create (
229    rtems_build_name ('I', '2', 'C', '1' + e->index),
230    0,
231    RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY,
232    0,
233    &e->mutex
234  );
235  RTEMS_CHECK_SC(sc, "create mutex");
236
237  /* Install interrupt handler and disable this vector */
238  sc = rtems_interrupt_handler_install(
239    e->vector,
240    "I2C",
241    RTEMS_INTERRUPT_UNIQUE,
242    stm32f4_i2c_handler,
243    e
244  );
245  RTEMS_CHECK_SC(sc, "install interrupt handler");
246  bsp_interrupt_vector_disable(e->vector);
247
248  /* Enable module clock */
249  stm32f4_rcc_set_clock(rcc_index, true);
250
251  /* Setup initial bit rate */
252  sc = stm32f4_i2c_set_bitrate(e, STM32F4_I2C_INITIAL_BITRATE);
253  RTEMS_CHECK_SC(sc, "set bitrate");
254
255  /* Set config registers */
256  cr2 = regs->cr2;
257  cr2 = STM32F4_I2C_CR2_FREQ_SET(cr2, pclk / 1000000);
258  cr2 |= STM32F4_I2C_CR2_ITEVTEN;
259  cr2 |= STM32F4_I2C_CR2_ITBUFEN;
260  regs->cr2 = cr2;
261
262  cr1 = regs->cr1;
263  cr1 |= STM32F4_I2C_CR1_PE;
264  regs->cr1 = cr1;
265
266  return RTEMS_SUCCESSFUL;
267}
268
269rtems_status_code stm32f4_i2c_process_message(
270  stm32f4_i2c_bus_entry *e,
271  stm32f4_i2c_message *msg
272)
273{
274  rtems_status_code sc = RTEMS_SUCCESSFUL;
275  rtems_status_code sc_return = RTEMS_SUCCESSFUL;
276  volatile stm32f4_i2c *regs = e->regs;
277  uint16_t max_7_bit_address = (1 << 7) - 1;
278  uint32_t cr1 = regs->cr1;
279
280  if(msg->addr > max_7_bit_address) {
281    return RTEMS_NOT_IMPLEMENTED;
282  }
283
284  if(msg->len == 0) {
285    return RTEMS_INVALID_SIZE;
286  }
287
288  sc = rtems_semaphore_obtain(e->mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
289  RTEMS_CHECK_SC(sc, "obtaining mutex");
290
291  e->data = msg->buf;
292  e->last = msg->buf + msg->len - 1;
293  e->len = msg->len;
294
295  e->addr_with_rw = msg->addr << 1;
296  if(msg->read) {
297    e->addr_with_rw |= I2C_RW_BIT;
298  }
299  e->read = msg->read;
300
301  /* Check if no stop is active. */
302  if(cr1 & STM32F4_I2C_CR1_STOP) {
303    return RTEMS_IO_ERROR;
304  }
305
306  /* Start */
307  cr1 = regs->cr1;
308  if(e->len == 2) {
309    cr1 |= STM32F4_I2C_CR1_POS;
310  } else {
311    cr1 &= ~STM32F4_I2C_CR1_POS;
312  }
313  cr1 |= STM32F4_I2C_CR1_ACK;
314  cr1 |= STM32F4_I2C_CR1_START;
315  regs->cr1 = cr1;
316
317  /* Wait for end of message */
318  sc = i2c_wait_done(e);
319
320  if(sc != RTEMS_SUCCESSFUL) {
321    sc_return = sc;
322  }
323
324  sc = rtems_semaphore_release(e->mutex);
325  RTEMS_CHECK_SC(sc, "releasing mutex");
326
327  return sc_return;
328}
329
Note: See TracBrowser for help on using the repository browser.