Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion source/kernel/dpl/TimerP.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
76 changes: 76 additions & 0 deletions source/kernel/nortos/dpl/common/TimerP.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
}