aboutsummaryrefslogtreecommitdiffstats
path: root/libmaple/include/libmaple/timer.h
blob: 7c1b2f08ab16cf4a5ef721da366489112cf70af0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
/******************************************************************************
 * The MIT License
 *
 * Copyright (c) 2011, 2012 LeafLabs, LLC.
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *****************************************************************************/

/**
 * @file   libmaple/include/libmaple/timer.h
 * @author Marti Bolivar <mbolivar@leaflabs.com>
 * @brief  Timer interface.
 */

#ifndef _LIBMAPLE_TIMER_H_
#define _LIBMAPLE_TIMER_H_

#ifdef __cplusplus
extern "C"{
#endif

#include <series/timer.h>
#include <libmaple/libmaple.h>
#include <libmaple/rcc.h>
#include <libmaple/nvic.h>
#include <libmaple/bitband.h>

/*
 * Register maps
 */

/** Advanced control timer register map type */
typedef struct timer_adv_reg_map {
    __io uint32 CR1;            /**< Control register 1 */
    __io uint32 CR2;            /**< Control register 2 */
    __io uint32 SMCR;           /**< Slave mode control register */
    __io uint32 DIER;           /**< DMA/interrupt enable register */
    __io uint32 SR;             /**< Status register */
    __io uint32 EGR;            /**< Event generation register  */
    __io uint32 CCMR1;          /**< Capture/compare mode register 1 */
    __io uint32 CCMR2;          /**< Capture/compare mode register 2 */
    __io uint32 CCER;           /**< Capture/compare enable register */
    __io uint32 CNT;            /**< Counter */
    __io uint32 PSC;            /**< Prescaler */
    __io uint32 ARR;            /**< Auto-reload register */
    __io uint32 RCR;            /**< Repetition counter register */
    __io uint32 CCR1;           /**< Capture/compare register 1 */
    __io uint32 CCR2;           /**< Capture/compare register 2 */
    __io uint32 CCR3;           /**< Capture/compare register 3 */
    __io uint32 CCR4;           /**< Capture/compare register 4 */
    __io uint32 BDTR;           /**< Break and dead-time register */
    __io uint32 DCR;            /**< DMA control register */
    __io uint32 DMAR;           /**< DMA address for full transfer */
} timer_adv_reg_map;

/* General purpose timer register map type: intentionally omitted.
 *
 * General purpose timers differ slightly across series, so leave it
 * up to the series header to define struct timer_gen_reg_map. */

/** Basic timer register map type */
typedef struct timer_bas_reg_map {
    __io uint32 CR1;            /**< Control register 1 */
    __io uint32 CR2;            /**< Control register 2 */
    const uint32 RESERVED1;     /**< Reserved */
    __io uint32 DIER;           /**< DMA/interrupt enable register */
    __io uint32 SR;             /**< Status register */
    __io uint32 EGR;            /**< Event generation register  */
    const uint32 RESERVED2;     /**< Reserved */
    const uint32 RESERVED3;     /**< Reserved */
    const uint32 RESERVED4;     /**< Reserved */
    __io uint32 CNT;            /**< Counter */
    __io uint32 PSC;            /**< Prescaler */
    __io uint32 ARR;            /**< Auto-reload register */
} timer_bas_reg_map;

/*
 * Timer devices
 */

/**
 * @brief Timer register map type.
 *
 * Just holds a pointer to the correct type of register map, based on
 * the timer's type.
 */
typedef union timer_reg_map {
    timer_adv_reg_map *adv;     /**< Advanced register map */
    timer_gen_reg_map *gen;     /**< General purpose register map */
    timer_bas_reg_map *bas;     /**< Basic register map */
} timer_reg_map;

/**
 * @brief Timer type
 *
 * Type marker for timer_dev.
 *
 * @see timer_dev
 */
typedef enum timer_type {
    TIMER_ADVANCED,             /**< Advanced type */
    TIMER_GENERAL,              /**< General purpose type */
    TIMER_BASIC,                /**< Basic type */
} timer_type;

/** Timer device type */
typedef struct timer_dev {
    timer_reg_map regs;         /**< Register map */
    rcc_clk_id clk_id;          /**< RCC clock information */
    timer_type type;            /**< Timer's type */
    voidFuncPtr handlers[];     /**<
                                 * Don't touch these. Use these instead:
                                 * @see timer_attach_interrupt()
                                 * @see timer_detach_interrupt() */
} timer_dev;

#if STM32_HAVE_TIMER(1)
extern timer_dev *TIMER1;
#endif
#if STM32_HAVE_TIMER(2)
extern timer_dev *TIMER2;
#endif
#if STM32_HAVE_TIMER(3)
extern timer_dev *TIMER3;
#endif
#if STM32_HAVE_TIMER(4)
extern timer_dev *TIMER4;
#endif
#if STM32_HAVE_TIMER(5)
extern timer_dev *TIMER5;
#endif
#if STM32_HAVE_TIMER(6)
extern timer_dev *TIMER6;
#endif
#if STM32_HAVE_TIMER(7)
extern timer_dev *TIMER7;
#endif
#if STM32_HAVE_TIMER(8)
extern timer_dev *TIMER8;
#endif
#if STM32_HAVE_TIMER(9)
extern timer_dev *TIMER9;
#endif
#if STM32_HAVE_TIMER(10)
extern timer_dev *TIMER10;
#endif
#if STM32_HAVE_TIMER(11)
extern timer_dev *TIMER11;
#endif
#if STM32_HAVE_TIMER(12)
extern timer_dev *TIMER12;
#endif
#if STM32_HAVE_TIMER(13)
extern timer_dev *TIMER13;
#endif
#if STM32_HAVE_TIMER(14)
extern timer_dev *TIMER14;
#endif

/*
 * Register bit definitions
 */

/* Control register 1 (CR1) */

#define TIMER_CR1_ARPE_BIT              7
#define TIMER_CR1_DIR_BIT               4
#define TIMER_CR1_OPM_BIT               3
#define TIMER_CR1_URS_BIT               2
#define TIMER_CR1_UDIS_BIT              1
#define TIMER_CR1_CEN_BIT               0

#define TIMER_CR1_CKD                   (0x3 << 8)
#define TIMER_CR1_CKD_1TCKINT           (0x0 << 8)
#define TIMER_CR1_CKD_2TCKINT           (0x1 << 8)
#define TIMER_CR1_CKD_4TICKINT          (0x2 << 8)
#define TIMER_CR1_ARPE                  (1U << TIMER_CR1_ARPE_BIT)
#define TIMER_CR1_CKD_CMS               (0x3 << 5)
#define TIMER_CR1_CKD_CMS_EDGE          (0x0 << 5)
#define TIMER_CR1_CKD_CMS_CENTER1       (0x1 << 5)
#define TIMER_CR1_CKD_CMS_CENTER2       (0x2 << 5)
#define TIMER_CR1_CKD_CMS_CENTER3       (0x3 << 5)
#define TIMER_CR1_DIR                   (1U << TIMER_CR1_DIR_BIT)
#define TIMER_CR1_OPM                   (1U << TIMER_CR1_OPM_BIT)
#define TIMER_CR1_URS                   (1U << TIMER_CR1_URS_BIT)
#define TIMER_CR1_UDIS                  (1U << TIMER_CR1_UDIS_BIT)
#define TIMER_CR1_CEN                   (1U << TIMER_CR1_CEN_BIT)

/* Control register 2 (CR2) */

#define TIMER_CR2_OIS4_BIT              14
#define TIMER_CR2_OIS3N_BIT             13
#define TIMER_CR2_OIS3_BIT              12
#define TIMER_CR2_OIS2N_BIT             11
#define TIMER_CR2_OIS2_BIT              10
#define TIMER_CR2_OIS1N_BIT             9
#define TIMER_CR2_OIS1_BIT              8
#define TIMER_CR2_TI1S_BIT              7
#define TIMER_CR2_CCDS_BIT              3
#define TIMER_CR2_CCUS_BIT              2
#define TIMER_CR2_CCPC_BIT              0

#define TIMER_CR2_OIS4                  (1U << TIMER_CR2_OIS4_BIT)
#define TIMER_CR2_OIS3N                 (1U << TIMER_CR2_OIS3N_BIT)
#define TIMER_CR2_OIS3                  (1U << TIMER_CR2_OIS3_BIT)
#define TIMER_CR2_OIS2N                 (1U << TIMER_CR2_OIS2N_BIT)
#define TIMER_CR2_OIS2                  (1U << TIMER_CR2_OIS2_BIT)
#define TIMER_CR2_OIS1N                 (1U << TIMER_CR2_OIS1N_BIT)
#define TIMER_CR2_OIS1                  (1U << TIMER_CR2_OIS1_BIT)
#define TIMER_CR2_TI1S                  (1U << TIMER_CR2_TI1S_BIT)
#define TIMER_CR2_MMS                   (0x7 << 4)
#define TIMER_CR2_MMS_RESET             (0x0 << 4)
#define TIMER_CR2_MMS_ENABLE            (0x1 << 4)
#define TIMER_CR2_MMS_UPDATE            (0x2 << 4)
#define TIMER_CR2_MMS_COMPARE_PULSE     (0x3 << 4)
#define TIMER_CR2_MMS_COMPARE_OC1REF    (0x4 << 4)
#define TIMER_CR2_MMS_COMPARE_OC2REF    (0x5 << 4)
#define TIMER_CR2_MMS_COMPARE_OC3REF    (0x6 << 4)
#define TIMER_CR2_MMS_COMPARE_OC4REF    (0x7 << 4)
#define TIMER_CR2_CCDS                  (1U << TIMER_CR2_CCDS_BIT)
#define TIMER_CR2_CCUS                  (1U << TIMER_CR2_CCUS_BIT)
#define TIMER_CR2_CCPC                  (1U << TIMER_CR2_CCPC_BIT)

/* Slave mode control register (SMCR) */

#define TIMER_SMCR_ETP_BIT              15
#define TIMER_SMCR_ECE_BIT              14
#define TIMER_SMCR_MSM_BIT              7

#define TIMER_SMCR_ETP                  (1U << TIMER_SMCR_ETP_BIT)
#define TIMER_SMCR_ECE                  (1U << TIMER_SMCR_ECE_BIT)
#define TIMER_SMCR_ETPS                 (0x3 << 12)
#define TIMER_SMCR_ETPS_OFF             (0x0 << 12)
#define TIMER_SMCR_ETPS_DIV2            (0x1 << 12)
#define TIMER_SMCR_ETPS_DIV4            (0x2 << 12)
#define TIMER_SMCR_ETPS_DIV8            (0x3 << 12)
#define TIMER_SMCR_ETF                  (0xF << 12)
#define TIMER_SMCR_MSM                  (1U << TIMER_SMCR_MSM_BIT)
#define TIMER_SMCR_TS                   (0x3 << 4)
#define TIMER_SMCR_TS_ITR0              (0x0 << 4)
#define TIMER_SMCR_TS_ITR1              (0x1 << 4)
#define TIMER_SMCR_TS_ITR2              (0x2 << 4)
#define TIMER_SMCR_TS_ITR3              (0x3 << 4)
#define TIMER_SMCR_TS_TI1F_ED           (0x4 << 4)
#define TIMER_SMCR_TS_TI1FP1            (0x5 << 4)
#define TIMER_SMCR_TS_TI2FP2            (0x6 << 4)
#define TIMER_SMCR_TS_ETRF              (0x7 << 4)
#define TIMER_SMCR_SMS                  0x3
#define TIMER_SMCR_SMS_DISABLED         0x0
#define TIMER_SMCR_SMS_ENCODER1         0x1
#define TIMER_SMCR_SMS_ENCODER2         0x2
#define TIMER_SMCR_SMS_ENCODER3         0x3
#define TIMER_SMCR_SMS_RESET            0x4
#define TIMER_SMCR_SMS_GATED            0x5
#define TIMER_SMCR_SMS_TRIGGER          0x6
#define TIMER_SMCR_SMS_EXTERNAL         0x7

/* DMA/Interrupt enable register (DIER) */

#define TIMER_DIER_TDE_BIT              14
#define TIMER_DIER_COMDE_BIT            13
#define TIMER_DIER_CC4DE_BIT            12
#define TIMER_DIER_CC3DE_BIT            11
#define TIMER_DIER_CC2DE_BIT            10
#define TIMER_DIER_CC1DE_BIT            9
#define TIMER_DIER_UDE_BIT              8
#define TIMER_DIER_BIE_BIT              7
#define TIMER_DIER_TIE_BIT              6
#define TIMER_DIER_COMIE_BIT            5
#define TIMER_DIER_CC4IE_BIT            4
#define TIMER_DIER_CC3IE_BIT            3
#define TIMER_DIER_CC2IE_BIT            2
#define TIMER_DIER_CC1IE_BIT            1
#define TIMER_DIER_UIE_BIT              0

#define TIMER_DIER_TDE                  (1U << TIMER_DIER_TDE_BIT)
#define TIMER_DIER_COMDE                (1U << TIMER_DIER_COMDE_BIT)
#define TIMER_DIER_CC4DE                (1U << TIMER_DIER_CC4DE_BIT)
#define TIMER_DIER_CC3DE                (1U << TIMER_DIER_CC3DE_BIT)
#define TIMER_DIER_CC2DE                (1U << TIMER_DIER_CC2DE_BIT)
#define TIMER_DIER_CC1DE                (1U << TIMER_DIER_CC1DE_BIT)
#define TIMER_DIER_UDE                  (1U << TIMER_DIER_UDE_BIT)
#define TIMER_DIER_BIE                  (1U << TIMER_DIER_BIE_BIT)
#define TIMER_DIER_TIE                  (1U << TIMER_DIER_TIE_BIT)
#define TIMER_DIER_COMIE                (1U << TIMER_DIER_COMIE_BIT)
#define TIMER_DIER_CC4IE                (1U << TIMER_DIER_CC4IE_BIT)
#define TIMER_DIER_CC3IE                (1U << TIMER_DIER_CC3IE_BIT)
#define TIMER_DIER_CC2IE                (1U << TIMER_DIER_CC2IE_BIT)
#define TIMER_DIER_CC1IE                (1U << TIMER_DIER_CC1IE_BIT)
#define TIMER_DIER_UIE                  (1U << TIMER_DIER_UIE_BIT)

/* Status register (SR) */

#define TIMER_SR_CC4OF_BIT              12
#define TIMER_SR_CC3OF_BIT              11
#define TIMER_SR_CC2OF_BIT              10
#define TIMER_SR_CC1OF_BIT              9
#define TIMER_SR_BIF_BIT                7
#define TIMER_SR_TIF_BIT                6
#define TIMER_SR_COMIF_BIT              5
#define TIMER_SR_CC4IF_BIT              4
#define TIMER_SR_CC3IF_BIT              3
#define TIMER_SR_CC2IF_BIT              2
#define TIMER_SR_CC1IF_BIT              1
#define TIMER_SR_UIF_BIT                0

#define TIMER_SR_CC4OF                  (1U << TIMER_SR_CC4OF_BIT)
#define TIMER_SR_CC3OF                  (1U << TIMER_SR_CC3OF_BIT)
#define TIMER_SR_CC2OF                  (1U << TIMER_SR_CC2OF_BIT)
#define TIMER_SR_CC1OF                  (1U << TIMER_SR_CC1OF_BIT)
#define TIMER_SR_BIF                    (1U << TIMER_SR_BIF_BIT)
#define TIMER_SR_TIF                    (1U << TIMER_SR_TIF_BIT)
#define TIMER_SR_COMIF                  (1U << TIMER_SR_COMIF_BIT)
#define TIMER_SR_CC4IF                  (1U << TIMER_SR_CC4IF_BIT)
#define TIMER_SR_CC3IF                  (1U << TIMER_SR_CC3IF_BIT)
#define TIMER_SR_CC2IF                  (1U << TIMER_SR_CC2IF_BIT)
#define TIMER_SR_CC1IF                  (1U << TIMER_SR_CC1IF_BIT)
#define TIMER_SR_UIF                    (1U << TIMER_SR_UIF_BIT)

/* Event generation register (EGR) */

#define TIMER_EGR_BG_BIT                7
#define TIMER_EGR_TG_BIT                6
#define TIMER_EGR_COMG_BIT              5
#define TIMER_EGR_CC4G_BIT              4
#define TIMER_EGR_CC3G_BIT              3
#define TIMER_EGR_CC2G_BIT              2
#define TIMER_EGR_CC1G_BIT              1
#define TIMER_EGR_UG_BIT                0

#define TIMER_EGR_BG                    (1U << TIMER_EGR_BG_BIT)
#define TIMER_EGR_TG                    (1U << TIMER_EGR_TG_BIT)
#define TIMER_EGR_COMG                  (1U << TIMER_EGR_COMG_BIT)
#define TIMER_EGR_CC4G                  (1U << TIMER_EGR_CC4G_BIT)
#define TIMER_EGR_CC3G                  (1U << TIMER_EGR_CC3G_BIT)
#define TIMER_EGR_CC2G                  (1U << TIMER_EGR_CC2G_BIT)
#define TIMER_EGR_CC1G                  (1U << TIMER_EGR_CC1G_BIT)
#define TIMER_EGR_UG                    (1U << TIMER_EGR_UG_BIT)

/* Capture/compare mode registers, common values */

#define TIMER_CCMR_CCS_OUTPUT           0x0
#define TIMER_CCMR_CCS_INPUT_TRC        0x3
#define TIMER_CCMR_CCS1S_INPUT_TI1      0x1
#define TIMER_CCMR_CCS1S_INPUT_TI2      0x2
#define TIMER_CCMR_CCS2S_INPUT_TI1      0x2
#define TIMER_CCMR_CCS2S_INPUT_TI2      0x1
#define TIMER_CCMR_CCS3S_INPUT_TI1      0x1
#define TIMER_CCMR_CCS3S_INPUT_TI2      0x2
#define TIMER_CCMR_CCS4S_INPUT_TI1      0x2
#define TIMER_CCMR_CCS4S_INPUT_TI2      0x1

/* Capture/compare mode register 1 (CCMR1) */

#define TIMER_CCMR1_OC2CE_BIT           15
#define TIMER_CCMR1_OC2PE_BIT           11
#define TIMER_CCMR1_OC2FE_BIT           10
#define TIMER_CCMR1_OC1CE_BIT           7
#define TIMER_CCMR1_OC1PE_BIT           3
#define TIMER_CCMR1_OC1FE_BIT           2

#define TIMER_CCMR1_OC2CE               (1U << TIMER_CCMR1_OC2CE_BIT)
#define TIMER_CCMR1_OC2M                (0x3 << 12)
#define TIMER_CCMR1_IC2F                (0xF << 12)
#define TIMER_CCMR1_OC2PE               (1U << TIMER_CCMR1_OC2PE_BIT)
#define TIMER_CCMR1_OC2FE               (1U << TIMER_CCMR1_OC2FE_BIT)
#define TIMER_CCMR1_IC2PSC              (0x3 << 10)
#define TIMER_CCMR1_CC2S                (0x3 << 8)
#define TIMER_CCMR1_CC2S_OUTPUT         (TIMER_CCMR_CCS_OUTPUT << 8)
#define TIMER_CCMR1_CC2S_INPUT_TI1      (TIMER_CCMR_CCS2S_INPUT_TI1 << 8)
#define TIMER_CCMR1_CC2S_INPUT_TI2      (TIMER_CCMR_CCS2S_INPUT_TI2 << 8)
#define TIMER_CCMR1_CC2S_INPUT_TRC      (TIMER_CCMR_CCS_INPUT_TRC << 8)
#define TIMER_CCMR1_OC1CE               (1U << TIMER_CCMR1_OC1CE_BIT)
#define TIMER_CCMR1_OC1M                (0x3 << 4)
#define TIMER_CCMR1_IC1F                (0xF << 4)
#define TIMER_CCMR1_OC1PE               (1U << TIMER_CCMR1_OC1PE_BIT)
#define TIMER_CCMR1_OC1FE               (1U << TIMER_CCMR1_OC1FE_BIT)
#define TIMER_CCMR1_IC1PSC              (0x3 << 2)
#define TIMER_CCMR1_CC1S                0x3
#define TIMER_CCMR1_CC1S_OUTPUT         TIMER_CCMR_CCS_OUTPUT
#define TIMER_CCMR1_CC1S_INPUT_TI1      TIMER_CCMR_CCS1S_INPUT_TI1
#define TIMER_CCMR1_CC1S_INPUT_TI2      TIMER_CCMR_CCS1S_INPUT_TI2
#define TIMER_CCMR1_CC1S_INPUT_TRC      TIMER_CCMR_CCS_INPUT_TRC

/* Capture/compare mode register 2 (CCMR2) */

#define TIMER_CCMR2_OC4CE_BIT           15
#define TIMER_CCMR2_OC4PE_BIT           11
#define TIMER_CCMR2_OC4FE_BIT           10
#define TIMER_CCMR2_OC3CE_BIT           7
#define TIMER_CCMR2_OC3PE_BIT           3
#define TIMER_CCMR2_OC3FE_BIT           2

#define TIMER_CCMR2_OC4CE               (1U << TIMER_CCMR2_OC4CE_BIT)
#define TIMER_CCMR2_OC4M                (0x3 << 12)
#define TIMER_CCMR2_IC4F                (0xF << 12)
#define TIMER_CCMR2_OC4PE               (1U << TIMER_CCMR2_OC4PE_BIT)
#define TIMER_CCMR2_OC4FE               (1U << TIMER_CCMR2_OC4FE_BIT)
#define TIMER_CCMR2_IC4PSC              (0x3 << 10)
#define TIMER_CCMR2_CC4S                (0x3 << 8)
#define TIMER_CCMR2_CC4S_OUTPUT         (TIMER_CCMR_CCS_OUTPUT << 8)
#define TIMER_CCMR2_CC4S_INPUT_TI1      (TIMER_CCMR_CCS4S_INPUT_TI1 << 8)
#define TIMER_CCMR2_CC4S_INPUT_TI2      (TIMER_CCMR_CCS4S_INPUT_TI2 << 8)
#define TIMER_CCMR2_CC4S_INPUT_TRC      (TIMER_CCMR_CCS_INPUT_TRC << 8)
#define TIMER_CCMR2_OC3CE               (1U << TIMER_CCMR2_OC3CE_BIT)
#define TIMER_CCMR2_OC3M                (0x3 << 4)
#define TIMER_CCMR2_IC3F                (0xF << 4)
#define TIMER_CCMR2_OC3PE               (1U << TIMER_CCMR2_OC3PE_BIT)
#define TIMER_CCMR2_OC3FE               (1U << TIMER_CCMR2_OC3FE_BIT)
#define TIMER_CCMR2_IC3PSC              (0x3 << 2)
#define TIMER_CCMR2_CC3S                0x3
#define TIMER_CCMR2_CC3S_OUTPUT         TIMER_CCMR_CCS_OUTPUT
#define TIMER_CCMR2_CC3S_INPUT_TI1      TIMER_CCMR_CCS3S_INPUT_TI1
#define TIMER_CCMR2_CC3S_INPUT_TI2      TIMER_CCMR_CCS3S_INPUT_TI2
#define TIMER_CCMR2_CC3S_INPUT_TRC      TIMER_CCMR_CCS_INPUT_TRC

/* Capture/compare enable register (CCER) */

#define TIMER_CCER_CC4P_BIT             13
#define TIMER_CCER_CC4E_BIT             12
#define TIMER_CCER_CC3NP_BIT            11
#define TIMER_CCER_CC3NE_BIT            10
#define TIMER_CCER_CC3P_BIT             9
#define TIMER_CCER_CC3E_BIT             8
#define TIMER_CCER_CC2NP_BIT            7
#define TIMER_CCER_CC2NE_BIT            6
#define TIMER_CCER_CC2P_BIT             5
#define TIMER_CCER_CC2E_BIT             4
#define TIMER_CCER_CC1NP_BIT            3
#define TIMER_CCER_CC1NE_BIT            2
#define TIMER_CCER_CC1P_BIT             1
#define TIMER_CCER_CC1E_BIT             0

#define TIMER_CCER_CC4P                 (1U << TIMER_CCER_CC4P_BIT)
#define TIMER_CCER_CC4E                 (1U << TIMER_CCER_CC4E_BIT)
#define TIMER_CCER_CC3NP                (1U << TIMER_CCER_CC3NP_BIT)
#define TIMER_CCER_CC3NE                (1U << TIMER_CCER_CC3NE_BIT)
#define TIMER_CCER_CC3P                 (1U << TIMER_CCER_CC3P_BIT)
#define TIMER_CCER_CC3E                 (1U << TIMER_CCER_CC3E_BIT)
#define TIMER_CCER_CC2NP                (1U << TIMER_CCER_CC2NP_BIT)
#define TIMER_CCER_CC2NE                (1U << TIMER_CCER_CC2NE_BIT)
#define TIMER_CCER_CC2P                 (1U << TIMER_CCER_CC2P_BIT)
#define TIMER_CCER_CC2E                 (1U << TIMER_CCER_CC2E_BIT)
#define TIMER_CCER_CC1NP                (1U << TIMER_CCER_CC1NP_BIT)
#define TIMER_CCER_CC1NE                (1U << TIMER_CCER_CC1NE_BIT)
#define TIMER_CCER_CC1P                 (1U << TIMER_CCER_CC1P_BIT)
#define TIMER_CCER_CC1E                 (1U << TIMER_CCER_CC1E_BIT)

/* Break and dead-time register (BDTR) */

#define TIMER_BDTR_MOE_BIT              15
#define TIMER_BDTR_AOE_BIT              14
#define TIMER_BDTR_BKP_BIT              13
#define TIMER_BDTR_BKE_BIT              12
#define TIMER_BDTR_OSSR_BIT             11
#define TIMER_BDTR_OSSI_BIT             10

#define TIMER_BDTR_MOE                  (1U << TIMER_BDTR_MOE_BIT)
#define TIMER_BDTR_AOE                  (1U << TIMER_BDTR_AOE_BIT)
#define TIMER_BDTR_BKP                  (1U << TIMER_BDTR_BKP_BIT)
#define TIMER_BDTR_BKE                  (1U << TIMER_BDTR_BKE_BIT)
#define TIMER_BDTR_OSSR                 (1U << TIMER_BDTR_OSSR_BIT)
#define TIMER_BDTR_OSSI                 (1U << TIMER_BDTR_OSSI_BIT)
#define TIMER_BDTR_LOCK                 (0x3 << 8)
#define TIMER_BDTR_LOCK_OFF             (0x0 << 8)
#define TIMER_BDTR_LOCK_LEVEL1          (0x1 << 8)
#define TIMER_BDTR_LOCK_LEVEL2          (0x2 << 8)
#define TIMER_BDTR_LOCK_LEVEL3          (0x3 << 8)
#define TIMER_BDTR_DTG                  0xFF

/* DMA control register (DCR) */

#define TIMER_DCR_DBL                   (0x1F << 8)
#define TIMER_DCR_DBL_1_XFER            (0x0 << 8)
#define TIMER_DCR_DBL_2_XFER            (0x1 << 8)
#define TIMER_DCR_DBL_3_XFER            (0x2 << 8)
#define TIMER_DCR_DBL_4_XFER            (0x3 << 8)
#define TIMER_DCR_DBL_5_XFER            (0x4 << 8)
#define TIMER_DCR_DBL_6_XFER            (0x5 << 8)
#define TIMER_DCR_DBL_7_XFER            (0x6 << 8)
#define TIMER_DCR_DBL_8_XFER            (0x7 << 8)
#define TIMER_DCR_DBL_9_XFER            (0x8 << 8)
#define TIMER_DCR_DBL_10_XFER           (0x9 << 8)
#define TIMER_DCR_DBL_11_XFER           (0xA << 8)
#define TIMER_DCR_DBL_12_XFER           (0xB << 8)
#define TIMER_DCR_DBL_13_XFER           (0xC << 8)
#define TIMER_DCR_DBL_14_XFER           (0xD << 8)
#define TIMER_DCR_DBL_15_XFER           (0xE << 8)
#define TIMER_DCR_DBL_16_XFER           (0xF << 8)
#define TIMER_DCR_DBL_17_XFER           (0x10 << 8)
#define TIMER_DCR_DBL_18_XFER           (0x11 << 8)
#define TIMER_DCR_DBA                   0x1F
#define TIMER_DCR_DBA_CR1               0x0
#define TIMER_DCR_DBA_CR2               0x1
#define TIMER_DCR_DBA_SMCR              0x2
#define TIMER_DCR_DBA_DIER              0x3
#define TIMER_DCR_DBA_SR                0x4
#define TIMER_DCR_DBA_EGR               0x5
#define TIMER_DCR_DBA_CCMR1             0x6
#define TIMER_DCR_DBA_CCMR2             0x7
#define TIMER_DCR_DBA_CCER              0x8
#define TIMER_DCR_DBA_CNT               0x9
#define TIMER_DCR_DBA_PSC               0xA
#define TIMER_DCR_DBA_ARR               0xB
#define TIMER_DCR_DBA_RCR               0xC
#define TIMER_DCR_DBA_CCR1              0xD
#define TIMER_DCR_DBA_CCR2              0xE
#define TIMER_DCR_DBA_CCR3              0xF
#define TIMER_DCR_DBA_CCR4              0x10
#define TIMER_DCR_DBA_BDTR              0x11
#define TIMER_DCR_DBA_DCR               0x12
#define TIMER_DCR_DBA_DMAR              0x13

/*
 * Convenience routines
 */

/**
 * @brief Used to configure the behavior of a timer channel.
 *
 * Be careful: not all timers can be configured in every mode.
 */
typedef enum timer_mode {
    /**
     * The timer stops counting, channel interrupts are detached, and
     * no state changes are output. */
    TIMER_DISABLED,

    /** PWM output. */
    TIMER_PWM,

    /* TIMER_PWM_CENTER_ALIGNED, TODO: Center-aligned PWM output mode. */

    /**
     * The timer counts from 0 to its reload value repeatedly; every
     * time the counter value reaches one of the channel compare
     * values, the corresponding interrupt is fired. */
    TIMER_OUTPUT_COMPARE,

    /* TIMER_INPUT_CAPTURE, TODO: In this mode, the timer can measure the
     *                            pulse lengths of input signals */
    /* TIMER_ONE_PULSE, TODO: In this mode, the timer can generate a single
     *                        pulse on a GPIO pin for a specified amount of
     *                        time. */
} timer_mode;

/** Timer channel numbers */
typedef enum timer_channel {
    TIMER_CH1 = 1, /**< Channel 1 */
    TIMER_CH2 = 2, /**< Channel 2 */
    TIMER_CH3 = 3, /**< Channel 3 */
    TIMER_CH4 = 4  /**< Channel 4 */
} timer_channel;

/*
 * Note: Don't require timer_channel arguments! We want to be able to say
 *
 * for (int channel = 1; channel <= 4; channel++) {
 *    ...
 * }
 *
 * without the compiler yelling at us.
 */

void timer_init(timer_dev *dev);
void timer_disable(timer_dev *dev);
void timer_set_mode(timer_dev *dev, uint8 channel, timer_mode mode);
void timer_foreach(void (*fn)(timer_dev*));
int timer_has_cc_channel(timer_dev *dev, uint8 channel);

/**
 * @brief Timer interrupt number.
 *
 * Not all timers support all of these values. All timers support
 * TIMER_UPDATE_INTERRUPT. "General purpose" timers can be a special
 * nuisance in this regard, as they individually support different
 * subsets of the available interupts. Consult your target's reference
 * manual for the details.
 */
typedef enum timer_interrupt_id {
    TIMER_UPDATE_INTERRUPT,     /**< Update interrupt. */
    TIMER_CC1_INTERRUPT,        /**< Capture/compare 1 interrupt. */
    TIMER_CC2_INTERRUPT,        /**< Capture/compare 2 interrupt. */
    TIMER_CC3_INTERRUPT,        /**< Capture/compare 3 interrupt. */
    TIMER_CC4_INTERRUPT,        /**< Capture/compare 4 interrupt. */
    TIMER_COM_INTERRUPT,        /**< COM interrupt. */
    TIMER_TRG_INTERRUPT,        /**< Trigger interrupt. */
    TIMER_BREAK_INTERRUPT,      /**< Break interrupt. */
} timer_interrupt_id;

void timer_attach_interrupt(timer_dev *dev,
                            uint8 interrupt,
                            voidFuncPtr handler);
void timer_detach_interrupt(timer_dev *dev, uint8 interrupt);

/**
 * Initialize all timer devices on the chip.
 */
static inline void timer_init_all(void) {
    timer_foreach(timer_init);
}

/**
 * Disables all timers on the device.
 */
static inline void timer_disable_all(void) {
    timer_foreach(timer_disable);
}

/**
 * @brief Stop a timer's counter from changing.
 *
 * Does not affect the timer's mode or other settings.
 *
 * @param dev Device whose counter to pause.
 */
static inline void timer_pause(timer_dev *dev) {
    *bb_perip(&(dev->regs).bas->CR1, TIMER_CR1_CEN_BIT) = 0;
}

/**
 * @brief Start a timer's counter.
 *
 * Does not affect the timer's mode or other settings.
 *
 * @param dev Device whose counter to resume
 */
static inline void timer_resume(timer_dev *dev) {
    *bb_perip(&(dev->regs).bas->CR1, TIMER_CR1_CEN_BIT) = 1;
}

/**
 * @brief Returns the timer's counter value.
 *
 * This value is likely to be inaccurate if the counter is running
 * with a low prescaler.
 *
 * @param dev Timer whose counter to return
 */
static inline uint16 timer_get_count(timer_dev *dev) {
    return (uint16)(dev->regs).bas->CNT;
}

/**
 * @brief Sets the counter value for the given timer.
 * @param dev Timer whose counter to set
 * @param value New counter value
 */
static inline void timer_set_count(timer_dev *dev, uint16 value) {
    (dev->regs).bas->CNT = value;
}

/**
 * @brief Returns the given timer's prescaler.
 *
 * Note that if the timer's prescaler is set (e.g. via
 * timer_set_prescaler() or accessing a TIMx_PSC register), the value
 * returned by this function will reflect the new setting, but the
 * timer's counter will only reflect the new prescaler at the next
 * update event.
 *
 * @param dev Timer whose prescaler to return
 * @see timer_generate_update()
 */
static inline uint16 timer_get_prescaler(timer_dev *dev) {
    return (uint16)(dev->regs).bas->PSC;
}

/**
 * @brief Set a timer's prescale value.
 *
 * Divides the input clock by (PSC+1).  The new value will not take
 * effect until the next update event.
 *
 * @param dev Timer whose prescaler to set
 * @param psc New prescaler value
 * @see timer_generate_update()
 */
static inline void timer_set_prescaler(timer_dev *dev, uint16 psc) {
    (dev->regs).bas->PSC = psc;
}

/**
 * @brief Returns a timer's reload value.
 * @param dev Timer whose reload value to return
 */
static inline uint16 timer_get_reload(timer_dev *dev) {
    return (uint16)(dev->regs).bas->ARR;
}

/**
 * @brief Set a timer's reload value.
 * @param dev Timer whose reload value to set
 * @param arr New reload value to use.  Takes effect at next update event.
 * @see timer_generate_update()
 */
static inline void timer_set_reload(timer_dev *dev, uint16 arr) {
    (dev->regs).bas->ARR = arr;
}

/**
 * @brief Get the compare value for the given timer channel.
 * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
 * @param channel Channel whose compare value to get.
 */
static inline uint16 timer_get_compare(timer_dev *dev, uint8 channel) {
    __io uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1);
    return *ccr;
}

/**
 * @brief Set the compare value for the given timer channel.
 * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
 * @param channel Channel whose compare value to set.
 * @param value   New compare value.
 */
static inline void timer_set_compare(timer_dev *dev,
                                     uint8 channel,
                                     uint16 value) {
    __io uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1);
    *ccr = value;
}

/**
 * @brief Generate an update event for the given timer.
 *
 * Normally, this will cause the prescaler and auto-reload values in
 * the PSC and ARR registers to take immediate effect.  However, this
 * function will do nothing if the UDIS bit is set in the timer's CR1
 * register (UDIS is cleared by default).
 *
 * @param dev Timer device to generate an update for.
 */
static inline void timer_generate_update(timer_dev *dev) {
    *bb_perip(&(dev->regs).bas->EGR, TIMER_EGR_UG_BIT) = 1;
}

/**
 * @brief Enable a timer's trigger DMA request
 * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL
 */
static inline void timer_dma_enable_trg_req(timer_dev *dev) {
    *bb_perip(&(dev->regs).gen->DIER, TIMER_DIER_TDE_BIT) = 1;
}

/**
 * @brief Disable a timer's trigger DMA request
 * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL
 */
static inline void timer_dma_disable_trg_req(timer_dev *dev) {
    *bb_perip(&(dev->regs).gen->DIER, TIMER_DIER_TDE_BIT) = 0;
}

/**
 * @brief Enable a timer channel's DMA request.
 * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL
 * @param channel Channel whose DMA request to enable.
 */
static inline void timer_dma_enable_req(timer_dev *dev, uint8 channel) {
    *bb_perip(&(dev->regs).gen->DIER, channel + 8) = 1;
}

/**
 * @brief Disable a timer channel's DMA request.
 * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
 * @param channel Channel whose DMA request to disable.
 */
static inline void timer_dma_disable_req(timer_dev *dev, uint8 channel) {
    *bb_perip(&(dev->regs).gen->DIER, channel + 8) = 0;
}

/**
 * @brief Enable a timer interrupt.
 * @param dev Timer device.
 * @param interrupt Interrupt number to enable; this may be any
 *                  timer_interrupt_id value appropriate for the timer.
 * @see timer_interrupt_id
 * @see timer_channel
 */
static inline void timer_enable_irq(timer_dev *dev, uint8 interrupt) {
    *bb_perip(&(dev->regs).adv->DIER, interrupt) = 1;
}

/**
 * @brief Disable a timer interrupt.
 * @param dev Timer device.
 * @param interrupt Interrupt number to disable; this may be any
 *                  timer_interrupt_id value appropriate for the timer.
 * @see timer_interrupt_id
 * @see timer_channel
 */
static inline void timer_disable_irq(timer_dev *dev, uint8 interrupt) {
    *bb_perip(&(dev->regs).adv->DIER, interrupt) = 0;
}

/**
 * @brief Enable a timer channel's capture/compare signal.
 *
 * If the channel is configured as output, the corresponding output
 * compare signal will be output on the corresponding output pin.  If
 * the channel is configured as input, enables capture of the counter
 * value into the input capture/compare register.
 *
 * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
 * @param channel Channel to enable, from 1 to 4.
 */
static inline void timer_cc_enable(timer_dev *dev, uint8 channel) {
    *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1)) = 1;
}

/**
 * @brief Disable a timer channel's output compare or input capture signal.
 * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
 * @param channel Channel to disable, from 1 to 4.
 * @see timer_cc_enable()
 */
static inline void timer_cc_disable(timer_dev *dev, uint8 channel) {
    *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1)) = 0;
}

/**
 * @brief Get a channel's capture/compare output polarity
 * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
 * @param channel Channel whose capture/compare output polarity to get.
 * @return Polarity, either 0 or 1.
 * @see timer_cc_set_polarity()
 */
static inline uint8 timer_cc_get_pol(timer_dev *dev, uint8 channel) {
    return *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1) + 1);
}

/**
 * @brief Set a timer channel's capture/compare output polarity.
 *
 * If the timer channel is configured as output: polarity == 0 means
 * the output channel will be active high; polarity == 1 means active
 * low.
 *
 * If the timer channel is configured as input: polarity == 0 means
 * capture is done on the rising edge of ICn; when used as an external
 * trigger, ICn is non-inverted.  polarity == 1 means capture is done
 * on the falling edge of ICn; when used as an external trigger, ICn
 * is inverted.
 *
 * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
 * @param channel Channel whose capture/compare output polarity to set.
 * @param pol New polarity, 0 or 1.
 */
static inline void timer_cc_set_pol(timer_dev *dev, uint8 channel, uint8 pol) {
    *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1) + 1) = pol;
}

/**
 * @brief Get a timer's DMA burst length.
 * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
 * @return Number of transfers per read or write to timer DMA register,
 *         from 1 to 18.
 */
static inline uint8 timer_dma_get_burst_len(timer_dev *dev) {
    uint32 dbl = ((dev->regs).gen->DCR & TIMER_DCR_DBL) >> 8;
    return dbl + 1;             /* 0 means 1 transfer, etc. */
}

/**
 * @brief Set a timer's DMA burst length.
 * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
 * @param length DMA burst length; i.e., number of DMA transfers per
 *               read/write to timer DMA register, from 1 to 18.
 */
static inline void timer_dma_set_burst_len(timer_dev *dev, uint8 length) {
    uint32 tmp = (dev->regs).gen->DCR;
    tmp &= ~TIMER_DCR_DBL;
    tmp |= (length - 1) << 8;
    (dev->regs).gen->DCR = tmp;
}

/**
 * @brief Timer DMA base address.
 *
 * Defines the base address for DMA transfers.
 */
typedef enum timer_dma_base_addr {
    /** Base is control register 1 */
    TIMER_DMA_BASE_CR1 = TIMER_DCR_DBA_CR1,
    /** Base is control register 2 */
    TIMER_DMA_BASE_CR2 = TIMER_DCR_DBA_CR2,
    /** Base is slave mode control register */
    TIMER_DMA_BASE_SMCR = TIMER_DCR_DBA_SMCR,
    /** Base is DMA interrupt enable register */
    TIMER_DMA_BASE_DIER  = TIMER_DCR_DBA_DIER,
    /** Base is status register */
    TIMER_DMA_BASE_SR = TIMER_DCR_DBA_SR,
    /** Base is event generation register */
    TIMER_DMA_BASE_EGR = TIMER_DCR_DBA_EGR,
    /** Base is capture/compare mode register 1 */
    TIMER_DMA_BASE_CCMR1 = TIMER_DCR_DBA_CCMR1,
    /** Base is capture/compare mode register 2 */
    TIMER_DMA_BASE_CCMR2 = TIMER_DCR_DBA_CCMR2,
    /** Base is capture/compare enable register */
    TIMER_DMA_BASE_CCER = TIMER_DCR_DBA_CCER,
    /** Base is counter */
    TIMER_DMA_BASE_CNT = TIMER_DCR_DBA_CNT,
    /** Base is prescaler */
    TIMER_DMA_BASE_PSC = TIMER_DCR_DBA_PSC,
    /** Base is auto-reload register */
    TIMER_DMA_BASE_ARR = TIMER_DCR_DBA_ARR,
    /** Base is repetition counter register */
    TIMER_DMA_BASE_RCR = TIMER_DCR_DBA_RCR,
    /** Base is capture/compare register 1 */
    TIMER_DMA_BASE_CCR1 = TIMER_DCR_DBA_CCR1,
    /** Base is capture/compare register 2 */
    TIMER_DMA_BASE_CCR2 = TIMER_DCR_DBA_CCR2,
    /** Base is capture/compare register 3 */
    TIMER_DMA_BASE_CCR3 = TIMER_DCR_DBA_CCR3,
    /** Base is capture/compare register 4 */
    TIMER_DMA_BASE_CCR4 = TIMER_DCR_DBA_CCR4,
    /** Base is break and dead-time register */
    TIMER_DMA_BASE_BDTR = TIMER_DCR_DBA_BDTR,
    /** Base is DMA control register */
    TIMER_DMA_BASE_DCR = TIMER_DCR_DBA_DCR,
    /** Base is DMA address for full transfer */
    TIMER_DMA_BASE_DMAR = TIMER_DCR_DBA_DMAR,
} timer_dma_base_addr;

/**
 * @brief Get the timer's DMA base address.
 *
 * Some restrictions apply; see the reference manual for your chip.
 *
 * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
 * @return DMA base address
 */
static inline timer_dma_base_addr timer_dma_get_base_addr(timer_dev *dev) {
    uint32 dcr = (dev->regs).gen->DCR;
    return (timer_dma_base_addr)(dcr & TIMER_DCR_DBA);
}

/**
 * @brief Set the timer's DMA base address.
 *
 * Some restrictions apply; see the reference manual for your chip.
 *
 * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
 * @param dma_base DMA base address.
 */
static inline void timer_dma_set_base_addr(timer_dev *dev,
                                           timer_dma_base_addr dma_base) {
    uint32 tmp = (dev->regs).gen->DCR;
    tmp &= ~TIMER_DCR_DBA;
    tmp |= dma_base;
    (dev->regs).gen->DCR = tmp;
}

/**
 * Timer output compare modes.
 */
typedef enum timer_oc_mode {
    /**
     * Frozen: comparison between output compare register and counter
     * has no effect on the outputs. */
    TIMER_OC_MODE_FROZEN = 0 << 4,
    /**
     * OCxREF signal is forced high when the count matches the channel
     * capture/compare register. */
    TIMER_OC_MODE_ACTIVE_ON_MATCH = 1 << 4,
    /**
     * OCxREF signal is forced low when the counter matches the
     * channel capture/compare register. */
    TIMER_OC_MODE_INACTIVE_ON_MATCH = 2 << 4,
    /**
     * OCxREF toggles when counter matches the channel capture/compare
     * register. */
    TIMER_OC_MODE_TOGGLE = 3 << 4,
    /** OCxREF is forced low. */
    TIMER_OC_MODE_FORCE_INACTIVE = 4 << 4,
    /** OCxREF is forced high. */
    TIMER_OC_MODE_FORCE_ACTIVE = 5 << 4,
    /**
     * PWM mode 1.  In upcounting, channel is active as long as count
     * is less than channel capture/compare register, else inactive.
     * In downcounting, channel is inactive as long as count exceeds
     * capture/compare register, else active. */
    TIMER_OC_MODE_PWM_1 = 6 << 4,
    /**
     * PWM mode 2. In upcounting, channel is inactive as long as count
     * is less than capture/compare register, else active.  In
     * downcounting, channel is active as long as count exceeds
     * capture/compare register, else inactive. */
    TIMER_OC_MODE_PWM_2 = 7 << 4,
} timer_oc_mode;

/**
 * Timer output compare mode flags.
 * @see timer_oc_set_mode()
 */
typedef enum timer_oc_mode_flags {
    TIMER_OC_CE = 1U << 7,       /**< Output compare clear enable. */
    TIMER_OC_PE = 1U << 3,       /**< Output compare preload enable. */
    TIMER_OC_FE = 1U << 2,       /**< Output compare fast enable. */
} timer_oc_mode_flags;

/**
 * @brief Configure a channel's output compare mode.
 *
 * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
 * @param channel Channel to configure in output compare mode.
 * @param mode Timer mode to set.
 * @param flags OR of timer_oc_mode_flags.
 * @see timer_oc_mode
 * @see timer_oc_mode_flags
 */
static inline void timer_oc_set_mode(timer_dev *dev,
                                     uint8 channel,
                                     timer_oc_mode mode,
                                     uint8 flags) {
    /* channel == 1,2 -> CCMR1; channel == 3,4 -> CCMR2 */
    __io uint32 *ccmr = &(dev->regs).gen->CCMR1 + (((channel - 1) >> 1) & 1);
    /* channel == 1,3 -> shift = 0, channel == 2,4 -> shift = 8 */
    uint8 shift = 8 * (1 - (channel & 1));

    uint32 tmp = *ccmr;
    tmp &= ~(0xFF << shift);
    tmp |= (mode | flags | TIMER_CCMR_CCS_OUTPUT) << shift;
    *ccmr = tmp;
}

/*
 * Old, erroneous bit definitions from previous releases, kept for
 * backwards compatibility:
 *
 */
/* FIXME: deprecated, remove in [0.1.0] */

/** Deprecated. Use TIMER_CCMR1_CC4S_OUTPUT instead. */
#define TIMER_CCMR1_CC4S_OUTPUT    TIMER_CCMR2_CC4S_OUTPUT
/** Deprecated. Use TIMER_CCMR1_CC4S_INPUT_TI1 instead. */
#define TIMER_CCMR1_CC4S_INPUT_TI1 TIMER_CCMR2_CC4S_INPUT_TI1
/** Deprecated. Use TIMER_CCMR1_CC4S_INPUT_TI2 instead. */
#define TIMER_CCMR1_CC4S_INPUT_TI2 TIMER_CCMR2_CC4S_INPUT_TI2
/** Deprecated. Use TIMER_CCMR1_CC4S_INPUT_TRC instead. */
#define TIMER_CCMR1_CC4S_INPUT_TRC TIMER_CCMR2_CC4S_INPUT_TRC
/** Deprecated. Use TIMER_CCMR2_IC4F instead. */
#define TIMER_CCMR2_IC2F           TIMER_CCMR2_IC4F
/** Deprecated. Use TIMER_CCMR2_IC4PSC instead. */
#define TIMER_CCMR2_IC2PSC         TIMER_CCMR2_IC4PSC
/** Deprecated. Use TIMER_CCMR2_IC3F instead. */
#define TIMER_CCMR2_IC1F           TIMER_CCMR2_IC3F
/** Deprecated. Use TIMER_CCMR2_IC3PSC instead. */
#define TIMER_CCMR2_IC1PSC         TIMER_CCMR2_IC3PSC
/** Deprecated. Use TIMER_CCMR1_CC3S_OUTPUT instead. */
#define TIMER_CCMR1_CC3S_OUTPUT    TIMER_CCMR2_CC3S_OUTPUT
/** Deprecated. Use TIMER_CCMR1_CC3S_INPUT_TI1 instead. */
#define TIMER_CCMR1_CC3S_INPUT_TI1 TIMER_CCMR2_CC3S_INPUT_TI1
/** Deprecated. Use TIMER_CCMR1_CC3S_INPUT_TI2 instead. */
#define TIMER_CCMR1_CC3S_INPUT_TI2 TIMER_CCMR2_CC3S_INPUT_TI2
/** Deprecated. Use TIMER_CCMR1_CC3S_INPUT_TRC instead. */
#define TIMER_CCMR1_CC3S_INPUT_TRC TIMER_CCMR2_CC3S_INPUT_TRC

/** Deprecated. Use TIMER_DCR_DBL_1_XFER instead. */
#define TIMER_DCR_DBL_1BYTE  TIMER_DCR_DBL_1_XFER
/** Deprecated. Use TIMER_DCR_DBL_2_XFER instead. */
#define TIMER_DCR_DBL_2BYTE  TIMER_DCR_DBL_2_XFER
/** Deprecated. Use TIMER_DCR_DBL_3_XFER instead. */
#define TIMER_DCR_DBL_3BYTE  TIMER_DCR_DBL_3_XFER
/** Deprecated. Use TIMER_DCR_DBL_4_XFER instead. */
#define TIMER_DCR_DBL_4BYTE  TIMER_DCR_DBL_4_XFER
/** Deprecated. Use TIMER_DCR_DBL_5_XFER instead. */
#define TIMER_DCR_DBL_5BYTE  TIMER_DCR_DBL_5_XFER
/** Deprecated. Use TIMER_DCR_DBL_6_XFER instead. */
#define TIMER_DCR_DBL_6BYTE  TIMER_DCR_DBL_6_XFER
/** Deprecated. Use TIMER_DCR_DBL_7_XFER instead. */
#define TIMER_DCR_DBL_7BYTE  TIMER_DCR_DBL_7_XFER
/** Deprecated. Use TIMER_DCR_DBL_8_XFER instead. */
#define TIMER_DCR_DBL_8BYTE  TIMER_DCR_DBL_8_XFER
/** Deprecated. Use TIMER_DCR_DBL_9_XFER instead. */
#define TIMER_DCR_DBL_9BYTE  TIMER_DCR_DBL_9_XFER
/** Deprecated. Use TIMER_DCR_DBL_10_XFER instead. */
#define TIMER_DCR_DBL_10BYTE TIMER_DCR_DBL_10_XFER
/** Deprecated. Use TIMER_DCR_DBL_11_XFER instead. */
#define TIMER_DCR_DBL_11BYTE TIMER_DCR_DBL_11_XFER
/** Deprecated. Use TIMER_DCR_DBL_12_XFER instead. */
#define TIMER_DCR_DBL_12BYTE TIMER_DCR_DBL_12_XFER
/** Deprecated. Use TIMER_DCR_DBL_13_XFER instead. */
#define TIMER_DCR_DBL_13BYTE TIMER_DCR_DBL_13_XFER
/** Deprecated. Use TIMER_DCR_DBL_14_XFER instead. */
#define TIMER_DCR_DBL_14BYTE TIMER_DCR_DBL_14_XFER
/** Deprecated. Use TIMER_DCR_DBL_15_XFER instead. */
#define TIMER_DCR_DBL_15BYTE TIMER_DCR_DBL_15_XFER
/** Deprecated. Use TIMER_DCR_DBL_16_XFER instead. */
#define TIMER_DCR_DBL_16BYTE TIMER_DCR_DBL_16_XFER
/** Deprecated. Use TIMER_DCR_DBL_17_XFER instead. */
#define TIMER_DCR_DBL_17BYTE TIMER_DCR_DBL_17_XFER
/** Deprecated. Use TIMER_DCR_DBL_18_XFER instead. */
#define TIMER_DCR_DBL_18BYTE TIMER_DCR_DBL_18_XFER

#ifdef __cplusplus
} // extern "C"
#endif

#endif