Statistics
| Branch: | Tag: | Revision:

amiro-os / kernel / patches / QEI-driver.patch @ 7da800ab

History | View | Annotate | Download (28.371 KB)

1
diff --git a/os/hal/hal.mk b/os/hal/hal.mk
2
index f177a3f..64d96d9 100644
3
--- a/os/hal/hal.mk
4
+++ b/os/hal/hal.mk
5
@@ -41,6 +41,9 @@ endif
6
 ifneq ($(findstring HAL_USE_ICU TRUE,$(HALCONF)),)
7
 HALSRC += $(CHIBIOS)/os/hal/src/hal_icu.c
8
 endif
9
+ifneq ($(findstring HAL_USE_QEI TRUE,$(HALCONF)),)
10
+HALSRC += $(CHIBIOS)/os/hal/src/hal_qei.c
11
+endif
12
 ifneq ($(findstring HAL_USE_MAC TRUE,$(HALCONF)),)
13
 HALSRC += $(CHIBIOS)/os/hal/src/hal_mac.c
14
 endif
15
@@ -94,6 +97,7 @@ HALSRC = $(CHIBIOS)/os/hal/src/hal.c \
16
          $(CHIBIOS)/os/hal/src/hal_i2c.c \
17
          $(CHIBIOS)/os/hal/src/hal_i2s.c \
18
          $(CHIBIOS)/os/hal/src/hal_icu.c \
19
+         $(CHIBIOS)/os/hal/src/hal_qei.c \
20
          $(CHIBIOS)/os/hal/src/hal_mac.c \
21
          $(CHIBIOS)/os/hal/src/hal_mmc_spi.c \
22
          $(CHIBIOS)/os/hal/src/hal_pal.c \
23
diff --git a/os/hal/include/hal.h b/os/hal/include/hal.h
24
index 79f7c42..8cf221f 100644
25
--- a/os/hal/include/hal.h
26
+++ b/os/hal/include/hal.h
27
@@ -78,6 +78,10 @@
28
 #define HAL_USE_PWM                         FALSE
29
 #endif
30
 
31
+#if !defined(HAL_USE_QEI)
32
+#define HAL_USE_QEI                         FALSE
33
+#endif
34
+
35
 #if !defined(HAL_USE_QSPI)
36
 #define HAL_USE_QSPI                        FALSE
37
 #endif
38
@@ -138,6 +142,7 @@
39
 #include "hal_icu.h"
40
 #include "hal_mac.h"
41
 #include "hal_pwm.h"
42
+#include "hal_qei.h"
43
 #include "hal_qspi.h"
44
 #include "hal_rtc.h"
45
 #include "hal_serial.h"
46
diff --git a/os/hal/include/hal_qei.h b/os/hal/include/hal_qei.h
47
new file mode 100644
48
index 0000000..8769729
49
--- /dev/null
50
+++ b/os/hal/include/hal_qei.h
51
@@ -0,0 +1,148 @@
52
+/*
53
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
54
+Copyright (C) 2016..2018  Thomas Schöpping et al.
55
+
56
+This program is free software: you can redistribute it and/or modify
57
+it under the terms of the GNU General Public License as published by
58
+the Free Software Foundation, either version 3 of the License, or
59
+(at your option) any later version.
60
+
61
+This program is distributed in the hope that it will be useful,
62
+but WITHOUT ANY WARRANTY; without even the implied warranty of
63
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
64
+GNU General Public License for more details.
65
+
66
+You should have received a copy of the GNU General Public License
67
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
68
+*/
69
+
70
+/**
71
+ * @file    hal_qei.h
72
+ * @brief   QEI Driver macros and structures.
73
+ *
74
+ * @addtogroup QEI
75
+ * @{
76
+ */
77
+
78
+#ifndef HAL_QEI_H
79
+#define HAL_QEI_H
80
+
81
+#if (HAL_USE_QEI == TRUE) || defined(__DOXYGEN__)
82
+
83
+/*===========================================================================*/
84
+/* Driver constants.                                                         */
85
+/*===========================================================================*/
86
+
87
+/*===========================================================================*/
88
+/* Driver pre-compile time settings.                                         */
89
+/*===========================================================================*/
90
+
91
+/*===========================================================================*/
92
+/* Derived constants and error checks.                                       */
93
+/*===========================================================================*/
94
+
95
+/*===========================================================================*/
96
+/* Driver data structures and types.                                         */
97
+/*===========================================================================*/
98
+
99
+/**
100
+ * @brief   Driver state machine possible states.
101
+ */
102
+typedef enum {
103
+  QEI_UNINIT = 0,                   /**< Not initialized.                   */
104
+  QEI_STOP = 1,                     /**< Stopped.                           */
105
+  QEI_READY = 2,                    /**< Ready.                             */
106
+  QEI_ACTIVE = 4,                   /**< Active.                            */
107
+} qeistate_t;
108
+
109
+/**
110
+ * @brief   Type of a structure representing an QEI driver.
111
+ */
112
+typedef struct QEIDriver QEIDriver;
113
+
114
+#include "hal_qei_lld.h"
115
+
116
+/*===========================================================================*/
117
+/* Driver macros.                                                            */
118
+/*===========================================================================*/
119
+
120
+/**
121
+ * @name    Macro Functions
122
+ * @{
123
+ */
124
+/**
125
+ * @brief   Enables the quadrature encoder.
126
+ *
127
+ * @param[in] qeip      pointer to the @p QEIDriver object
128
+ *
129
+ * @iclass
130
+ */
131
+#define qeiEnableI(qeip) qei_lld_enable(qeip)
132
+
133
+/**
134
+ * @brief   Disables the quadrature encoder.
135
+ *
136
+ * @param[in] qeip      pointer to the @p QEIDriver object
137
+ *
138
+ * @iclass
139
+ */
140
+#define qeiDisableI(qeip) qei_lld_disable(qeip)
141
+
142
+/**
143
+ * @brief   Returns the direction of the last transition.
144
+ * @details The direction is defined as boolean and is
145
+ *          calculated at each transition on any input.
146
+ *
147
+ * @param[in] qeip      pointer to the @p QEIDriver object
148
+ * @return              The request direction.
149
+ * @retval FALSE        Position counted up.
150
+ * @retval TRUE         Position counted down.
151
+ * @iclass
152
+ */
153
+#define qeiGetDirectionI(qeip) qei_lld_get_direction(qeip)
154
+
155
+/**
156
+ * @brief   Returns the position of the encoder.
157
+ * @details The position is defined as number of pulses since last reset.
158
+ *
159
+ * @param[in] qeip      pointer to the @p QEIDriver object
160
+ * @return              The number of pulses.
161
+ *
162
+ * @iclass
163
+ */
164
+#define qeiGetPositionI(qeip) qei_lld_get_position(qeip)
165
+
166
+/**
167
+ * @brief   Returns the range of the encoder.
168
+ * @details The range is defined as number of maximum pulse count.
169
+ *
170
+ * @param[in] qeip      pointer to the @p QEIDriver object
171
+ * @return              The number of pulses.
172
+ *
173
+ * @iclass
174
+ */
175
+#define qeiGetRangeI(qeip) qei_lld_get_range(qeip)
176
+/** @} */
177
+
178
+/*===========================================================================*/
179
+/* External declarations.                                                    */
180
+/*===========================================================================*/
181
+
182
+#ifdef __cplusplus
183
+extern "C" {
184
+#endif
185
+  void qeiInit(void);
186
+  void qeiObjectInit(QEIDriver *qeip);
187
+  void qeiStart(QEIDriver *qeip, const QEIConfig *config);
188
+  void qeiStop(QEIDriver *qeip);
189
+  void qeiEnable(QEIDriver *qeip);
190
+  void qeiDisable(QEIDriver *qeip);
191
+#ifdef __cplusplus
192
+}
193
+#endif
194
+
195
+#endif /* HAL_USE_QEI */
196
+
197
+#endif /* HAL_QEI_H */
198
+
199
+/** @} */
200
diff --git a/os/hal/ports/STM32/LLD/TIMv1/driver.mk b/os/hal/ports/STM32/LLD/TIMv1/driver.mk
201
index 032d75a..13e3571 100644
202
--- a/os/hal/ports/STM32/LLD/TIMv1/driver.mk
203
+++ b/os/hal/ports/STM32/LLD/TIMv1/driver.mk
204
@@ -10,10 +10,14 @@ endif
205
 ifneq ($(findstring HAL_USE_PWM TRUE,$(HALCONF)),)
206
 PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_pwm_lld.c
207
 endif
208
+ifneq ($(findstring HAL_USE_QEI TRUE,$(HALCONF)),)
209
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_qei_lld.c
210
+endif
211
 else
212
 PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_gpt_lld.c
213
 PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_icu_lld.c
214
 PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_pwm_lld.c
215
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_qei_lld.c
216
 endif
217
 
218
 PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1
219
diff --git a/os/hal/ports/STM32/LLD/TIMv1/hal_qei_lld.c b/os/hal/ports/STM32/LLD/TIMv1/hal_qei_lld.c
220
new file mode 100644
221
index 0000000..cd1ab9b
222
--- /dev/null
223
+++ b/os/hal/ports/STM32/LLD/TIMv1/hal_qei_lld.c
224
@@ -0,0 +1,304 @@
225
+/*
226
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
227
+Copyright (C) 2016..2018  Thomas Schöpping et al.
228
+
229
+This program is free software: you can redistribute it and/or modify
230
+it under the terms of the GNU General Public License as published by
231
+the Free Software Foundation, either version 3 of the License, or
232
+(at your option) any later version.
233
+
234
+This program is distributed in the hope that it will be useful,
235
+but WITHOUT ANY WARRANTY; without even the implied warranty of
236
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
237
+GNU General Public License for more details.
238
+
239
+You should have received a copy of the GNU General Public License
240
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
241
+*/
242
+
243
+/**
244
+ * @file    STM32/hal_qei_lld.c
245
+ * @brief   STM32 QEI subsystem low level driver.
246
+ *
247
+ * @addtogroup QEI
248
+ * @{
249
+ */
250
+
251
+#include "hal.h"
252
+
253
+#if (HAL_USE_QEI == TRUE) || defined(__DOXYGEN__)
254
+
255
+/*===========================================================================*/
256
+/* Driver local definitions.                                                 */
257
+/*===========================================================================*/
258
+
259
+/*===========================================================================*/
260
+/* Driver exported variables.                                                */
261
+/*===========================================================================*/
262
+
263
+/**
264
+ * @brief   QEID1 driver identifier.
265
+ * @note    The driver QEID1 allocates the complex timer TIM1 when enabled.
266
+ */
267
+#if STM32_QEI_USE_TIM1 || defined(__DOXYGEN__)
268
+QEIDriver QEID1;
269
+#endif
270
+
271
+/**
272
+ * @brief   QEID2 driver identifier.
273
+ * @note    The driver QEID1 allocates the timer TIM2 when enabled.
274
+ */
275
+#if STM32_QEI_USE_TIM2 || defined(__DOXYGEN__)
276
+QEIDriver QEID2;
277
+#endif
278
+
279
+/**
280
+ * @brief   QEID3 driver identifier.
281
+ * @note    The driver QEID1 allocates the timer TIM3 when enabled.
282
+ */
283
+#if STM32_QEI_USE_TIM3 || defined(__DOXYGEN__)
284
+QEIDriver QEID3;
285
+#endif
286
+
287
+/**
288
+ * @brief   QEID4 driver identifier.
289
+ * @note    The driver QEID4 allocates the timer TIM4 when enabled.
290
+ */
291
+#if STM32_QEI_USE_TIM4 || defined(__DOXYGEN__)
292
+QEIDriver QEID4;
293
+#endif
294
+
295
+/**
296
+ * @brief   QEID5 driver identifier.
297
+ * @note    The driver QEID5 allocates the timer TIM5 when enabled.
298
+ */
299
+#if STM32_QEI_USE_TIM5 || defined(__DOXYGEN__)
300
+QEIDriver QEID5;
301
+#endif
302
+
303
+/**
304
+ * @brief   QEID8 driver identifier.
305
+ * @note    The driver QEID8 allocates the timer TIM8 when enabled.
306
+ */
307
+#if STM32_QEI_USE_TIM8 || defined(__DOXYGEN__)
308
+QEIDriver QEID8;
309
+#endif
310
+
311
+/*===========================================================================*/
312
+/* Driver local variables and types.                                         */
313
+/*===========================================================================*/
314
+
315
+/*===========================================================================*/
316
+/* Driver local functions.                                                   */
317
+/*===========================================================================*/
318
+
319
+/*===========================================================================*/
320
+/* Driver interrupt handlers.                                                */
321
+/*===========================================================================*/
322
+
323
+/*===========================================================================*/
324
+/* Driver exported functions.                                                */
325
+/*===========================================================================*/
326
+
327
+/**
328
+ * @brief   Low level QEI driver initialization.
329
+ *
330
+ * @notapi
331
+ */
332
+void qei_lld_init(void) {
333
+
334
+#if STM32_QEI_USE_TIM1
335
+  /* Driver initialization.*/
336
+  qeiObjectInit(&QEID1);
337
+  QEID1.tim = STM32_TIM1;
338
+#endif
339
+
340
+#if STM32_QEI_USE_TIM2
341
+  /* Driver initialization.*/
342
+  qeiObjectInit(&QEID2);
343
+  QEID2.tim = STM32_TIM2;
344
+#endif
345
+
346
+#if STM32_QEI_USE_TIM3
347
+  /* Driver initialization.*/
348
+  qeiObjectInit(&QEID3);
349
+  QEID3.tim = STM32_TIM3;
350
+#endif
351
+
352
+#if STM32_QEI_USE_TIM4
353
+  /* Driver initialization.*/
354
+  qeiObjectInit(&QEID4);
355
+  QEID4.tim = STM32_TIM4;
356
+#endif
357
+
358
+#if STM32_QEI_USE_TIM5
359
+  /* Driver initialization.*/
360
+  qeiObjectInit(&QEID5);
361
+  QEID5.tim = STM32_TIM5;
362
+#endif
363
+
364
+#if STM32_QEI_USE_TIM8
365
+  /* Driver initialization.*/
366
+  qeiObjectInit(&QEID8);
367
+  QEID8.tim = STM32_TIM8;
368
+#endif
369
+}
370
+
371
+/**
372
+ * @brief   Configures and activates the QEI peripheral.
373
+ *
374
+ * @param[in] qeip      pointer to the @p QEIDriver object
375
+ *
376
+ * @notapi
377
+ */
378
+void qei_lld_start(QEIDriver *qeip) {
379
+  uint32_t arr, ccer;
380
+
381
+  if (qeip->state == QEI_STOP) {
382
+    /* Clock activation and timer reset.*/
383
+#if STM32_QEI_USE_TIM1
384
+    if (&QEID1 == qeip) {
385
+      rccEnableTIM1();
386
+      rccResetTIM1();
387
+    }
388
+#endif
389
+#if STM32_QEI_USE_TIM2
390
+    if (&QEID2 == qeip) {
391
+      rccEnableTIM2();
392
+      rccResetTIM2();
393
+    }
394
+#endif
395
+#if STM32_QEI_USE_TIM3
396
+    if (&QEID3 == qeip) {
397
+      rccEnableTIM3();
398
+      rccResetTIM3();
399
+    }
400
+#endif
401
+#if STM32_QEI_USE_TIM4
402
+    if (&QEID4 == qeip) {
403
+      rccEnableTIM4();
404
+      rccResetTIM4();
405
+    }
406
+#endif
407
+
408
+#if STM32_QEI_USE_TIM5
409
+    if (&QEID5 == qeip) {
410
+      rccEnableTIM5();
411
+      rccResetTIM5();
412
+    }
413
+#endif
414
+#if STM32_QEI_USE_TIM8
415
+    if (&QEID8 == qeip) {
416
+      rccEnableTIM8();
417
+      rccResetTIM8();
418
+    }
419
+#endif
420
+  }
421
+  else {
422
+    /* Driver re-configuration scenario, it must be stopped first.*/
423
+    qeip->tim->CR1    = 0;                  /* Timer disabled.              */
424
+    qeip->tim->DIER   = 0;                  /* All IRQs disabled.           */
425
+    qeip->tim->SR     = 0;                  /* Clear eventual pending IRQs. */
426
+    qeip->tim->CCR[0] = 0;                  /* Comparator 1 disabled.       */
427
+    qeip->tim->CCR[1] = 0;                  /* Comparator 2 disabled.       */
428
+    qeip->tim->CNT    = 0;                  /* Counter reset to zero.       */
429
+  }
430
+
431
+  /* Timer configuration.*/
432
+  qeip->tim->PSC  = 0;
433
+  arr = qeip->config->range - 1;
434
+  osalDbgAssert((arr <= 0xFFFF), "invalid range");
435
+  qeip->tim->ARR  = arr & 0xFFFF;
436
+
437
+  /* CCMR1_CC1S = 01 - CH1 Input on TI1.
438
+     CCMR1_CC2S = 01 - CH2 Input on TI2.*/
439
+  qeip->tim->CCMR1 = TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_0;
440
+
441
+  ccer = 0;
442
+  if (qeip->config->channels[0].mode == QEI_INPUT_INVERTED)
443
+    ccer |= TIM_CCER_CC1P;
444
+  if (qeip->config->channels[1].mode == QEI_INPUT_INVERTED)
445
+    ccer |= TIM_CCER_CC2P;
446
+  qeip->tim->CCER = ccer;
447
+
448
+  if (qeip->config->mode == QEI_COUNT_CH1)
449
+    qeip->tim->SMCR  = TIM_SMCR_SMS_1;
450
+  else if (qeip->config->mode == QEI_COUNT_CH2)
451
+    qeip->tim->SMCR  = TIM_SMCR_SMS_0;
452
+  else
453
+    qeip->tim->SMCR  = TIM_SMCR_SMS_0 | TIM_SMCR_SMS_1;
454
+}
455
+
456
+/**
457
+ * @brief   Deactivates the QEI peripheral.
458
+ *
459
+ * @param[in] qeip      pointer to the @p QEIDriver object
460
+ *
461
+ * @notapi
462
+ */
463
+void qei_lld_stop(QEIDriver *qeip) {
464
+
465
+  if (qeip->state == QEI_READY) {
466
+    /* Clock deactivation.*/
467
+    qeip->tim->CR1  = 0;                    /* Timer disabled.              */
468
+
469
+#if STM32_QEI_USE_TIM1
470
+    if (&QEID1 == qeip) {
471
+      rccDisableTIM1();
472
+    }
473
+#endif
474
+#if STM32_QEI_USE_TIM2
475
+    if (&QEID2 == qeip) {
476
+      rccDisableTIM2();
477
+    }
478
+#endif
479
+#if STM32_QEI_USE_TIM3
480
+    if (&QEID3 == qeip) {
481
+      rccDisableTIM3();
482
+    }
483
+#endif
484
+#if STM32_QEI_USE_TIM4
485
+    if (&QEID4 == qeip) {
486
+      rccDisableTIM4();
487
+    }
488
+#endif
489
+#if STM32_QEI_USE_TIM5
490
+    if (&QEID5 == qeip) {
491
+      rccDisableTIM5();
492
+    }
493
+#endif
494
+  }
495
+#if STM32_QEI_USE_TIM8
496
+    if (&QEID8 == qeip) {
497
+      rccDisableTIM8();
498
+    }
499
+#endif
500
+}
501
+
502
+/**
503
+ * @brief   Enables the quadrature encoder.
504
+ *
505
+ * @param[in] qeip      pointer to the @p QEIDriver object
506
+ *
507
+ * @notapi
508
+ */
509
+void qei_lld_enable(QEIDriver *qeip) {
510
+
511
+  qeip->tim->CR1  = TIM_CR1_CEN;
512
+}
513
+
514
+/**
515
+ * @brief   Disables the quadrature encoder.
516
+ *
517
+ * @param[in] qeip      pointer to the @p QEIDriver object
518
+ *
519
+ * @notapi
520
+ */
521
+void qei_lld_disable(QEIDriver *qeip) {
522
+
523
+  qeip->tim->CR1  = 0;
524
+}
525
+
526
+#endif /* HAL_USE_QEI */
527
+
528
+/** @} */
529
diff --git a/os/hal/ports/STM32/LLD/TIMv1/hal_qei_lld.h b/os/hal/ports/STM32/LLD/TIMv1/hal_qei_lld.h
530
new file mode 100644
531
index 0000000..ec1cd42
532
--- /dev/null
533
+++ b/os/hal/ports/STM32/LLD/TIMv1/hal_qei_lld.h
534
@@ -0,0 +1,302 @@
535
+/*
536
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
537
+Copyright (C) 2016..2018  Thomas Schöpping et al.
538
+
539
+This program is free software: you can redistribute it and/or modify
540
+it under the terms of the GNU General Public License as published by
541
+the Free Software Foundation, either version 3 of the License, or
542
+(at your option) any later version.
543
+
544
+This program is distributed in the hope that it will be useful,
545
+but WITHOUT ANY WARRANTY; without even the implied warranty of
546
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
547
+GNU General Public License for more details.
548
+
549
+You should have received a copy of the GNU General Public License
550
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
551
+*/
552
+
553
+/**
554
+ * @file    STM32/hal_qei_lld.h
555
+ * @brief   STM32 QEI subsystem low level driver header.
556
+ *
557
+ * @addtogroup QEI
558
+ * @{
559
+ */
560
+
561
+#ifndef HAL_QEI_LLD_H
562
+#define HAL_QEI_LLD_H
563
+
564
+#if (HAL_USE_QEI == TRUE) || defined(__DOXYGEN__)
565
+
566
+#include "stm32_tim.h"
567
+
568
+/*===========================================================================*/
569
+/* Driver constants.                                                         */
570
+/*===========================================================================*/
571
+
572
+/**
573
+ * @brief   Number of input channels per QEI driver.
574
+ */
575
+#define QEI_CHANNELS                            2
576
+
577
+/*===========================================================================*/
578
+/* Driver pre-compile time settings.                                         */
579
+/*===========================================================================*/
580
+
581
+/**
582
+ * @name    Configuration options
583
+ * @{
584
+ */
585
+/**
586
+ * @brief   QEID1 driver enable switch.
587
+ * @details If set to @p TRUE the support for QEID1 is included.
588
+ * @note    The default is @p TRUE.
589
+ */
590
+#if !defined(STM32_QEI_USE_TIM1) || defined(__DOXYGEN__)
591
+#define STM32_QEI_USE_TIM1                  FALSE
592
+#endif
593
+
594
+/**
595
+ * @brief   QEID2 driver enable switch.
596
+ * @details If set to @p TRUE the support for QEID2 is included.
597
+ * @note    The default is @p TRUE.
598
+ */
599
+#if !defined(STM32_QEI_USE_TIM2) || defined(__DOXYGEN__)
600
+#define STM32_QEI_USE_TIM2                  FALSE
601
+#endif
602
+
603
+/**
604
+ * @brief   QEID3 driver enable switch.
605
+ * @details If set to @p TRUE the support for QEID3 is included.
606
+ * @note    The default is @p TRUE.
607
+ */
608
+#if !defined(STM32_QEI_USE_TIM3) || defined(__DOXYGEN__)
609
+#define STM32_QEI_USE_TIM3                  FALSE
610
+#endif
611
+
612
+/**
613
+ * @brief   QEID4 driver enable switch.
614
+ * @details If set to @p TRUE the support for QEID4 is included.
615
+ * @note    The default is @p TRUE.
616
+ */
617
+#if !defined(STM32_QEI_USE_TIM4) || defined(__DOXYGEN__)
618
+#define STM32_QEI_USE_TIM4                  FALSE
619
+#endif
620
+
621
+/**
622
+ * @brief   QEID5 driver enable switch.
623
+ * @details If set to @p TRUE the support for QEID5 is included.
624
+ * @note    The default is @p TRUE.
625
+ */
626
+#if !defined(STM32_QEI_USE_TIM5) || defined(__DOXYGEN__)
627
+#define STM32_QEI_USE_TIM5                  FALSE
628
+#endif
629
+
630
+/**
631
+ * @brief   QEID8 driver enable switch.
632
+ * @details If set to @p TRUE the support for QEID8 is included.
633
+ * @note    The default is @p TRUE.
634
+ */
635
+#if !defined(STM32_QEI_USE_TIM8) || defined(__DOXYGEN__)
636
+#define STM32_QEI_USE_TIM8                  FALSE
637
+#endif
638
+/** @} */
639
+
640
+/*===========================================================================*/
641
+/* Derived constants and error checks.                                       */
642
+/*===========================================================================*/
643
+
644
+#if STM32_QEI_USE_TIM1 && !STM32_HAS_TIM1
645
+#error "TIM1 not present in the selected device"
646
+#endif
647
+
648
+#if STM32_QEI_USE_TIM2 && !STM32_HAS_TIM2
649
+#error "TIM2 not present in the selected device"
650
+#endif
651
+
652
+#if STM32_QEI_USE_TIM3 && !STM32_HAS_TIM3
653
+#error "TIM3 not present in the selected device"
654
+#endif
655
+
656
+#if STM32_QEI_USE_TIM4 && !STM32_HAS_TIM4
657
+#error "TIM4 not present in the selected device"
658
+#endif
659
+
660
+#if STM32_QEI_USE_TIM5 && !STM32_HAS_TIM5
661
+#error "TIM5 not present in the selected device"
662
+#endif
663
+
664
+#if STM32_QEI_USE_TIM8 && !STM32_HAS_TIM8
665
+#error "TIM8 not present in the selected device"
666
+#endif
667
+
668
+#if !STM32_QEI_USE_TIM1 && !STM32_QEI_USE_TIM2 &&                           \
669
+    !STM32_QEI_USE_TIM3 && !STM32_QEI_USE_TIM4 &&                           \
670
+    !STM32_QEI_USE_TIM5 && !STM32_QEI_USE_TIM8
671
+#error "QEI driver activated but no TIM peripheral assigned"
672
+#endif
673
+
674
+/*===========================================================================*/
675
+/* Driver data structures and types.                                         */
676
+/*===========================================================================*/
677
+
678
+/**
679
+ * @brief QEI driver mode.
680
+ */
681
+typedef enum {
682
+  QEI_COUNT_BOTH = 0,
683
+  QEI_COUNT_CH1 = 1,
684
+  QEI_COUNT_CH2 = 2,
685
+} qeimode_t;
686
+
687
+/**
688
+ * @brief QEI input mode.
689
+ */
690
+typedef enum {
691
+  QEI_INPUT_NONINVERTED = 0, /**< Input channel noninverted.*/
692
+  QEI_INPUT_INVERTED = 1, /**< Input channel inverted.*/
693
+} qeiinputmode_t;
694
+
695
+/**
696
+ * @brief   QEI count type.
697
+ */
698
+typedef uint32_t qeicnt_t;
699
+
700
+/**
701
+ * @brief   Driver channel configuration structure.
702
+ */
703
+typedef struct {
704
+  /**
705
+   * @brief Channel input logic.
706
+   */
707
+  qeiinputmode_t                 mode;
708
+  /* End of the mandatory fields.*/
709
+} QEIChannelConfig;
710
+
711
+/**
712
+ * @brief   Driver configuration structure.
713
+ */
714
+typedef struct {
715
+  /**
716
+   * @brief   Driver mode.
717
+   */
718
+  qeimode_t                 mode;
719
+  /**
720
+   * @brief   Channels configurations.
721
+   */
722
+  QEIChannelConfig          channels[QEI_CHANNELS];
723
+  /**
724
+   * @brief   Range in pulses.
725
+   */
726
+  qeicnt_t                  range;
727
+  /* End of the mandatory fields.*/
728
+} QEIConfig;
729
+
730
+/**
731
+ * @brief   Structure representing an QEI driver.
732
+ */
733
+struct QEIDriver {
734
+  /**
735
+   * @brief Driver state.
736
+   */
737
+  qeistate_t                state;
738
+  /**
739
+   * @brief Current configuration data.
740
+   */
741
+  const QEIConfig           *config;
742
+#if defined(QEI_DRIVER_EXT_FIELDS)
743
+  QEI_DRIVER_EXT_FIELDS
744
+#endif
745
+  /* End of the mandatory fields.*/
746
+  /**
747
+   * @brief Pointer to the TIMx registers block.
748
+   */
749
+  stm32_tim_t               *tim;
750
+};
751
+
752
+/*===========================================================================*/
753
+/* Driver macros.                                                            */
754
+/*===========================================================================*/
755
+
756
+/**
757
+ * @brief   Returns the direction of the last transition.
758
+ * @details The direction is defined as boolean and is
759
+ *          calculated at each transition on any input.
760
+ *
761
+ * @param[in] qeip      pointer to the @p QEIDriver object
762
+ * @return              The request direction.
763
+ * @retval FALSE        Position counted up.
764
+ * @retval TRUE         Position counted down.
765
+ *
766
+ * @iclass
767
+ */
768
+#define qei_lld_get_direction(qeip) !!((qeip)->tim->CR1 & TIM_CR1_DIR)
769
+
770
+/**
771
+ * @brief   Returns the position of the encoder.
772
+ * @details The position is defined as number of pulses since last reset.
773
+ *
774
+ * @param[in] qeip      pointer to the @p QEIDriver object
775
+ * @return              The number of pulses.
776
+ *
777
+ * @iclass
778
+ */
779
+#define qei_lld_get_position(qeip) ((qeip)->tim->CNT)
780
+
781
+/**
782
+ * @brief   Returns the range of the encoder.
783
+ * @details The range is defined as number of maximum pulse count.
784
+ *
785
+ * @param[in] qeip      pointer to the @p QEIDriver object
786
+ * @return              The number of pulses.
787
+ *
788
+ * @iclass
789
+ */
790
+#define qei_lld_get_range(qeip) ((qeip)->tim->ARR + 1)
791
+
792
+/*===========================================================================*/
793
+/* External declarations.                                                    */
794
+/*===========================================================================*/
795
+
796
+#if STM32_QEI_USE_TIM1 && !defined(__DOXYGEN__)
797
+extern QEIDriver QEID1;
798
+#endif
799
+
800
+#if STM32_QEI_USE_TIM2 && !defined(__DOXYGEN__)
801
+extern QEIDriver QEID2;
802
+#endif
803
+
804
+#if STM32_QEI_USE_TIM3 && !defined(__DOXYGEN__)
805
+extern QEIDriver QEID3;
806
+#endif
807
+
808
+#if STM32_QEI_USE_TIM4 && !defined(__DOXYGEN__)
809
+extern QEIDriver QEID4;
810
+#endif
811
+
812
+#if STM32_QEI_USE_TIM5 && !defined(__DOXYGEN__)
813
+extern QEIDriver QEID5;
814
+#endif
815
+
816
+#if STM32_QEI_USE_TIM8 && !defined(__DOXYGEN__)
817
+extern QEIDriver QEID8;
818
+#endif
819
+
820
+#ifdef __cplusplus
821
+extern "C" {
822
+#endif
823
+  void qei_lld_init(void);
824
+  void qei_lld_start(QEIDriver *qeip);
825
+  void qei_lld_stop(QEIDriver *qeip);
826
+  void qei_lld_enable(QEIDriver *qeip);
827
+  void qei_lld_disable(QEIDriver *qeip);
828
+#ifdef __cplusplus
829
+}
830
+#endif
831
+
832
+#endif /* HAL_USE_QEI */
833
+
834
+#endif /* HAL_QEI_LLD_H */
835
+
836
+/** @} */
837
diff --git a/os/hal/src/hal_qei.c b/os/hal/src/hal_qei.c
838
new file mode 100644
839
index 0000000..00334bb
840
--- /dev/null
841
+++ b/os/hal/src/hal_qei.c
842
@@ -0,0 +1,152 @@
843
+/*
844
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
845
+Copyright (C) 2016..2018  Thomas Schöpping et al.
846
+
847
+This program is free software: you can redistribute it and/or modify
848
+it under the terms of the GNU General Public License as published by
849
+the Free Software Foundation, either version 3 of the License, or
850
+(at your option) any later version.
851
+
852
+This program is distributed in the hope that it will be useful,
853
+but WITHOUT ANY WARRANTY; without even the implied warranty of
854
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
855
+GNU General Public License for more details.
856
+
857
+You should have received a copy of the GNU General Public License
858
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
859
+*/
860
+
861
+/**
862
+ * @file    hal_qei.c
863
+ * @brief   QEI Driver code.
864
+ *
865
+ * @addtogroup QEI
866
+ * @{
867
+ */
868
+
869
+#include "hal.h"
870
+
871
+#if (HAL_USE_QEI == TRUE) || defined(__DOXYGEN__)
872
+
873
+/*===========================================================================*/
874
+/* Driver local definitions.                                                 */
875
+/*===========================================================================*/
876
+
877
+/*===========================================================================*/
878
+/* Driver exported variables.                                                */
879
+/*===========================================================================*/
880
+
881
+/*===========================================================================*/
882
+/* Driver local variables.                                                   */
883
+/*===========================================================================*/
884
+
885
+/*===========================================================================*/
886
+/* Driver local functions.                                                   */
887
+/*===========================================================================*/
888
+
889
+/*===========================================================================*/
890
+/* Driver exported functions.                                                */
891
+/*===========================================================================*/
892
+
893
+/**
894
+ * @brief   QEI Driver initialization.
895
+ * @note    This function is implicitly invoked by @p halInit(), there is
896
+ *          no need to explicitly initialize the driver.
897
+ *
898
+ * @init
899
+ */
900
+void qeiInit(void) {
901
+
902
+  qei_lld_init();
903
+}
904
+
905
+/**
906
+ * @brief   Initializes the standard part of a @p QEIDriver structure.
907
+ *
908
+ * @param[out] qeip     pointer to the @p QEIDriver object
909
+ *
910
+ * @init
911
+ */
912
+void qeiObjectInit(QEIDriver *qeip) {
913
+
914
+  qeip->state  = QEI_STOP;
915
+  qeip->config = NULL;
916
+}
917
+
918
+/**
919
+ * @brief   Configures and activates the QEI peripheral.
920
+ *
921
+ * @param[in] qeip      pointer to the @p QEIDriver object
922
+ * @param[in] config    pointer to the @p QEIConfig object
923
+ *
924
+ * @api
925
+ */
926
+void qeiStart(QEIDriver *qeip, const QEIConfig *config) {
927
+
928
+  osalDbgCheck((qeip != NULL) && (config != NULL));
929
+
930
+  osalSysLock();
931
+  osalDbgAssert((qeip->state == QEI_STOP) || (qeip->state == QEI_READY), "invalid state");
932
+  qeip->config = config;
933
+  qei_lld_start(qeip);
934
+  qeip->state = QEI_READY;
935
+  osalSysUnlock();
936
+}
937
+
938
+/**
939
+ * @brief   Deactivates the QEI peripheral.
940
+ *
941
+ * @param[in] qeip      pointer to the @p QEIDriver object
942
+ *
943
+ * @api
944
+ */
945
+void qeiStop(QEIDriver *qeip) {
946
+
947
+  osalDbgCheck(qeip != NULL);
948
+
949
+  osalSysLock();
950
+  osalDbgAssert((qeip->state == QEI_STOP) || (qeip->state == QEI_READY), "invalid state");
951
+  qei_lld_stop(qeip);
952
+  qeip->state = QEI_STOP;
953
+  osalSysUnlock();
954
+}
955
+
956
+/**
957
+ * @brief   Enables the quadrature encoder.
958
+ *
959
+ * @param[in] qeip      pointer to the @p QEIDriver object
960
+ *
961
+ * @api
962
+ */
963
+void qeiEnable(QEIDriver *qeip) {
964
+
965
+  osalDbgCheck(qeip != NULL);
966
+
967
+  osalSysLock();
968
+  osalDbgAssert(qeip->state == QEI_READY, "invalid state");
969
+  qei_lld_enable(qeip);
970
+  qeip->state = QEI_ACTIVE;
971
+  osalSysUnlock();
972
+}
973
+
974
+/**
975
+ * @brief   Disables the quadrature encoder.
976
+ *
977
+ * @param[in] qeip      pointer to the @p QEIDriver object
978
+ *
979
+ * @api
980
+ */
981
+void qeiDisable(QEIDriver *qeip) {
982
+
983
+  osalDbgCheck(qeip != NULL);
984
+
985
+  osalSysLock();
986
+  osalDbgAssert((qeip->state == QEI_READY) || (qeip->state == QEI_ACTIVE), "invalid state");
987
+  qei_lld_disable(qeip);
988
+  qeip->state = QEI_READY;
989
+  osalSysUnlock();
990
+}
991
+
992
+#endif /* HAL_USE_QEI */
993
+
994
+/** @} */