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
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
|
//*****************************************************************************
//
// am_hal_ctimer.c
//! @file
//!
//! @brief Functions for interfacing with the Counter/Timer module.
//!
//! @addtogroup ctimer2 Counter/Timer (CTIMER)
//! @ingroup apollo2hal
//! @{
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2017, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 1.2.11 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#include <stdint.h>
#include <stdbool.h>
#include "am_mcu_apollo.h"
//*****************************************************************************
//
// Address space distance between timer configuration registers.
//
//*****************************************************************************
#define MAX_CTIMERS 4
#define TIMER_OFFSET (AM_REG_CTIMER_TMR1_O - AM_REG_CTIMER_TMR0_O)
#define CTIMER_CMPR_OFFSET (AM_REG_CTIMER_CMPRB0_O - AM_REG_CTIMER_CMPRA0_O)
//*****************************************************************************
//
// Adjacency check
//
// This is related to the timer read workaround. This macro checks to see if
// the two supplied count values are within one "tick" of eachother. It should
// still pass in the event of a timer rollover.
//
//*****************************************************************************
//! Timer read workaround: Do count values differ by one tick or less.
#define adjacent(A, B) (((A) == (B)) || (((A) + 1) == (B)) || ((B) == 0))
//*****************************************************************************
//
//! Array of function pointers for handling CTimer interrupts.
//
//*****************************************************************************
am_hal_ctimer_handler_t am_hal_ctimer_ppfnHandlers[16];
//*****************************************************************************
//
// Static function for reading the timer value.
//
//*****************************************************************************
#if defined(__GNUC_STDC_INLINE__)
__attribute__((naked))
static
void
back2back_reads(uint32_t u32TimerAddr, uint32_t u32Data[])
{
// u32TimerAddr = address of the timer to be read.
// u32Data[] is a pointer to a 3 word data array provided by the caller.
__asm
(
// Do 3 back-to-back reads of the register
" push {r4}\n" // Save r4
" push {r1}\n" // Save the data array ptr for later
" mov r2, r0\n" // Get Timer Addr
" mrs r4, PRIMASK\n" // Save PRIMASK
" cpsid i\n" // __disable_irq()
" nop\n" // Give the disable a cycle to take affect (but almost certainly not really needed)
" ldr r0, [r2, #0]\n" // Get TMRn register value
" ldr r1, [r2, #0]\n" // Get TMRn register value again
" ldr r3, [r2, #0]\n" // Get TMRn register value for a third time
" msr PRIMASK, r4\n" // Restore PRIMASK
" pop {r2}\n" // Get the array ptr
" str r0, [r2, #0]\n" // Store register value to variable
" str r1, [r2, #4]\n" // Store register value to variable
" str r3, [r2, #8]\n" // Store register value to variable
" pop {r4}\n" // restore r4
" bx lr\n"
);
}
#elif defined(__ARMCC_VERSION)
__asm static uint32_t
back2back_reads( uint32_t u32TimerAddr, uint32_t u32Data[])
{
push {r4} // Save r4
push {r1} // Save the data array ptr for later
mov r2, r0 // Get Timer Addr
mrs r4, PRIMASK // Save PRIMASK
cpsid i // __disable_irq()
nop // Give the disable a cycle to take affect (but almost certainly not really needed)
ldr r0, [r2, #0] // Get TMRn register value
ldr r1, [r2, #0] // Get TMRn register value again
ldr r3, [r2, #0] // Get TMRn register value for a third time
msr PRIMASK, r4 // Restore PRIMASK
pop {r2} // Get the array ptr
str r0, [r2, #0] // Store register value to variable
str r1, [r2, #4] // Store register value to variable
str r3, [r2, #8] // Store register value to variable
pop {r4} // Restore r4
bx lr
}
#elif defined(__IAR_SYSTEMS_ICC__)
#pragma diag_suppress = Pe940 // Suppress IAR compiler warning about missing
// return statement on a non-void function
__stackless static uint32_t
back2back_reads( uint32_t u32TimerAddr, uint32_t u32Data[])
{
__asm(" push {r4}"); // Save r4
__asm(" push {r1}"); // Save the data array ptr for later
__asm(" mov r2, r0"); // Get Timer Addr
__asm(" mrs r4, PRIMASK"); // Save PRIMASK"
__asm(" cpsid i"); // __disable_irq()
__asm(" nop"); // Give the disable a cycle to take affect (but almost certainly not really needed)
__asm(" ldr r0, [r2, #0]"); // Get TMRn register value
__asm(" ldr r1, [r2, #0]"); // Get TMRn register value again
__asm(" ldr r3, [r2, #0]"); // Get TMRn register value for a third time
__asm(" msr PRIMASK, r4"); // Restore PRIMASK
__asm(" pop {r2}"); // Get the array ptr
__asm(" str r0, [r2, #0]"); // Store register value to variable
__asm(" str r1, [r2, #4]"); // Store register value to variable
__asm(" str r3, [r2, #8]"); // Store register value to variable
__asm(" pop {r4}"); // Restore r4
__asm(" bx lr");
}
#pragma diag_default = Pe940 // Restore IAR compiler warning
#endif
//*****************************************************************************
//
//! @brief Check to see if the given CTimer is using the HFRC
//!
//! @note Calls to this function should be from inside a critical section.
//!
//! @return None.
//
//*****************************************************************************
static bool
ctimer_source_hfrc(uint32_t ui32CtimerNum)
{
uint32_t *pui32ConfigReg;
uint32_t ui32TimerASrc, ui32TimerBSrc;
//
// Find the correct register to write.
//
pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
(ui32CtimerNum * TIMER_OFFSET));
//
// Determine if this timer is using HFRC as the clock source.
// The value we are looking for is HFRC_DIV4 to HFRC_DIV4K.
// Get the clock sources and 0-base the extracted value.
//
ui32TimerASrc = AM_BFX(CTIMER, CTRL0, TMRA0CLK, *pui32ConfigReg) -
AM_ENUMX(CTIMER, CTRL0, TMRA0CLK, HFRC_DIV4);
ui32TimerBSrc = AM_BFX(CTIMER, CTRL0, TMRB0CLK, *pui32ConfigReg) -
AM_ENUMX(CTIMER, CTRL0, TMRB0CLK, HFRC_DIV4);
//
// If the source value is 0 to (HFRC_DIV4K - HFRC_DIV4), then it's HFRC.
//
if ( (ui32TimerASrc <= (AM_ENUMX(CTIMER, CTRL0, TMRA0CLK, HFRC_DIV4K) -
AM_ENUMX(CTIMER, CTRL0, TMRA0CLK, HFRC_DIV4))) ||
(ui32TimerBSrc <= (AM_ENUMX(CTIMER, CTRL0, TMRB0CLK, HFRC_DIV4K) -
AM_ENUMX(CTIMER, CTRL0, TMRB0CLK, HFRC_DIV4))) )
{
return true;
}
else
{
return false;
}
} // ctimer_source_hfrc()
//*****************************************************************************
//
// @brief Check to see if any of the CTimers or STimer are using the HFRC.
//
// This function should be used to check if the HFRC is being used in order
// to correctly establish power related settings.
//
// Note - Calls to this function should be from inside a critical section.
//
//! @return None.
//
//*****************************************************************************
static bool
timers_use_hfrc(void)
{
uint32_t ui32TimerASrc, ui32CtimerNum;
//
// Check STimer to see if it is using HFRC.
//
ui32TimerASrc = AM_BFR(CTIMER, STCFG, CLKSEL);
if ( (ui32TimerASrc == AM_REG_CTIMER_STCFG_CLKSEL_HFRC_DIV16) ||
(ui32TimerASrc == AM_REG_CTIMER_STCFG_CLKSEL_HFRC_DIV256) )
{
return true;
}
//
// Check the CTimers to see if any are using HFRC as their clock source.
//
for ( ui32CtimerNum = 0; ui32CtimerNum < MAX_CTIMERS; ui32CtimerNum++ )
{
if ( ctimer_source_hfrc(ui32CtimerNum) )
{
return true;
}
}
return false;
} // timers_use_hfrc()
//*****************************************************************************
//
//! @brief Convenience function for responding to CTimer interrupts.
//!
//! @param ui32Status is the interrupt status as returned by
//! am_hal_ctimer_int_status_get()
//!
//! This function may be called from am_ctimer_isr() to read the status of
//! the CTimer interrupts, determine which source caused the most recent
//! interrupt, and call an interrupt handler function to respond. The interrupt
//! handler to be called must be first registered with the
//! am_hal_ctimer_int_register() function.
//!
//! In the event that multiple sources are active, the corresponding
//! interrupt handlers will be called in numerical order based on interrupt def.
//!
//! @return None.
//
//*****************************************************************************
void
am_hal_ctimer_int_service(uint32_t ui32Status)
{
uint32_t ui32Clz;
am_hal_ctimer_handler_t pfnHandler;
ui32Status &= 0xFFFF;
while ( ui32Status )
{
//
// Pick one of any remaining active interrupt bits
//
#ifdef __IAR_SYSTEMS_ICC__
ui32Clz = __CLZ(ui32Status);
#else
ui32Clz = __builtin_clz(ui32Status);
#endif
//
// Turn off the bit we picked in the working copy
//
ui32Status &= ~(0x80000000 >> ui32Clz);
//
// Check the bit handler table to see if there is an interrupt handler
// registered for this particular bit.
//
pfnHandler = am_hal_ctimer_ppfnHandlers[31 - ui32Clz];
if ( pfnHandler )
{
//
// If we found an interrupt handler routine, call it now.
//
pfnHandler();
}
}
} // am_hal_ctimer_int_service()
//*****************************************************************************
//
//! @brief Register an interrupt handler for CTimer.
//!
//! @param ui32Interrupt - interrupt number to assign this interrupt handler to.
//! @param pfnHandler - Function to call when this interrupt is received.
//!
//! This function allows the caller to specify a function that should be called
//! any time a Ctimer interrupt is received. Registering an
//! interrupt handler using this function adds the function pointer to an array
//! in SRAM. This interrupt handler will be called by am_hal_ctimer_int_service()
//! whenever the ui32Status parameter indicates that the corresponding interrupt.
//!
//! To remove an interrupt handler that has already been registered, the
//! pfnHandler parameter may be set to zero.
//!
//! @note This function will not have any effect unless the
//! am_hal_ctimer_int_service() function is being used.
//!
//! @return None.
//
//*****************************************************************************
void
am_hal_ctimer_int_register(uint32_t ui32Interrupt,
am_hal_ctimer_handler_t pfnHandler)
{
uint32_t intIdx = 0;
//
// Check to make sure the interrupt number is valid. (Debug builds only)
//
switch (ui32Interrupt)
{
case AM_REG_CTIMER_INTEN_CTMRA0C0INT_M:
intIdx = AM_REG_CTIMER_INTEN_CTMRA0C0INT_S;
break;
case AM_REG_CTIMER_INTEN_CTMRB0C0INT_M:
intIdx = AM_REG_CTIMER_INTEN_CTMRB0C0INT_S;
break;
case AM_REG_CTIMER_INTEN_CTMRA1C0INT_M:
intIdx = AM_REG_CTIMER_INTEN_CTMRA1C0INT_S;
break;
case AM_REG_CTIMER_INTEN_CTMRB1C0INT_M:
intIdx = AM_REG_CTIMER_INTEN_CTMRB1C0INT_S;
break;
case AM_REG_CTIMER_INTEN_CTMRA2C0INT_M:
intIdx = AM_REG_CTIMER_INTEN_CTMRA2C0INT_S;
break;
case AM_REG_CTIMER_INTEN_CTMRB2C0INT_M:
intIdx = AM_REG_CTIMER_INTEN_CTMRB2C0INT_S;
break;
case AM_REG_CTIMER_INTEN_CTMRA3C0INT_M:
intIdx = AM_REG_CTIMER_INTEN_CTMRA3C0INT_S;
break;
case AM_REG_CTIMER_INTEN_CTMRB3C0INT_M:
intIdx = AM_REG_CTIMER_INTEN_CTMRB3C0INT_S;
break;
case AM_REG_CTIMER_INTEN_CTMRA0C1INT_M:
intIdx = AM_REG_CTIMER_INTEN_CTMRA0C1INT_S;
break;
case AM_REG_CTIMER_INTEN_CTMRB0C1INT_M:
intIdx = AM_REG_CTIMER_INTEN_CTMRB0C1INT_S;
break;
case AM_REG_CTIMER_INTEN_CTMRA1C1INT_M:
intIdx = AM_REG_CTIMER_INTEN_CTMRA1C1INT_S;
break;
case AM_REG_CTIMER_INTEN_CTMRB1C1INT_M:
intIdx = AM_REG_CTIMER_INTEN_CTMRB1C1INT_S;
break;
case AM_REG_CTIMER_INTEN_CTMRA2C1INT_M:
intIdx = AM_REG_CTIMER_INTEN_CTMRA2C1INT_S;
break;
case AM_REG_CTIMER_INTEN_CTMRB2C1INT_M:
intIdx = AM_REG_CTIMER_INTEN_CTMRB2C1INT_S;
break;
case AM_REG_CTIMER_INTEN_CTMRA3C1INT_M:
intIdx = AM_REG_CTIMER_INTEN_CTMRA3C1INT_S;
break;
case AM_REG_CTIMER_INTEN_CTMRB3C1INT_M:
intIdx = AM_REG_CTIMER_INTEN_CTMRB3C1INT_S;
break;
default:
am_hal_debug_assert_msg(false, "CTimer interrupt number out of range.");
}
am_hal_ctimer_ppfnHandlers[intIdx] = pfnHandler;
} // am_hal_ctimer_int_register()
//*****************************************************************************
//
//! @brief Set up the counter/timer.
//!
//! @param ui32TimerNumber is the number of the Timer that should be
//! configured.
//!
//! @param psConfig is a pointer to a structure that holds important settings
//! for the timer.
//!
//! This function should be used to perform the initial set-up of the
//! counter-timer.
//!
//! @note This function will eventually be replaced by
//! am_hal_ctimer_config_single(), which performs the same configuration
//! without requiring a structure. Please use am_hal_ctimer_config_single() for
//! new development.
//!
//! @return None.
//
//*****************************************************************************
void
am_hal_ctimer_config(uint32_t ui32TimerNumber,
am_hal_ctimer_config_t *psConfig)
{
uint32_t *pui32ConfigReg;
uint32_t ui32ConfigVal;
//
// Start preparing the configuration word for this timer. The configuration
// values for Timer A and Timer B provided in the config structure should
// match the register definitions already, so we will mostly just need to
// OR them together.
//
ui32ConfigVal = ( (psConfig->ui32TimerAConfig) |
(psConfig->ui32TimerBConfig << 16) );
//
// OR in the Link bit if the timers need to be linked.
//
ui32ConfigVal |= psConfig->ui32Link ? AM_HAL_CTIMER_LINK : 0;
//
// Begin critical section while config registers are read and modified.
//
AM_CRITICAL_BEGIN_ASM
//
// Find the correct register to write.
//
pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
(ui32TimerNumber * TIMER_OFFSET));
//
// Write our configuration value.
//
AM_REGVAL(pui32ConfigReg) = ui32ConfigVal;
//
// If all of the clock sources are not HRFC disable LDO when sleeping if timers are enabled.
//
if ( timers_use_hfrc() )
{
AM_BFW(PWRCTRL, MISCOPT, DIS_LDOLPMODE_TIMERS, 0);
}
else
{
AM_BFW(PWRCTRL, MISCOPT, DIS_LDOLPMODE_TIMERS, 1);
}
//
// Done with critical section.
//
AM_CRITICAL_END_ASM
} // am_hal_ctimer_config()
//*****************************************************************************
//
//! @brief Set up the counter/timer.
//!
//! @param ui32TimerNumber is the number of the Timer that should be
//! configured.
//!
//! @param ui32TimerSegment specifies which segment of the timer should be
//! enabled.
//!
//! @param ui32ConfigVal specifies the configuration options for the selected
//! timer.
//!
//! This function should be used to perform the initial set-up of the
//! counter-timer. It can be used to configure either a 16-bit timer (A or B) or a
//! 32-bit timer using the BOTH option.
//!
//! Valid values for ui32TimerSegment are:
//!
//! AM_HAL_CTIMER_TIMERA
//! AM_HAL_CTIMER_TIMERB
//! AM_HAL_CTIMER_BOTH
//!
//! The timer's clock source, mode, interrupt, and external pin behavior are
//! all controlled through the \e ui32Configval parameter. The valid options
//! for ui32ConfigVal include any ORed together combination of the following:
//!
//! Clock configuration macros:
//!
//! AM_HAL_CTIMER_HFRC_24MHZ
//! AM_HAL_CTIMER_LFRC_512HZ
//! ... etc. (See am_hal_ctimer.h for the full set of options.)
//!
//! Mode selection macros:
//!
//! AM_HAL_CTIMER_FN_ONCE
//! AM_HAL_CTIMER_FN_REPEAT
//! AM_HAL_CTIMER_FN_PWM_ONCE
//! AM_HAL_CTIMER_FN_PWM_REPEAT
//! AM_HAL_CTIMER_FN_CONTINUOUS
//!
//! Interrupt control:
//!
//! AM_HAL_CTIMER_INT_ENABLE
//!
//! Pin control:
//!
//! AM_HAL_CTIMER_PIN_ENABLE
//! AM_HAL_CTIMER_PIN_INVERT
//!
//! ADC trigger (Timer 3 only):
//!
//! AM_HAL_CTIMER_ADC_TRIG
//!
//! @return None.
//
//*****************************************************************************
void
am_hal_ctimer_config_single(uint32_t ui32TimerNumber,
uint32_t ui32TimerSegment,
uint32_t ui32ConfigVal)
{
volatile uint32_t *pui32ConfigReg;
uint32_t ui32WriteVal;
//
// Find the correct register to write based on the timer number.
//
pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
(ui32TimerNumber * TIMER_OFFSET));
//
// Begin critical section while config registers are read and modified.
//
AM_CRITICAL_BEGIN_ASM
//
// Save the value that's already in the register.
//
ui32WriteVal = AM_REGVAL(pui32ConfigReg);
//
// If we're working with TIMERB, we need to shift our configuration value
// up by 16 bits.
//
if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERB )
{
ui32ConfigVal = ((ui32ConfigVal & 0xFFFF) << 16);
}
//
// Replace part of the saved register value with the configuration value
// from the caller.
//
ui32WriteVal = (ui32WriteVal & ~(ui32TimerSegment)) | ui32ConfigVal;
//
// If we're configuring both timers, we need to set the "link" bit.
//
if ( ui32TimerSegment == AM_HAL_CTIMER_BOTH )
{
ui32WriteVal |= AM_HAL_CTIMER_LINK;
}
//
// Write our completed configuration value.
//
AM_REGVAL(pui32ConfigReg) = ui32WriteVal;
//
// If all of the clock sources are not HRFC disable LDO when sleeping if timers are enabled.
//
if ( timers_use_hfrc() )
{
AM_BFW(PWRCTRL, MISCOPT, DIS_LDOLPMODE_TIMERS, 0);
}
else
{
AM_BFW(PWRCTRL, MISCOPT, DIS_LDOLPMODE_TIMERS, 1);
}
//
// Done with critical section.
//
AM_CRITICAL_END_ASM
} // am_hal_ctimer_config_single()
//*****************************************************************************
//
//! @brief Start a timer
//!
//! @param ui32TimerNumber is the number of the timer to enable
//!
//! @param ui32TimerSegment specifies which segment of the timer should be
//! enabled. Valid values for ui32TimerSegment are:
//! AM_HAL_CTIMER_TIMERA
//! AM_HAL_CTIMER_TIMERB
//! AM_HAL_CTIMER_BOTH
//!
//! This function will enable a timer to begin incrementing. The \e
//! ui32TimerNumber parameter selects the timer that should be enabled, for
//! example, a 0 would target TIMER0. The \e ui32TimerSegment parameter allows
//! the caller to individually select a segment within a timer to be enabled,
//! such as TIMER0A, TIMER0B, or both.
//!
//! @return None.
//
//*****************************************************************************
void
am_hal_ctimer_start(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment)
{
volatile uint32_t *pui32ConfigReg;
uint32_t ui32ConfigVal;
//
// Find the correct control register.
//
pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
(ui32TimerNumber * TIMER_OFFSET));
//
// Begin critical section while config registers are read and modified.
//
AM_CRITICAL_BEGIN_ASM
//
// Read the current value.
//
ui32ConfigVal = *pui32ConfigReg;
//
// Clear out the "clear" bit.
//
ui32ConfigVal &= ~(ui32TimerSegment & (AM_REG_CTIMER_CTRL0_TMRA0CLR_M |
AM_REG_CTIMER_CTRL0_TMRB0CLR_M));
//
// Set the "enable bit"
//
ui32ConfigVal |= (ui32TimerSegment & (AM_REG_CTIMER_CTRL0_TMRA0EN_M |
AM_REG_CTIMER_CTRL0_TMRB0EN_M));
//
// Write the value back to the register.
//
AM_REGVAL(pui32ConfigReg) = ui32ConfigVal;
//
// Done with critical section.
//
AM_CRITICAL_END_ASM
} // am_hal_ctimer_start()
//*****************************************************************************
//
//! @brief Stop a timer
//!
//! @param ui32TimerNumber is the number of the timer to disable.
//!
//! @param ui32TimerSegment specifies which segment of the timer should be
//! disabled.
//!
//! This function will stop the selected timer from incrementing. The \e
//! ui32TimerNumber parameter selects the timer that should be disabled, for
//! example, a 0 would target TIMER0. The \e ui32TimerSegment parameter allows
//! the caller to individually select a segment within a timer to be disabled,
//! such as TIMER0A, TIMER0B, or both.
//!
//! This function will stop a counter/timer from counting, but does not return
//! the count value to 'zero'. If you would like to reset the counter back to
//! zero, try the am_hal_ctimer_clear() function instead.
//!
//! Valid values for ui32TimerSegment are:
//!
//! AM_HAL_CTIMER_TIMERA
//! AM_HAL_CTIMER_TIMERB
//! AM_HAL_CTIMER_BOTH
//!
//! @return None.
//
//*****************************************************************************
void
am_hal_ctimer_stop(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment)
{
volatile uint32_t *pui32ConfigReg;
//
// Find the correct control register.
//
pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
(ui32TimerNumber * TIMER_OFFSET));
//
// Begin critical section.
//
AM_CRITICAL_BEGIN_ASM
//
// Clear the "enable" bit
//
AM_REGVAL(pui32ConfigReg) &= ~(ui32TimerSegment &
(AM_REG_CTIMER_CTRL0_TMRA0EN_M |
AM_REG_CTIMER_CTRL0_TMRB0EN_M));
//
// Done with critical section.
//
AM_CRITICAL_END_ASM
} // am_hal_ctimer_stop()
//*****************************************************************************
//
//! @brief Stops a timer and resets its value back to zero.
//!
//! @param ui32TimerNumber is the number of the timer to clear.
//!
//! @param ui32TimerSegment specifies which segment of the timer should be
//! cleared.
//!
//! This function will stop a free-running counter-timer, reset its value to
//! zero, and leave the timer disabled. When you would like to restart the
//! counter, you will need to call am_hal_ctimer_start().
//!
//! The \e ui32TimerSegment parameter allows the caller to individually select
//! a segment within, such as TIMER0A, TIMER0B, or both.
//!
//! Valid values for ui32TimerSegment are:
//!
//! AM_HAL_CTIMER_TIMERA
//! AM_HAL_CTIMER_TIMERB
//! AM_HAL_CTIMER_BOTH
//!
//! @return None.
//
//*****************************************************************************
void
am_hal_ctimer_clear(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment)
{
volatile uint32_t *pui32ConfigReg;
//
// Find the correct control register.
//
pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
(ui32TimerNumber * TIMER_OFFSET));
//
// Begin critical section.
//
AM_CRITICAL_BEGIN_ASM
//
// Set the "clear" bit
//
AM_REGVAL(pui32ConfigReg) |= (ui32TimerSegment &
(AM_REG_CTIMER_CTRL0_TMRA0CLR_M |
AM_REG_CTIMER_CTRL0_TMRB0CLR_M));
//
// Done with critical section.
//
AM_CRITICAL_END_ASM
} // am_hal_ctimer_clear()
//*****************************************************************************
//
//! @brief Returns the current free-running value of the selected timer.
//!
//! @param ui32TimerNumber is the number of the timer to read.
//! @param ui32TimerSegment specifies which segment of the timer should be
//! read.
//!
//! This function returns the current free-running value of the selected timer.
//!
//! @note When reading from a linked timer, be sure to use AM_HAL_CTIMER both
//! for the segment argument.
//!
//! Valid values for ui32TimerSegment are:
//!
//! AM_HAL_CTIMER_TIMERA
//! AM_HAL_CTIMER_TIMERB
//! AM_HAL_CTIMER_BOTH
//!
//! @return Current timer value.
//
//*****************************************************************************
uint32_t
am_hal_ctimer_read(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment)
{
volatile uint32_t ui32Value = 0;
uint32_t ui32Values[4] = {0, };
uint32_t ui32TimerAddrTbl[4] =
{
REG_CTIMER_BASEADDR + AM_REG_CTIMER_TMR0_O,
REG_CTIMER_BASEADDR + AM_REG_CTIMER_TMR1_O,
REG_CTIMER_BASEADDR + AM_REG_CTIMER_TMR2_O,
REG_CTIMER_BASEADDR + AM_REG_CTIMER_TMR3_O
};
//
// Read the timer with back2back reads. This is a workaround for a clock
// domain synchronization issue. Some timer bits may be slow to increment,
// which means that the value in the timer register will sometimes be
// wrong.
//
// The architecture guarantees that:
//
// 1) If the timer is running at a speed close to the core frequency, the
// core and timer clock domains will be synchronized, and no "bad" reads
// will happen.
//
// 2) Bad reads will only happen if the core reads the timer register while
// the timer value is transitioning from one count to the next.
//
// 3) The timer will resolve to the correct value within one 24 MHz clock
// cycle.
//
// If we read the timer three times in a row with back-to-back load
// instructions, then we can guarantee that the timer will only have time
// to increment once, and that only one of the three reads can be wrong.
// This routine will perform the back-to-back reads and return all three
// values. The rest of this fuction determines which value we should
// actually use.
//
back2back_reads(ui32TimerAddrTbl[ui32TimerNumber], ui32Values);
//
// Shift or mask the values based on the given timer segment.
//
if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERB )
{
ui32Values[0] >>= 16;
ui32Values[1] >>= 16;
ui32Values[2] >>= 16;
}
else if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERA )
{
ui32Values[0] &= 0xFFFF;
ui32Values[1] &= 0xFFFF;
ui32Values[2] &= 0xFFFF;
}
//
// Now, we'll figure out which of the three values is the correct time.
//
if (ui32Values[0] == ui32Values[1])
{
//
// If the first two values match, then neither one was a bad read.
// We'll take this as the current time.
//
ui32Value = ui32Values[1];
}
else
{
//
// If the first two values didn't match, then one of them might be bad.
// If one of the first two values is bad, then the third one should
// always be correct. We'll take the third value as the correct time.
//
ui32Value = ui32Values[2];
//
// If all of the statements about the architecture are true, the third
// value should be correct, and it should always be within one count of
// either the first or the second value.
//
// Just in case, we'll check against the previous two values to make
// sure that our final answer was reasonable. If it isn't, we will
// flag it as a "bad read", and fail this assert statement.
//
// This shouldn't ever happen, and it hasn't ever happened in any of
// our tests so far.
//
am_hal_debug_assert_msg((adjacent(ui32Values[1], ui32Values[2]) ||
adjacent(ui32Values[0], ui32Values[2])),
"Bad CTIMER read");
}
return ui32Value;
} // am_hal_ctimer_read()
//*****************************************************************************
//
//! @brief Enable output to the timer pin
//!
//! @param ui32TimerNumber is the number of the timer to configure.
//!
//! @param ui32TimerSegment specifies which segment of the timer to use.
//!
//! This function will enable the output pin for the selected timer. The \e
//! ui32TimerSegment parameter allows the caller to individually select a
//! segment within, such as TIMER0A, TIMER0B, or both.
//!
//! Valid values for ui32TimerSegment are:
//!
//! AM_HAL_CTIMER_TIMERA
//! AM_HAL_CTIMER_TIMERB
//! AM_HAL_CTIMER_BOTH
//!
//! @return None.
//
//*****************************************************************************
void
am_hal_ctimer_pin_enable(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment)
{
volatile uint32_t *pui32ConfigReg;
//
// Find the correct control register.
//
pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
(ui32TimerNumber * TIMER_OFFSET));
//
// Begin critical section.
//
AM_CRITICAL_BEGIN_ASM
//
// Set the pin enable bit
//
AM_REGVAL(pui32ConfigReg) |= (ui32TimerSegment &
(AM_REG_CTIMER_CTRL0_TMRA0PE_M |
AM_REG_CTIMER_CTRL0_TMRB0PE_M));
//
// Done with critical section.
//
AM_CRITICAL_END_ASM
} // am_hal_ctimer_pin_enable()
//*****************************************************************************
//
//! @brief Disable the output pin.
//!
//! @param ui32TimerNumber is the number of the timer to configure.
//!
//! @param ui32TimerSegment specifies which segment of the timer to use.
//!
//! This function will disable the output pin for the selected timer. The \e
//! ui32TimerSegment parameter allows the caller to individually select a
//! segment within, such as TIMER0A, TIMER0B, or both.
//!
//! Valid values for ui32TimerSegment are:
//!
//! AM_HAL_CTIMER_TIMERA
//! AM_HAL_CTIMER_TIMERB
//! AM_HAL_CTIMER_BOTH
//!
//! @return None.
//
//*****************************************************************************
void
am_hal_ctimer_pin_disable(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment)
{
volatile uint32_t *pui32ConfigReg;
//
// Find the correct control register.
//
pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
(ui32TimerNumber * TIMER_OFFSET));
//
// Begin critical section.
//
AM_CRITICAL_BEGIN_ASM
//
// Clear the pin enable bit
//
AM_REGVAL(pui32ConfigReg) &= ~(ui32TimerSegment &
(AM_REG_CTIMER_CTRL0_TMRA0PE_M |
AM_REG_CTIMER_CTRL0_TMRB0PE_M));
//
// Done with critical section.
//
AM_CRITICAL_END_ASM
} // am_hal_ctimer_pin_disable()
//*****************************************************************************
//
//! @brief Set the polarity of the output pin.
//!
//! @param ui32TimerNumber is the number of the timer to configure.
//!
//! @param ui32TimerSegment specifies which segment of the timer to use.
//!
//! @param bInvertOutput determines whether the output should be inverted. If
//! true, the timer output pin for the selected timer segment will be
//! inverted.
//!
//! This function will set the polarity of the the output pin for the selected
//! timer. The \e ui32TimerSegment parameter allows the caller to individually
//! select a segment within, such as TIMER0A, TIMER0B, or both.
//!
//! Valid values for ui32TimerSegment are:
//!
//! AM_HAL_CTIMER_TIMERA
//! AM_HAL_CTIMER_TIMERB
//! AM_HAL_CTIMER_BOTH
//!
//! @return None.
//
//*****************************************************************************
void
am_hal_ctimer_pin_invert(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment,
bool bInvertOutput)
{
volatile uint32_t *pui32ConfigReg;
//
// Find the correct control register.
//
pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
(ui32TimerNumber * TIMER_OFFSET));
//
// Begin critical section.
//
AM_CRITICAL_BEGIN_ASM
//
// Figure out if we're supposed to be setting or clearing the polarity bit.
//
if ( bInvertOutput )
{
//
// Set the polarity bit to invert the output.
//
AM_REGVAL(pui32ConfigReg) |= (ui32TimerSegment &
(AM_REG_CTIMER_CTRL0_TMRA0POL_M |
AM_REG_CTIMER_CTRL0_TMRB0POL_M));
}
else
{
//
// Clear the polarity bit.
//
AM_REGVAL(pui32ConfigReg) &= ~(ui32TimerSegment &
(AM_REG_CTIMER_CTRL0_TMRA0POL_M |
AM_REG_CTIMER_CTRL0_TMRB0POL_M));
}
//
// Done with critical section.
//
AM_CRITICAL_END_ASM
} // am_hal_ctimer_pin_invert()
//*****************************************************************************
//
//! @brief Set a compare register.
//!
//! @param ui32TimerNumber is the number of the timer to configure.
//!
//! @param ui32TimerSegment specifies which segment of the timer to use.
//! Valid values for ui32TimerSegment are:
//!
//! AM_HAL_CTIMER_TIMERA
//! AM_HAL_CTIMER_TIMERB
//! AM_HAL_CTIMER_BOTH
//!
//! @param ui32CompareReg specifies which compare register should be set
//! (either 0 or 1)
//!
//! @param ui32Value is the value that should be written to the compare
//! register.
//!
//! This function allows the caller to set the values in the compare registers
//! for a timer. These registers control the period and duty cycle of the
//! timers and their associated output pins. Please see the datasheet for
//! further information on the operation of the compare registers. The \e
//! ui32TimerSegment parameter allows the caller to individually select a
//! segment within, such as TIMER0A, TIMER0B, or both.
//!
//! @note For simple manipulations of period or duty cycle for timers and PWMs,
//! you may find it easier to use the am_hal_ctimer_period_set() function.
//!
//! @return None.
//
//*****************************************************************************
void
am_hal_ctimer_compare_set(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment,
uint32_t ui32CompareReg, uint32_t ui32Value)
{
volatile uint32_t *pui32CmprRegA, *pui32CmprRegB;
uint32_t ui32CmprRegA, ui32CmprRegB;
//
// Find the correct compare register to write.
// Assume A or BOTH. We'll change later if B.
//
pui32CmprRegA = (uint32_t *)(AM_REG_CTIMERn(0) +
AM_REG_CTIMER_CMPRA0_O +
(ui32TimerNumber * TIMER_OFFSET));
pui32CmprRegB = pui32CmprRegA + CTIMER_CMPR_OFFSET / 4;
//
// Write the compare register with the selected value.
// Begin critical section while CMPR registers are modified.
//
AM_CRITICAL_BEGIN_ASM
ui32CmprRegA = *pui32CmprRegA;
ui32CmprRegB = *pui32CmprRegB;
if ( ui32CompareReg == 1 )
{
//
// CMPR reg 1
// Get the lower 16b (but may not be used if TIMERB).
//
ui32CmprRegA = ( (ui32CmprRegA & AM_REG_CTIMER_CMPRA0_CMPR0A0_M) |
AM_REG_CTIMER_CMPRA0_CMPR1A0(ui32Value & 0xFFFF) );
//
// Get the upper 16b (but may not be used if TIMERA)
//
ui32CmprRegB = ( (ui32CmprRegB & AM_REG_CTIMER_CMPRA0_CMPR0A0_M) |
AM_REG_CTIMER_CMPRA0_CMPR1A0(ui32Value >> 16) );
}
else
{
//
// CMPR reg 0
// Get the lower 16b (but may not be used if TIMERB)
//
ui32CmprRegA = ( (ui32CmprRegA & AM_REG_CTIMER_CMPRA0_CMPR1A0_M) |
AM_REG_CTIMER_CMPRA0_CMPR0A0(ui32Value & 0xFFFF) );
//
// Set the upper 16b (but may not be used if TIMERA)
//
ui32CmprRegB = ( (ui32CmprRegB & AM_REG_CTIMER_CMPRA0_CMPR1A0_M) |
AM_REG_CTIMER_CMPRA0_CMPR0A0(ui32Value >> 16) );
}
if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERB )
{
*pui32CmprRegB = ui32CmprRegB;
}
else
{
//
// It's TIMERA or BOTH.
//
*pui32CmprRegA = ui32CmprRegA;
if ( ui32TimerSegment == AM_HAL_CTIMER_BOTH )
{
*pui32CmprRegB = ui32CmprRegB;
}
}
//
// Done with critical section.
//
AM_CRITICAL_END_ASM
} // am_hal_ctimer_compare_set()
//*****************************************************************************
//
//! @brief Set the period and duty cycle of a timer.
//!
//! @param ui32TimerNumber is the number of the timer to configure.
//!
//! @param ui32TimerSegment specifies which segment of the timer to use.
//!
//! @param ui32Period specifies the desired period. This parameter effectively
//! specifies the CTIMER CMPR field(s). The CMPR fields are handled in hardware
//! as (n+1) values, therefore ui32Period is actually specified as 1 less than
//! the desired period. Finally, as mentioned in the data sheet, the CMPR fields
//! cannot be 0 (a value of 1), so neither can ui32Period be 0.
//!
//! @param ui32OnTime set the number of clocks where the output signal is high.
//!
//! This function should be used for simple manipulations of the period and
//! duty cycle of a counter/timer. To set the period and/or duty cycle of a
//! linked timer pair, use AM_HAL_CTIMER_BOTH as the timer segment argument. If
//! you would like to set the period and/or duty cycle for both TIMERA and
//! TIMERB you will need to call this function twice: once for TIMERA, and once
//! for TIMERB.
//!
//! Valid values for ui32TimerSegment are:
//!
//! AM_HAL_CTIMER_TIMERA
//! AM_HAL_CTIMER_TIMERB
//! AM_HAL_CTIMER_BOTH
//!
//! @note The ui32OnTime parameter will only work if the timer is currently
//! operating in one of the PWM modes.
//!
//! @return None.
//
//*****************************************************************************
void
am_hal_ctimer_period_set(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment,
uint32_t ui32Period, uint32_t ui32OnTime)
{
volatile uint32_t *pui32ControlReg;
volatile uint32_t *pui32CompareRegA;
volatile uint32_t *pui32CompareRegB;
uint32_t ui32Mode, ui32Comp0, ui32Comp1;
//
// Find the correct control register to pull the function select field
// from.
//
pui32ControlReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
(ui32TimerNumber * TIMER_OFFSET));
//
// Find the correct compare registers to write.
//
pui32CompareRegA = (uint32_t *)(AM_REG_CTIMERn(0) +
AM_REG_CTIMER_CMPRA0_O +
(ui32TimerNumber * TIMER_OFFSET));
pui32CompareRegB = (uint32_t *)(AM_REG_CTIMERn(0) +
AM_REG_CTIMER_CMPRB0_O +
(ui32TimerNumber * TIMER_OFFSET));
//
// Begin critical section.
//
AM_CRITICAL_BEGIN_ASM
//
// Extract the timer mode from the register based on the ui32TimerSegment
// selected by the user.
//
ui32Mode = *pui32ControlReg;
if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERB )
{
ui32Mode = ui32Mode >> 16;
}
//
// Mask to get to the bits we're interested in.
//
ui32Mode = ui32Mode & AM_REG_CTIMER_CTRL0_TMRA0FN_M;
//
// If the mode is a PWM mode, we'll need to calculate the correct CMPR0 and
// CMPR1 values here.
//
if (ui32Mode == AM_HAL_CTIMER_FN_PWM_ONCE ||
ui32Mode == AM_HAL_CTIMER_FN_PWM_REPEAT)
{
ui32Comp0 = ui32Period - ui32OnTime;
ui32Comp1 = ui32Period;
}
else
{
ui32Comp0 = ui32Period;
ui32Comp1 = 0;
}
//
// Based on the timer segment argument, write the calculated Compare 0 and
// Compare 1 values to the correct halves of the correct registers.
//
if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERA )
{
//
// For timer A, write the values to the TIMERA compare register.
//
*pui32CompareRegA = (AM_REG_CTIMER_CMPRA0_CMPR0A0(ui32Comp0) |
AM_REG_CTIMER_CMPRA0_CMPR1A0(ui32Comp1));
}
else if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERB )
{
//
// For timer B, write the values to the TIMERA compare register.
//
*pui32CompareRegB = (AM_REG_CTIMER_CMPRA0_CMPR0A0(ui32Comp0) |
AM_REG_CTIMER_CMPRA0_CMPR1A0(ui32Comp1));
}
else
{
//
// For the linked case, write the lower halves of the values to the
// TIMERA compare register, and the upper halves to the TIMERB compare
// register.
//
*pui32CompareRegA = (AM_REG_CTIMER_CMPRA0_CMPR0A0(ui32Comp0) |
AM_REG_CTIMER_CMPRA0_CMPR1A0(ui32Comp1));
*pui32CompareRegB = (AM_REG_CTIMER_CMPRA0_CMPR0A0(ui32Comp0 >> 16) |
AM_REG_CTIMER_CMPRA0_CMPR1A0(ui32Comp1 >> 16));
}
//
// Done with critical section.
//
AM_CRITICAL_END_ASM
} // am_hal_ctimer_period_set()
//*****************************************************************************
//
//! @brief Enable the TIMERA3 ADC trigger
//!
//! This function enables the ADC trigger within TIMERA3.
//!
//! @return None.
//
//*****************************************************************************
void
am_hal_ctimer_adc_trigger_enable(void)
{
//
// Begin critical section.
//
AM_CRITICAL_BEGIN_ASM
//
// Enable the ADC trigger.
//
AM_REGn(CTIMER, 0, CTRL3) |= AM_REG_CTIMER_CTRL3_ADCEN_M;
//
// Done with critical section.
//
AM_CRITICAL_END_ASM
} // am_hal_ctimer_adc_trigger_enable()
//*****************************************************************************
//
//! @brief Disable the TIMERA3 ADC trigger
//!
//! This function disables the ADC trigger within TIMERA3.
//!
//! @return None.
//
//*****************************************************************************
void
am_hal_ctimer_adc_trigger_disable(void)
{
//
// Begin critical section.
//
AM_CRITICAL_BEGIN_ASM
//
// Disable the ADC trigger.
//
AM_REGn(CTIMER, 0, CTRL3) &= ~AM_REG_CTIMER_CTRL3_ADCEN_M;
//
// Done with critical section.
//
AM_CRITICAL_END_ASM
} // am_hal_ctimer_adc_trigger_disable()
//*****************************************************************************
//
//! @brief Enables the selected timer interrupt.
//!
//! @param ui32Interrupt is the interrupt to be used.
//!
//! This function will enable the selected interrupts in the main CTIMER
//! interrupt enable register. In order to receive an interrupt from a timer,
//! you will need to enable the interrupt for that timer in this main register,
//! as well as in the timer control register (accessible though
//! am_hal_ctimer_config()), and in the NVIC.
//!
//! ui32Interrupt should be the logical OR of one or more of the following
//! values:
//!
//! AM_HAL_CTIMER_INT_TIMERA0C0
//! AM_HAL_CTIMER_INT_TIMERA0C1
//! AM_HAL_CTIMER_INT_TIMERB0C0
//! AM_HAL_CTIMER_INT_TIMERB0C1
//! AM_HAL_CTIMER_INT_TIMERA1C0
//! AM_HAL_CTIMER_INT_TIMERA1C1
//! AM_HAL_CTIMER_INT_TIMERB1C0
//! AM_HAL_CTIMER_INT_TIMERB1C1
//! AM_HAL_CTIMER_INT_TIMERA2C0
//! AM_HAL_CTIMER_INT_TIMERA2C1
//! AM_HAL_CTIMER_INT_TIMERB2C0
//! AM_HAL_CTIMER_INT_TIMERB2C1
//! AM_HAL_CTIMER_INT_TIMERA3C0
//! AM_HAL_CTIMER_INT_TIMERA3C1
//! AM_HAL_CTIMER_INT_TIMERB3C0
//! AM_HAL_CTIMER_INT_TIMERB3C1
//!
//! @return None.
//
//*****************************************************************************
void
am_hal_ctimer_int_enable(uint32_t ui32Interrupt)
{
//
// Begin critical section.
//
AM_CRITICAL_BEGIN_ASM
//
// Enable the interrupt at the module level.
//
AM_REGn(CTIMER, 0, INTEN) |= ui32Interrupt;
//
// Done with critical section.
//
AM_CRITICAL_END_ASM
} // am_hal_ctimer_int_enable()
//*****************************************************************************
//
//! @brief Return the enabled timer interrupts.
//!
//! This function will return all enabled interrupts in the main CTIMER
//! interrupt enable register.
//!
//! @return return enabled interrupts. This will be a logical or of:
//!
//! AM_HAL_CTIMER_INT_TIMERA0C0
//! AM_HAL_CTIMER_INT_TIMERA0C1
//! AM_HAL_CTIMER_INT_TIMERB0C0
//! AM_HAL_CTIMER_INT_TIMERB0C1
//! AM_HAL_CTIMER_INT_TIMERA1C0
//! AM_HAL_CTIMER_INT_TIMERA1C1
//! AM_HAL_CTIMER_INT_TIMERB1C0
//! AM_HAL_CTIMER_INT_TIMERB1C1
//! AM_HAL_CTIMER_INT_TIMERA2C0
//! AM_HAL_CTIMER_INT_TIMERA2C1
//! AM_HAL_CTIMER_INT_TIMERB2C0
//! AM_HAL_CTIMER_INT_TIMERB2C1
//! AM_HAL_CTIMER_INT_TIMERA3C0
//! AM_HAL_CTIMER_INT_TIMERA3C1
//! AM_HAL_CTIMER_INT_TIMERB3C0
//! AM_HAL_CTIMER_INT_TIMERB3C1
//!
//! @return Return the enabled timer interrupts.
//
//*****************************************************************************
uint32_t
am_hal_ctimer_int_enable_get(void)
{
//
// Return enabled interrupts.
//
return AM_REGn(CTIMER, 0, INTEN);
} // am_hal_ctimer_int_enable_get()
//*****************************************************************************
//
//! @brief Disables the selected timer interrupt.
//!
//! @param ui32Interrupt is the interrupt to be used.
//!
//! This function will disable the selected interrupts in the main CTIMER
//! interrupt register.
//!
//! ui32Interrupt should be the logical OR of one or more of the following
//! values:
//!
//! AM_HAL_CTIMER_INT_TIMERA0C0
//! AM_HAL_CTIMER_INT_TIMERA0C1
//! AM_HAL_CTIMER_INT_TIMERB0C0
//! AM_HAL_CTIMER_INT_TIMERB0C1
//! AM_HAL_CTIMER_INT_TIMERA1C0
//! AM_HAL_CTIMER_INT_TIMERA1C1
//! AM_HAL_CTIMER_INT_TIMERB1C0
//! AM_HAL_CTIMER_INT_TIMERB1C1
//! AM_HAL_CTIMER_INT_TIMERA2C0
//! AM_HAL_CTIMER_INT_TIMERA2C1
//! AM_HAL_CTIMER_INT_TIMERB2C0
//! AM_HAL_CTIMER_INT_TIMERB2C1
//! AM_HAL_CTIMER_INT_TIMERA3C0
//! AM_HAL_CTIMER_INT_TIMERA3C1
//! AM_HAL_CTIMER_INT_TIMERB3C0
//! AM_HAL_CTIMER_INT_TIMERB3C1
//!
//! @return None.
//
//*****************************************************************************
void
am_hal_ctimer_int_disable(uint32_t ui32Interrupt)
{
//
// Begin critical section.
//
AM_CRITICAL_BEGIN_ASM
//
// Disable the interrupt at the module level.
//
AM_REGn(CTIMER, 0, INTEN) &= ~ui32Interrupt;
//
// Done with critical section.
//
AM_CRITICAL_END_ASM
} // am_hal_ctimer_int_disable()
//*****************************************************************************
//
//! @brief Clears the selected timer interrupt.
//!
//! @param ui32Interrupt is the interrupt to be used.
//!
//! This function will clear the selected interrupts in the main CTIMER
//! interrupt register.
//!
//! ui32Interrupt should be the logical OR of one or more of the following
//! values:
//!
//! AM_HAL_CTIMER_INT_TIMERA0C0
//! AM_HAL_CTIMER_INT_TIMERA0C1
//! AM_HAL_CTIMER_INT_TIMERB0C0
//! AM_HAL_CTIMER_INT_TIMERB0C1
//! AM_HAL_CTIMER_INT_TIMERA1C0
//! AM_HAL_CTIMER_INT_TIMERA1C1
//! AM_HAL_CTIMER_INT_TIMERB1C0
//! AM_HAL_CTIMER_INT_TIMERB1C1
//! AM_HAL_CTIMER_INT_TIMERA2C0
//! AM_HAL_CTIMER_INT_TIMERA2C1
//! AM_HAL_CTIMER_INT_TIMERB2C0
//! AM_HAL_CTIMER_INT_TIMERB2C1
//! AM_HAL_CTIMER_INT_TIMERA3C0
//! AM_HAL_CTIMER_INT_TIMERA3C1
//! AM_HAL_CTIMER_INT_TIMERB3C0
//! AM_HAL_CTIMER_INT_TIMERB3C1
//!
//! @return None.
//
//*****************************************************************************
void
am_hal_ctimer_int_clear(uint32_t ui32Interrupt)
{
//
// Disable the interrupt at the module level.
//
AM_REGn(CTIMER, 0, INTCLR) = ui32Interrupt;
} // am_hal_ctimer_int_clear()
//*****************************************************************************
//
//! @brief Sets the selected timer interrupt.
//!
//! @param ui32Interrupt is the interrupt to be used.
//!
//! This function will set the selected interrupts in the main CTIMER
//! interrupt register.
//!
//! ui32Interrupt should be the logical OR of one or more of the following
//! values:
//!
//! AM_HAL_CTIMER_INT_TIMERA0C0
//! AM_HAL_CTIMER_INT_TIMERA0C1
//! AM_HAL_CTIMER_INT_TIMERB0C0
//! AM_HAL_CTIMER_INT_TIMERB0C1
//! AM_HAL_CTIMER_INT_TIMERA1C0
//! AM_HAL_CTIMER_INT_TIMERA1C1
//! AM_HAL_CTIMER_INT_TIMERB1C0
//! AM_HAL_CTIMER_INT_TIMERB1C1
//! AM_HAL_CTIMER_INT_TIMERA2C0
//! AM_HAL_CTIMER_INT_TIMERA2C1
//! AM_HAL_CTIMER_INT_TIMERB2C0
//! AM_HAL_CTIMER_INT_TIMERB2C1
//! AM_HAL_CTIMER_INT_TIMERA3C0
//! AM_HAL_CTIMER_INT_TIMERA3C1
//! AM_HAL_CTIMER_INT_TIMERB3C0
//! AM_HAL_CTIMER_INT_TIMERB3C1
//!
//! @return None.
//
//*****************************************************************************
void
am_hal_ctimer_int_set(uint32_t ui32Interrupt)
{
//
// Set the interrupts.
//
AM_REGn(CTIMER, 0, INTSET) = ui32Interrupt;
} // am_hal_ctimer_int_set()
//*****************************************************************************
//
//! @brief Returns either the enabled or raw timer interrupt status.
//!
//! This function will return the timer interrupt status.
//!
//! @return bEnabledOnly if true returns the status of the enabled interrupts
//! only.
//!
//! The return value will be the logical OR of one or more of the following
//! values:
//!
//! AM_HAL_CTIMER_INT_TIMERA0C0
//! AM_HAL_CTIMER_INT_TIMERA0C1
//! AM_HAL_CTIMER_INT_TIMERB0C0
//! AM_HAL_CTIMER_INT_TIMERB0C1
//! AM_HAL_CTIMER_INT_TIMERA1C0
//! AM_HAL_CTIMER_INT_TIMERA1C1
//! AM_HAL_CTIMER_INT_TIMERB1C0
//! AM_HAL_CTIMER_INT_TIMERB1C1
//! AM_HAL_CTIMER_INT_TIMERA2C0
//! AM_HAL_CTIMER_INT_TIMERA2C1
//! AM_HAL_CTIMER_INT_TIMERB2C0
//! AM_HAL_CTIMER_INT_TIMERB2C1
//! AM_HAL_CTIMER_INT_TIMERA3C0
//! AM_HAL_CTIMER_INT_TIMERA3C1
//! AM_HAL_CTIMER_INT_TIMERB3C0
//! AM_HAL_CTIMER_INT_TIMERB3C1
//!
//! @return Returns either the timer interrupt status.
//
//*****************************************************************************
uint32_t
am_hal_ctimer_int_status_get(bool bEnabledOnly)
{
//
// Return the desired status.
//
if ( bEnabledOnly )
{
uint32_t u32RetVal;
//
// Begin critical section.
//
AM_CRITICAL_BEGIN_ASM
u32RetVal = AM_REGn(CTIMER, 0, INTSTAT);
u32RetVal &= AM_REGn(CTIMER, 0, INTEN);
//
// Done with critical section.
//
AM_CRITICAL_END_ASM
return u32RetVal;
}
else
{
return AM_REGn(CTIMER, 0, INTSTAT);
}
} // am_hal_ctimer_int_status_get()
//*****************************************************************************
//
// End Doxygen group.
//! @}
//
//*****************************************************************************
|