blob: c5dc23a5699ef59444b43a3341f6b7de91fe637d [file] [log] [blame]
/**
* \addtogroup BSP
* \{
* \addtogroup DEVICES
* \{
* \addtogroup Timer0
* \{
* \brief Timer0
*/
/**
*****************************************************************************************
*
* @file hw_timer0.h
*
* @brief Definition of API for the Timer0 Low Level Driver.
*
* Copyright (c) 2016, Dialog Semiconductor
* 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.
*
*
*****************************************************************************************
*/
#ifndef HW_TIMER0_H_
#define HW_TIMER0_H_
#if dg_configUSE_HW_TIMER0
#include <stdbool.h>
#include <stdint.h>
#include <sdk_defs.h>
/**
* \brief Get the mask of a field of an TIMER0 register.
*
* \param [in] reg is the register to access
* \param [in] field is the register field to access
*
*/
#define HW_TIMER0_REG_FIELD_MASK(reg, field) \
(GP_TIMERS_TIMER0_##reg##_REG_##field##_Msk)
/**
* \brief Get the bit position of a field of an TIMER0 register.
*
* \param [in] reg is the register to access
* \param [in] field is the register field to access
*
*/
#define HW_TIMER0_REG_FIELD_POS(reg, field) \
(GP_TIMERS_TIMER0_##reg##_REG_##field##_Pos)
/**
* \brief Get the value of a field of an TIMER0 register.
*
* \param [in] reg is the register to access
* \param [in] field is the register field to write
*
* \return the value of the register field
*
*/
#define HW_TIMER0_REG_GETF(reg, field) \
((GP_TIMERS->TIMER0_##reg##_REG & (GP_TIMERS_TIMER0_##reg##_REG_##field##_Msk)) >> (GP_TIMERS_TIMER0_##reg##_REG_##field##_Pos))
/**
* \brief Set the value of a field of an TIMER0 register.
*
* \param [in] reg is the register to access
* \param [in] field is the register field to write
* \param [in] new_val is the value to write
*
*/
#define HW_TIMER0_REG_SETF(reg, field, new_val) \
GP_TIMERS->TIMER0_##reg##_REG = ((GP_TIMERS->TIMER0_##reg##_REG & ~(GP_TIMERS_TIMER0_##reg##_REG_##field##_Msk)) | \
((GP_TIMERS_TIMER0_##reg##_REG_##field##_Msk) & ((new_val) << (GP_TIMERS_TIMER0_##reg##_REG_##field##_Pos))))
/**
* \brief Clock source for timer
*
*/
typedef enum {
HW_TIMER0_CLK_SRC_SLOW = 0, /**< 32kHz (slow) clock */
HW_TIMER0_CLK_SRC_FAST = 1 /**< 2/4/8/16MHz (fast) clock */
} HW_TIMER0_CLK_SRC;
/**
* \brief Fast clock division factor
*
*/
typedef enum {
HW_TIMER0_FAST_CLK_DIV_1 = 0, /**< divide by 1 */
HW_TIMER0_FAST_CLK_DIV_2, /**< divide by 2 */
HW_TIMER0_FAST_CLK_DIV_4, /**< divide by 4 */
HW_TIMER0_FAST_CLK_DIV_8, /**< divide by 8 */
} HW_TIMER0_FAST_CLK_DIV;
/**
* \brief PWM mode
*
*/
typedef enum {
HW_TIMER0_MODE_PWM = 0, /**< PWM signal is '1' during high state */
HW_TIMER0_MODE_CLOCK = 1 /**< PWM signal is clock divided by 2 during high state */
} HW_TIMER0_MODE;
/**
* \brief Timer interrupt callback
*
*/
typedef void (*hw_timer0_interrupt_cb)(void);
/*
* \brief Timer configuration
*
*/
typedef struct {
HW_TIMER0_CLK_SRC clk_src; /**< clock source */
HW_TIMER0_FAST_CLK_DIV fast_clk_div; /**< clock division factor (only applicable when fast clock is selected as source) */
bool on_clock_div; /**< enable ON-counter clock divider (clock for ON-counter is divided by 10) */
uint16_t on_reload; /**< reload value for ON-counter */
uint16_t t0_reload_m; /**< reload value for T0-counter M-register */
uint16_t t0_reload_n; /**< reload value for T0-counter N-register */
} timer0_config;
/**
* \brief Initialize the timer
*
* Turn on clock for timer and configure timer. After initialization both timer and its interrupt
* are disabled. \p cfg can be NULL - no configuration is performed in such case.
*
* \param [in] cfg configuration
*
*/
void hw_timer0_init(const timer0_config *cfg);
/**
* \brief Timer configuration
*
* Shortcut to call appropriate configuration function. If \p cfg is NULL, this function does
* nothing.
*
* \param [in] cfg configuration
*
*/
void hw_timer0_configure(const timer0_config *cfg);
/**
* \brief Register an interrupt handler
*
* \param [in] handler Function pointer to call when timer interrupt occurs
*
*/
void hw_timer0_register_int(hw_timer0_interrupt_cb handler);
/**
* \brief Unregister an interrupt handler
*
*/
void hw_timer0_unregister_int(void);
/**
* \brief Enable the timer
*
*/
static inline void hw_timer0_enable(void)
{
HW_TIMER0_REG_SETF(CTRL, TIM0_CTRL, 1);
}
/**
* \brief Disable the timer
*
*/
static inline void hw_timer0_disable(void)
{
HW_TIMER0_REG_SETF(CTRL, TIM0_CTRL, 0);
}
/**
* \brief Set clock source for timer
*
* \param [in] clk_src clock source
*
* \sa TIMER0_CLK_SRC
*
*/
static inline void hw_timer0_set_clock_source(HW_TIMER0_CLK_SRC clk_src)
{
HW_TIMER0_REG_SETF(CTRL, TIM0_CLK_SEL, clk_src);
}
/**
* \brief Get current clock source for timer
*
* \return clock source
*
*/
static inline HW_TIMER0_CLK_SRC hw_timer0_get_clock_source(void)
{
return HW_TIMER0_REG_GETF(CTRL, TIM0_CLK_SEL);
}
/**
* \brief Set fast clock division factor
*
* \param [in] div division factor
*
* \sa TIMER0_FAST_CLK_DIV
*
*/
static inline void hw_timer0_set_fast_clock_div(HW_TIMER0_FAST_CLK_DIV div)
{
GLOBAL_INT_DISABLE();
REG_SETF(CRG_TOP, CLK_TMR_REG, TMR0_DIV, div);
GLOBAL_INT_RESTORE();
}
/**
* \brief Get current fast clock division factor
*
* \return division factor
*
*/
static inline HW_TIMER0_FAST_CLK_DIV hw_timer0_get_fast_clock_div(void)
{
return REG_GETF(CRG_TOP, CLK_TMR_REG, TMR0_DIV);
}
/**
* \brief Set state of clock divider for ON-counter
*
* Once enabled, ON-counter clock will be divided by 10.
*
* \param [in] enabled clock divider status
*
*/
static inline void hw_timer0_set_on_clock_div(bool enabled)
{
HW_TIMER0_REG_SETF(CTRL, TIM0_CLK_DIV, !enabled);
}
/**
* \brief Get current state of clock divider for ON-counter
*
* \return clock divider status
*
*/
static inline bool hw_timer0_get_on_clock_div(void)
{
return !HW_TIMER0_REG_GETF(CTRL, TIM0_CLK_DIV);
}
/**
* \brief Set PWM mode for timer
*
* \param [in] mode PWM mode
*
* \sa TIMER0_MODE
*
*/
static inline void hw_timer0_set_pwm_mode(HW_TIMER0_MODE mode)
{
HW_TIMER0_REG_SETF(CTRL, PWM_MODE, mode);
}
/**
* \brief Get current PWM mode for timer
*
* \return PWM mode
*
*/
static inline HW_TIMER0_MODE hw_timer0_get_pwm_mode(void)
{
return HW_TIMER0_REG_GETF(CTRL, PWM_MODE);
}
/**
* \brief Set reload value for T0-counter
*
* T0 counter value is decremented on each clock cycle. At the beginning it's loaded from M-register
* and then, once reached zero, loaded from N-register (and then M and N again).
*
* PWM0 is high when counting down M-register and low when counting down N-register.
* For PWM1 is the opposite.
*
* \param [in] m_value M-register reload value
* \param [in] n_value N-register reload value
*
*/
static inline void hw_timer0_set_t0_reload(uint16_t m_value, uint16_t n_value)
{
GP_TIMERS->TIMER0_RELOAD_M_REG = m_value;
GP_TIMERS->TIMER0_RELOAD_N_REG = n_value;
}
/**
* \brief Set reload value for ON-counter
*
* ON counter value is decremented on each clock cycle. Once ON reaches zero it will remain zero
* until T0 counter completes decrementing N-register value. When this happens, interrupt is
* generated.
*
* \param [in] value reload value
*
* \sa hw_timer0_set_on_clock_div
*
*/
static inline void hw_timer0_set_on_reload(uint16_t value)
{
GP_TIMERS->TIMER0_ON_REG = value;
}
/**
* \brief Get T0-counter value
*
* \return counter value
*
*/
static inline uint16_t hw_timer0_get_t0(void)
{
return (GP_TIMERS->TIMER0_RELOAD_M_REG);
}
/**
* \brief Get ON-counter value
*
* \return counter value
*
*/
static inline uint16_t hw_timer0_get_on(void)
{
return (GP_TIMERS->TIMER0_ON_REG);
}
/**
* \brief Freeze timer
*
*/
static inline void hw_timer0_freeze(void)
{
GPREG->SET_FREEZE_REG = GPREG_SET_FREEZE_REG_FRZ_SWTIM0_Msk;
}
/**
* \brief Unfreeze timer
*
*/
static inline void hw_timer0_unfreeze(void)
{
GPREG->RESET_FREEZE_REG = GPREG_SET_FREEZE_REG_FRZ_SWTIM0_Msk;
}
#endif /* dg_configUSE_HW_TIMER0 */
#endif /* HW_TIMER0_H_ */
/**
* \}
* \}
* \}
*/