-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtimer.c
150 lines (127 loc) · 3.21 KB
/
timer.c
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
/*
* timer.c
*
* Module for the BCM2835 system timer.
* Does not prevent using ST_COMPARE0 or ST_COMPARE2 that are used by the GPU!
*
* Resources:
* https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
*
* TODO Add option for timer interrupts
*/
#include "bcm2835.h"
#include "timer.h"
#include "irq.h"
/* -----------------------------------------
Definitions
----------------------------------------- */
/* -----------------------------------------
Types and data structures
----------------------------------------- */
/* -----------------------------------------
Module static functions
----------------------------------------- */
/* -----------------------------------------
Module globals
----------------------------------------- */
static system_timer_regs_t *pTimer = (system_timer_regs_t*)BCM2835_ST_BASE;
/*------------------------------------------------
* bcm2835_st_read()
*
* Read the System Timer Counter (low 32-bits)
*
* param: none
* return: Low 32-bit running counter
*
*/
uint32_t bcm2835_st_read(void)
{
uint32_t timer_low;
timer_low = pTimer->st_clo;
dmb();
return timer_low;
}
/*------------------------------------------------
* bcm2835_st_delay()
*
* Delays for the specified number of microseconds with
* 1 to 4,294,967,295 (~71.5 minutes)
*
* param: Microseconds to delay
* return: none
*
*/
void bcm2835_st_delay(uint32_t micros)
{
uint32_t now;
if ( micros == 0 )
return;
now = bcm2835_st_read();
while( (bcm2835_st_read() - now) < micros )
{
/* Wait for timer to expire.
* This type of calculation and comparison to the delta
* with unsigned math solved the 0-crossing
* problem of the free running timer register.
*/
}
}
/*------------------------------------------------
* bcm2835_st_set_compare()
*
* Setup timer compare register for a compare interval
* 1 to 4,294,967,295 (~71.5 minutes)
*
* param: Timer compare register ID, interval
* return: 1- success, 0- otherwise
*
*/
int bcm2835_st_set_compare(comp_reg_t compare_reg, uint32_t interval)
{
uint32_t next_compare_val;
if ( interval == 0 )
return 0;
/* Update the timer compare match register
*/
next_compare_val = pTimer->st_clo + interval;
dmb();
if ( compare_reg == ST_COMPARE1 )
{
pTimer->st_c1 = next_compare_val;
}
else /* ST_COMPARE3 */
{
pTimer->st_c3 = next_compare_val;
}
return 1;
}
/*------------------------------------------------
* bcm2835_st_is_compare_match()
*
* Check by polling if a compare match has been achieved.
*
* param: Timer compare register ID
* return: 1- match, 0- otherwise
*
*/
int bcm2835_st_is_compare_match(comp_reg_t compare_reg)
{
int match;
match = pTimer->st_cs & (1 << compare_reg);
dmb();
return (match ? 1 : 0);
}
/*------------------------------------------------
* bcm2835_st_clr_compare_match()
*
* Clear a compare match status.
*
* param: Timer compare register ID
* return: none
*
*/
void bcm2835_st_clr_compare_match(comp_reg_t compare_reg)
{
dmb();
pTimer->st_cs = (1 << compare_reg);
}