Statistics
| Branch: | Tag: | Revision:

amiro-os / kernel / patches / QEI-driver.patch @ 69b23c6c

History | View | Annotate | Download (56.639 KB)

1
commit a23878ddb85bb8fd069f02042f15ad4be2a0d709
2
Author: Marc Rothmann <mrothmann@techfak.uni-bielefeld.de>
3
Date:   Mon Sep 17 11:40:39 2018 +0200
4

    
5
    Added QEI driver to HAL.
6

    
7
diff --git a/os/hal/hal.mk b/os/hal/hal.mk
8
index f177a3f..64d96d9 100644
9
--- a/os/hal/hal.mk
10
+++ b/os/hal/hal.mk
11
@@ -41,6 +41,9 @@ endif
12
 ifneq ($(findstring HAL_USE_ICU TRUE,$(HALCONF)),)
13
 HALSRC += $(CHIBIOS)/os/hal/src/hal_icu.c
14
 endif
15
+ifneq ($(findstring HAL_USE_QEI TRUE,$(HALCONF)),)
16
+HALSRC += $(CHIBIOS)/os/hal/src/hal_qei.c
17
+endif
18
 ifneq ($(findstring HAL_USE_MAC TRUE,$(HALCONF)),)
19
 HALSRC += $(CHIBIOS)/os/hal/src/hal_mac.c
20
 endif
21
@@ -94,6 +97,7 @@ HALSRC = $(CHIBIOS)/os/hal/src/hal.c \
22
          $(CHIBIOS)/os/hal/src/hal_i2c.c \
23
          $(CHIBIOS)/os/hal/src/hal_i2s.c \
24
          $(CHIBIOS)/os/hal/src/hal_icu.c \
25
+         $(CHIBIOS)/os/hal/src/hal_qei.c \
26
          $(CHIBIOS)/os/hal/src/hal_mac.c \
27
          $(CHIBIOS)/os/hal/src/hal_mmc_spi.c \
28
          $(CHIBIOS)/os/hal/src/hal_pal.c \
29
diff --git a/os/hal/include/hal_qei.h b/os/hal/include/hal_qei.h
30
new file mode 100644
31
index 0000000..aef5e62
32
--- /dev/null
33
+++ b/os/hal/include/hal_qei.h
34
@@ -0,0 +1,148 @@
35
+/*
36
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
37
+Copyright (C) 2016..2018  Thomas Schöpping et al.
38
+
39
+This program is free software: you can redistribute it and/or modify
40
+it under the terms of the GNU General Public License as published by
41
+the Free Software Foundation, either version 3 of the License, or
42
+(at your option) any later version.
43
+
44
+This program is distributed in the hope that it will be useful,
45
+but WITHOUT ANY WARRANTY; without even the implied warranty of
46
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
47
+GNU General Public License for more details.
48
+
49
+You should have received a copy of the GNU General Public License
50
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
51
+*/
52
+
53
+/**
54
+ * @file    hal_qei.h
55
+ * @brief   QEI Driver macros and structures.
56
+ *
57
+ * @addtogroup QEI
58
+ * @{
59
+ */
60
+
61
+#ifndef _HAL_QEI_H_
62
+#define _HAL_QEI_H_
63
+
64
+#if HAL_USE_QEI || defined(__DOXYGEN__)
65
+
66
+/*===========================================================================*/
67
+/* Driver constants.                                                         */
68
+/*===========================================================================*/
69
+
70
+/*===========================================================================*/
71
+/* Driver pre-compile time settings.                                         */
72
+/*===========================================================================*/
73
+
74
+/*===========================================================================*/
75
+/* Derived constants and error checks.                                       */
76
+/*===========================================================================*/
77
+
78
+/*===========================================================================*/
79
+/* Driver data structures and types.                                         */
80
+/*===========================================================================*/
81
+
82
+/**
83
+ * @brief   Driver state machine possible states.
84
+ */
85
+typedef enum {
86
+  QEI_UNINIT = 0,                   /**< Not initialized.                   */
87
+  QEI_STOP = 1,                     /**< Stopped.                           */
88
+  QEI_READY = 2,                    /**< Ready.                             */
89
+  QEI_ACTIVE = 4,                   /**< Active.                            */
90
+} qeistate_t;
91
+
92
+/**
93
+ * @brief   Type of a structure representing an QEI driver.
94
+ */
95
+typedef struct QEIDriver QEIDriver;
96
+
97
+#include "hal_qei_lld.h"
98
+
99
+/*===========================================================================*/
100
+/* Driver macros.                                                            */
101
+/*===========================================================================*/
102
+
103
+/**
104
+ * @name    Macro Functions
105
+ * @{
106
+ */
107
+/**
108
+ * @brief   Enables the quadrature encoder.
109
+ *
110
+ * @param[in] qeip      pointer to the @p QEIDriver object
111
+ *
112
+ * @iclass
113
+ */
114
+#define qeiEnableI(qeip) qei_lld_enable(qeip)
115
+
116
+/**
117
+ * @brief   Disables the quadrature encoder.
118
+ *
119
+ * @param[in] qeip      pointer to the @p QEIDriver object
120
+ *
121
+ * @iclass
122
+ */
123
+#define qeiDisableI(qeip) qei_lld_disable(qeip)
124
+
125
+/**
126
+ * @brief   Returns the direction of the last transition.
127
+ * @details The direction is defined as boolean and is
128
+ *          calculated at each transition on any input.
129
+ *
130
+ * @param[in] qeip      pointer to the @p QEIDriver object
131
+ * @return              The request direction.
132
+ * @retval FALSE        Position counted up.
133
+ * @retval TRUE         Position counted down.
134
+ * @iclass
135
+ */
136
+#define qeiGetDirectionI(qeip) qei_lld_get_direction(qeip)
137
+
138
+/**
139
+ * @brief   Returns the position of the encoder.
140
+ * @details The position is defined as number of pulses since last reset.
141
+ *
142
+ * @param[in] qeip      pointer to the @p QEIDriver object
143
+ * @return              The number of pulses.
144
+ *
145
+ * @iclass
146
+ */
147
+#define qeiGetPositionI(qeip) qei_lld_get_position(qeip)
148
+
149
+/**
150
+ * @brief   Returns the range of the encoder.
151
+ * @details The range is defined as number of maximum pulse count.
152
+ *
153
+ * @param[in] qeip      pointer to the @p QEIDriver object
154
+ * @return              The number of pulses.
155
+ *
156
+ * @iclass
157
+ */
158
+#define qeiGetRangeI(qeip) qei_lld_get_range(qeip)
159
+/** @} */
160
+
161
+/*===========================================================================*/
162
+/* External declarations.                                                    */
163
+/*===========================================================================*/
164
+
165
+#ifdef __cplusplus
166
+extern "C" {
167
+#endif
168
+  void qeiInit(void);
169
+  void qeiObjectInit(QEIDriver *qeip);
170
+  void qeiStart(QEIDriver *qeip, const QEIConfig *config);
171
+  void qeiStop(QEIDriver *qeip);
172
+  void qeiEnable(QEIDriver *qeip);
173
+  void qeiDisable(QEIDriver *qeip);
174
+#ifdef __cplusplus
175
+}
176
+#endif
177
+
178
+#endif /* HAL_USE_QEI */
179
+
180
+#endif /* _HAL_QEI_H_ */
181
+
182
+/** @} */
183
diff --git a/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c b/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c
184
index 6ade226..96c9da0 100644
185
--- a/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c
186
+++ b/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c
187
@@ -34,6 +34,7 @@
188
 /* Driver local definitions.                                                 */
189
 /*===========================================================================*/
190
 
191
+#if STM32_I2C_I2C1_USE_DMA
192
 #define I2C1_RX_DMA_CHANNEL                                                 \
193
   STM32_DMA_GETCHANNEL(STM32_I2C_I2C1_RX_DMA_STREAM,                        \
194
                        STM32_I2C1_RX_DMA_CHN)
195
@@ -41,7 +42,9 @@
196
 #define I2C1_TX_DMA_CHANNEL                                                 \
197
   STM32_DMA_GETCHANNEL(STM32_I2C_I2C1_TX_DMA_STREAM,                        \
198
                        STM32_I2C1_TX_DMA_CHN)
199
+#endif
200
 
201
+#if STM32_I2C_I2C2_USE_DMA
202
 #define I2C2_RX_DMA_CHANNEL                                                 \
203
   STM32_DMA_GETCHANNEL(STM32_I2C_I2C2_RX_DMA_STREAM,                        \
204
                        STM32_I2C2_RX_DMA_CHN)
205
@@ -49,7 +52,9 @@
206
 #define I2C2_TX_DMA_CHANNEL                                                 \
207
   STM32_DMA_GETCHANNEL(STM32_I2C_I2C2_TX_DMA_STREAM,                        \
208
                        STM32_I2C2_TX_DMA_CHN)
209
+#endif
210
 
211
+#if STM32_I2C_I2C3_USE_DMA
212
 #define I2C3_RX_DMA_CHANNEL                                                 \
213
   STM32_DMA_GETCHANNEL(STM32_I2C_I2C3_RX_DMA_STREAM,                        \
214
                        STM32_I2C3_RX_DMA_CHN)
215
@@ -57,6 +62,7 @@
216
 #define I2C3_TX_DMA_CHANNEL                                                 \
217
   STM32_DMA_GETCHANNEL(STM32_I2C_I2C3_TX_DMA_STREAM,                        \
218
                        STM32_I2C3_TX_DMA_CHN)
219
+#endif
220
 
221
 /*===========================================================================*/
222
 /* Driver constants.                                                         */
223
@@ -72,6 +78,20 @@
224
 #define I2C_EV6_MASTER_REC_MODE_SELECTED                                    \
225
   ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY)<< 16) | I2C_SR1_ADDR))
226
 
227
+#define I2C_EV7_MASTER_REC_BYTE_RECEIVED                                    \
228
+  ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY)<< 16) | I2C_SR1_RXNE))
229
+
230
+#define I2C_EV7_MASTER_REC_BYTE_RECEIVED_STOP                               \
231
+  ((uint32_t)(I2C_SR1_RXNE))
232
+
233
+#define I2C_EV7_2_EV7_3_MASTER_REC_BYTE_QUEUED                              \
234
+  ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY)<< 16) |                         \
235
+              I2C_SR1_BTF | I2C_SR1_RXNE))
236
+
237
+#define I2C_EV8_MASTER_BYTE_TRANSMITTING                                    \
238
+  ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA)<< 16) |           \
239
+              I2C_SR1_TXE))
240
+
241
 #define I2C_EV8_2_MASTER_BYTE_TRANSMITTED                                   \
242
   ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA) << 16) |          \
243
               I2C_SR1_BTF | I2C_SR1_TXE))
244
@@ -129,8 +149,24 @@ static void i2c_lld_abort_operation(I2CDriver *i2cp) {
245
   dp->SR1 = 0;
246
 
247
   /* Stops the associated DMA streams.*/
248
-  dmaStreamDisable(i2cp->dmatx);
249
-  dmaStreamDisable(i2cp->dmarx);
250
+#if STM32_I2C_USE_I2C1 && STM32_I2C_I2C1_USE_DMA
251
+  if (&I2CD1 == i2cp) {
252
+    dmaStreamDisable(i2cp->dmatx);
253
+    dmaStreamDisable(i2cp->dmarx);
254
+  }
255
+#endif
256
+#if STM32_I2C_USE_I2C2 && STM32_I2C_I2C2_USE_DMA
257
+  if (&I2CD2 == i2cp) {
258
+    dmaStreamDisable(i2cp->dmatx);
259
+    dmaStreamDisable(i2cp->dmarx);
260
+  }
261
+#endif
262
+#if STM32_I2C_USE_I2C3 && STM32_I2C_I2C3_USE_DMA
263
+  if (&I2CD3 == i2cp) {
264
+    dmaStreamDisable(i2cp->dmatx);
265
+    dmaStreamDisable(i2cp->dmarx);
266
+  }
267
+#endif
268
 }
269
 
270
 /**
271
@@ -236,13 +272,17 @@ static void i2c_lld_set_opmode(I2CDriver *i2cp) {
272
 }
273
 
274
 /**
275
- * @brief   I2C shared ISR code.
276
+ * @brief   I2C shared ISR code for DMA access.
277
  *
278
  * @param[in] i2cp      pointer to the @p I2CDriver object
279
  *
280
  * @notapi
281
  */
282
-static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) {
283
+#if (STM32_I2C_USE_I2C1 && STM32_I2C_I2C1_USE_DMA) ||                       \
284
+    (STM32_I2C_USE_I2C2 && STM32_I2C_I2C2_USE_DMA) ||                       \
285
+    (STM32_I2C_USE_I2C3 && STM32_I2C_I2C3_USE_DMA) ||                       \
286
+    defined(__DOXYGEN__)
287
+static void i2c_lld_serve_event_interrupt_dma(I2CDriver *i2cp) {
288
   I2C_TypeDef *dp = i2cp->i2c;
289
   uint32_t regSR2 = dp->SR2;
290
   uint32_t event = dp->SR1;
291
@@ -252,7 +292,7 @@ static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) {
292
      done by the DMA.*/
293
   switch (I2C_EV_MASK & (event | (regSR2 << 16))) {
294
   case I2C_EV5_MASTER_MODE_SELECT:
295
-    if ((i2cp->addr >> 8) > 0) { 
296
+    if ((i2cp->addr >> 8) > 0) {
297
       /* 10-bit address: 1 1 1 1 0 X X R/W */
298
       dp->DR = 0xF0 | (0x6 & (i2cp->addr >> 8)) | (0x1 & i2cp->addr);
299
     } else {
300
@@ -293,6 +333,140 @@ static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) {
301
   if (event & (I2C_SR1_ADDR | I2C_SR1_ADD10))
302
     (void)dp->SR2;
303
 }
304
+#endif /* any I2CDx uses DMA mode */
305
+
306
+/**
307
+ * @brief   I2C shared ISR code for non-DMA access.
308
+ *
309
+ * @param[in] i2cp      pointer to the @p I2CDriver object
310
+ *
311
+ * @notapi
312
+ */
313
+#if (STM32_I2C_USE_I2C1 && !STM32_I2C_I2C1_USE_DMA) ||                      \
314
+    (STM32_I2C_USE_I2C2 && !STM32_I2C_I2C2_USE_DMA) ||                      \
315
+    (STM32_I2C_USE_I2C3 && !STM32_I2C_I2C3_USE_DMA) ||                      \
316
+    defined(__DOXYGEN__)
317
+static void i2c_lld_serve_event_interrupt_isr(I2CDriver *i2cp) {
318
+  I2C_TypeDef *dp = i2cp->i2c;
319
+  uint32_t regSR2 = dp->SR2;
320
+  uint32_t event = dp->SR1;
321
+
322
+  switch (I2C_EV_MASK & (event | (regSR2 << 16))) {
323
+  case I2C_EV5_MASTER_MODE_SELECT:
324
+    dp->CR2 |= I2C_CR2_ITBUFEN;
325
+    dp->DR = i2cp->addr;
326
+    break;
327
+  case I2C_EV6_MASTER_TRA_MODE_SELECTED:
328
+    (void)dp->SR2; // clear ADDR flag
329
+    /* EV8_1 */
330
+    dp->DR = *(i2cp->txbuf);
331
+
332
+    ++i2cp->txbuf;
333
+    --i2cp->txbytes;
334
+
335
+    /* if N == 1, skip the I2C_EV8_MASTER_BYTE_TRANSMITTING event
336
+     * but enter I2C_EV8_2_MASTER_BYTE_TRANSMITTED next */
337
+    if (i2cp->txbytes == 0) {
338
+      dp->CR2 &= ~I2C_CR2_ITBUFEN;
339
+    }
340
+    break;
341
+  case I2C_EV6_MASTER_REC_MODE_SELECTED:
342
+    switch (i2cp->rxbytes) {
343
+    case 1:
344
+      dp->CR1 &= ~I2C_CR1_ACK;
345
+      (void)dp->SR2; // clear ADDR flag
346
+      dp->CR1 |= I2C_CR1_STOP;
347
+      break;
348
+    case 2:
349
+      (void)dp->SR2; // clear ADDR flag
350
+      /* EV6_1 */
351
+      dp->CR1 |= I2C_CR1_POS;
352
+      dp->CR1 &= ~I2C_CR1_ACK;
353
+      dp->CR2 &= ~I2C_CR2_ITBUFEN;
354
+      break;
355
+    case 3: /* N == 3 is a very special case, since EV7 is completely skipped */
356
+      (void)dp->SR2; // clear ADDR flag
357
+      /* Disable the I2C_EV7_MASTER_REC_BYTE_RECEIVED event
358
+       * but enter I2C_EV7_MASTER_REC_BYTE_RECEIVED_STOP next */
359
+      dp->CR2 &= ~I2C_CR2_ITBUFEN;
360
+      break;
361
+    default: /* N > 2 */
362
+      (void)dp->SR2; // clear ADDR flag
363
+      break;
364
+    }
365
+    break;
366
+  case I2C_EV7_MASTER_REC_BYTE_RECEIVED:
367
+    if (i2cp->rxbytes > 3) {
368
+      *(i2cp->rxbuf) = dp->DR;
369
+      ++i2cp->rxbuf;
370
+      --i2cp->rxbytes;
371
+    }
372
+    if (i2cp->rxbytes == 3) {
373
+      /* Disable this event for DataN-2, but force into event
374
+       * I2C_EV7_2_EV7_3_MASTER_REC_BYTE_RECEIVED_QUEUED by not reading dp->DR. */
375
+      dp->CR2 &= ~I2C_CR2_ITBUFEN;
376
+    }
377
+    break;
378
+  case I2C_EV7_MASTER_REC_BYTE_RECEIVED_STOP:
379
+    osalDbgAssert(i2cp->rxbytes == 1, "more than 1 byte to be received");
380
+    *(i2cp->rxbuf) = dp->DR;
381
+    --i2cp->rxbytes;
382
+    dp->CR2 &= ~(I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN);
383
+    _i2c_wakeup_isr(i2cp);
384
+    break;
385
+  case I2C_EV7_2_EV7_3_MASTER_REC_BYTE_QUEUED:
386
+    if (i2cp->rxbytes == 3) {
387
+      /* EV7_2 (N > 2) */
388
+      dp->CR1 &= ~I2C_CR1_ACK;
389
+      *(i2cp->rxbuf) = dp->DR;
390
+      ++i2cp->rxbuf;
391
+      dp->CR1 |= I2C_CR1_STOP;
392
+      *(i2cp->rxbuf) = dp->DR;
393
+      ++i2cp->rxbuf;
394
+      i2cp->rxbytes -= 2;
395
+      /* enable I2C_EV7_MASTER_REC_BYTE_RECEIVED_STOP event */
396
+      dp->CR2 |= I2C_CR2_ITBUFEN;
397
+    } else {
398
+      /* EV7_3 (N == 2) */
399
+      dp->CR1 |= I2C_CR1_STOP;
400
+      *(i2cp->rxbuf) = dp->DR;
401
+      ++i2cp->rxbuf;
402
+      *(i2cp->rxbuf) = dp->DR;
403
+      i2cp->rxbytes -= 2;
404
+
405
+      dp->CR1 &= ~I2C_CR1_POS;
406
+      dp->CR2 &= ~(I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN);
407
+
408
+      _i2c_wakeup_isr(i2cp);
409
+    }
410
+    break;
411
+  case I2C_EV8_MASTER_BYTE_TRANSMITTING:
412
+    dp->DR = *(i2cp->txbuf);
413
+    ++i2cp->txbuf;
414
+    --i2cp->txbytes;
415
+
416
+    /* if this was the last byte, ensure that this event is not entered again */
417
+    if (i2cp->txbytes == 0) {
418
+      dp->CR2 &= ~I2C_CR2_ITBUFEN;
419
+    }
420
+    break;
421
+  case I2C_EV8_2_MASTER_BYTE_TRANSMITTED:
422
+    if (i2cp->rxbytes > 0) {
423
+      /* start "read after write" operation (LSB of address = 1 => read) */
424
+      i2cp->addr |= 0x01;
425
+      dp->CR1 |= I2C_CR1_START | I2C_CR1_ACK;
426
+    } else {
427
+      dp->CR1 |= I2C_CR1_STOP;
428
+      dp->CR2 &= ~(I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN);
429
+      _i2c_wakeup_isr(i2cp);
430
+    }
431
+    break;
432
+  default:
433
+    osalDbgAssert(i2cp->rxbytes != 1, "more than 1 byte to be received");
434
+    break;
435
+  }
436
+}
437
+#endif /* any I2CDx uses non-DMA mode */
438
 
439
 /**
440
  * @brief   DMA RX end IRQ handler.
441
@@ -302,6 +476,10 @@ static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) {
442
  *
443
  * @notapi
444
  */
445
+#if (STM32_I2C_USE_I2C1 && STM32_I2C_I2C1_USE_DMA) ||                      \
446
+    (STM32_I2C_USE_I2C2 && STM32_I2C_I2C2_USE_DMA) ||                      \
447
+    (STM32_I2C_USE_I2C3 && STM32_I2C_I2C3_USE_DMA) ||                      \
448
+    defined(__DOXYGEN__)
449
 static void i2c_lld_serve_rx_end_irq(I2CDriver *i2cp, uint32_t flags) {
450
   I2C_TypeDef *dp = i2cp->i2c;
451
 
452
@@ -347,6 +525,7 @@ static void i2c_lld_serve_tx_end_irq(I2CDriver *i2cp, uint32_t flags) {
453
      of R/W transaction itself.*/
454
   dp->CR2 |= I2C_CR2_ITEVTEN;
455
 }
456
+#endif /* any I2CDx uses DMA mode */
457
 
458
 /**
459
  * @brief   I2C error handler.
460
@@ -359,8 +538,24 @@ static void i2c_lld_serve_tx_end_irq(I2CDriver *i2cp, uint32_t flags) {
461
 static void i2c_lld_serve_error_interrupt(I2CDriver *i2cp, uint16_t sr) {
462
 
463
   /* Clears interrupt flags just to be safe.*/
464
-  dmaStreamDisable(i2cp->dmatx);
465
-  dmaStreamDisable(i2cp->dmarx);
466
+#if STM32_I2C_USE_I2C1 && STM32_I2C_I2C1_USE_DMA
467
+  if (&I2CD1 == i2cp) {
468
+    dmaStreamDisable(i2cp->dmatx);
469
+    dmaStreamDisable(i2cp->dmarx);
470
+  }
471
+#endif
472
+#if STM32_I2C_USE_I2C2 && STM32_I2C_I2C2_USE_DMA
473
+  if (&I2CD2 == i2cp) {
474
+    dmaStreamDisable(i2cp->dmatx);
475
+    dmaStreamDisable(i2cp->dmarx);
476
+  }
477
+#endif
478
+#if STM32_I2C_USE_I2C3 && STM32_I2C_I2C3_USE_DMA
479
+  if (&I2CD3 == i2cp) {
480
+    dmaStreamDisable(i2cp->dmatx);
481
+    dmaStreamDisable(i2cp->dmarx);
482
+  }
483
+#endif
484
 
485
   i2cp->errors = I2C_NO_ERROR;
486
 
487
@@ -407,7 +602,11 @@ OSAL_IRQ_HANDLER(STM32_I2C1_EVENT_HANDLER) {
488
 
489
   OSAL_IRQ_PROLOGUE();
490
 
491
-  i2c_lld_serve_event_interrupt(&I2CD1);
492
+#if STM32_I2C_I2C1_USE_DMA
493
+  i2c_lld_serve_event_interrupt_dma(&I2CD1);
494
+#else
495
+  i2c_lld_serve_event_interrupt_isr(&I2CD1);
496
+#endif
497
 
498
   OSAL_IRQ_EPILOGUE();
499
 }
500
@@ -437,7 +636,11 @@ OSAL_IRQ_HANDLER(STM32_I2C2_EVENT_HANDLER) {
501
 
502
   OSAL_IRQ_PROLOGUE();
503
 
504
-  i2c_lld_serve_event_interrupt(&I2CD2);
505
+#if STM32_I2C_I2C2_USE_DMA
506
+  i2c_lld_serve_event_interrupt_dma(&I2CD2);
507
+#else
508
+  i2c_lld_serve_event_interrupt_isr(&I2CD2);
509
+#endif
510
 
511
   OSAL_IRQ_EPILOGUE();
512
 }
513
@@ -469,7 +672,11 @@ OSAL_IRQ_HANDLER(STM32_I2C3_EVENT_HANDLER) {
514
 
515
   OSAL_IRQ_PROLOGUE();
516
 
517
-  i2c_lld_serve_event_interrupt(&I2CD3);
518
+#if STM32_I2C_I2C3_USE_DMA
519
+  i2c_lld_serve_event_interrupt_dma(&I2CD3);
520
+#else
521
+  i2c_lld_serve_event_interrupt_isr(&I2CD3);
522
+#endif
523
 
524
   OSAL_IRQ_EPILOGUE();
525
 }
526
@@ -506,24 +713,30 @@ void i2c_lld_init(void) {
527
   i2cObjectInit(&I2CD1);
528
   I2CD1.thread = NULL;
529
   I2CD1.i2c    = I2C1;
530
+#if STM32_I2C_I2C1_USE_DMA
531
   I2CD1.dmarx  = STM32_DMA_STREAM(STM32_I2C_I2C1_RX_DMA_STREAM);
532
   I2CD1.dmatx  = STM32_DMA_STREAM(STM32_I2C_I2C1_TX_DMA_STREAM);
533
+#endif
534
 #endif /* STM32_I2C_USE_I2C1 */
535
 
536
 #if STM32_I2C_USE_I2C2
537
   i2cObjectInit(&I2CD2);
538
   I2CD2.thread = NULL;
539
   I2CD2.i2c    = I2C2;
540
+#if STM32_I2C_I2C2_USE_DMA
541
   I2CD2.dmarx  = STM32_DMA_STREAM(STM32_I2C_I2C2_RX_DMA_STREAM);
542
   I2CD2.dmatx  = STM32_DMA_STREAM(STM32_I2C_I2C2_TX_DMA_STREAM);
543
+#endif
544
 #endif /* STM32_I2C_USE_I2C2 */
545
 
546
 #if STM32_I2C_USE_I2C3
547
   i2cObjectInit(&I2CD3);
548
   I2CD3.thread = NULL;
549
   I2CD3.i2c    = I2C3;
550
+#if STM32_I2C_I2C3_USE_DMA
551
   I2CD3.dmarx  = STM32_DMA_STREAM(STM32_I2C_I2C3_RX_DMA_STREAM);
552
   I2CD3.dmatx  = STM32_DMA_STREAM(STM32_I2C_I2C3_TX_DMA_STREAM);
553
+#endif
554
 #endif /* STM32_I2C_USE_I2C3 */
555
 }
556
 
557
@@ -540,20 +753,24 @@ void i2c_lld_start(I2CDriver *i2cp) {
558
   /* If in stopped state then enables the I2C and DMA clocks.*/
559
   if (i2cp->state == I2C_STOP) {
560
 
561
-    i2cp->txdmamode = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE |
562
-                      STM32_DMA_CR_MINC       | STM32_DMA_CR_DMEIE |
563
-                      STM32_DMA_CR_TEIE       | STM32_DMA_CR_TCIE |
564
-                      STM32_DMA_CR_DIR_M2P;
565
-    i2cp->rxdmamode = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE |
566
-                      STM32_DMA_CR_MINC       | STM32_DMA_CR_DMEIE |
567
-                      STM32_DMA_CR_TEIE       | STM32_DMA_CR_TCIE |
568
-                      STM32_DMA_CR_DIR_P2M;
569
-
570
 #if STM32_I2C_USE_I2C1
571
     if (&I2CD1 == i2cp) {
572
+#if STM32_I2C_I2C1_USE_DMA
573
       bool b;
574
 
575
+      i2cp->txdmamode = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE |
576
+                        STM32_DMA_CR_MINC       | STM32_DMA_CR_DMEIE |
577
+                        STM32_DMA_CR_TEIE       | STM32_DMA_CR_TCIE |
578
+                        STM32_DMA_CR_DIR_M2P;
579
+      i2cp->rxdmamode = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE |
580
+                        STM32_DMA_CR_MINC       | STM32_DMA_CR_DMEIE |
581
+                        STM32_DMA_CR_TEIE       | STM32_DMA_CR_TCIE |
582
+                        STM32_DMA_CR_DIR_P2M;
583
+#endif
584
+
585
       rccResetI2C1();
586
+
587
+#if STM32_I2C_I2C1_USE_DMA
588
       b = dmaStreamAllocate(i2cp->dmarx,
589
                             STM32_I2C_I2C1_IRQ_PRIORITY,
590
                             (stm32_dmaisr_t)i2c_lld_serve_rx_end_irq,
591
@@ -564,22 +781,52 @@ void i2c_lld_start(I2CDriver *i2cp) {
592
                             (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq,
593
                             (void *)i2cp);
594
       osalDbgAssert(!b, "stream already allocated");
595
+#endif
596
+
597
       rccEnableI2C1(true);
598
       nvicEnableVector(I2C1_EV_IRQn, STM32_I2C_I2C1_IRQ_PRIORITY);
599
       nvicEnableVector(I2C1_ER_IRQn, STM32_I2C_I2C1_IRQ_PRIORITY);
600
 
601
+#if STM32_I2C_I2C1_USE_DMA
602
       i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C1_RX_DMA_CHANNEL) |
603
                        STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY);
604
       i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C1_TX_DMA_CHANNEL) |
605
                        STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY);
606
+
607
+      /* I2C registers pointed by the DMA.*/
608
+      dmaStreamSetPeripheral(i2cp->dmarx, &dp->DR);
609
+      dmaStreamSetPeripheral(i2cp->dmatx, &dp->DR);
610
+#endif
611
+
612
+      /* Reset i2c peripheral.*/
613
+      dp->CR1 = I2C_CR1_SWRST;
614
+      dp->CR1 = 0;
615
+#if STM32_I2C_I2C1_USE_DMA
616
+      dp->CR2 = I2C_CR2_ITERREN | I2C_CR2_DMAEN;
617
+#else
618
+      dp->CR2 = I2C_CR2_ITERREN;
619
+#endif
620
     }
621
 #endif /* STM32_I2C_USE_I2C1 */
622
 
623
 #if STM32_I2C_USE_I2C2
624
     if (&I2CD2 == i2cp) {
625
+#if STM32_I2C_I2C2_USE_DMA
626
       bool b;
627
 
628
+      i2cp->txdmamode = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE |
629
+                        STM32_DMA_CR_MINC       | STM32_DMA_CR_DMEIE |
630
+                        STM32_DMA_CR_TEIE       | STM32_DMA_CR_TCIE |
631
+                        STM32_DMA_CR_DIR_M2P;
632
+      i2cp->rxdmamode = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE |
633
+                        STM32_DMA_CR_MINC       | STM32_DMA_CR_DMEIE |
634
+                        STM32_DMA_CR_TEIE       | STM32_DMA_CR_TCIE |
635
+                        STM32_DMA_CR_DIR_P2M;
636
+#endif
637
+
638
       rccResetI2C2();
639
+
640
+#if STM32_I2C_I2C2_USE_DMA
641
       b = dmaStreamAllocate(i2cp->dmarx,
642
                             STM32_I2C_I2C2_IRQ_PRIORITY,
643
                             (stm32_dmaisr_t)i2c_lld_serve_rx_end_irq,
644
@@ -590,22 +837,52 @@ void i2c_lld_start(I2CDriver *i2cp) {
645
                             (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq,
646
                             (void *)i2cp);
647
       osalDbgAssert(!b, "stream already allocated");
648
+#endif
649
+
650
       rccEnableI2C2(true);
651
       nvicEnableVector(I2C2_EV_IRQn, STM32_I2C_I2C2_IRQ_PRIORITY);
652
       nvicEnableVector(I2C2_ER_IRQn, STM32_I2C_I2C2_IRQ_PRIORITY);
653
 
654
+#if STM32_I2C_I2C2_USE_DMA
655
       i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C2_RX_DMA_CHANNEL) |
656
                        STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY);
657
       i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C2_TX_DMA_CHANNEL) |
658
                        STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY);
659
+
660
+      /* I2C registers pointed by the DMA.*/
661
+      dmaStreamSetPeripheral(i2cp->dmarx, &dp->DR);
662
+      dmaStreamSetPeripheral(i2cp->dmatx, &dp->DR);
663
+#endif
664
+
665
+      /* Reset i2c peripheral.*/
666
+      dp->CR1 = I2C_CR1_SWRST;
667
+      dp->CR1 = 0;
668
+#if STM32_I2C_I2C2_USE_DMA
669
+      dp->CR2 = I2C_CR2_ITERREN | I2C_CR2_DMAEN;
670
+#else
671
+      dp->CR2 = I2C_CR2_ITERREN;
672
+#endif
673
     }
674
 #endif /* STM32_I2C_USE_I2C2 */
675
 
676
 #if STM32_I2C_USE_I2C3
677
     if (&I2CD3 == i2cp) {
678
+#if STM32_I2C_I2C3_USE_DMA
679
       bool b;
680
 
681
+      i2cp->txdmamode = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE |
682
+                        STM32_DMA_CR_MINC       | STM32_DMA_CR_DMEIE |
683
+                        STM32_DMA_CR_TEIE       | STM32_DMA_CR_TCIE |
684
+                        STM32_DMA_CR_DIR_M2P;
685
+      i2cp->rxdmamode = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE |
686
+                        STM32_DMA_CR_MINC       | STM32_DMA_CR_DMEIE |
687
+                        STM32_DMA_CR_TEIE       | STM32_DMA_CR_TCIE |
688
+                        STM32_DMA_CR_DIR_P2M;
689
+#endif
690
+
691
       rccResetI2C3();
692
+
693
+#if STM32_I2C_I2C3_USE_DMA
694
       b = dmaStreamAllocate(i2cp->dmarx,
695
                             STM32_I2C_I2C3_IRQ_PRIORITY,
696
                             (stm32_dmaisr_t)i2c_lld_serve_rx_end_irq,
697
@@ -616,27 +893,35 @@ void i2c_lld_start(I2CDriver *i2cp) {
698
                             (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq,
699
                             (void *)i2cp);
700
       osalDbgAssert(!b, "stream already allocated");
701
+#endif
702
+
703
       rccEnableI2C3(true);
704
       nvicEnableVector(I2C3_EV_IRQn, STM32_I2C_I2C3_IRQ_PRIORITY);
705
       nvicEnableVector(I2C3_ER_IRQn, STM32_I2C_I2C3_IRQ_PRIORITY);
706
 
707
+#if STM32_I2C_I2C3_USE_DMA
708
       i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C3_RX_DMA_CHANNEL) |
709
                        STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY);
710
       i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C3_TX_DMA_CHANNEL) |
711
                        STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY);
712
+
713
+      /* I2C registers pointed by the DMA.*/
714
+      dmaStreamSetPeripheral(i2cp->dmarx, &dp->DR);
715
+      dmaStreamSetPeripheral(i2cp->dmatx, &dp->DR);
716
+#endif
717
+
718
+      /* Reset i2c peripheral.*/
719
+      dp->CR1 = I2C_CR1_SWRST;
720
+      dp->CR1 = 0;
721
+#if STM32_I2C_I2C3_USE_DMA
722
+      dp->CR2 = I2C_CR2_ITERREN | I2C_CR2_DMAEN;
723
+#else
724
+      dp->CR2 = I2C_CR2_ITERREN;
725
+#endif
726
     }
727
 #endif /* STM32_I2C_USE_I2C3 */
728
   }
729
 
730
-  /* I2C registers pointed by the DMA.*/
731
-  dmaStreamSetPeripheral(i2cp->dmarx, &dp->DR);
732
-  dmaStreamSetPeripheral(i2cp->dmatx, &dp->DR);
733
-
734
-  /* Reset i2c peripheral.*/
735
-  dp->CR1 = I2C_CR1_SWRST;
736
-  dp->CR1 = 0;
737
-  dp->CR2 = I2C_CR2_ITERREN | I2C_CR2_DMAEN;
738
-
739
   /* Setup I2C parameters.*/
740
   i2c_lld_set_clock(i2cp);
741
   i2c_lld_set_opmode(i2cp);
742
@@ -659,11 +944,13 @@ void i2c_lld_stop(I2CDriver *i2cp) {
743
 
744
     /* I2C disable.*/
745
     i2c_lld_abort_operation(i2cp);
746
-    dmaStreamRelease(i2cp->dmatx);
747
-    dmaStreamRelease(i2cp->dmarx);
748
 
749
 #if STM32_I2C_USE_I2C1
750
     if (&I2CD1 == i2cp) {
751
+#if STM32_I2C_I2C1_USE_DMA
752
+      dmaStreamRelease(i2cp->dmatx);
753
+      dmaStreamRelease(i2cp->dmarx);
754
+ #endif
755
       nvicDisableVector(I2C1_EV_IRQn);
756
       nvicDisableVector(I2C1_ER_IRQn);
757
       rccDisableI2C1();
758
@@ -672,6 +959,10 @@ void i2c_lld_stop(I2CDriver *i2cp) {
759
 
760
 #if STM32_I2C_USE_I2C2
761
     if (&I2CD2 == i2cp) {
762
+#if STM32_I2C_I2C2_USE_DMA
763
+      dmaStreamRelease(i2cp->dmatx);
764
+      dmaStreamRelease(i2cp->dmarx);
765
+ #endif
766
       nvicDisableVector(I2C2_EV_IRQn);
767
       nvicDisableVector(I2C2_ER_IRQn);
768
       rccDisableI2C2();
769
@@ -680,6 +971,10 @@ void i2c_lld_stop(I2CDriver *i2cp) {
770
 
771
 #if STM32_I2C_USE_I2C3
772
     if (&I2CD3 == i2cp) {
773
+#if STM32_I2C_I2C3_USE_DMA
774
+      dmaStreamRelease(i2cp->dmatx);
775
+      dmaStreamRelease(i2cp->dmarx);
776
+ #endif
777
       nvicDisableVector(I2C3_EV_IRQn);
778
       nvicDisableVector(I2C3_ER_IRQn);
779
       rccDisableI2C3();
780
@@ -730,10 +1025,43 @@ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
781
   /* Releases the lock from high level driver.*/
782
   osalSysUnlock();
783
 
784
-  /* RX DMA setup.*/
785
-  dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
786
-  dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
787
-  dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
788
+  /* RX (DMA) setup.*/
789
+#if STM32_I2C_USE_I2C1
790
+  if (&I2CD1 == i2cp) {
791
+#if STM32_I2C_I2C1_USE_DMA
792
+    dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
793
+    dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
794
+    dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
795
+#else
796
+    i2cp->rxbuf = rxbuf;
797
+    i2cp->rxbytes = rxbytes;
798
+#endif
799
+  }
800
+#endif
801
+#if STM32_I2C_USE_I2C2
802
+  if (&I2CD2 == i2cp) {
803
+#if STM32_I2C_I2C2_USE_DMA
804
+    dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
805
+    dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
806
+    dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
807
+#else
808
+    i2cp->rxbuf = rxbuf;
809
+    i2cp->rxbytes = rxbytes;
810
+#endif
811
+  }
812
+#endif
813
+#if STM32_I2C_USE_I2C3
814
+  if (&I2CD3 == i2cp) {
815
+#if STM32_I2C_I2C3_USE_DMA
816
+    dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
817
+    dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
818
+    dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
819
+#else
820
+    i2cp->rxbuf = rxbuf;
821
+    i2cp->rxbytes = rxbytes;
822
+#endif
823
+  }
824
+#endif
825
 
826
   /* Calculating the time window for the timeout on the busy bus condition.*/
827
   start = osalOsGetSystemTimeX();
828
@@ -810,15 +1138,61 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
829
   /* Releases the lock from high level driver.*/
830
   osalSysUnlock();
831
 
832
-  /* TX DMA setup.*/
833
-  dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode);
834
-  dmaStreamSetMemory0(i2cp->dmatx, txbuf);
835
-  dmaStreamSetTransactionSize(i2cp->dmatx, txbytes);
836
-
837
-  /* RX DMA setup.*/
838
-  dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
839
-  dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
840
-  dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
841
+  /* TX (DMA) and RX (DMA) setup */
842
+#if STM32_I2C_USE_I2C1
843
+  if (&I2CD1 == i2cp) {
844
+#if STM32_I2C_I2C1_USE_DMA
845
+    dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode);
846
+    dmaStreamSetMemory0(i2cp->dmatx, txbuf);
847
+    dmaStreamSetTransactionSize(i2cp->dmatx, txbytes);
848
+
849
+    dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
850
+    dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
851
+    dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
852
+#else
853
+    i2cp->txbuf = txbuf;
854
+    i2cp->txbytes = txbytes;
855
+    i2cp->rxbuf = rxbuf;
856
+    i2cp->rxbytes = rxbytes;
857
+#endif
858
+  }
859
+#endif
860
+#if STM32_I2C_USE_I2C2
861
+  if (&I2CD2 == i2cp) {
862
+#if STM32_I2C_I2C2_USE_DMA
863
+    dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode);
864
+    dmaStreamSetMemory0(i2cp->dmatx, txbuf);
865
+    dmaStreamSetTransactionSize(i2cp->dmatx, txbytes);
866
+
867
+    dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
868
+    dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
869
+    dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
870
+#else
871
+    i2cp->txbuf = txbuf;
872
+    i2cp->txbytes = txbytes;
873
+    i2cp->rxbuf = rxbuf;
874
+    i2cp->rxbytes = rxbytes;
875
+#endif
876
+  }
877
+#endif
878
+#if STM32_I2C_USE_I2C3
879
+  if (&I2CD3 == i2cp) {
880
+#if STM32_I2C_I2C3_USE_DMA
881
+    dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode);
882
+    dmaStreamSetMemory0(i2cp->dmatx, txbuf);
883
+    dmaStreamSetTransactionSize(i2cp->dmatx, txbytes);
884
+
885
+    dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
886
+    dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
887
+    dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
888
+#else
889
+    i2cp->txbuf = txbuf;
890
+    i2cp->txbytes = txbytes;
891
+    i2cp->rxbuf = rxbuf;
892
+    i2cp->rxbytes = rxbytes;
893
+#endif
894
+  }
895
+#endif
896
 
897
   /* Calculating the time window for the timeout on the busy bus condition.*/
898
   start = osalOsGetSystemTimeX();
899
diff --git a/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h b/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h
900
index 1328d47..68f91e1 100644
901
--- a/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h
902
+++ b/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h
903
@@ -104,6 +104,33 @@
904
 #endif
905
 
906
 /**
907
+ * @brief   I2C1 DMA enable switch.
908
+ * @details If set to @p TRUE the I2C1 driver will use DMA.
909
+ * @note    The default is @p TRUE.
910
+ */
911
+#if !defined(STM32_I2C_I2C1_USE_DMA) || defined(__DOXYGEN__)
912
+#define STM32_I2C_I2C1_USE_DMA              TRUE
913
+#endif
914
+
915
+/**
916
+ * @brief   I2C2 DMA enable switch.
917
+ * @details If set to @p TRUE the I2C2 driver will use DMA.
918
+ * @note    The default is @p TRUE.
919
+ */
920
+#if !defined(STM32_I2C_I2C2_USE_DMA) || defined(__DOXYGEN__)
921
+#define STM32_I2C_I2C2_USE_DMA              TRUE
922
+#endif
923
+
924
+/**
925
+ * @brief   I2C3 DMA enable switch.
926
+ * @details If set to @p TRUE the I2C3 driver will use DMA.
927
+ * @note    The default is @p TRUE.
928
+ */
929
+#if !defined(STM32_I2C_I2C3_USE_DMA) || defined(__DOXYGEN__)
930
+#define STM32_I2C_I2C3_USE_DMA              TRUE
931
+#endif
932
+
933
+/**
934
 * @brief   I2C1 DMA priority (0..3|lowest..highest).
935
 * @note    The priority level is used for both the TX and RX DMA streams but
936
 *          because of the streams ordering the RX stream has always priority
937
@@ -250,16 +277,19 @@
938
 #endif
939
 
940
 #if STM32_I2C_USE_I2C1 &&                                                   \
941
+    STM32_I2C_I2C1_USE_DMA &&                                               \
942
     !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C1_DMA_PRIORITY)
943
 #error "Invalid DMA priority assigned to I2C1"
944
 #endif
945
 
946
 #if STM32_I2C_USE_I2C2 &&                                                   \
947
+    STM32_I2C_I2C2_USE_DMA &&                                               \
948
     !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C2_DMA_PRIORITY)
949
 #error "Invalid DMA priority assigned to I2C2"
950
 #endif
951
 
952
 #if STM32_I2C_USE_I2C3 &&                                                   \
953
+    STM32_I2C_I2C3_USE_DMA &&                                               \
954
     !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C3_DMA_PRIORITY)
955
 #error "Invalid DMA priority assigned to I2C3"
956
 #endif
957
@@ -316,7 +346,10 @@
958
 #endif
959
 #endif /* STM32_ADVANCED_DMA */
960
 
961
-#if !defined(STM32_DMA_REQUIRED)
962
+#if ((STM32_I2C_USE_I2C1 && STM32_I2C_I2C1_USE_DMA) ||                       \
963
+     (STM32_I2C_USE_I2C2 && STM32_I2C_I2C2_USE_DMA) ||                       \
964
+     (STM32_I2C_USE_I2C3 && STM32_I2C_I2C3_USE_DMA)) &&                      \
965
+    !defined(STM32_DMA_REQUIRED)
966
 #define STM32_DMA_REQUIRED
967
 #endif
968
 
969
@@ -437,21 +470,52 @@ struct I2CDriver {
970
    */
971
   i2caddr_t                 addr;
972
   /**
973
-   * @brief RX DMA mode bit mask.
974
-   */
975
-  uint32_t                  rxdmamode;
976
-  /**
977
-   * @brief TX DMA mode bit mask.
978
-   */
979
-  uint32_t                  txdmamode;
980
-  /**
981
-   * @brief     Receive DMA channel.
982
-   */
983
-  const stm32_dma_stream_t  *dmarx;
984
-  /**
985
-   * @brief     Transmit DMA channel.
986
+   * @brief   Anonymous union to store transmission related data for either DMA or non-DMA mode.
987
    */
988
-  const stm32_dma_stream_t  *dmatx;
989
+  union {
990
+    /**
991
+     * @brief   Anonymous struct to store data for DMA mode.
992
+     */
993
+    struct {
994
+      /**
995
+       * @brief RX DMA mode bit mask.
996
+       */
997
+      uint32_t                  rxdmamode;
998
+      /**
999
+       * @brief TX DMA mode bit mask.
1000
+       */
1001
+      uint32_t                  txdmamode;
1002
+      /**
1003
+       * @brief     Receive DMA channel.
1004
+       */
1005
+      const stm32_dma_stream_t  *dmarx;
1006
+      /**
1007
+       * @brief     Transmit DMA channel.
1008
+       */
1009
+      const stm32_dma_stream_t  *dmatx;
1010
+    };
1011
+    /**
1012
+     * @brief   Anonymous struct to store data for non-DMA mode.
1013
+     */
1014
+    struct {
1015
+      /**
1016
+       * @brief   Receive buffer.
1017
+       */
1018
+      uint8_t                   *rxbuf;
1019
+      /**
1020
+       * @brief   Size of the receive buffer.
1021
+       */
1022
+      size_t                    rxbytes;
1023
+      /**
1024
+       * @brief   Transmit buffer.
1025
+       */
1026
+      const uint8_t             *txbuf;
1027
+      /**
1028
+       * @brief   Size of the transmit buffer.
1029
+       */
1030
+      size_t                    txbytes;
1031
+    };
1032
+  };
1033
   /**
1034
    * @brief     Pointer to the I2Cx registers block.
1035
    */
1036
diff --git a/os/hal/ports/STM32/LLD/TIMv1/driver.mk b/os/hal/ports/STM32/LLD/TIMv1/driver.mk
1037
index 032d75a..13e3571 100644
1038
--- a/os/hal/ports/STM32/LLD/TIMv1/driver.mk
1039
+++ b/os/hal/ports/STM32/LLD/TIMv1/driver.mk
1040
@@ -10,10 +10,14 @@ endif
1041
 ifneq ($(findstring HAL_USE_PWM TRUE,$(HALCONF)),)
1042
 PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_pwm_lld.c
1043
 endif
1044
+ifneq ($(findstring HAL_USE_QEI TRUE,$(HALCONF)),)
1045
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_qei_lld.c
1046
+endif
1047
 else
1048
 PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_gpt_lld.c
1049
 PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_icu_lld.c
1050
 PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_pwm_lld.c
1051
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_qei_lld.c
1052
 endif
1053
 
1054
 PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1
1055
diff --git a/os/hal/ports/STM32/LLD/TIMv1/hal_qei_lld.c b/os/hal/ports/STM32/LLD/TIMv1/hal_qei_lld.c
1056
new file mode 100644
1057
index 0000000..700704a
1058
--- /dev/null
1059
+++ b/os/hal/ports/STM32/LLD/TIMv1/hal_qei_lld.c
1060
@@ -0,0 +1,302 @@
1061
+/*
1062
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
1063
+Copyright (C) 2016..2018  Thomas Schöpping et al.
1064
+
1065
+This program is free software: you can redistribute it and/or modify
1066
+it under the terms of the GNU General Public License as published by
1067
+the Free Software Foundation, either version 3 of the License, or
1068
+(at your option) any later version.
1069
+
1070
+This program is distributed in the hope that it will be useful,
1071
+but WITHOUT ANY WARRANTY; without even the implied warranty of
1072
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1073
+GNU General Public License for more details.
1074
+
1075
+You should have received a copy of the GNU General Public License
1076
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
1077
+*/
1078
+
1079
+/**
1080
+ * @file    STM32/hal_qei_lld.c
1081
+ * @brief   STM32 QEI subsystem low level driver.
1082
+ *
1083
+ * @addtogroup QEI
1084
+ * @{
1085
+ */
1086
+
1087
+#include "hal.h"
1088
+
1089
+#include "hal_qei.h"
1090
+
1091
+#if HAL_USE_QEI || defined(__DOXYGEN__)
1092
+
1093
+/*===========================================================================*/
1094
+/* Driver exported variables.                                                */
1095
+/*===========================================================================*/
1096
+
1097
+/**
1098
+ * @brief   QEID1 driver identifier.
1099
+ * @note    The driver QEID1 allocates the complex timer TIM1 when enabled.
1100
+ */
1101
+#if STM32_QEI_USE_TIM1 || defined(__DOXYGEN__)
1102
+QEIDriver QEID1;
1103
+#endif
1104
+
1105
+/**
1106
+ * @brief   QEID2 driver identifier.
1107
+ * @note    The driver QEID1 allocates the timer TIM2 when enabled.
1108
+ */
1109
+#if STM32_QEI_USE_TIM2 || defined(__DOXYGEN__)
1110
+QEIDriver QEID2;
1111
+#endif
1112
+
1113
+/**
1114
+ * @brief   QEID3 driver identifier.
1115
+ * @note    The driver QEID1 allocates the timer TIM3 when enabled.
1116
+ */
1117
+#if STM32_QEI_USE_TIM3 || defined(__DOXYGEN__)
1118
+QEIDriver QEID3;
1119
+#endif
1120
+
1121
+/**
1122
+ * @brief   QEID4 driver identifier.
1123
+ * @note    The driver QEID4 allocates the timer TIM4 when enabled.
1124
+ */
1125
+#if STM32_QEI_USE_TIM4 || defined(__DOXYGEN__)
1126
+QEIDriver QEID4;
1127
+#endif
1128
+
1129
+/**
1130
+ * @brief   QEID5 driver identifier.
1131
+ * @note    The driver QEID5 allocates the timer TIM5 when enabled.
1132
+ */
1133
+#if STM32_QEI_USE_TIM5 || defined(__DOXYGEN__)
1134
+QEIDriver QEID5;
1135
+#endif
1136
+
1137
+/**
1138
+ * @brief   QEID8 driver identifier.
1139
+ * @note    The driver QEID8 allocates the timer TIM8 when enabled.
1140
+ */
1141
+#if STM32_QEI_USE_TIM8 || defined(__DOXYGEN__)
1142
+QEIDriver QEID8;
1143
+#endif
1144
+
1145
+/*===========================================================================*/
1146
+/* Driver local variables.                                                   */
1147
+/*===========================================================================*/
1148
+
1149
+/*===========================================================================*/
1150
+/* Driver local functions.                                                   */
1151
+/*===========================================================================*/
1152
+
1153
+/*===========================================================================*/
1154
+/* Driver interrupt handlers.                                                */
1155
+/*===========================================================================*/
1156
+
1157
+/*===========================================================================*/
1158
+/* Driver exported functions.                                                */
1159
+/*===========================================================================*/
1160
+
1161
+/**
1162
+ * @brief   Low level QEI driver initialization.
1163
+ *
1164
+ * @notapi
1165
+ */
1166
+void qei_lld_init(void) {
1167
+
1168
+#if STM32_QEI_USE_TIM1
1169
+  /* Driver initialization.*/
1170
+  qeiObjectInit(&QEID1);
1171
+  QEID1.tim = STM32_TIM1;
1172
+#endif
1173
+
1174
+#if STM32_QEI_USE_TIM2
1175
+  /* Driver initialization.*/
1176
+  qeiObjectInit(&QEID2);
1177
+  QEID2.tim = STM32_TIM2;
1178
+#endif
1179
+
1180
+#if STM32_QEI_USE_TIM3
1181
+  /* Driver initialization.*/
1182
+  qeiObjectInit(&QEID3);
1183
+  QEID3.tim = STM32_TIM3;
1184
+#endif
1185
+
1186
+#if STM32_QEI_USE_TIM4
1187
+  /* Driver initialization.*/
1188
+  qeiObjectInit(&QEID4);
1189
+  QEID4.tim = STM32_TIM4;
1190
+#endif
1191
+
1192
+#if STM32_QEI_USE_TIM5
1193
+  /* Driver initialization.*/
1194
+  qeiObjectInit(&QEID5);
1195
+  QEID5.tim = STM32_TIM5;
1196
+#endif
1197
+
1198
+#if STM32_QEI_USE_TIM8
1199
+  /* Driver initialization.*/
1200
+  qeiObjectInit(&QEID8);
1201
+  QEID8.tim = STM32_TIM8;
1202
+#endif
1203
+}
1204
+
1205
+/**
1206
+ * @brief   Configures and activates the QEI peripheral.
1207
+ *
1208
+ * @param[in] qeip      pointer to the @p QEIDriver object
1209
+ *
1210
+ * @notapi
1211
+ */
1212
+void qei_lld_start(QEIDriver *qeip) {
1213
+  uint32_t arr, ccer;
1214
+
1215
+  if (qeip->state == QEI_STOP) {
1216
+    /* Clock activation and timer reset.*/
1217
+#if STM32_QEI_USE_TIM1
1218
+    if (&QEID1 == qeip) {
1219
+      rccEnableTIM1();
1220
+      rccResetTIM1();
1221
+    }
1222
+#endif
1223
+#if STM32_QEI_USE_TIM2
1224
+    if (&QEID2 == qeip) {
1225
+      rccEnableTIM2();
1226
+      rccResetTIM2();
1227
+    }
1228
+#endif
1229
+#if STM32_QEI_USE_TIM3
1230
+    if (&QEID3 == qeip) {
1231
+      rccEnableTIM3();
1232
+      rccResetTIM3();
1233
+    }
1234
+#endif
1235
+#if STM32_QEI_USE_TIM4
1236
+    if (&QEID4 == qeip) {
1237
+      rccEnableTIM4();
1238
+      rccResetTIM4();
1239
+    }
1240
+#endif
1241
+
1242
+#if STM32_QEI_USE_TIM5
1243
+    if (&QEID5 == qeip) {
1244
+      rccEnableTIM5();
1245
+      rccResetTIM5();
1246
+    }
1247
+#endif
1248
+#if STM32_QEI_USE_TIM8
1249
+    if (&QEID8 == qeip) {
1250
+      rccEnableTIM8();
1251
+      rccResetTIM8();
1252
+    }
1253
+#endif
1254
+  }
1255
+  else {
1256
+    /* Driver re-configuration scenario, it must be stopped first.*/
1257
+    qeip->tim->CR1    = 0;                  /* Timer disabled.              */
1258
+    qeip->tim->DIER   = 0;                  /* All IRQs disabled.           */
1259
+    qeip->tim->SR     = 0;                  /* Clear eventual pending IRQs. */
1260
+    qeip->tim->CCR[0] = 0;                  /* Comparator 1 disabled.       */
1261
+    qeip->tim->CCR[1] = 0;                  /* Comparator 2 disabled.       */
1262
+    qeip->tim->CNT    = 0;                  /* Counter reset to zero.       */
1263
+  }
1264
+
1265
+  /* Timer configuration.*/
1266
+  qeip->tim->PSC  = 0;
1267
+  arr = qeip->config->range - 1;
1268
+  osalDbgAssert((arr <= 0xFFFF), "qei_lld_start(), #1" /*, "invalid range"*/);
1269
+  qeip->tim->ARR  = arr & 0xFFFF;
1270
+
1271
+  /* CCMR1_CC1S = 01 - CH1 Input on TI1.
1272
+     CCMR1_CC2S = 01 - CH2 Input on TI2.*/
1273
+  qeip->tim->CCMR1 = TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_0;
1274
+
1275
+  ccer = 0;
1276
+  if (qeip->config->channels[0].mode == QEI_INPUT_INVERTED)
1277
+    ccer |= TIM_CCER_CC1P;
1278
+  if (qeip->config->channels[1].mode == QEI_INPUT_INVERTED)
1279
+    ccer |= TIM_CCER_CC2P;
1280
+  qeip->tim->CCER = ccer;
1281
+
1282
+  if (qeip->config->mode == QEI_COUNT_CH1)
1283
+    qeip->tim->SMCR  = TIM_SMCR_SMS_1;
1284
+  else if (qeip->config->mode == QEI_COUNT_CH2)
1285
+    qeip->tim->SMCR  = TIM_SMCR_SMS_0;
1286
+  else
1287
+    qeip->tim->SMCR  = TIM_SMCR_SMS_0 | TIM_SMCR_SMS_1;
1288
+}
1289
+
1290
+/**
1291
+ * @brief   Deactivates the QEI peripheral.
1292
+ *
1293
+ * @param[in] qeip      pointer to the @p QEIDriver object
1294
+ *
1295
+ * @notapi
1296
+ */
1297
+void qei_lld_stop(QEIDriver *qeip) {
1298
+
1299
+  if (qeip->state == QEI_READY) {
1300
+    /* Clock deactivation.*/
1301
+    qeip->tim->CR1  = 0;                    /* Timer disabled.              */
1302
+
1303
+#if STM32_QEI_USE_TIM1
1304
+    if (&QEID1 == qeip) {
1305
+      rccDisableTIM1();
1306
+    }
1307
+#endif
1308
+#if STM32_QEI_USE_TIM2
1309
+    if (&QEID2 == qeip) {
1310
+      rccDisableTIM2();
1311
+    }
1312
+#endif
1313
+#if STM32_QEI_USE_TIM3
1314
+    if (&QEID3 == qeip) {
1315
+      rccDisableTIM3();
1316
+    }
1317
+#endif
1318
+#if STM32_QEI_USE_TIM4
1319
+    if (&QEID4 == qeip) {
1320
+      rccDisableTIM4();
1321
+    }
1322
+#endif
1323
+#if STM32_QEI_USE_TIM5
1324
+    if (&QEID5 == qeip) {
1325
+      rccDisableTIM5();
1326
+    }
1327
+#endif
1328
+  }
1329
+#if STM32_QEI_USE_TIM8
1330
+    if (&QEID8 == qeip) {
1331
+      rccDisableTIM8();
1332
+    }
1333
+#endif
1334
+}
1335
+
1336
+/**
1337
+ * @brief   Enables the quadrature encoder.
1338
+ *
1339
+ * @param[in] qeip      pointer to the @p QEIDriver object
1340
+ *
1341
+ * @notapi
1342
+ */
1343
+void qei_lld_enable(QEIDriver *qeip) {
1344
+
1345
+  qeip->tim->CR1  = TIM_CR1_CEN;
1346
+}
1347
+
1348
+/**
1349
+ * @brief   Disables the quadrature encoder.
1350
+ *
1351
+ * @param[in] qeip      pointer to the @p QEIDriver object
1352
+ *
1353
+ * @notapi
1354
+ */
1355
+void qei_lld_disable(QEIDriver *qeip) {
1356
+
1357
+  qeip->tim->CR1  = 0;
1358
+}
1359
+
1360
+#endif /* HAL_USE_QEI */
1361
+
1362
+/** @} */
1363
diff --git a/os/hal/ports/STM32/LLD/TIMv1/hal_qei_lld.h b/os/hal/ports/STM32/LLD/TIMv1/hal_qei_lld.h
1364
new file mode 100644
1365
index 0000000..d4b7acc
1366
--- /dev/null
1367
+++ b/os/hal/ports/STM32/LLD/TIMv1/hal_qei_lld.h
1368
@@ -0,0 +1,302 @@
1369
+/*
1370
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
1371
+Copyright (C) 2016..2018  Thomas Schöpping et al.
1372
+
1373
+This program is free software: you can redistribute it and/or modify
1374
+it under the terms of the GNU General Public License as published by
1375
+the Free Software Foundation, either version 3 of the License, or
1376
+(at your option) any later version.
1377
+
1378
+This program is distributed in the hope that it will be useful,
1379
+but WITHOUT ANY WARRANTY; without even the implied warranty of
1380
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1381
+GNU General Public License for more details.
1382
+
1383
+You should have received a copy of the GNU General Public License
1384
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
1385
+*/
1386
+
1387
+/**
1388
+ * @file    STM32/hal_qei_lld.h
1389
+ * @brief   STM32 QEI subsystem low level driver header.
1390
+ *
1391
+ * @addtogroup QEI
1392
+ * @{
1393
+ */
1394
+
1395
+#ifndef _HAL_QEI_LLD_H_
1396
+#define _HAL_QEI_LLD_H_
1397
+
1398
+#include "stm32_tim.h"
1399
+
1400
+#if HAL_USE_QEI || defined(__DOXYGEN__)
1401
+
1402
+/*===========================================================================*/
1403
+/* Driver constants.                                                         */
1404
+/*===========================================================================*/
1405
+
1406
+/**
1407
+ * @brief   Number of input channels per QEI driver.
1408
+ */
1409
+#define QEI_CHANNELS                            2
1410
+
1411
+/*===========================================================================*/
1412
+/* Driver pre-compile time settings.                                         */
1413
+/*===========================================================================*/
1414
+
1415
+/**
1416
+ * @name    Configuration options
1417
+ * @{
1418
+ */
1419
+/**
1420
+ * @brief   QEID1 driver enable switch.
1421
+ * @details If set to @p TRUE the support for QEID1 is included.
1422
+ * @note    The default is @p TRUE.
1423
+ */
1424
+#if !defined(STM32_QEI_USE_TIM1) || defined(__DOXYGEN__)
1425
+#define STM32_QEI_USE_TIM1                  TRUE
1426
+#endif
1427
+
1428
+/**
1429
+ * @brief   QEID2 driver enable switch.
1430
+ * @details If set to @p TRUE the support for QEID2 is included.
1431
+ * @note    The default is @p TRUE.
1432
+ */
1433
+#if !defined(STM32_QEI_USE_TIM2) || defined(__DOXYGEN__)
1434
+#define STM32_QEI_USE_TIM2                  TRUE
1435
+#endif
1436
+
1437
+/**
1438
+ * @brief   QEID3 driver enable switch.
1439
+ * @details If set to @p TRUE the support for QEID3 is included.
1440
+ * @note    The default is @p TRUE.
1441
+ */
1442
+#if !defined(STM32_QEI_USE_TIM3) || defined(__DOXYGEN__)
1443
+#define STM32_QEI_USE_TIM3                  TRUE
1444
+#endif
1445
+
1446
+/**
1447
+ * @brief   QEID4 driver enable switch.
1448
+ * @details If set to @p TRUE the support for QEID4 is included.
1449
+ * @note    The default is @p TRUE.
1450
+ */
1451
+#if !defined(STM32_QEI_USE_TIM4) || defined(__DOXYGEN__)
1452
+#define STM32_QEI_USE_TIM4                  TRUE
1453
+#endif
1454
+
1455
+/**
1456
+ * @brief   QEID5 driver enable switch.
1457
+ * @details If set to @p TRUE the support for QEID5 is included.
1458
+ * @note    The default is @p TRUE.
1459
+ */
1460
+#if !defined(STM32_QEI_USE_TIM5) || defined(__DOXYGEN__)
1461
+#define STM32_QEI_USE_TIM5                  TRUE
1462
+#endif
1463
+
1464
+/**
1465
+ * @brief   QEID8 driver enable switch.
1466
+ * @details If set to @p TRUE the support for QEID8 is included.
1467
+ * @note    The default is @p TRUE.
1468
+ */
1469
+#if !defined(STM32_QEI_USE_TIM8) || defined(__DOXYGEN__)
1470
+#define STM32_QEI_USE_TIM8                  TRUE
1471
+#endif
1472
+/** @} */
1473
+
1474
+/*===========================================================================*/
1475
+/* Derived constants and error checks.                                       */
1476
+/*===========================================================================*/
1477
+
1478
+#if STM32_QEI_USE_TIM1 && !STM32_HAS_TIM1
1479
+#error "TIM1 not present in the selected device"
1480
+#endif
1481
+
1482
+#if STM32_QEI_USE_TIM2 && !STM32_HAS_TIM2
1483
+#error "TIM2 not present in the selected device"
1484
+#endif
1485
+
1486
+#if STM32_QEI_USE_TIM3 && !STM32_HAS_TIM3
1487
+#error "TIM3 not present in the selected device"
1488
+#endif
1489
+
1490
+#if STM32_QEI_USE_TIM4 && !STM32_HAS_TIM4
1491
+#error "TIM4 not present in the selected device"
1492
+#endif
1493
+
1494
+#if STM32_QEI_USE_TIM5 && !STM32_HAS_TIM5
1495
+#error "TIM5 not present in the selected device"
1496
+#endif
1497
+
1498
+#if STM32_QEI_USE_TIM8 && !STM32_HAS_TIM8
1499
+#error "TIM8 not present in the selected device"
1500
+#endif
1501
+
1502
+#if !STM32_QEI_USE_TIM1 && !STM32_QEI_USE_TIM2 &&                           \
1503
+    !STM32_QEI_USE_TIM3 && !STM32_QEI_USE_TIM4 &&                           \
1504
+    !STM32_QEI_USE_TIM5 && !STM32_QEI_USE_TIM8
1505
+#error "QEI driver activated but no TIM peripheral assigned"
1506
+#endif
1507
+
1508
+/*===========================================================================*/
1509
+/* Driver data structures and types.                                         */
1510
+/*===========================================================================*/
1511
+
1512
+/**
1513
+ * @brief QEI driver mode.
1514
+ */
1515
+typedef enum {
1516
+  QEI_COUNT_BOTH = 0,
1517
+  QEI_COUNT_CH1 = 1,
1518
+  QEI_COUNT_CH2 = 2,
1519
+} qeimode_t;
1520
+
1521
+/**
1522
+ * @brief QEI input mode.
1523
+ */
1524
+typedef enum {
1525
+  QEI_INPUT_NONINVERTED = 0, /**< Input channel noninverted.*/
1526
+  QEI_INPUT_INVERTED = 1, /**< Input channel inverted.*/
1527
+} qeiinputmode_t;
1528
+
1529
+/**
1530
+ * @brief   QEI count type.
1531
+ */
1532
+typedef uint32_t qeicnt_t;
1533
+
1534
+/**
1535
+ * @brief   Driver channel configuration structure.
1536
+ */
1537
+typedef struct {
1538
+  /**
1539
+   * @brief Channel input logic.
1540
+   */
1541
+  qeiinputmode_t                 mode;
1542
+  /* End of the mandatory fields.*/
1543
+} QEIChannelConfig;
1544
+
1545
+/**
1546
+ * @brief   Driver configuration structure.
1547
+ */
1548
+typedef struct {
1549
+  /**
1550
+   * @brief   Driver mode.
1551
+   */
1552
+  qeimode_t                 mode;
1553
+  /**
1554
+   * @brief   Channels configurations.
1555
+   */
1556
+  QEIChannelConfig          channels[QEI_CHANNELS];
1557
+  /**
1558
+   * @brief   Range in pulses.
1559
+   */
1560
+  qeicnt_t                  range;
1561
+  /* End of the mandatory fields.*/
1562
+} QEIConfig;
1563
+
1564
+/**
1565
+ * @brief   Structure representing an QEI driver.
1566
+ */
1567
+struct QEIDriver {
1568
+  /**
1569
+   * @brief Driver state.
1570
+   */
1571
+  qeistate_t                state;
1572
+  /**
1573
+   * @brief Current configuration data.
1574
+   */
1575
+  const QEIConfig           *config;
1576
+#if defined(QEI_DRIVER_EXT_FIELDS)
1577
+  QEI_DRIVER_EXT_FIELDS
1578
+#endif
1579
+  /* End of the mandatory fields.*/
1580
+  /**
1581
+   * @brief Pointer to the TIMx registers block.
1582
+   */
1583
+  stm32_tim_t               *tim;
1584
+};
1585
+
1586
+/*===========================================================================*/
1587
+/* Driver macros.                                                            */
1588
+/*===========================================================================*/
1589
+
1590
+/**
1591
+ * @brief   Returns the direction of the last transition.
1592
+ * @details The direction is defined as boolean and is
1593
+ *          calculated at each transition on any input.
1594
+ *
1595
+ * @param[in] qeip      pointer to the @p QEIDriver object
1596
+ * @return              The request direction.
1597
+ * @retval FALSE        Position counted up.
1598
+ * @retval TRUE         Position counted down.
1599
+ *
1600
+ * @iclass
1601
+ */
1602
+#define qei_lld_get_direction(qeip) !!((qeip)->tim->CR1 & TIM_CR1_DIR)
1603
+
1604
+/**
1605
+ * @brief   Returns the position of the encoder.
1606
+ * @details The position is defined as number of pulses since last reset.
1607
+ *
1608
+ * @param[in] qeip      pointer to the @p QEIDriver object
1609
+ * @return              The number of pulses.
1610
+ *
1611
+ * @iclass
1612
+ */
1613
+#define qei_lld_get_position(qeip) ((qeip)->tim->CNT)
1614
+
1615
+/**
1616
+ * @brief   Returns the range of the encoder.
1617
+ * @details The range is defined as number of maximum pulse count.
1618
+ *
1619
+ * @param[in] qeip      pointer to the @p QEIDriver object
1620
+ * @return              The number of pulses.
1621
+ *
1622
+ * @iclass
1623
+ */
1624
+#define qei_lld_get_range(qeip) ((qeip)->tim->ARR + 1)
1625
+
1626
+/*===========================================================================*/
1627
+/* External declarations.                                                    */
1628
+/*===========================================================================*/
1629
+
1630
+#if STM32_QEI_USE_TIM1 && !defined(__DOXYGEN__)
1631
+extern QEIDriver QEID1;
1632
+#endif
1633
+
1634
+#if STM32_QEI_USE_TIM2 && !defined(__DOXYGEN__)
1635
+extern QEIDriver QEID2;
1636
+#endif
1637
+
1638
+#if STM32_QEI_USE_TIM3 && !defined(__DOXYGEN__)
1639
+extern QEIDriver QEID3;
1640
+#endif
1641
+
1642
+#if STM32_QEI_USE_TIM4 && !defined(__DOXYGEN__)
1643
+extern QEIDriver QEID4;
1644
+#endif
1645
+
1646
+#if STM32_QEI_USE_TIM5 && !defined(__DOXYGEN__)
1647
+extern QEIDriver QEID5;
1648
+#endif
1649
+
1650
+#if STM32_QEI_USE_TIM8 && !defined(__DOXYGEN__)
1651
+extern QEIDriver QEID8;
1652
+#endif
1653
+
1654
+#ifdef __cplusplus
1655
+extern "C" {
1656
+#endif
1657
+  void qei_lld_init(void);
1658
+  void qei_lld_start(QEIDriver *qeip);
1659
+  void qei_lld_stop(QEIDriver *qeip);
1660
+  void qei_lld_enable(QEIDriver *qeip);
1661
+  void qei_lld_disable(QEIDriver *qeip);
1662
+#ifdef __cplusplus
1663
+}
1664
+#endif
1665
+
1666
+#endif /* HAL_USE_QEI */
1667
+
1668
+#endif /* _HAL_QEI_LLD_H_ */
1669
+
1670
+/** @} */
1671
diff --git a/os/hal/src/hal_qei.c b/os/hal/src/hal_qei.c
1672
new file mode 100644
1673
index 0000000..c08d175
1674
--- /dev/null
1675
+++ b/os/hal/src/hal_qei.c
1676
@@ -0,0 +1,156 @@
1677
+/*
1678
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
1679
+Copyright (C) 2016..2018  Thomas Schöpping et al.
1680
+
1681
+This program is free software: you can redistribute it and/or modify
1682
+it under the terms of the GNU General Public License as published by
1683
+the Free Software Foundation, either version 3 of the License, or
1684
+(at your option) any later version.
1685
+
1686
+This program is distributed in the hope that it will be useful,
1687
+but WITHOUT ANY WARRANTY; without even the implied warranty of
1688
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1689
+GNU General Public License for more details.
1690
+
1691
+You should have received a copy of the GNU General Public License
1692
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
1693
+*/
1694
+
1695
+/**
1696
+ * @file    hal_qei.c
1697
+ * @brief   QEI Driver code.
1698
+ *
1699
+ * @addtogroup QEI
1700
+ * @{
1701
+ */
1702
+
1703
+#include "hal.h"
1704
+#include "hal_qei.h"
1705
+
1706
+#if HAL_USE_QEI || defined(__DOXYGEN__)
1707
+
1708
+/*===========================================================================*/
1709
+/* Driver local definitions.                                                 */
1710
+/*===========================================================================*/
1711
+
1712
+/*===========================================================================*/
1713
+/* Driver exported variables.                                                */
1714
+/*===========================================================================*/
1715
+
1716
+/*===========================================================================*/
1717
+/* Driver local variables.                                                   */
1718
+/*===========================================================================*/
1719
+
1720
+/*===========================================================================*/
1721
+/* Driver local functions.                                                   */
1722
+/*===========================================================================*/
1723
+
1724
+/*===========================================================================*/
1725
+/* Driver exported functions.                                                */
1726
+/*===========================================================================*/
1727
+
1728
+/**
1729
+ * @brief   QEI Driver initialization.
1730
+ * @note    This function is implicitly invoked by @p halInit(), there is
1731
+ *          no need to explicitly initialize the driver.
1732
+ *
1733
+ * @init
1734
+ */
1735
+void qeiInit(void) {
1736
+
1737
+  qei_lld_init();
1738
+}
1739
+
1740
+/**
1741
+ * @brief   Initializes the standard part of a @p QEIDriver structure.
1742
+ *
1743
+ * @param[out] qeip     pointer to the @p QEIDriver object
1744
+ *
1745
+ * @init
1746
+ */
1747
+void qeiObjectInit(QEIDriver *qeip) {
1748
+
1749
+  qeip->state  = QEI_STOP;
1750
+  qeip->config = NULL;
1751
+}
1752
+
1753
+/**
1754
+ * @brief   Configures and activates the QEI peripheral.
1755
+ *
1756
+ * @param[in] qeip      pointer to the @p QEIDriver object
1757
+ * @param[in] config    pointer to the @p QEIConfig object
1758
+ *
1759
+ * @api
1760
+ */
1761
+void qeiStart(QEIDriver *qeip, const QEIConfig *config) {
1762
+
1763
+  chDbgCheck((qeip != NULL) && (config != NULL) /*, "qeiStart"*/);
1764
+
1765
+  chSysLock();
1766
+  chDbgAssert((qeip->state == QEI_STOP) || (qeip->state == QEI_READY),
1767
+              "qeiStart(), #1" /*, "invalid state"*/);
1768
+  qeip->config = config;
1769
+  qei_lld_start(qeip);
1770
+  qeip->state = QEI_READY;
1771
+  chSysUnlock();
1772
+}
1773
+
1774
+/**
1775
+ * @brief   Deactivates the QEI peripheral.
1776
+ *
1777
+ * @param[in] qeip      pointer to the @p QEIDriver object
1778
+ *
1779
+ * @api
1780
+ */
1781
+void qeiStop(QEIDriver *qeip) {
1782
+
1783
+  chDbgCheck(qeip != NULL /*, "qeiStop"*/);
1784
+
1785
+  chSysLock();
1786
+  chDbgAssert((qeip->state == QEI_STOP) || (qeip->state == QEI_READY),
1787
+              "qeiStop(), #1" /*, "invalid state"*/);
1788
+  qei_lld_stop(qeip);
1789
+  qeip->state = QEI_STOP;
1790
+  chSysUnlock();
1791
+}
1792
+
1793
+/**
1794
+ * @brief   Enables the quadrature encoder.
1795
+ *
1796
+ * @param[in] qeip      pointer to the @p QEIDriver object
1797
+ *
1798
+ * @api
1799
+ */
1800
+void qeiEnable(QEIDriver *qeip) {
1801
+
1802
+  chDbgCheck(qeip != NULL /*, "qeiEnable"*/);
1803
+
1804
+  chSysLock();
1805
+  chDbgAssert(qeip->state == QEI_READY, "qeiEnable(), #1" /*, "invalid state"*/);
1806
+  qei_lld_enable(qeip);
1807
+  qeip->state = QEI_ACTIVE;
1808
+  chSysUnlock();
1809
+}
1810
+
1811
+/**
1812
+ * @brief   Disables the quadrature encoder.
1813
+ *
1814
+ * @param[in] qeip      pointer to the @p QEIDriver object
1815
+ *
1816
+ * @api
1817
+ */
1818
+void qeiDisable(QEIDriver *qeip) {
1819
+
1820
+  chDbgCheck(qeip != NULL /*, "qeiDisable"*/);
1821
+
1822
+  chSysLock();
1823
+  chDbgAssert((qeip->state == QEI_READY) || (qeip->state == QEI_ACTIVE),
1824
+              "qeiDisable(), #1" /*, "invalid state"*/);
1825
+  qei_lld_disable(qeip);
1826
+  qeip->state = QEI_READY;
1827
+  chSysUnlock();
1828
+}
1829
+
1830
+#endif /* HAL_USE_QEI */
1831
+
1832
+/** @} */