diff --git a/source/kernel/dpl/TimerP.h b/source/kernel/dpl/TimerP.h index 4d72dd5d8b..f2cc752a7a 100755 --- a/source/kernel/dpl/TimerP.h +++ b/source/kernel/dpl/TimerP.h @@ -46,7 +46,7 @@ extern "C" { * * This module define's generic APIs to configure and control a timer * Depending on the SOC there can be different timer implementation's - * + * * For more details and example usage, see \ref KERNEL_DPL_TIMER_PAGE * * Timer is used by \ref KERNEL_DPL_CLOCK_PAGE to generate system ticks. @@ -190,6 +190,45 @@ void TimerP_clearOverflowInt(uint32_t baseAddr); */ uint32_t TimerP_isOverflowed(uint32_t baseAddr); +/** + * \brief Configure masked overflows for the timer + * + * \note Ensure the base address is valid before calling this function. + * + * \param baseAddr [in] HW timer base address + * \param value [in] Value to be set in the timer overflow register + */ +void TimerP_configMaskedOverflows(volatile uint32_t baseAddr, uint16_t value); + +/** + * \brief Set the compare value for the timer + * + * \note Ensure the timer is properly configured before setting the compare value. + * + * \param baseAddr [in] HW timer base address + * \param value [in] Compare value to be set + */ +void TimerP_setCompare(volatile uint32_t baseAddr, uint16_t value); + +/** + * \brief Configure the timer for PWM mode + * + * \note Ensure the timer is properly initialized before calling this function. + * The function calculates and sets the timer registers to generate the + * desired PWM signal based on the provided frequency and duty cycle. + * Remember to multiplex the output pins correctly for the + * configured timer. + * + * \param baseAddr [in] HW timer base address + * \param params [in] Pointer to TimerP_Params containing clock settings + * \param frequency [in] Desired PWM frequency in Hz + * \param duty_cycle [in] Duty cycle percentage (0-100) + * + * \return 0 on success, -22 if input parameters are invalid + */ +int TimerP_configPwm(volatile uint32_t baseAddr, TimerP_Params *params, + uint32_t frequency, uint8_t duty_cycle); + /** @} */ #ifdef __cplusplus diff --git a/source/kernel/nortos/dpl/common/TimerP.c b/source/kernel/nortos/dpl/common/TimerP.c index e33a1e2d7e..a5e1ecde88 100755 --- a/source/kernel/nortos/dpl/common/TimerP.c +++ b/source/kernel/nortos/dpl/common/TimerP.c @@ -45,6 +45,8 @@ #define TIMER_TCRR (0x3cu) #define TIMER_TLDR (0x40u) #define TIMER_TWPS (0x48u) +#define TIMER_TMAR (0x4Cu) +#define TIMER_TOWR (0x6Cu) #define TIMER_TCLR_PEND_SHIFT (0U) #define TIMER_TCRR_PEND_SHIFT (1U) #define TIMER_TLDR_PEND_SHIFT (2U) @@ -253,3 +255,77 @@ uint32_t TimerP_isOverflowed(uint32_t baseAddr) return ((val >> TIMER_OVF_INT_SHIFT) & 0x1U); } + +void TimerP_configMaskedOverflows(volatile uint32_t baseAddr, uint16_t value) +{ + volatile uint32_t *towr_addr = NULL; + + towr_addr = (volatile uint32_t *)(baseAddr + TIMER_TOWR); + + *towr_addr = (uint32_t)value; +} + +void TimerP_setCompare(volatile uint32_t baseAddr, uint16_t value) +{ + volatile uint32_t *tmar_addr = NULL; + + tmar_addr = (volatile uint32_t *)(baseAddr + TIMER_TMAR); + + *tmar_addr = (uint32_t)value; +} + +int TimerP_configPwm(volatile uint32_t baseAddr, TimerP_Params *params, + uint32_t frequency, uint8_t duty_cycle) +{ + volatile uint32_t *tldr_reg = (volatile uint32_t *)(baseAddr + TIMER_TLDR); + volatile uint32_t *tcrr_reg = (volatile uint32_t *)(baseAddr + TIMER_TCRR); + volatile uint32_t *tmar_reg = (volatile uint32_t *)(baseAddr + TIMER_TMAR); + volatile uint32_t *twps_reg = (volatile uint32_t *)(baseAddr + TIMER_TWPS); + + uint64_t abs_clock = 0U; + uint64_t period_in_ns = 0U; + uint64_t counter_ticks = 0U; + uint64_t duty_ticks = 0U; + + if (params == NULL) + return -22; + + if (params->inputPreScaler == 0U || params->inputClkHz == 0U) + return -22; + + if (duty_cycle > 100U || frequency == 0U) + return -22; + + if ((params->inputClkHz % params->inputPreScaler) != 0U) + return -22; + + abs_clock = (uint64_t)(params->inputClkHz / params->inputPreScaler); + + period_in_ns = TIME_IN_NANO_SECONDS / (uint64_t)frequency; + + counter_ticks = (abs_clock * period_in_ns) / TIME_IN_NANO_SECONDS; + if (counter_ticks == 0U) + counter_ticks = 1U; + + duty_ticks = counter_ticks - ((counter_ticks * (uint64_t)duty_cycle) / 100U); + + if (duty_ticks == 0U) + duty_ticks = 1U; + if (duty_ticks >= counter_ticks) + duty_ticks = counter_ticks - 1U; + + /* TLDR */ + while ((*twps_reg & TIMER_TLDR_PEND_MASK) == TIMER_TLDR_PEND_MASK) { } + *tldr_reg = (uint32_t)(MAX_TIMER_COUNT_VALUE - (uint32_t)(counter_ticks - 1U)); + while ((*twps_reg & TIMER_TLDR_PEND_MASK) == TIMER_TLDR_PEND_MASK) { } + + /* TCRR */ + while ((*twps_reg & TIMER_TCRR_PEND_MASK) == TIMER_TCRR_PEND_MASK) { } + *tcrr_reg = (uint32_t)(MAX_TIMER_COUNT_VALUE - (uint32_t)(counter_ticks - 1U)); + while ((*twps_reg & TIMER_TCRR_PEND_MASK) == TIMER_TCRR_PEND_MASK) { } + + /* TMAR */ + *tmar_reg = (uint32_t)(MAX_TIMER_COUNT_VALUE - (uint32_t)(duty_ticks - 1U)); + + return 0; +}