Statistics
| Branch: | Tag: | Revision:

amiro-os / kernel / patches / I2C-without-DMA.patch @ 10853947

History | View | Annotate | Download (29.719 KB)

1
diff --git a/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c b/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c
2
--- a/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c
3
+++ b/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c
4
@@ -34,6 +34,7 @@
5
 /* Driver local definitions.                                                 */
6
 /*===========================================================================*/
7
 
8
+#if STM32_I2C_I2C1_USE_DMA
9
 #define I2C1_RX_DMA_CHANNEL                                                 \
10
   STM32_DMA_GETCHANNEL(STM32_I2C_I2C1_RX_DMA_STREAM,                        \
11
                        STM32_I2C1_RX_DMA_CHN)
12
@@ -41,7 +42,9 @@
13
 #define I2C1_TX_DMA_CHANNEL                                                 \
14
   STM32_DMA_GETCHANNEL(STM32_I2C_I2C1_TX_DMA_STREAM,                        \
15
                        STM32_I2C1_TX_DMA_CHN)
16
+#endif
17
 
18
+#if STM32_I2C_I2C2_USE_DMA
19
 #define I2C2_RX_DMA_CHANNEL                                                 \
20
   STM32_DMA_GETCHANNEL(STM32_I2C_I2C2_RX_DMA_STREAM,                        \
21
                        STM32_I2C2_RX_DMA_CHN)
22
@@ -49,7 +52,9 @@
23
 #define I2C2_TX_DMA_CHANNEL                                                 \
24
   STM32_DMA_GETCHANNEL(STM32_I2C_I2C2_TX_DMA_STREAM,                        \
25
                        STM32_I2C2_TX_DMA_CHN)
26
+#endif
27
 
28
+#if STM32_I2C_I2C3_USE_DMA
29
 #define I2C3_RX_DMA_CHANNEL                                                 \
30
   STM32_DMA_GETCHANNEL(STM32_I2C_I2C3_RX_DMA_STREAM,                        \
31
                        STM32_I2C3_RX_DMA_CHN)
32
@@ -57,6 +62,7 @@
33
 #define I2C3_TX_DMA_CHANNEL                                                 \
34
   STM32_DMA_GETCHANNEL(STM32_I2C_I2C3_TX_DMA_STREAM,                        \
35
                        STM32_I2C3_TX_DMA_CHN)
36
+#endif
37
 
38
 /*===========================================================================*/
39
 /* Driver constants.                                                         */
40
@@ -75,6 +81,20 @@
41
 #define I2C_EV6_MASTER_REC_MODE_SELECTED                                    \
42
   ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY)<< 16) | I2C_SR1_ADDR))
43
 
44
+#define I2C_EV7_MASTER_REC_BYTE_RECEIVED                                    \
45
+  ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY)<< 16) | I2C_SR1_RXNE))
46
+
47
+#define I2C_EV7_MASTER_REC_BYTE_RECEIVED_STOP                               \
48
+  ((uint32_t)(I2C_SR1_RXNE))
49
+
50
+#define I2C_EV7_2_EV7_3_MASTER_REC_BYTE_QUEUED                              \
51
+  ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY)<< 16) |                         \
52
+              I2C_SR1_BTF | I2C_SR1_RXNE))
53
+
54
+#define I2C_EV8_MASTER_BYTE_TRANSMITTING                                    \
55
+  ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA)<< 16) |           \
56
+              I2C_SR1_TXE))
57
+
58
 #define I2C_EV8_2_MASTER_BYTE_TRANSMITTED                                   \
59
   ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA) << 16) |          \
60
               I2C_SR1_BTF | I2C_SR1_TXE))
61
@@ -132,8 +152,24 @@ static void i2c_lld_abort_operation(I2CDriver *i2cp) {
62
   dp->SR1 = 0;
63
 
64
   /* Stops the associated DMA streams.*/
65
-  dmaStreamDisable(i2cp->dmatx);
66
-  dmaStreamDisable(i2cp->dmarx);
67
+#if STM32_I2C_USE_I2C1 && STM32_I2C_I2C1_USE_DMA
68
+  if (&I2CD1 == i2cp) {
69
+    dmaStreamDisable(i2cp->dmatx);
70
+    dmaStreamDisable(i2cp->dmarx);
71
+  }
72
+#endif
73
+#if STM32_I2C_USE_I2C2 && STM32_I2C_I2C2_USE_DMA
74
+  if (&I2CD2 == i2cp) {
75
+    dmaStreamDisable(i2cp->dmatx);
76
+    dmaStreamDisable(i2cp->dmarx);
77
+  }
78
+#endif
79
+#if STM32_I2C_USE_I2C3 && STM32_I2C_I2C3_USE_DMA
80
+  if (&I2CD3 == i2cp) {
81
+    dmaStreamDisable(i2cp->dmatx);
82
+    dmaStreamDisable(i2cp->dmarx);
83
+  }
84
+#endif
85
 }
86
 
87
 /**
88
@@ -238,14 +274,18 @@ static void i2c_lld_set_opmode(I2CDriver *i2cp) {
89
   dp->CR1 = regCR1;
90
 }
91
 
92
+#if (STM32_I2C_USE_I2C1 && STM32_I2C_I2C1_USE_DMA) ||                       \
93
+    (STM32_I2C_USE_I2C2 && STM32_I2C_I2C2_USE_DMA) ||                       \
94
+    (STM32_I2C_USE_I2C3 && STM32_I2C_I2C3_USE_DMA) ||                       \
95
+    defined(__DOXYGEN__)
96
 /**
97
- * @brief   I2C shared ISR code.
98
+ * @brief   I2C shared ISR code for DMA access.
99
  *
100
  * @param[in] i2cp      pointer to the @p I2CDriver object
101
  *
102
  * @notapi
103
  */
104
-static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) {
105
+static void i2c_lld_serve_event_interrupt_dma(I2CDriver *i2cp) {
106
   I2C_TypeDef *dp = i2cp->i2c;
107
   uint32_t regSR2 = dp->SR2;
108
   uint32_t event = dp->SR1;
109
@@ -303,7 +343,146 @@ static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) {
110
     dp->SR1 &= ~I2C_SR1_BERR;
111
   }
112
 }
113
+#endif /* any I2CDx uses DMA mode */
114
+
115
+#if (STM32_I2C_USE_I2C1 && !STM32_I2C_I2C1_USE_DMA) ||                      \
116
+    (STM32_I2C_USE_I2C2 && !STM32_I2C_I2C2_USE_DMA) ||                      \
117
+    (STM32_I2C_USE_I2C3 && !STM32_I2C_I2C3_USE_DMA) ||                      \
118
+    defined(__DOXYGEN__)
119
+/**
120
+ * @brief   I2C shared ISR code for non-DMA access.
121
+ *
122
+ * @param[in] i2cp      pointer to the @p I2CDriver object
123
+ *
124
+ * @notapi
125
+ */
126
+static void i2c_lld_serve_event_interrupt_isr(I2CDriver *i2cp) {
127
+  I2C_TypeDef *dp = i2cp->i2c;
128
+  uint32_t regSR2 = dp->SR2;
129
+  uint32_t event = dp->SR1;
130
+
131
+  switch (I2C_EV_MASK & (event | (regSR2 << 16))) {
132
+  case I2C_EV5_MASTER_MODE_SELECT:
133
+    dp->CR2 |= I2C_CR2_ITBUFEN;
134
+    dp->DR = i2cp->addr;
135
+    break;
136
+  case I2C_EV6_MASTER_TRA_MODE_SELECTED:
137
+    (void)dp->SR2; // clear ADDR flag
138
+    /* EV8_1 */
139
+    dp->DR = *(i2cp->txbuf);
140
+
141
+    ++i2cp->txbuf;
142
+    --i2cp->txbytes;
143
+
144
+    /* if N == 1, skip the I2C_EV8_MASTER_BYTE_TRANSMITTING event
145
+     * but enter I2C_EV8_2_MASTER_BYTE_TRANSMITTED next */
146
+    if (i2cp->txbytes == 0) {
147
+      dp->CR2 &= ~I2C_CR2_ITBUFEN;
148
+    }
149
+    break;
150
+  case I2C_EV6_MASTER_REC_MODE_SELECTED:
151
+    switch (i2cp->rxbytes) {
152
+    case 1:
153
+      dp->CR1 &= ~I2C_CR1_ACK;
154
+      (void)dp->SR2; // clear ADDR flag
155
+      dp->CR1 |= I2C_CR1_STOP;
156
+      break;
157
+    case 2:
158
+      (void)dp->SR2; // clear ADDR flag
159
+      /* EV6_1 */
160
+      dp->CR1 |= I2C_CR1_POS;
161
+      dp->CR1 &= ~I2C_CR1_ACK;
162
+      dp->CR2 &= ~I2C_CR2_ITBUFEN;
163
+      break;
164
+    case 3: /* N == 3 is a very special case, since EV7 is completely skipped */
165
+      (void)dp->SR2; // clear ADDR flag
166
+      /* Disable the I2C_EV7_MASTER_REC_BYTE_RECEIVED event
167
+       * but enter I2C_EV7_MASTER_REC_BYTE_RECEIVED_STOP next */
168
+      dp->CR2 &= ~I2C_CR2_ITBUFEN;
169
+      break;
170
+    default: /* N > 2 */
171
+      (void)dp->SR2; // clear ADDR flag
172
+      break;
173
+    }
174
+    break;
175
+  case I2C_EV7_MASTER_REC_BYTE_RECEIVED:
176
+    if (i2cp->rxbytes > 3) {
177
+      *(i2cp->rxbuf) = dp->DR;
178
+      ++i2cp->rxbuf;
179
+      --i2cp->rxbytes;
180
+    }
181
+    if (i2cp->rxbytes == 3) {
182
+      /* Disable this event for DataN-2, but force into event
183
+       * I2C_EV7_2_EV7_3_MASTER_REC_BYTE_RECEIVED_QUEUED by not reading dp->DR. */
184
+      dp->CR2 &= ~I2C_CR2_ITBUFEN;
185
+    }
186
+    break;
187
+  case I2C_EV7_MASTER_REC_BYTE_RECEIVED_STOP:
188
+    osalDbgAssert(i2cp->rxbytes == 1, "more than 1 byte to be received");
189
+    *(i2cp->rxbuf) = dp->DR;
190
+    --i2cp->rxbytes;
191
+    dp->CR2 &= ~(I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN);
192
+    _i2c_wakeup_isr(i2cp);
193
+    break;
194
+  case I2C_EV7_2_EV7_3_MASTER_REC_BYTE_QUEUED:
195
+    if (i2cp->rxbytes == 3) {
196
+      /* EV7_2 (N > 2) */
197
+      dp->CR1 &= ~I2C_CR1_ACK;
198
+      *(i2cp->rxbuf) = dp->DR;
199
+      ++i2cp->rxbuf;
200
+      dp->CR1 |= I2C_CR1_STOP;
201
+      *(i2cp->rxbuf) = dp->DR;
202
+      ++i2cp->rxbuf;
203
+      i2cp->rxbytes -= 2;
204
+      /* enable I2C_EV7_MASTER_REC_BYTE_RECEIVED_STOP event */
205
+      dp->CR2 |= I2C_CR2_ITBUFEN;
206
+    } else {
207
+      /* EV7_3 (N == 2) */
208
+      dp->CR1 |= I2C_CR1_STOP;
209
+      *(i2cp->rxbuf) = dp->DR;
210
+      ++i2cp->rxbuf;
211
+      *(i2cp->rxbuf) = dp->DR;
212
+      i2cp->rxbytes -= 2;
213
+
214
+      dp->CR1 &= ~I2C_CR1_POS;
215
+      dp->CR2 &= ~(I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN);
216
+
217
+      _i2c_wakeup_isr(i2cp);
218
+    }
219
+    break;
220
+  case I2C_EV8_MASTER_BYTE_TRANSMITTING:
221
+    dp->DR = *(i2cp->txbuf);
222
+    ++i2cp->txbuf;
223
+    --i2cp->txbytes;
224
+
225
+    /* if this was the last byte, ensure that this event is not entered again */
226
+    if (i2cp->txbytes == 0) {
227
+      dp->CR2 &= ~I2C_CR2_ITBUFEN;
228
+    }
229
+    break;
230
+  case I2C_EV8_2_MASTER_BYTE_TRANSMITTED:
231
+    if (i2cp->rxbytes > 0) {
232
+      /* start "read after write" operation (LSB of address = 1 => read) */
233
+      i2cp->addr |= 0x01;
234
+      dp->CR1 |= I2C_CR1_START | I2C_CR1_ACK;
235
+    } else {
236
+      dp->CR1 |= I2C_CR1_STOP;
237
+      dp->CR2 &= ~(I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN);
238
+      _i2c_wakeup_isr(i2cp);
239
+    }
240
+    break;
241
+  default:
242
+    osalDbgAssert(i2cp->rxbytes != 1, "more than 1 byte to be received");
243
+    break;
244
+  }
245
+}
246
+#endif /* any I2CDx uses non-DMA mode */
247
+
248
 
249
+#if (STM32_I2C_USE_I2C1 && STM32_I2C_I2C1_USE_DMA) ||                      \
250
+    (STM32_I2C_USE_I2C2 && STM32_I2C_I2C2_USE_DMA) ||                      \
251
+    (STM32_I2C_USE_I2C3 && STM32_I2C_I2C3_USE_DMA) ||                      \
252
+    defined(__DOXYGEN__)
253
 /**
254
  * @brief   DMA RX end IRQ handler.
255
  *
256
@@ -357,6 +536,7 @@ static void i2c_lld_serve_tx_end_irq(I2CDriver *i2cp, uint32_t flags) {
257
      of R/W transaction itself.*/
258
   dp->CR2 |= I2C_CR2_ITEVTEN;
259
 }
260
+#endif /* any I2CDx uses DMA mode */
261
 
262
 /**
263
  * @brief   I2C error handler.
264
@@ -369,8 +549,24 @@ static void i2c_lld_serve_tx_end_irq(I2CDriver *i2cp, uint32_t flags) {
265
 static void i2c_lld_serve_error_interrupt(I2CDriver *i2cp, uint16_t sr) {
266
 
267
   /* Clears interrupt flags just to be safe.*/
268
-  dmaStreamDisable(i2cp->dmatx);
269
-  dmaStreamDisable(i2cp->dmarx);
270
+#if STM32_I2C_USE_I2C1 && STM32_I2C_I2C1_USE_DMA
271
+  if (&I2CD1 == i2cp) {
272
+    dmaStreamDisable(i2cp->dmatx);
273
+    dmaStreamDisable(i2cp->dmarx);
274
+  }
275
+#endif
276
+#if STM32_I2C_USE_I2C2 && STM32_I2C_I2C2_USE_DMA
277
+  if (&I2CD2 == i2cp) {
278
+    dmaStreamDisable(i2cp->dmatx);
279
+    dmaStreamDisable(i2cp->dmarx);
280
+  }
281
+#endif
282
+#if STM32_I2C_USE_I2C3 && STM32_I2C_I2C3_USE_DMA
283
+  if (&I2CD3 == i2cp) {
284
+    dmaStreamDisable(i2cp->dmatx);
285
+    dmaStreamDisable(i2cp->dmarx);
286
+  }
287
+#endif
288
 
289
   i2cp->errors = I2C_NO_ERROR;
290
 
291
@@ -421,7 +617,11 @@ OSAL_IRQ_HANDLER(STM32_I2C1_EVENT_HANDLER) {
292
 
293
   OSAL_IRQ_PROLOGUE();
294
 
295
-  i2c_lld_serve_event_interrupt(&I2CD1);
296
+#if STM32_I2C_I2C1_USE_DMA
297
+  i2c_lld_serve_event_interrupt_dma(&I2CD1);
298
+#else
299
+  i2c_lld_serve_event_interrupt_isr(&I2CD1);
300
+#endif