libopencm3
A free/libre/open-source firmware library for various ARM Cortex-M3 microcontrollers.
timer.c
Go to the documentation of this file.
1/** @defgroup timer_file Timer peripheral API
2 * @brief SWM050 Timer API.
3 * @ingroup peripheral_apis
4 * LGPL License Terms @ref lgpl_license
5 * @author @htmlonly © @endhtmlonly 2020
6 * Caleb Szalacinski <contact@skiboy.net>
7 */
8/*
9 * This file is part of the libopencm3 project.
10 *
11 * Copyright (C) 2020 Caleb Szalacinski <contact@skiboy.net>
12 *
13 * This library is free software: you can redistribute it and/or modify
14 * it under the terms of the GNU Lesser General Public License as published by
15 * the Free Software Foundation, either version 3 of the License, or
16 * (at your option) any later version.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public License
24 * along with this library. If not, see <http://www.gnu.org/licenses/>.
25 */
26/**@{*/
30
31/**
32 * Internal function for timer setup.
33 * @param timer Select timer @ref timer_select
34 * @param timer_int_en Passed to @ref timer_int_enable()
35 * @param op_mode Passed to @ref timer_operation_mode()
36 * @param edge_mode Passed to @ref timer_edge_mode()
37 * @param loop_mode Passed to @ref timer_loop_mode()
38 * @param clk_src Passed to @ref timer_clock_source()
39 * @param output_mode Passed to @ref timer_output_mode()
40 * @param output_level Passed to @ref timer_output_level()
41 */
42static void timer_setup_internal(uint32_t timer,
43 bool timer_int_en,
44 enum timer_operation_modes op_mode,
45 enum timer_edge_modes edge_mode,
46 enum timer_loop_modes loop_mode,
47 enum timer_clk_src clk_src,
48 enum timer_output_modes output_mode,
49 enum timer_level output_level)
50{
51 timer_enable(timer, false);
52
53 /* Conserve power by shutting off the unneeded clock */
54 timer_clock_enable(timer, (clk_src == TIMER_CLK_INTERNAL));
55
56 timer_loop_mode(timer, loop_mode);
57 timer_output_mode(timer, output_mode);
58 timer_output_level(timer, output_level);
59 timer_clock_source(timer, clk_src);
60 timer_operation_mode(timer, op_mode);
61 timer_edge_mode(timer, edge_mode);
62 timer_int_enable(timer, timer_int_en);
64}
65
66/**
67 * Setup the timer in counter mode.
68 * @note Call @ref timer_enable() when you are ready to start the timer.
69 * @note Be sure to set the alternate functions of the timer pins
70 * with @ref syscon_sel_af() and disable SWD on those pins
71 * with @ref syscon_sel_swd() as needed.
72 * @note If interrupts are enabled here, the interrupt should also be enabled
73 * using the NVIC before enabling the timer.
74 * @param timer Select timer @ref timer_select
75 * @param timer_int_en Passed to @ref timer_int_enable()
76 * @param edge_mode Passed to @ref timer_edge_mode()
77 * @param loop_mode Passed to @ref timer_loop_mode()
78 * @param clk_src Passed to @ref timer_clock_source()
79 * @param output_mode Passed to @ref timer_output_mode()
80 * @param output_level Passed to @ref timer_output_level()
81 * @param target Passed to @ref timer_counter_target_value()
82 */
83void timer_counter_setup(uint32_t timer,
84 bool timer_int_en,
85 enum timer_edge_modes edge_mode,
86 enum timer_loop_modes loop_mode,
87 enum timer_clk_src clk_src,
88 enum timer_output_modes output_mode,
89 enum timer_level output_level,
90 uint32_t target)
91{
92 timer_setup_internal(timer, timer_int_en, TIMER_MODE_COUNTER, edge_mode,
93 loop_mode, clk_src, output_mode, output_level);
94 timer_counter_target_value(timer, target);
95}
96
97/**
98 * Setup the timer in PWM mode.
99 * @note Call @ref timer_enable() when you are ready to start the timer.
100 * @note Be sure to set the alternate functions of the timer pins
101 * with @ref syscon_sel_af() and disable SWD on those pins
102 * with @ref syscon_sel_swd() as needed.
103 * @note If interrupts are enabled here, the interrupt should also be enabled
104 * using the NVIC before enabling the timer.
105 * @param timer Select timer @ref timer_select
106 * @param timer_int_en Passed to @ref timer_int_enable()
107 * @param edge_mode Passed to @ref timer_edge_mode()
108 * @param clk_src Passed to @ref timer_clock_source()
109 * @param output_level Passed to @ref timer_output_level()
110 * @param period0 Passed to @ref timer_pwm_target_value()
111 * @param period1 Passed to @ref timer_pwm_target_value()
112 */
113void timer_pwm_setup(uint32_t timer,
114 bool timer_int_en,
115 enum timer_edge_modes edge_mode,
116 enum timer_clk_src clk_src,
117 enum timer_level output_level,
118 uint16_t period0,
119 uint16_t period1)
120{
121 timer_setup_internal(timer, timer_int_en, TIMER_MODE_PWM, edge_mode,
123 output_level);
124 timer_pwm_target_value(timer, period0, period1);
125}
126
127/**
128 * Setup the timer in pulse capture mode.
129 * @note Call @ref timer_enable() when you are ready to start the timer.
130 * @note Be sure to set the alternate functions of the timer pins
131 * with @ref syscon_sel_af() and disable SWD on those pins
132 * with @ref syscon_sel_swd() as needed.
133 * @note If interrupts are enabled here, the interrupt should also be enabled
134 * using the NVIC before enabling the timer.
135 * @param timer Select timer @ref timer_select
136 * @param timer_int_en Passed to @ref timer_int_enable()
137 * @param edge_mode Passed to @ref timer_edge_mode()
138 * @param loop_mode Passed to @ref timer_loop_mode()
139 */
140void timer_pulse_capture_setup(uint32_t timer,
141 bool timer_int_en,
142 enum timer_edge_modes edge_mode,
143 enum timer_loop_modes loop_mode)
144{
146 edge_mode, loop_mode, TIMER_CLK_INTERNAL,
148}
149
150/**
151 * Setup the timer in duty cycle capture mode.
152 * @note Call @ref timer_enable() when you are ready to start the timer.
153 * @note Be sure to set the alternate functions of the timer pins
154 * with @ref syscon_sel_af() and disable SWD on those pins
155 * with @ref syscon_sel_swd() as needed.
156 * @note If interrupts are enabled here, the interrupt should also be enabled
157 * using the NVIC before enabling the timer.
158 * @param timer Select timer @ref timer_select
159 * @param timer_int_en Passed to @ref timer_int_enable()
160 * @param edge_mode Passed to @ref timer_edge_mode()
161 * @param loop_mode Passed to @ref timer_loop_mode()
162 */
164 bool timer_int_en,
165 enum timer_edge_modes edge_mode,
166 enum timer_loop_modes loop_mode)
167{
169 edge_mode, loop_mode, TIMER_CLK_INTERNAL,
171}
172
173/**
174 * Set the timer clock divider, based off of the 18MHz oscillator
175 * @param div Timer clock divider. Only the 6 least-significant bits are used,
176 * Takes values from 0 to 63 (in reality the possible values are the even
177 * numbers from 2 to 62, as well as the number 1). Anything after the 6
178 * least-significant bits are stripped off of the value. If the value is 0,
179 * it will be treated as a 1. All odd values other than 1 are rounded down
180 * to the closest even value, due to the fact that all odd values are
181 * treated by the register as a 1, which would likely be unexpected. A
182 * value of 0 would also normally be treated as a 2, which would also be
183 * unexpected behavior.
184 */
185void timer_clock_div(uint8_t div)
186{
187 /* If the value is 0 or 1, make it odd, meaning no divide. */
188 /* Otherwise, drop div to the closest even value. */
189 div = (div <= 1) ? 1 : (div & ~0x1);
190 SYSCTL_SYS_CFG_0 = (~TIMER_DIV_MASK & SYSCTL_SYS_CFG_0) | (div << 16);
191}
192
193/**
194 * Enables or disables the timer.
195 * @param timer Select timer @ref timer_select
196 * @param en Enable or disable the timer
197 */
198void timer_enable(uint32_t timer, bool en)
199{
200 if (en) {
201 TIMER_CTRL(timer) |= TIMER_CTRL_EN;
202 } else {
203 TIMER_CTRL(timer) &= ~TIMER_CTRL_EN;
204 }
205}
206
207/**
208 * Enables or disables the timer's internal clock.
209 * @param timer Select timer @ref timer_select
210 * @param en Enable or disable the internal clock
211 */
212void timer_clock_enable(uint32_t timer, bool en)
213{
214 if (timer == TIMER_SE1) {
215 if (en) {
217 } else {
218 SYSCTL_SYS_CFG_1 &= ~SYSCTL_SYS_CFG_1_TIMERSE1;
219 }
220 } else {
221 if (en) {
223 } else {
224 SYSCTL_SYS_CFG_1 &= ~SYSCTL_SYS_CFG_1_TIMERSE0;
225 }
226 }
227}
228
229/**
230 * Selects the mode of operation.
231 * @param timer Select timer @ref timer_select
232 * @param mode The mode of operation @ref timer_operation_modes
233 */
234void timer_operation_mode(uint32_t timer, enum timer_operation_modes mode)
235{
236 uint32_t reg = TIMER_CTRL(timer) & ~(TIMER_CTRL_OUTMOD_MASK << TIMER_CTRL_OUTMOD_SHIFT);
237 TIMER_CTRL(timer) = reg | (mode << TIMER_CTRL_OUTMOD_SHIFT);
238}
239
240/**
241 * Selects the output mode.
242 * Only used in counter mode.
243 * When done counting, the pin can be set to no output,
244 * to invert the current pin level, to set the pin high,
245 * or to set the pin low.
246 * @note Be sure to set the alternate functions of the timer pins
247 * with @ref syscon_sel_af() and disable SWD on those pins
248 * with @ref syscon_sel_swd() as needed.
249 * @param timer Select timer @ref timer_select
250 * @param mode The output mode @ref timer_output_modes
251 */
252void timer_output_mode(uint32_t timer, enum timer_output_modes mode)
253{
254 uint32_t reg = TIMER_CTRL(timer) & ~(TIMER_CTRL_WMOD_MASK << TIMER_CTRL_WMOD_SHIFT);
255 TIMER_CTRL(timer) = reg | (mode << TIMER_CTRL_WMOD_SHIFT);
256}
257
258/**
259 * Selects the initial output level.
260 * Only used in counter and PWM modes.
261 * @param timer Select timer @ref timer_select
262 * @param level The initial output level @ref timer_level
263 */
264void timer_output_level(uint32_t timer, enum timer_level level)
265{
266 TIMER_OUTPVAL(timer) = level;
267}
268
269/**
270 * Selects the edge mode.
271 * @param timer Select timer @ref timer_select
272 * @param mode The edge mode @ref timer_edge_modes
273 */
274void timer_edge_mode(uint32_t timer, enum timer_edge_modes mode)
275{
276 if (mode) {
277 TIMER_CTRL(timer) |= TIMER_CTRL_TMOD;
278 } else {
279 TIMER_CTRL(timer) &= ~TIMER_CTRL_TMOD;
280 }
281}
282
283/**
284 * Selects the loop mode.
285 * This has no use in PWM mode.
286 * In loop mode with counter mode, the counter will constantly loop.
287 * In loop mode with the capture modes, the values will be captured
288 * again and again. In single mode, these operations happen only once.
289 * @param timer Select timer @ref timer_select
290 * @param mode The loop mode @ref timer_loop_modes
291 */
292void timer_loop_mode(uint32_t timer, enum timer_loop_modes mode)
293{
294 if (mode) {
295 TIMER_CTRL(timer) |= TIMER_CTRL_LMOD;
296 } else {
297 TIMER_CTRL(timer) &= ~TIMER_CTRL_LMOD;
298 }
299}
300
301/**
302 * Selects the clock source for the timer.
303 * @note Be sure to set the alternate functions of the timer pins
304 * with @ref syscon_sel_af() and disable SWD on those pins
305 * with @ref syscon_sel_swd() as needed.
306 * @note If not using the internal clock, you can disable it
307 * with @ref timer_clock_enable() for power savings.
308 * @param timer Select timer @ref timer_select
309 * @param src Select the internal or external clock source @ref timer_clk_src
310 */
311void timer_clock_source(uint32_t timer, enum timer_clk_src src)
312{
313 if (src) {
315 } else {
316 TIMER_CTRL(timer) &= ~TIMER_CTRL_OSCMOD;
317 }
318}
319
320/**
321 * Sets the target values for counter mode.
322 * @param timer Select timer @ref timer_select
323 * @param target The value to count up to
324 */
325void timer_counter_target_value(uint32_t timer, uint32_t target)
326{
327 TIMER_TARVAL(timer) = target;
328}
329
330/**
331 * Sets the target values for PWM mode.
332 * @param timer Select timer @ref timer_select
333 * @param period0 length of period 0 in clock cycles. Whether
334 * it is high or low is set in @ref timer_output_level()
335 * @param period1 length of period 1
336 */
337void timer_pwm_target_value(uint32_t timer, uint16_t period0, uint16_t period1)
338{
339 timer_counter_target_value(timer, (period1 << 16) | period0);
340}
341
342/**
343 * Enable or disable the interrupt.
344 * In counter mode, when the count has been completed,
345 * an interrupt is generated.
346 * In PWM mode, on a level change, an interupt is generated.
347 * In either capture mode, when a capture is complete,
348 * an interrupt is generated.
349 * @note If interrupts are enabled here, the interrupt should also be enabled
350 * using the NVIC before enabling the timer.
351 * @param timer Select timer @ref timer_select
352 * @param en Enable or disable the interrupt
353 */
354void timer_int_enable(uint32_t timer, bool en)
355{
356 if (en) {
358 } else {
359 TIMER_INTCTL(timer) &= ~TIMER_INTCTL_INTEN;
360 }
361}
362
363/**
364 * Sets the interrupt mask.
365 * @param timer Select timer @ref timer_select
366 * @param masked Whether or not to mask the interrupt @ref timer_int_masked
367 */
368void timer_int_mask(uint32_t timer, enum timer_int_masked masked)
369{
370 if (masked) {
371 TIMER_INTCTL(timer) &= ~TIMER_INTCTL_INTMSK;
372 } else {
374 }
375}
376
377/**
378 * Gets the current counter value, and clears the interrupt/interrupt overflow.
379 * If in PWM mode, this is only used for clearing the interrupt.
380 * @param timer Select timer @ref timer_select
381 * @return The current counter value
382 */
383uint32_t timer_get_current_value(uint32_t timer)
384{
385 return TIMER_CURVAL(timer);
386}
387
388/**
389 * Gets the cycle width.
390 * Only used in duty cycle capture mode.
391 * @note See the datasheet for more concise diagrams.
392 * @param timer Select timer @ref timer_select
393 * @return The cycle width
394 */
395uint32_t timer_get_cycle_width(uint32_t timer)
396{
397 return TIMER_CAPW(timer);
398}
399
400/**
401 * Gets the pulse width in pulse capture mode,
402 * or gets the period width in duty cycle capture mode.
403 * @note See the datasheet for more concise diagrams.
404 * @param timer Select timer @ref timer_select
405 * @return The pulse width
406 */
407uint32_t timer_get_pulse_width(uint32_t timer)
408{
409 return TIMER_CAPLH(timer);
410}
411
412/**
413 * Gets the current output period in PWM mode.
414 * @param timer Select timer @ref timer_select
415 * @return The current output period @ref timer_pwm_period
416 */
418{
419 return TIMER_MOD2LF(timer) & 0x1;
420}
421
422/**
423 * Gets the interrupt status after masking.
424 * @param timer Select timer @ref timer_select
425 * @return The interrupt status after masking
426 */
427bool timer_int_status(uint32_t timer)
428{
429 return TIMER_INTMSKSTAT(timer) & 0x1;
430}
431
432/**
433 * Gets the interrupt status before masking.
434 * @param timer Select timer @ref timer_select
435 * @return The interrupt status before masking
436 */
437bool timer_int_raw_status(uint32_t timer)
438{
439 return TIMER_INTSTAT(timer) & 0x1;
440}
441
442/**
443 * Gets the interrupt overflow status.
444 * Overflow will occur if the interrupt has not been cleared when a second
445 * interrupt happens.
446 * @param timer Select timer @ref timer_select
447 * @return The interrupt overflow status
448 */
449bool timer_int_overflow_status(uint32_t timer)
450{
451 return TIMER_INTFLAG(timer) & 0x1;
452}
453
454/**@}*/
#define SYSCTL_SYS_CFG_1_TIMERSE0
Definition: sysctl.h:38
#define SYSCTL_SYS_CFG_1_TIMERSE1
Definition: sysctl.h:37
#define SYSCTL_SYS_CFG_0
Clock dividers for TIMERSE and SCLK.
Definition: sysctl.h:46
#define SYSCTL_SYS_CFG_1
TIMERSE0, TIMERSE1, and WDT enable.
Definition: sysctl.h:48
uint32_t timer_get_cycle_width(uint32_t timer)
Gets the cycle width.
Definition: timer.c:395
bool timer_int_overflow_status(uint32_t timer)
Gets the interrupt overflow status.
Definition: timer.c:449
void timer_pwm_target_value(uint32_t timer, uint16_t period0, uint16_t period1)
Sets the target values for PWM mode.
Definition: timer.c:337
void timer_output_level(uint32_t timer, enum timer_level level)
Selects the initial output level.
Definition: timer.c:264
void timer_int_mask(uint32_t timer, enum timer_int_masked masked)
Sets the interrupt mask.
Definition: timer.c:368
static void timer_setup_internal(uint32_t timer, bool timer_int_en, enum timer_operation_modes op_mode, enum timer_edge_modes edge_mode, enum timer_loop_modes loop_mode, enum timer_clk_src clk_src, enum timer_output_modes output_mode, enum timer_level output_level)
Internal function for timer setup.
Definition: timer.c:42
void timer_operation_mode(uint32_t timer, enum timer_operation_modes mode)
Selects the mode of operation.
Definition: timer.c:234
bool timer_int_status(uint32_t timer)
Gets the interrupt status after masking.
Definition: timer.c:427
void timer_clock_div(uint8_t div)
Set the timer clock divider, based off of the 18MHz oscillator.
Definition: timer.c:185
enum timer_pwm_period timer_get_pwm_period(uint32_t timer)
Gets the current output period in PWM mode.
Definition: timer.c:417
void timer_edge_mode(uint32_t timer, enum timer_edge_modes mode)
Selects the edge mode.
Definition: timer.c:274
void timer_counter_setup(uint32_t timer, bool timer_int_en, enum timer_edge_modes edge_mode, enum timer_loop_modes loop_mode, enum timer_clk_src clk_src, enum timer_output_modes output_mode, enum timer_level output_level, uint32_t target)
Setup the timer in counter mode.
Definition: timer.c:83
void timer_clock_enable(uint32_t timer, bool en)
Enables or disables the timer's internal clock.
Definition: timer.c:212
void timer_counter_target_value(uint32_t timer, uint32_t target)
Sets the target values for counter mode.
Definition: timer.c:325
uint32_t timer_get_current_value(uint32_t timer)
Gets the current counter value, and clears the interrupt/interrupt overflow.
Definition: timer.c:383
void timer_clock_source(uint32_t timer, enum timer_clk_src src)
Selects the clock source for the timer.
Definition: timer.c:311
void timer_output_mode(uint32_t timer, enum timer_output_modes mode)
Selects the output mode.
Definition: timer.c:252
void timer_duty_cycle_capture_setup(uint32_t timer, bool timer_int_en, enum timer_edge_modes edge_mode, enum timer_loop_modes loop_mode)
Setup the timer in duty cycle capture mode.
Definition: timer.c:163
void timer_enable(uint32_t timer, bool en)
Enables or disables the timer.
Definition: timer.c:198
void timer_loop_mode(uint32_t timer, enum timer_loop_modes mode)
Selects the loop mode.
Definition: timer.c:292
void timer_pulse_capture_setup(uint32_t timer, bool timer_int_en, enum timer_edge_modes edge_mode, enum timer_loop_modes loop_mode)
Setup the timer in pulse capture mode.
Definition: timer.c:140
uint32_t timer_get_pulse_width(uint32_t timer)
Gets the pulse width in pulse capture mode, or gets the period width in duty cycle capture mode.
Definition: timer.c:407
bool timer_int_raw_status(uint32_t timer)
Gets the interrupt status before masking.
Definition: timer.c:437
void timer_pwm_setup(uint32_t timer, bool timer_int_en, enum timer_edge_modes edge_mode, enum timer_clk_src clk_src, enum timer_level output_level, uint16_t period0, uint16_t period1)
Setup the timer in PWM mode.
Definition: timer.c:113
void timer_int_enable(uint32_t timer, bool en)
Enable or disable the interrupt.
Definition: timer.c:354
#define TIMER_INTCTL_INTEN
Interrupt enable.
Definition: timer.h:141
#define TIMER_CTRL_OUTMOD_SHIFT
Definition: timer.h:134
#define TIMER_CTRL_LMOD
Loop mode selection.
Definition: timer.h:131
#define TIMER_CTRL_EN
Definition: timer.h:125
#define TIMER_CTRL_TMOD
Valid edge selection.
Definition: timer.h:129
#define TIMER_CTRL_OSCMOD
Clock source selection.
Definition: timer.h:127
#define TIMER_CTRL_WMOD_MASK
Timer Operation Mode Mask.
Definition: timer.h:136
#define TIMER_CTRL_OUTMOD_MASK
Timer Output Mode Mask.
Definition: timer.h:133
#define TIMER_CTRL_WMOD_SHIFT
Definition: timer.h:137
#define TIMER_INTCTL_INTMSK
Interrupt mask.
Definition: timer.h:139
#define TIMER_OUTPVAL(x)
Timer output pin value.
Definition: timer.h:112
#define TIMER_CAPLH(x)
Pulse width in modes 2 and 3.
Definition: timer.h:108
#define TIMER_INTMSKSTAT(x)
Interrupt status after masking.
Definition: timer.h:118
#define TIMER_INTSTAT(x)
Interrupt status before masking.
Definition: timer.h:116
#define TIMER_INTFLAG(x)
Interrupt overflow; 1 if interrupt occurs again without being cleared.
Definition: timer.h:120
#define TIMER_CURVAL(x)
Current count value in modes 0, 2, and 3.
Definition: timer.h:104
#define TIMER_CAPW(x)
Cycle width in mode 3.
Definition: timer.h:106
#define TIMER_MOD2LF(x)
PWM state in mode 1.
Definition: timer.h:110
#define TIMER_CTRL(x)
Timer control register.
Definition: timer.h:99
#define TIMER_TARVAL(x)
The target value(s).
Definition: timer.h:102
#define TIMER_INTCTL(x)
Interrupt enable and mask.
Definition: timer.h:114
timer_output_modes
Timer Output Modes.
Definition: timer.h:80
timer_level
Timer Level.
Definition: timer.h:40
timer_pwm_period
Timer PWM Periods.
Definition: timer.h:88
timer_loop_modes
Timer Loop Modes.
Definition: timer.h:74
timer_edge_modes
Timer Edge Modes.
Definition: timer.h:46
timer_clk_src
Timer Clock Source.
Definition: timer.h:62
timer_int_masked
Timer Interrupt Mask.
Definition: timer.h:68
#define TIMER_SE1
Definition: timer.h:36
timer_operation_modes
Timer Operation Modes.
Definition: timer.h:54
@ TIMER_OUTPUT_NONE
Definition: timer.h:81
@ TIMER_LEVEL_LOW
Definition: timer.h:41
@ TIMER_LOOP_MODE
Definition: timer.h:75
@ TIMER_CLK_INTERNAL
Definition: timer.h:63
@ TIMER_UNMASKED
Definition: timer.h:69
@ TIMER_MODE_DUTY_CYCLE_CAPTURE
Definition: timer.h:58
@ TIMER_MODE_COUNTER
Definition: timer.h:55
@ TIMER_MODE_PULSE_CAPTURE
Definition: timer.h:57
@ TIMER_MODE_PWM
Definition: timer.h:56