| /** |
| * \addtogroup BSP |
| * \{ |
| * \addtogroup DEVICES |
| * \{ |
| * \addtogroup Timer1 |
| * \{ |
| * \brief Timer1 |
| */ |
| |
| /** |
| ***************************************************************************************** |
| * |
| * @file hw_timer1.h |
| * |
| * @brief Definition of API for the Timer1 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_TIMER1_H_ |
| #define HW_TIMER1_H_ |
| |
| #if dg_configUSE_HW_TIMER1 |
| |
| #include <stdbool.h> |
| #include <stdint.h> |
| #include <sdk_defs.h> |
| |
| |
| /** |
| * \brief Get the mask of a field of an TIMER1 register. |
| * |
| * \param [in] reg is the register to access |
| * \param [in] field is the register field to access |
| * |
| */ |
| #define HW_TIMER1_REG_FIELD_MASK(reg, field) \ |
| (TIMER1_CAPTIM_##reg##_REG_##field##_Msk) |
| |
| /** |
| * \brief Get the bit position of a field of an TIMER1 register. |
| * |
| * \param [in] reg is the register to access |
| * \param [in] field is the register field to access |
| * |
| */ |
| #define HW_TIMER1_REG_FIELD_POS(reg, field) \ |
| (TIMER1_CAPTIM_##reg##_REG_##field##_Pos) |
| |
| /** |
| * \brief Get the value of a field of an TIMER1 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_TIMER1_REG_GETF(reg, field) \ |
| ((TIMER1->CAPTIM_##reg##_REG & (TIMER1_CAPTIM_##reg##_REG_##field##_Msk)) >> (TIMER1_CAPTIM_##reg##_REG_##field##_Pos)) |
| |
| /** |
| * \brief Set the value of a field of an TIMER1 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_TIMER1_REG_SETF(reg, field, new_val) \ |
| TIMER1->CAPTIM_##reg##_REG = ((TIMER1->CAPTIM_##reg##_REG & ~(TIMER1_CAPTIM_##reg##_REG_##field##_Msk)) | \ |
| ((TIMER1_CAPTIM_##reg##_REG_##field##_Msk) & ((new_val) << (TIMER1_CAPTIM_##reg##_REG_##field##_Pos)))) |
| |
| |
| #define EXT_CLK 16 // 16 MHz |
| #define INT_CLK 32 // 32 kHz |
| |
| /** |
| * \brief Mode of operation |
| * |
| * PWM is enabled in both modes. |
| * |
| */ |
| typedef enum { |
| HW_TIMER1_MODE_TIMER = 0, /**< timer/capture mode */ |
| HW_TIMER1_MODE_ONESHOT = 1 /**< one-shot mode */ |
| } HW_TIMER1_MODE; |
| |
| /** |
| * \brief Clock source for timer |
| * |
| */ |
| typedef enum { |
| HW_TIMER1_CLK_SRC_INT = 0, /**< Internal clock 32 kHz (slow) */ |
| HW_TIMER1_CLK_SRC_EXT = 1 /**< External clock 2/4/8/16 MHz (fast) */ |
| } HW_TIMER1_CLK_SRC; |
| |
| /** |
| * \brief Counting direction |
| * |
| */ |
| typedef enum { |
| HW_TIMER1_DIR_UP = 0, /**< Timer counts up (counter is incremented) */ |
| HW_TIMER1_DIR_DOWN = 1 /**< Timer counts down (counter is decremented) */ |
| } HW_TIMER1_DIR; |
| |
| /** |
| * \brief Type of triggering events |
| * |
| */ |
| typedef enum { |
| HW_TIMER1_TRIGGER_RISING = 0, /**< Event activated rising edge */ |
| HW_TIMER1_TRIGGER_FALLING = 1 /**< Event activated falling edge */ |
| } HW_TIMER1_TRIGGER; |
| |
| /** |
| * \brief One shot mode phases |
| * |
| */ |
| typedef enum { |
| HW_TIMER1_ONESHOT_WAIT = 0, /**< Wait for the event */ |
| HW_TIMER1_ONESHOT_DELAY = 1, /**< Delay before started */ |
| HW_TIMER1_ONESHOT_STARTED = 2, /**< Start shot */ |
| HW_TIMER1_ONESHOT_ACTIVE = 3 /**< Shot is active */ |
| } HW_TIMER1_ONESHOT; |
| |
| /** |
| * \brief GPIOs for timer1 |
| * |
| * Mainly use for mark which GPIO will triggers timer counting. |
| * |
| */ |
| typedef enum { |
| HW_TIMER1_GPIO_NONE = 0, /**< None of GPIO */ |
| /* port 0 */ |
| HW_TIMER1_GPIO_P00 = 1, /**< Port 0, pin 0 */ |
| HW_TIMER1_GPIO_P01 = 2, /**< Port 0, pin 1 */ |
| HW_TIMER1_GPIO_P02 = 3, /**< Port 0, pin 2 */ |
| HW_TIMER1_GPIO_P03 = 4, /**< Port 0, pin 3 */ |
| HW_TIMER1_GPIO_P04 = 5, /**< Port 0, pin 4 */ |
| HW_TIMER1_GPIO_P05 = 6, /**< Port 0, pin 5 */ |
| HW_TIMER1_GPIO_P06 = 7, /**< Port 0, pin 6 */ |
| HW_TIMER1_GPIO_P07 = 8, /**< Port 0, pin 7 */ |
| /* port 1 */ |
| HW_TIMER1_GPIO_P10 = 9, /**< Port 1, pin 0 */ |
| HW_TIMER1_GPIO_P11 = 10, /**< Port 1, pin 1 */ |
| HW_TIMER1_GPIO_P12 = 11, /**< Port 1, pin 2 */ |
| HW_TIMER1_GPIO_P13 = 12, /**< Port 1, pin 3 */ |
| HW_TIMER1_GPIO_P14 = 13, /**< Port 1, pin 4 */ |
| HW_TIMER1_GPIO_P15 = 14, /**< Port 1, pin 5 */ |
| HW_TIMER1_GPIO_P16 = 15, /**< Port 1, pin 6 */ |
| HW_TIMER1_GPIO_P17 = 16, /**< Port 1, pin 7 */ |
| /* port 2 */ |
| HW_TIMER1_GPIO_P20 = 17, /**< Port 2, pin 0 */ |
| HW_TIMER1_GPIO_P21 = 18, /**< Port 2, pin 1 */ |
| HW_TIMER1_GPIO_P22 = 19, /**< Port 2, pin 2 */ |
| HW_TIMER1_GPIO_P23 = 20, /**< Port 2, pin 3 */ |
| HW_TIMER1_GPIO_P24 = 21, /**< Port 2, pin 4 */ |
| /* port 3 */ |
| HW_TIMER1_GPIO_P30 = 22, /**< Port 3, pin 0 */ |
| HW_TIMER1_GPIO_P31 = 23, /**< Port 3, pin 1 */ |
| HW_TIMER1_GPIO_P32 = 24, /**< Port 3, pin 2 */ |
| HW_TIMER1_GPIO_P33 = 25, /**< Port 3, pin 3 */ |
| HW_TIMER1_GPIO_P34 = 26, /**< Port 3, pin 4 */ |
| HW_TIMER1_GPIO_P35 = 27, /**< Port 3, pin 5 */ |
| HW_TIMER1_GPIO_P36 = 28, /**< Port 3, pin 6 */ |
| HW_TIMER1_GPIO_P37 = 29, /**< Port 3, pin 7 */ |
| /* port 4 */ |
| HW_TIMER1_GPIO_P40 = 30, /**< Port 4, pin 0 */ |
| HW_TIMER1_GPIO_P41 = 31, /**< Port 4, pin 1 */ |
| HW_TIMER1_GPIO_P42 = 32, /**< Port 4, pin 2 */ |
| HW_TIMER1_GPIO_P43 = 33, /**< Port 4, pin 3 */ |
| HW_TIMER1_GPIO_P44 = 34, /**< Port 4, pin 4 */ |
| HW_TIMER1_GPIO_P45 = 35, /**< Port 4, pin 5 */ |
| HW_TIMER1_GPIO_P46 = 36, /**< Port 4, pin 6 */ |
| HW_TIMER1_GPIO_P47 = 37, /**< Port 4, pin 7 */ |
| } HW_TIMER1_GPIO; |
| |
| /** |
| * \brief Timer interrupt callback |
| * |
| */ |
| typedef void (*hw_timer1_handler_cb)(void); |
| |
| /* |
| * \brief Timer configuration for timer/capture mode |
| * |
| * \sa timer1_config |
| * \sa hw_timer1_configure_timer |
| * |
| */ |
| typedef struct { |
| HW_TIMER1_DIR direction; /**< counting direction */ |
| uint32_t reload_val; /**< reload value */ |
| bool free_run; /**< free-running mode state */ |
| |
| HW_TIMER1_GPIO gpio1; /**< 1st GPIO for capture mode */ |
| HW_TIMER1_TRIGGER trigger1; /**< 1st GPIO capture trigger */ |
| HW_TIMER1_GPIO gpio2; /**< 2nd GPIO for capture mode */ |
| HW_TIMER1_TRIGGER trigger2; /**< 2nd GPIO capture trigger */ |
| } timer1_config_timer_capture; |
| |
| /* |
| * \brief Timer configuration for oneshot mode |
| * |
| * \sa timer1_config |
| * \sa hw_timer1_configure_oneshot |
| * |
| */ |
| typedef struct { |
| uint16_t delay; /**< delay (ticks) between GPIO event and output pulse */ |
| uint32_t shot_width; /**< width (ticks) of generated pulse */ |
| HW_TIMER1_GPIO gpio; /**< GPIO to wait for event */ |
| HW_TIMER1_TRIGGER trigger; /**< GPIO trigger */ |
| } timer1_config_oneshot; |
| |
| /* |
| * \brief Timer PWM configuration |
| * |
| * \sa timer1_config |
| * \sa hw_timer1_configure_pwm |
| * \sa hw_timer1_set_pwm_freq |
| * \sa hw_timer1_set_pwm_duty_cycle |
| */ |
| typedef struct { |
| uint16_t frequency; /**< frequency */ |
| uint16_t duty_cycle; /**< duty cycle */ |
| } timer1_config_pwm; |
| |
| /* |
| * \brief Timer configuration |
| * |
| * Only one of \p timer and \p oneshot configuration can be set since they are stored in the same |
| * union (and will overwrite each other). Proper configuration structure is selected depending on |
| * timer mode set. |
| * |
| * \sa timer1_config_timer_capture |
| * \sa timer1_config_oneshot |
| * \sa timer1_config_pwm |
| * \sa hw_timer1_configure |
| * |
| */ |
| typedef struct { |
| HW_TIMER1_CLK_SRC clk_src; /**< clock source */ |
| uint16_t prescaler; /**< clock prescaler */ |
| |
| union { |
| timer1_config_timer_capture timer; /**< configuration for timer/capture mode */ |
| timer1_config_oneshot oneshot; /**< configuration for oneshot mode */ |
| }; |
| timer1_config_pwm pwm; /**< PWM configuration */ |
| } timer1_config; |
| |
| |
| #if dg_configUSER_CAN_USE_TIMER1 == 1 |
| |
| /** |
| * \brief Timer initialization |
| * |
| * 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] mode timer mode |
| * \param [in] cfg configuration |
| * |
| */ |
| void hw_timer1_init(HW_TIMER1_MODE mode, const timer1_config *cfg); |
| |
| /** |
| * \brief Timer configuration |
| * |
| * Shortcut to call appropriate configuration function. If \p cfg is NULL, this function does |
| * nothing except switching timer to selected mode. |
| * |
| * \param [in] mode timer mode |
| * \param [in] cfg configuration |
| * |
| */ |
| void hw_timer1_configure(HW_TIMER1_MODE mode, const timer1_config *cfg); |
| |
| /** |
| * \brief Timer configuration for timer/capture mode |
| * |
| * Shortcut to call appropriate configuration function. This does not switch timer to timer/capture |
| * mode, it should be done separately using hw_timer1_set_mode(). |
| * |
| * \param [in] cfg configuration |
| * |
| */ |
| void hw_timer1_configure_timer(const timer1_config_timer_capture *cfg); |
| |
| /** |
| * \brief Timer configuration for oneshot mode |
| * |
| * Shortcut to call appropriate configuration function. This does not switch timer to oneshot |
| * mode, it should be done separately using hw_timer1_set_mode(). |
| * |
| * \param [in] cfg configuration |
| * |
| */ |
| void hw_timer1_configure_oneshot(const timer1_config_oneshot *cfg); |
| |
| /** |
| * \brief Freeze timer |
| * |
| */ |
| static inline void hw_timer1_freeze(void) |
| { |
| GPREG->SET_FREEZE_REG = GPREG_SET_FREEZE_REG_FRZ_SWTIM1_Msk; |
| } |
| |
| /** |
| * \brief Unfreeze timer |
| * |
| */ |
| static inline void hw_timer1_unfreeze(void) |
| { |
| GPREG->RESET_FREEZE_REG = GPREG_RESET_FREEZE_REG_FRZ_SWTIM1_Msk; |
| } |
| |
| /** |
| * \brief Check if timer is frozen |
| * |
| * \return true if it is frozen else false |
| * |
| */ |
| static inline bool hw_timer1_frozen(void) |
| { |
| return GPREG->SET_FREEZE_REG & GPREG_SET_FREEZE_REG_FRZ_SWTIM1_Msk ? true : false; |
| } |
| |
| /** |
| * \brief Set clock source of the timer |
| * |
| * \param [in] clk clock source of the timer, external or internal |
| * |
| */ |
| static inline void hw_timer1_set_clk(HW_TIMER1_CLK_SRC clk) |
| { |
| HW_TIMER1_REG_SETF(CTRL, CAPTIM_SYS_CLK_EN, clk); |
| } |
| |
| /** |
| * \brief Set timer clock prescaler |
| * |
| * Actual timer frequency is \p timer_freq = \p freq_clock / (\p value + 1) |
| * |
| * \param [in] value prescaler |
| * |
| */ |
| static inline void hw_timer1_set_prescaler(uint16_t value) |
| { |
| TIMER1->CAPTIM_PRESCALER_REG = value; |
| } |
| |
| /** |
| * \brief Set timer reload value |
| * |
| * \note This changes the same register value as hw_timer1_set_oneshot_delay() since both parameters |
| * share the same register (value is interpreted differently depending on timer mode). |
| * |
| * \param [in] value reload value |
| * |
| * \sa hw_timer1_set_oneshot_delay |
| * \note For DA14682/3 chips, setting the reload value will also freeze the timer until both |
| * reload registers are set. |
| */ |
| static inline void hw_timer1_set_reload(uint32_t value) |
| { |
| #if (dg_configBLACK_ORCA_IC_REV != BLACK_ORCA_IC_REV_A) && (dg_configUSE_AUTO_CHIP_DETECTION != 1) |
| bool timer1_frozen = hw_timer1_frozen(); |
| if (!timer1_frozen) { |
| hw_timer1_freeze(); |
| } |
| TIMER1->CAPTIM_RELOAD_REG = (uint16_t) value; |
| TIMER1->CAPTIM_RELOAD_HIGH_REG = (uint16_t) value >> 16; |
| if (!timer1_frozen) { |
| hw_timer1_unfreeze(); |
| } |
| #else |
| TIMER1->CAPTIM_RELOAD_REG = (uint16_t) value; |
| #endif |
| } |
| |
| /** |
| * \brief Set pulse delay in oneshot mode |
| * |
| * \note This changes the same register value as hw_timer1_set_reload() since both parameters share |
| * the same register (value is interpreted differently depending on timer mode). |
| * |
| * \param [in] delay delay (ticks) |
| * |
| * \sa hw_timer1_set_reload |
| * |
| */ |
| static inline void hw_timer1_set_oneshot_delay(uint32_t delay) |
| { |
| TIMER1->CAPTIM_RELOAD_REG = (uint16_t) delay; |
| } |
| |
| /** |
| * \brief Set shot width |
| * |
| * This applies only to one-shot mode. |
| * |
| * \param [in] duration shot phase duration |
| * |
| */ |
| static inline void hw_timer1_set_shot_width(uint32_t duration) |
| { |
| TIMER1->CAPTIM_SHOTWIDTH_REG = (uint16_t) duration; |
| } |
| |
| /** |
| * \brief Turn on free run mode of the timer |
| * |
| */ |
| static inline void hw_timer1_set_freerun(bool enabled) |
| { |
| HW_TIMER1_REG_SETF(CTRL, CAPTIM_FREE_RUN_MODE_EN, enabled); |
| } |
| |
| /** |
| * \brief Set a type of the edge which triggers event1 |
| * |
| * \param [in] edge type of edge, rising or falling |
| * |
| */ |
| static inline void hw_timer1_set_event1_trigger(HW_TIMER1_TRIGGER edge) |
| { |
| HW_TIMER1_REG_SETF(CTRL, CAPTIM_IN1_EVENT_FALL_EN, edge); |
| } |
| |
| /** |
| * \brief Set a type of the edge which triggers event2 |
| * |
| * \param [in] edge type of edge, rising or falling |
| * |
| */ |
| static inline void hw_timer1_set_event2_trigger(HW_TIMER1_TRIGGER edge) |
| { |
| HW_TIMER1_REG_SETF(CTRL, CAPTIM_IN2_EVENT_FALL_EN, edge); |
| } |
| |
| /** |
| * \brief Set a GPIO input which triggers event1 |
| * |
| * \param [in] gpio GPIO input |
| * |
| */ |
| static inline void hw_timer1_set_event1_gpio(HW_TIMER1_GPIO gpio) |
| { |
| TIMER1->CAPTIM_GPIO1_CONF_REG = gpio; |
| } |
| |
| /** |
| * \brief Set a GPIO input which triggers event2 |
| * |
| * \param [in] gpio GPIO input |
| * |
| */ |
| static inline void hw_timer1_set_event2_gpio(HW_TIMER1_GPIO gpio) |
| { |
| TIMER1->CAPTIM_GPIO2_CONF_REG = gpio; |
| } |
| |
| /** |
| * \brief Get clock source of the timer |
| * |
| * \return clock source |
| * |
| */ |
| static inline HW_TIMER1_CLK_SRC hw_timer1_get_clk(void) |
| { |
| return HW_TIMER1_REG_GETF(CTRL, CAPTIM_SYS_CLK_EN); |
| } |
| |
| /** |
| * \brief Get timer clock prescaler |
| * |
| * Actual timer frequency is \p timer_freq = \p freq_clock / (\p retval + 1) |
| * |
| * \return prescaler value |
| * |
| * \sa hw_timer1_get_prescaler_val |
| * |
| */ |
| static inline uint16_t hw_timer1_get_prescaler(void) |
| { |
| return TIMER1->CAPTIM_PRESCALER_REG; |
| } |
| |
| /** |
| * \brief Get timer reload value |
| * |
| * \return reload value |
| * |
| * \sa hw_timer1_set_reload |
| * |
| */ |
| static inline uint32_t hw_timer1_get_reload(void) |
| { |
| return TIMER1->CAPTIM_RELOAD_REG; |
| } |
| |
| /** |
| * \brief Get pulse delay in oneshot mode |
| * |
| * \return delay (ticks) |
| * |
| * \sa hw_timer1_get_oneshot_delay |
| * |
| */ |
| static inline uint32_t hw_timer1_get_oneshot_delay(void) |
| { |
| return TIMER1->CAPTIM_RELOAD_REG; |
| } |
| |
| /** |
| * \brief Get shot width |
| * |
| * This applies only to one-shot mode. |
| * |
| * \return shot width value |
| * |
| */ |
| static inline uint32_t hw_timer1_get_shot_width(void) |
| { |
| return TIMER1->CAPTIM_SHOTWIDTH_REG; |
| } |
| |
| /** |
| * \brief Get free-running mode state |
| * |
| * \return free-running mode state |
| * |
| */ |
| static inline bool hw_timer1_get_freerun(void) |
| { |
| return HW_TIMER1_REG_GETF(CTRL, CAPTIM_FREE_RUN_MODE_EN); |
| } |
| |
| /** |
| * \brief Get a type of the edge which triggers event1 |
| * |
| * \return edge type |
| * |
| */ |
| static inline HW_TIMER1_TRIGGER hw_timer1_get_event1_trigger(void) |
| { |
| return HW_TIMER1_REG_GETF(CTRL, CAPTIM_IN1_EVENT_FALL_EN); |
| } |
| |
| /** |
| * \brief Get a type of the edge which triggers event2 |
| * |
| * \return edge type |
| * |
| */ |
| static inline HW_TIMER1_TRIGGER hw_timer1_get_event2_trigger(void) |
| { |
| return HW_TIMER1_REG_GETF(CTRL, CAPTIM_IN2_EVENT_FALL_EN); |
| } |
| |
| /** |
| * \brief Get a GPIO input which triggers event1 |
| * |
| * \return GPIO input |
| * |
| */ |
| static inline HW_TIMER1_GPIO hw_timer1_get_event1_gpio(void) |
| { |
| return TIMER1->CAPTIM_GPIO1_CONF_REG; |
| } |
| |
| /** |
| * \brief Get a GPIO input which triggers event2 |
| * |
| * \return GPIO input |
| * |
| */ |
| static inline HW_TIMER1_GPIO hw_timer1_get_event2_gpio(void) |
| { |
| return TIMER1->CAPTIM_GPIO2_CONF_REG; |
| } |
| |
| /** |
| * \brief Get the capture time for event on GPIO1 |
| * |
| * \return time for event on GPIO1 |
| * |
| */ |
| static inline uint32_t hw_timer1_get_capture1(void) |
| { |
| return TIMER1->CAPTIM_CAPTURE_GPIO1_REG; |
| } |
| |
| /** |
| * \brief Get the capture time for event on GPIO2 |
| * |
| * \return time for event on GPIO2 |
| * |
| */ |
| static inline uint32_t hw_timer1_get_capture2(void) |
| { |
| return TIMER1->CAPTIM_CAPTURE_GPIO2_REG; |
| } |
| |
| /** |
| * \brief Set the direction of timer counting |
| * |
| * \param [in] dir counting direction of the timer, up or down |
| * |
| */ |
| static inline void hw_timer1_set_direction(HW_TIMER1_DIR dir) |
| { |
| HW_TIMER1_REG_SETF(CTRL, CAPTIM_COUNT_DOWN_EN, dir); |
| } |
| |
| /** |
| * \brief Turn on one shot mode |
| * |
| */ |
| static inline void hw_timer1_set_mode(HW_TIMER1_MODE mode) |
| { |
| HW_TIMER1_REG_SETF(CTRL, CAPTIM_ONESHOT_MODE_EN, mode); |
| } |
| |
| /** |
| * \brief Turn on capture mode |
| * |
| */ |
| static inline HW_TIMER1_MODE hw_timer1_get_mode(void) |
| { |
| return HW_TIMER1_REG_GETF(CTRL, CAPTIM_ONESHOT_MODE_EN); |
| } |
| |
| /** |
| * \brief Get the tick count of the timer |
| * |
| * \return current value of the timer ticks |
| * |
| * \sa hw_timer1_get_prescaler_val |
| * |
| */ |
| static inline uint32_t hw_timer1_get_count(void) |
| { |
| #if (dg_configBLACK_ORCA_IC_REV != BLACK_ORCA_IC_REV_A) && (dg_configUSE_AUTO_CHIP_DETECTION != 1) |
| uint32_t lo, hi; |
| GLOBAL_INT_DISABLE(); |
| do { |
| lo = TIMER1->CAPTIM_TIMER_VAL_REG; |
| hi = TIMER1->CAPTIM_TIMER_HVAL_REG; |
| } while (lo != TIMER1->CAPTIM_TIMER_VAL_REG); |
| GLOBAL_INT_RESTORE(); |
| return (hi << 16) | lo; |
| #else |
| return TIMER1->CAPTIM_TIMER_VAL_REG; |
| #endif |
| } |
| |
| /** |
| * \brief Get the current phase of the one shot mode |
| * |
| * \return current phase of the one shot mode |
| * |
| */ |
| static inline HW_TIMER1_ONESHOT hw_timer1_get_oneshot_phase(void) |
| { |
| return HW_TIMER1_REG_GETF(STATUS, CAPTIM_ONESHOT_PHASE); |
| } |
| |
| /** |
| * \brief Get the current state of IN1 |
| * |
| * \return current logic level of IN1 |
| * |
| */ |
| static inline bool hw_timer1_get_gpio1_state(void) |
| { |
| return HW_TIMER1_REG_GETF(STATUS, CAPTIM_IN1_STATE); |
| } |
| |
| /** |
| * \brief Get the current state of IN2 |
| * |
| * \return current logic level of IN2 |
| * |
| */ |
| static inline bool hw_timer1_get_gpio2_state(void) |
| { |
| return HW_TIMER1_REG_GETF(STATUS, CAPTIM_IN2_STATE); |
| } |
| |
| /** |
| * \brief Get the current prescaler counter value |
| * |
| * This is value of internal counter used for prescaling. It can be used to have finer granularity |
| * when reading timer value. |
| * |
| * For reading current setting of prescaler, see hw_timer1_get_prescaler(). |
| * |
| * \return current prescaler counter value |
| * |
| * \sa hw_timer1_get_count |
| * \sa hw_timer1_get_prescaler |
| * |
| */ |
| static inline uint16_t hw_timer1_get_prescaler_val(void) |
| { |
| return TIMER1->CAPTIM_PRESCALER_VAL_REG; |
| } |
| |
| /** |
| * \brief Register an interrupt handler. |
| * |
| * \param [in] handler function pointer to handler to call when an interrupt occurs |
| * |
| */ |
| void hw_timer1_register_int(hw_timer1_handler_cb handler); |
| |
| /** |
| * \brief Unregister an interrupt handler |
| * |
| */ |
| void hw_timer1_unregister_int(void); |
| |
| #else // (dg_configUSER_CAN_USE_TIMER1 == 0) |
| |
| #if dg_configBLACK_ORCA_IC_REV == BLACK_ORCA_IC_REV_A |
| #define LP_CNT_REG_RANGE ( 16 ) |
| #else |
| #define LP_CNT_REG_RANGE ( 32 ) |
| #endif |
| #define LP_CNT_MAX_VALUE ( (1ULL << LP_CNT_REG_RANGE) - 1 ) |
| #define LP_CNT_PRESCALED_MASK ( LP_CNT_MAX_VALUE ) |
| #if dg_configBLACK_ORCA_IC_REV == BLACK_ORCA_IC_REV_A |
| #define LP_CNT_NATIVE_MASK ( (1ULL << (LP_CNT_REG_RANGE + dg_configTim1PrescalerBitRange)) - 1 ) |
| #else |
| #define LP_CNT_NATIVE_MASK ( (1ULL << (LP_CNT_REG_RANGE)) - 1 ) |
| #endif |
| |
| /** |
| * \brief Configure timer as tick timer |
| * |
| * \details Setup Timer1 for use as a tick timer: |
| * <ul> |
| * <li> use LP clock and prescaler (if configured) |
| * <li> free running mode |
| * <li> IRQ masked |
| * <li> up counter |
| * <li> timer mode |
| * <li> disabled |
| * </ul> |
| * |
| */ |
| void hw_timer1_lp_clk_init(void); |
| |
| |
| /** |
| * \brief Enable interrupt |
| * |
| * \return void |
| * |
| */ |
| static inline void hw_timer1_int_enable(void) __attribute__((always_inline)); |
| |
| static inline void hw_timer1_int_enable(void) |
| { |
| HW_TIMER1_REG_SETF(CTRL, CAPTIM_IRQ_EN, 1); |
| NVIC_ClearPendingIRQ(SWTIM1_IRQn); |
| NVIC_EnableIRQ(SWTIM1_IRQn); |
| } |
| |
| |
| /** |
| * \brief Disable interrupt |
| * |
| * \return void |
| * |
| */ |
| static inline void hw_timer1_int_disable(void) __attribute__((always_inline)); |
| |
| static inline void hw_timer1_int_disable(void) |
| { |
| NVIC_DisableIRQ(SWTIM1_IRQn); |
| HW_TIMER1_REG_SETF(CTRL, CAPTIM_IRQ_EN, 0); |
| } |
| |
| |
| /** |
| * \brief Get counter's value |
| * |
| * \return The current value of the counter (prescaled). |
| * |
| */ |
| static inline uint32_t hw_timer1_get_value(void) __attribute__((always_inline)); |
| |
| static inline uint32_t hw_timer1_get_value(void) |
| { |
| #if dg_configBLACK_ORCA_IC_REV == BLACK_ORCA_IC_REV_A |
| return TIMER1->CAPTIM_TIMER_VAL_REG; |
| #else |
| uint32_t lo, hi; |
| GLOBAL_INT_DISABLE(); |
| do { |
| lo = TIMER1->CAPTIM_TIMER_VAL_REG; |
| hi = TIMER1->CAPTIM_TIMER_HVAL_REG; |
| } while (lo != TIMER1->CAPTIM_TIMER_VAL_REG); |
| GLOBAL_INT_RESTORE(); |
| return (hi << 16) | lo; |
| #endif |
| } |
| |
| |
| /** |
| * \brief Macro to get the current value of the timer, both prescaled and in LP clock cycles. |
| * |
| * \details Special care is needed when a prescaler is used. In this case, the |
| * counting sequence is the following (assuminga prescaler of 3): |
| * prescaler: 0 1 2 3 0 1 2 3 0 |
| * counter: 0 1 2 |
| * |
| * If not implemented properly then the following may happen: |
| * - let's assume that we are at the end of the {0, 3} period |
| * - the counter's value is read and the result is 0 |
| * - at that moment, the counter increases it's prescaler value (and the counter's value |
| * respectively), so the time becomes {1, 0} |
| * - the reading of the prescaler's value will give 0 but {0, 0} is earlier than {0, 3} (when |
| * the operation started) and this may result in errors in time computations. |
| * \note This macro should be used inside a critical section. |
| * |
| */ |
| #if dg_configBLACK_ORCA_IC_REV == BLACK_ORCA_IC_REV_A |
| #define HW_TIMER1_GET_INSTANT(prescaled, fine) \ |
| do { \ |
| if (dg_configTim1Prescaler != 0) { \ |
| uint32_t prescaler_v; \ |
| \ |
| do { \ |
| prescaler_v = TIMER1->CAPTIM_PRESCALER_VAL_REG; \ |
| prescaled = TIMER1->CAPTIM_TIMER_VAL_REG; \ |
| } while (prescaler_v != TIMER1->CAPTIM_PRESCALER_VAL_REG); \ |
| \ |
| fine = ( (uint32_t)prescaled * (1 + dg_configTim1Prescaler) + prescaler_v); \ |
| } \ |
| else { \ |
| prescaled = TIMER1->CAPTIM_TIMER_VAL_REG; \ |
| fine = prescaled; \ |
| } \ |
| } while (0) |
| #else |
| #define HW_TIMER1_GET_INSTANT(prescaled, fine) \ |
| do { \ |
| uint32_t lo, hi; \ |
| do { \ |
| lo = TIMER1->CAPTIM_TIMER_VAL_REG; \ |
| hi = TIMER1->CAPTIM_TIMER_HVAL_REG; \ |
| } while (lo != TIMER1->CAPTIM_TIMER_VAL_REG); \ |
| prescaled = fine = (hi << 16) | lo; \ |
| } while (0) |
| #endif |
| /** |
| * \brief Macro to set the trigger value. The previous trigger value is returned to the caller. |
| * \note For DA14682/3 chips, this macro will disable timer1 interrupt until reload registers |
| * programmed so that false interrupts are avoided. |
| */ |
| #if dg_configBLACK_ORCA_IC_REV == BLACK_ORCA_IC_REV_A |
| #define HW_TIMER1_SET_TRIGGER(value, last_value) \ |
| do { \ |
| last_value = TIMER1->CAPTIM_RELOAD_REG; \ |
| TIMER1->CAPTIM_RELOAD_REG = value; \ |
| } while (0) |
| #else |
| #define HW_TIMER1_SET_TRIGGER(value, last_value) \ |
| do { \ |
| bool timer1_irq_en = \ |
| TIMER1->CAPTIM_CTRL_REG & TIMER1_CAPTIM_CTRL_REG_CAPTIM_IRQ_EN_Msk ? true : false; \ |
| last_value = TIMER1->CAPTIM_RELOAD_REG | \ |
| ((uint32_t) TIMER1->CAPTIM_RELOAD_HIGH_REG) << 16; \ |
| if (timer1_irq_en) { \ |
| TIMER1->CAPTIM_CTRL_REG &= ~TIMER1_CAPTIM_CTRL_REG_CAPTIM_IRQ_EN_Msk; \ |
| } \ |
| TIMER1->CAPTIM_RELOAD_REG = (uint16_t) value; \ |
| TIMER1->CAPTIM_RELOAD_HIGH_REG = (uint16_t) ((value) >> 16); \ |
| if (timer1_irq_en) { \ |
| TIMER1->CAPTIM_CTRL_REG |= TIMER1_CAPTIM_CTRL_REG_CAPTIM_IRQ_EN_Msk; \ |
| } \ |
| } while (0) |
| #endif |
| |
| /** |
| * \brief Get trigger value |
| * |
| * \return The current value of the trigger (prescaled). |
| * |
| */ |
| static inline uint32_t hw_timer1_get_trigger(void) |
| { |
| #if dg_configBLACK_ORCA_IC_REV == BLACK_ORCA_IC_REV_A |
| return TIMER1->CAPTIM_RELOAD_REG; |
| #else |
| return TIMER1->CAPTIM_RELOAD_REG | ((uint32_t) TIMER1->CAPTIM_RELOAD_HIGH_REG) << 16; |
| #endif |
| } |
| |
| /** |
| * \brief Set an "invalid" trigger value, which refers far away in the future |
| * |
| */ |
| static inline void hw_timer1_invalidate_trigger(void) __attribute__((always_inline)); |
| |
| static inline void hw_timer1_invalidate_trigger(void) |
| { |
| uint32_t lp_current_time; // prescaled |
| uint32_t trigger; |
| uint32_t dummy __attribute__((unused)); |
| |
| lp_current_time = hw_timer1_get_value(); // Get current time |
| trigger = (lp_current_time - 1) & LP_CNT_PRESCALED_MASK; // Get an "invalid" trigger |
| HW_TIMER1_SET_TRIGGER(trigger, dummy); // Move trigger too far in the future so |
| // that no interrupt from the timer arrives. |
| } |
| |
| #endif // dg_configUSER_CAN_USE_TIMER1 |
| |
| |
| /** |
| * \brief Enable the timer |
| * |
| */ |
| static inline void hw_timer1_enable(void) |
| { |
| HW_TIMER1_REG_SETF(CTRL, CAPTIM_EN, 1); |
| GLOBAL_INT_DISABLE(); |
| REG_SET_BIT(CRG_TOP, CLK_TMR_REG, TMR1_ENABLE); |
| GLOBAL_INT_RESTORE(); |
| } |
| |
| /** |
| * \brief Disable the timer |
| * |
| */ |
| static inline void hw_timer1_disable(void) |
| { |
| HW_TIMER1_REG_SETF(CTRL, CAPTIM_EN, 0); |
| GLOBAL_INT_DISABLE(); |
| REG_CLR_BIT(CRG_TOP, CLK_TMR_REG, TMR1_ENABLE); |
| GLOBAL_INT_RESTORE(); |
| } |
| |
| /** |
| * \brief Timer PWM configuration |
| * |
| * Shortcut to call appropriate configuration function. |
| * |
| * \param [in] cfg configuration |
| * |
| */ |
| void hw_timer1_configure_pwm(const timer1_config_pwm *cfg); |
| |
| /** |
| * \brief Set PWM frequency prescaler |
| * |
| * Actual PWM frequency is \p pwm_freq = \p timer_freq / (\p value + 1) |
| * |
| * \param [in] value PWM frequency defined as above |
| * |
| * \sa hw_timer1_set_prescaler |
| * |
| */ |
| static inline void hw_timer1_set_pwm_freq(uint16_t value) |
| { |
| TIMER1->CAPTIM_PWM_FREQ_REG = value; |
| } |
| |
| /** |
| * \brief Set PWM duty cycle |
| * |
| * Actualy PWM duty cycle is \p pwm_dc = \p value / (\p pwm_freq + 1) |
| * |
| * \param [in] value PWM duty cycle defined as above |
| * |
| * \sa hw_timer1_set_pwm_freq |
| * |
| */ |
| static inline void hw_timer1_set_pwm_duty_cycle(uint16_t value) |
| { |
| TIMER1->CAPTIM_PWM_DC_REG = value; |
| } |
| |
| /** |
| * \brief Get PWM frequency prescaler |
| * |
| * Actual PWM frequency is \p pwm_freq = \p timer_freq / (\p retval + 1) |
| * |
| * \return PWM frequency as defined above |
| * |
| */ |
| static inline uint16_t hw_timer1_get_pwm_freq(void) |
| { |
| return TIMER1->CAPTIM_PWM_FREQ_REG; |
| } |
| |
| /** |
| * \brief Get PWM duty cycle |
| * |
| * Actualy PWM duty cycle is \p pwm_dc = \p retval / (\p pwm_freq + 1) |
| * |
| * \return PWM duty cycle as defined above |
| * |
| */ |
| static inline uint16_t hw_timer1_get_pwm_duty_cycle(void) |
| { |
| return TIMER1->CAPTIM_PWM_DC_REG; |
| } |
| |
| #endif /* dg_configUSE_HW_TIMER1 */ |
| |
| #endif /* HW_TIMER1_H_ */ |
| |
| /** |
| * \} |
| * \} |
| * \} |
| */ |