-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhires_timer.c
More file actions
126 lines (98 loc) · 3.03 KB
/
Copy pathhires_timer.c
File metadata and controls
126 lines (98 loc) · 3.03 KB
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
#include "hires_timer.h"
#include <stddef.h>
#include "utils/critical.h"
//! Тип структуры высокоточного таймера.
typedef struct _Drive_Hires_Timer {
TIM_TypeDef* timer; //!< Периферия таймера.
uint32_t counter; //!< Счётчик переполнений таймера.
} hires_timer_t;
//! Высокоточный таймер.
static hires_timer_t hires_timer;
static void init_timer_priph(TIM_TypeDef* TIM)
{
TIM->CR1 = 0;
TIM->CR2 = 0;
TIM->DIER = 0;
TIM->PSC = HIRES_TIMER_PRESCALER - 1;
TIM->ARR = HIRES_TIMER_PERIOD_TICKS - 1;
TIM->CNT = 0;
TIM->SR = 0;
}
err_t hires_timer_init(TIM_TypeDef* timer)
{
if(timer == NULL) return E_NULL_POINTER;
hires_timer.timer = timer;
init_timer_priph(timer);
return E_NO_ERROR;
}
void hires_timer_irq_handler(void)
{
if(hires_timer.timer->SR & TIM_SR_UIF){
hires_timer.timer->SR = ~TIM_SR_UIF;
hires_timer.counter ++;
}
}
bool hires_timer_irq_enabled(void)
{
return hires_timer.timer->DIER & TIM_DIER_UIE;
}
void hires_timer_irq_set_enabled(bool enabled)
{
if(enabled){
hires_timer.timer->DIER |= TIM_DIER_UIE;
}else{
hires_timer.timer->DIER &= ~TIM_DIER_UIE;
}
}
bool hires_timer_running(void)
{
return hires_timer.timer->CR1 & TIM_CR1_CEN;
}
void hires_timer_set_running(bool running)
{
if(running){
hires_timer.timer->CR1 |= TIM_CR1_CEN;
}else{
hires_timer.timer->CR1 &= ~TIM_CR1_CEN;
}
}
void hires_timer_start(void)
{
hires_timer.timer->CR1 |= TIM_CR1_CEN;
}
void hires_timer_stop(void)
{
hires_timer.timer->CR1 &= ~TIM_CR1_CEN;
}
void hires_timer_reset(void)
{
hires_timer.timer->CNT = 0;
}
void hires_timer_value(struct timeval* tv)
{
if(tv == NULL) return;
// Сохраним флаг разрешения прерывания.
uint16_t dier = hires_timer.timer->DIER;
// Запретим прерывание переполнения.
hires_timer.timer->DIER &= ~TIM_DIER_UIE;
// Считаем значение счётчиков.
uint32_t cnt_us = hires_timer.timer->CNT;
uint32_t cnt_ms = hires_timer.counter;
// Защита от переполнения.
// Повторно считаем счётчик таймера.
uint32_t cnt_us2 = hires_timer.timer->CNT;
// Если прерывание переполнения было разрешено.
if(dier & TIM_DIER_UIE){
// Вновь разрешим прерывание переполнения.
hires_timer.timer->DIER |= TIM_DIER_UIE;
}
// Если он меньше предыдущего значения - таймер переполнился.
if(cnt_us2 < cnt_us){
// Присвоим новое значение.
cnt_us = cnt_us2;
// И увеличим счётчик миллисекунд.
cnt_ms ++;
}
tv->tv_sec = cnt_ms / 1000;
tv->tv_usec = (cnt_ms % 1000) * 1000 + cnt_us;
}