1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/drivers/include/periph/timer.h
Marian Buschsieweke b917807444
drivers/periph_timer: add periph_timer_query_freqs
Allow accessing supported timer frequencies with a dedicated API.
This API needs to be implemented per platform and is available with
the feature periph_timer_query_freqs.
2023-12-05 16:07:24 +01:00

304 lines
9.5 KiB
C

/*
* Copyright (C) 2014-2015 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup drivers_periph_timer Timer
* @ingroup drivers_periph
* @brief Low-level timer peripheral driver
*
* # (Low-) Power Implications
*
* After calling timer_init(), the underlying hardware timer **should** be
* powered on and running. When a timer is explicitly stopped by calling
* timer_stop(), the timer **should** be stopped and powered down (e.g. by
* peripheral clock gating). Once the timer is started again (by calling
* timer_start()), it should transparently continue its previously configured
* operation.
*
* While the timer is active, the implementation might need to block certain
* power modes on specific CPU implementation.
*
* @{
* @file
* @brief Low-level timer peripheral driver interface definitions
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*/
#ifndef PERIPH_TIMER_H
#define PERIPH_TIMER_H
#include <limits.h>
#include <stdint.h>
#include "architecture.h"
#include "periph_cpu.h"
#include "periph_conf.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Default timer definition macro
*
* Overwrite this in your CPUs periph_cpu.h file if needed
*/
#ifndef TIMER_DEV
#define TIMER_DEV(x) (x)
#endif
/**
* @brief Default value for timer not defined
*/
#ifndef TIMER_UNDEF
#define TIMER_UNDEF (UINT_FAST8_MAX)
#endif
/**
* @brief Default timer type
*
* We chose the name of tim_t here to avoid naming clashes with other libraries
* and vendor device header.
*/
#ifndef HAVE_TIMER_T
typedef uint_fast8_t tim_t;
#endif
/**
* @brief Reset the timer when the set() function is called
*
* When set, calling the timer_set_periodic() function resets the timer count value.
*/
#ifndef TIM_FLAG_RESET_ON_SET
#define TIM_FLAG_RESET_ON_SET (0x01)
#endif
/**
* @brief Reset the timer on match
*
* When set, a match on this channel will reset the timer count value.
* When set on multiple channels, only the channel with the lowest match value
* will be reached.
*/
#ifndef TIM_FLAG_RESET_ON_MATCH
#define TIM_FLAG_RESET_ON_MATCH (0x02)
#endif
/**
* @brief Keep the timer stopped after setting alarm.
*
* When set, the timer will remained stopped after a timer_set_periodic() and
* can be started manually with timer_start().
*/
#ifndef TIM_FLAG_SET_STOPPED
#define TIM_FLAG_SET_STOPPED (0x04)
#endif
/**
* @brief Signature of event callback functions triggered from interrupts
*
* @param[in] arg optional context for the callback
* @param[in] channel timer channel that triggered the interrupt
*/
typedef void (*timer_cb_t)(void *arg, int channel);
/**
* @brief Default interrupt context entry holding callback and argument
*/
#ifndef HAVE_TIMER_ISR_CTX_T
typedef struct {
timer_cb_t cb; /**< callback executed from timer interrupt */
void *arg; /**< optional argument given to that callback */
} timer_isr_ctx_t;
#endif
/**
* @brief Initialize the given timer
*
* Each timer device is running with the given speed. Each can contain one or
* more channels as defined in periph_conf.h. The timer is configured in
* up-counting mode and will count until TIMER_x_MAX_VALUE as defined in used
* board's periph_conf.h until overflowing.
*
* The timer will be started automatically after initialization with interrupts
* enabled.
*
* @param[in] dev the timer to initialize
* @param[in] freq requested number of ticks per second
* @param[in] cb this callback is called in interrupt context, the
* emitting channel is passed as argument
* @param[in] arg argument to the callback
*
* @return 0 on success
* @return -1 if speed not applicable or unknown device given
*/
int timer_init(tim_t dev, uint32_t freq, timer_cb_t cb, void *arg);
/**
* @brief Set a given timer channel for the given timer device
*
* The callback given during initialization is called when timeout ticks have
* passed after calling this function
*
* @param[in] dev the timer device to set
* @param[in] channel the channel to set
* @param[in] timeout timeout in ticks after that the registered callback
* is executed
*
* @return 0 on success
* @return -1 on error
*/
int timer_set(tim_t dev, int channel, unsigned int timeout);
/**
* @brief Set an absolute timeout value for the given channel of the given timer
*
* Timers that are less wide than `unsigned int` accept and truncate overflown
* values.
*
* @param[in] dev the timer device to set
* @param[in] channel the channel to set
* @param[in] value the absolute compare value when the callback will be
* triggered
*
* @return 0 on success
* @return -1 on error
*/
int timer_set_absolute(tim_t dev, int channel, unsigned int value);
/**
* @brief Set an absolute timeout value for the given channel of the given timer.
* The timeout will be called periodically for each iteration.
*
* @note Only one channel with `TIM_FLAG_RESET_ON_MATCH` can be active.
* Some platforms (Atmel) only allow to use the first channel as TOP value.
*
* @note Needs to be enabled with `FEATURES_REQUIRED += periph_timer_periodic`.
*
* @param[in] dev the timer device to set
* @param[in] channel the channel to set
* @param[in] value the absolute compare value when the callback will be
* triggered
* @param[in] flags options
*
* @return 0 on success
* @return -1 on error
*/
int timer_set_periodic(tim_t dev, int channel, unsigned int value, uint8_t flags);
/**
* @brief Clear the given channel of the given timer device
*
* @param[in] dev the timer device to clear
* @param[in] channel the channel on the given device to clear
*
* @return 0 on success
* @return -1 on error
*/
int timer_clear(tim_t dev, int channel);
/**
* @brief Read the current value of the given timer device
*
* @param[in] dev the timer to read the current value from
*
* @return the timers current value
*/
unsigned int timer_read(tim_t dev);
/**
* @brief Start the given timer
*
* This function is only needed if the timer was stopped manually before.
*
* @param[in] dev the timer device to start
*/
void timer_start(tim_t dev);
/**
* @brief Stop the given timer
*
* This will effect all of the timer's channels.
*
* When the timer is stopped, the underlying timer peripheral should be
* completely powered off.
*
* @param[in] dev the timer to stop
*/
void timer_stop(tim_t dev);
/**
* @brief Get the number of different frequencies supported by the given
* timer
*
* If calling @ref timer_query_freqs_numof for the same timer with an index
* smaller this number, it hence MUST return a frequency (and not zero).
*
* @details This function is marked with attribute pure to tell the compiler
* that this function has no side affects and will return the same
* value when called with the same parameter. (E.g. to not call this
* function in every loop iteration when iterating over all
* supported frequencies.)
*/
__attribute__((pure))
uword_t timer_query_freqs_numof(tim_t dev);
/**
* @brief Get the number of timer channels for the given timer
*
* @details This function is marked with attribute pure to tell the compiler
* that this function has no side affects and will return the same
* value when called with the same timer as parameter.
* @details There is a weak default implementation that returns the value of
* `TIMER_CHANNEL_NUMOF`. For some MCUs the number of supported
* channels depends on @p dev - those are expected to provide there
* own implementation of this function.
*/
__attribute__((pure))
uword_t timer_query_channel_numof(tim_t dev);
/**
* @brief Iterate over supported frequencies
*
* @param dev Timer to get the next supported frequency of
* @param index Index of the frequency to get
* @return The @p index highest frequency supported by the timer
* @retval 0 @p index is too high
*
* @note Add `FEATURES_REQUIRED += periph_timer_query_freqs` to your `Makefile`.
*
* When called with a value of 0 for @p index, the highest supported frequency
* is returned. For a value 1 the second highest is returned, and so on. For
* values out of range, 0 is returned. A program hence can iterate over all
* supported frequencies using:
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.c}
* uint32_t freq:
* for (uword_t i; (freq = timer_query_freqs(dev, i)); i++) {
* work_with_frequency(freq);
* }
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Or alternatively:
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.c}
* for (uword_t i; i < timer_query_freqs_numof(dev); i++) {
* work_with_frequency(timer_query_freqs(dev, i));
* }
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
uint32_t timer_query_freqs(tim_t dev, uword_t index);
#ifdef __cplusplus
}
#endif
#endif /* PERIPH_TIMER_H */
/** @} */