Statistics
| Branch: | Tag: | Revision:

amiro-os / kernel / patches / QEI-driver.patch @ 23ec8223

History | View | Annotate | Download (28.646 KB)

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