diff --git a/arch/arm/src/tiva/Kconfig b/arch/arm/src/tiva/Kconfig index c4cf4b57a6f..0f1d99a1f67 100644 --- a/arch/arm/src/tiva/Kconfig +++ b/arch/arm/src/tiva/Kconfig @@ -1327,7 +1327,11 @@ config TIVA_TIMER16_TIMECAP config TIVA_TIMER16_PWM bool "16-bit PWM output support" default n - depends on EXPERIMENTAL + ---help--- + Enables 24-bit PWM mode using a 16-bit half-timer of a + Tiva 16/32-bit General Purpose Timer Module (GPTM) block. + The 24-bit resolution is achieved by using the prescaler + as the high 8 bits. endif # TIVA_TIMER_16BIT diff --git a/arch/arm/src/tiva/common/tiva_timerlib.c b/arch/arm/src/tiva/common/tiva_timerlib.c index f009ae33dba..5a8176fc038 100644 --- a/arch/arm/src/tiva/common/tiva_timerlib.c +++ b/arch/arm/src/tiva/common/tiva_timerlib.c @@ -211,6 +211,11 @@ static int tiva_input_time_mode16(struct tiva_gptmstate_s *priv, const struct tiva_timer16config_s *timer, int tmndx); #endif #ifdef CONFIG_TIVA_TIMER16_PWM +static uint32_t tiva_pwm16_sel_event(struct tiva_gptmstate_s *priv, + const struct tiva_timer16config_s *timer, + int tmndx); +#endif +#ifdef CONFIG_TIVA_TIMER16_PWM static int tiva_pwm_mode16(struct tiva_gptmstate_s *priv, const struct tiva_timer16config_s *timer, int tmndx); @@ -1444,6 +1449,79 @@ static int tiva_input_time_mode16(struct tiva_gptmstate_s *priv, } #endif +/**************************************************************************** + * Name: tiva_pwm16_sel_event + * + * Description: + * Select which event to program into the TnEVENT field in the GPTMCTL + * register based on configured flags. Note that the caller must first + * clear the bit field (using either TIMER_CTL_TAEVENT_MASK or + * TIMER_CTL_TBEVENT_MASK depending on whether Timer A or Timer B is + * used) before writing the value returned by this function. + * + * Input Parameters: + * handle - The handle value returned by tiva_gptm_configure() + * timer - The timer A or B configuration structure. This is located + * within the configuration passed to tiva_gptm_configure(). + * tmndx - Either TIMER16A or TIMER16B to select the 16-bit timer + * + * Returned Value: + * Value to be programmed into the TnEVENT field in the GPTMCTL register + * after clearing the bit field as described above. + * + ****************************************************************************/ + +#ifdef CONFIG_TIVA_TIMER16_PWM +static uint32_t tiva_pwm16_sel_event(struct tiva_gptmstate_s *priv, + const struct tiva_timer16config_s *timer, + int tmndx) +{ + /* For PWM interrupt edge selection, we can interrupt on positive edge + * (TIMER_CTL_TnEVENT_POS), negative edge (TIMER_CTL_TnEVENT_NEG), or both + * edges (TIMER_CTL_TnEVENT_BOTH). If PWM output is inverted, then edge + * detect interrupt behavior is reversed by the hardware. We will normalize + * this so that higher level logic won't have to. + */ + + if (TIMER_ISPWMINTBOTH(timer)) + { + /* When interrupting on both edges, it doesn't matter if PWM output + * is inverted. + */ + return tmndx ? TIMER_CTL_TBEVENT_BOTH : TIMER_CTL_TAEVENT_BOTH; + } + + if (TIMER_ISPWMINTPOS(timer)) + { + if (TIMER_ISPWMINVERT(timer)) + { + return tmndx ? TIMER_CTL_TBEVENT_NEG : TIMER_CTL_TAEVENT_NEG; + } + else + { + return tmndx ? TIMER_CTL_TBEVENT_POS : TIMER_CTL_TAEVENT_POS; + } + } + + if (TIMER_ISPWMINTNEG(timer)) + { + if (TIMER_ISPWMINVERT(timer)) + { + return tmndx ? TIMER_CTL_TBEVENT_POS : TIMER_CTL_TAEVENT_POS; + } + else + { + return tmndx ? TIMER_CTL_TBEVENT_NEG : TIMER_CTL_TAEVENT_NEG; + } + } + + /* Not interrupting on any edge + */ + + return 0; +} +#endif + /**************************************************************************** * Name: tiva_pwm_mode16 * @@ -1468,6 +1546,11 @@ static int tiva_pwm_mode16(struct tiva_gptmstate_s *priv, const struct tiva_timer16config_s *timer, int tmndx) { + unsigned int regoffset; + uint32_t regval; + uint32_t clrbits; + uint32_t setbits; + /* A timer is configured to PWM mode using the following sequence: * * 1. Ensure the timer is disabled (the TnEN bit is cleared) before making @@ -1483,26 +1566,60 @@ static int tiva_pwm_mode16(struct tiva_gptmstate_s *priv, * tiva_gptm_configure() before this function was called. * * 3. In the GPTM Timer Mode (GPTMTnMR) register, set the TnAMS bit to - * 0x1, the TnCMR bit to 0x0, and the TnMR field to 0x2. + * 0x1 (enables PWM), the TnCMR bit to 0x0 (edge count mode), and the + * TnMR field to 0x2 (periodic timer mode). */ + regoffset = tmndx ? TIVA_TIMER_TBMR_OFFSET : TIVA_TIMER_TAMR_OFFSET; + clrbits = TIMER_TnMR_TnMR_MASK | TIMER_TnMR_TnCMR | TIMER_TnMR_TnAMS; + setbits = TIMER_TnMR_TnMR_PERIODIC | TIMER_TnMR_TnCMR_EDGECOUNT | TIMER_TnMR_TnAMS_PWM; + tiva_modifyreg(priv, regoffset, clrbits, setbits); + /* 4. Configure the output state of the PWM signal (whether or not it is * inverted) in the TnPWML field of the GPTM Control (GPTMCTL) register. */ - /* 5. If a prescaler is to be used, write the prescale value to the GPTM - * Timer n Prescale Register (GPTMTnPR). + regval = tmndx ? TIMER_CTL_TBPWML : TIMER_CTL_TAPWML; + + if (TIMER_ISPWMINVERT(timer)) + { + tiva_modifyreg(priv, TIVA_TIMER_CTL_OFFSET, 0, regval); + } + else + { + tiva_modifyreg(priv, TIVA_TIMER_CTL_OFFSET, regval, 0); + } + + /* 5. If PWM interrupts are used, configure which signal edge(s) trigger + * the interrupt by setting the TnEVENT field in the GPTMCTL register. + * This can be the positive edge (TIMER_CTL_TnEVENT_POS), the negative + * edge (TIMER_CTL_TnEVENT_NEG), or both edges (TIMER_CTL_TnEVENT_BOTH). + * Note that if the PWM output is inverted (see above), then edge detect + * interrupt behavior is reversed. We will normalize this so that higher + * level logic won't have to. + * + * Enable the interrupts by setting the TnPWMIE bit in the GPTMTnMR + * register. Note that edge detect interrupt behavior is reversed when + * the PWM output is inverted. */ - /* 6. If PWM interrupts are used, configure the interrupt condition in the - * TnEVENT field in the GPTMCTL register and enable the interrupts by - * setting the TnPWMIE bit in the GPTMTnMR register. Note that edge - * detect interrupt behavior is reversed when the PWM output is - * inverted. - */ + clrbits = tmndx ? TIMER_CTL_TBEVENT_MASK : TIMER_CTL_TAEVENT_MASK; + setbits = tiva_pwm16_sel_event(priv, timer, tmndx); + tiva_modifyreg(priv, TIVA_TIMER_CTL_OFFSET, clrbits, setbits); - /* 7. Load the timer start value into the GPTM Timer n Interval Load - * (GPTMTnILR) register. + regoffset = tmndx ? TIVA_TIMER_TBMR_OFFSET : TIVA_TIMER_TAMR_OFFSET; + tiva_modifyreg(priv, regoffset, 0, TIMER_TnMR_TnPWMIE); + + /* 6. Set PWM period: This is a 24-bit value. Put the high byte (bits 16 + * thru 23) in the prescaler register (TIVA_TIMER_TnPR_OFFSET). Put the + * low word (bits 0 through 15) in the interval load register + * (TIVA_TIMER_TnILR_OFFSET). + * + * NOTE: This is done when tiva_timer16pwm_setperiodduty() is called. + * That must be done by other logic, prior to starting the clock running. + * + * The following note was here before implementation of this function + * was written: * * REVISIT: When the ALTCLK bit is set in the GPTMCC register to enable * using the alternate clock source, the synchronization imposes @@ -1521,23 +1638,29 @@ static int tiva_pwm_mode16(struct tiva_gptmstate_s *priv, * interrupt enabled are: GPTMTAMATCHR = 0x23 GPTMTAILR = 0x46" */ - /* 8. Load the GPTM Timer n Match (GPTMTnMATCHR) register with the match - * value. + /* 7. Set PWM duty cycle: This is a 24-bit value. Put the high byte (bits + * 16 thru 23) in the prescale match register (TIVA_TIMER_TnPMR_OFFSET). + * Put the low word (bits 0 thru 16) in the match register + * (TIVA_TIMER_TnMATCHR_OFFSET). + * + * NOTE: This is done when tiva_timer16pwm_setperiodduty() is called. + * That must be done by other logic, prior to starting the clock running. + * Once the period and initial duty cycle are set, the duty cycle can + * be changed at any time by calling tiva_timer16pwm_setduty(). */ -#warning Missing Logic - /* 9. Set the TnEN bit in the GPTM Control (GPTMCTL) register to enable + /* 8. Set the TnEN bit in the GPTM Control (GPTMCTL) register to enable * the timer and begin generation of the output PWM signal. * - * In PWM Time mode, the timer continues running after the PWM signal has - * been generated. The PWM period can be adjusted at any time by writing - * the GPTMTnILR register, and the change takes effect at the next cycle - * after the write. + * This is done when tiva_timer16_start() is called. * - * NOTE: This timer is not started until tiva_gptm_enableclk() is called. + * In PWM Time mode, the timer continues running after the PWM signal + * has been generated. The PWM period can be adjusted at any time by + * writing the GPTMTnILR register, and the change takes effect at the + * next cycle after the write. */ - return -ENOSYS; + return OK; } #endif @@ -1613,8 +1736,8 @@ static int tiva_timer16_configure(struct tiva_gptmstate_s *priv, #endif #ifdef CONFIG_TIVA_TIMER16_PWM - case TIMER16_MODE_PWM: /* 16-bit PWM output mode w/8-bit - * prescaler */ + case TIMER16_MODE_PWM: /* 24-bit PWM output mode with upper + * 8-bits in prescaler register */ return tiva_pwm_mode16(priv, timer, tmndx); #endif @@ -1762,7 +1885,7 @@ TIMER_HANDLE tiva_gptm_configure(const struct tiva_gptmconfig_s *config) /* Wait for the reset to complete */ - while (!tiva_gptm_periphrdy()); + while (!tiva_gptm_periphrdy(config->gptm)); up_udelay(250); /* Select the alternate timer clock source is so requested. The general @@ -1921,7 +2044,7 @@ void tiva_gptm_release(TIMER_HANDLE handle) /* Wait for the reset to complete */ - while (!tiva_gptm_periphrdy()); + while (!tiva_gptm_periphrdy(config->gptm)); up_udelay(250); /* Disable power and clocking to the GPTM module */ @@ -2497,8 +2620,8 @@ void tiva_timer16_setinterval(TIMER_HANDLE handle, uint16_t interval, int tmndx) toints = false; if (timer->handler && - (config->cmn.mode == TIMER16_MODE_ONESHOT || - config->cmn.mode == TIMER16_MODE_PERIODIC)) + (timer->mode == TIMER16_MODE_ONESHOT || + timer->mode == TIMER16_MODE_PERIODIC)) { toints = true; } @@ -3068,3 +3191,173 @@ void tiva_timer16_relmatch(TIMER_HANDLE handle, uint32_t relmatch, int tmndx) #endif } #endif + +/**************************************************************************** + * Name: tiva_timer16pwm_setperiodduty + * + * Description: + * Set the period and initial duty cycle for a 16-bit timer operating in + * PWM mode. Also, enable interrupts if a handler is provided. The timer + * is not started until tiva_timer16_start() is called. + * + * Input Parameters: + * handle - The handle value returned by tiva_gptm_configure() + * period - The PWM period, a 24-bit value. + * duty - The initial PWM duty cycle, a 24-bit value. + * tmndx - Either TIMER16A or TIMER16B to select the 16-bit timer + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_TIVA_TIMER16_PWM +void tiva_timer16pwm_setperiodduty(TIMER_HANDLE handle, uint32_t period, + uint32_t duty, int tmndx) +{ + struct tiva_gptmstate_s *priv = (struct tiva_gptmstate_s *)handle; + const struct tiva_gptm16config_s *config; + const struct tiva_timer16config_s *timer; + irqstate_t flags; + uintptr_t base; + bool toints; + uint32_t imr; + uint32_t periodhi; + uint32_t dutyhi; + + DEBUGASSERT(priv && priv->attr && priv->config && + priv->config->mode == TIMER16_MODE && + (period & 0x00ffffff) && (duty & 0x00ffffff) && + (unsigned)tmndx < 2); + + config = (const struct tiva_gptm16config_s *)priv->config; + timer = &config->config[tmndx]; + base = priv->attr->base; + + /* Do we need to enable timeout interrupts? Interrupts are only enabled + * if (1) the user has provided a handler, and (2) the timer is + * configured for PWM. + */ + + toints = false; + imr = 0; + + if (timer->handler && timer->mode == TIMER16_MODE_PWM) + { + toints = true; + } + + /* To set PWM period: + * Put high byte (8 bits) in prescaler register. + * Put low word (16 bits) in interval load register. + * + * To set PWM duty cycle: + * Put high byte (8 bits) in prescale match register. + * Put low word (16 bits) in match register. + */ + + periodhi = (period >> 16) & 0xff; + period &= 0xffff; + dutyhi = (duty >> 16) & 0xff; + duty &= 0xffff; + + /* Make the following atomic */ + + flags = enter_critical_section(); + + if (tmndx) + { + putreg32(periodhi, base + TIVA_TIMER_TBPR_OFFSET); + putreg32(period, base + TIVA_TIMER_TBILR_OFFSET); + + putreg32(dutyhi, base + TIVA_TIMER_TBPMR_OFFSET); + putreg32(duty, base + TIVA_TIMER_TBMATCHR_OFFSET); + + imr |= TIMER_INT_CBE; + } + else + { + putreg32(periodhi, base + TIVA_TIMER_TAPR_OFFSET); + putreg32(period, base + TIVA_TIMER_TAILR_OFFSET); + + putreg32(dutyhi, base + TIVA_TIMER_TAPMR_OFFSET); + putreg32(duty, base + TIVA_TIMER_TAMATCHR_OFFSET); + + imr |= TIMER_INT_CAE; + } + + /* Enable the capture mode event interrupt at the timer peripheral. + * The interrupt will not fire until enabled at the NVIC. That will be + * done when tiva_timer16_start() is called. */ + + if (toints) + { + priv->imr = imr; + putreg32(priv->imr, base + TIVA_TIMER_IMR_OFFSET); + } + + leave_critical_section(flags); +} +#endif + +/**************************************************************************** + * Name: tiva_timer16pwm_setduty + * + * Description: + * Update the duty cycle for a 16-bit timer operating in PWM mode. + * + * Input Parameters: + * handle - The handle value returned by tiva_gptm_configure() + * duty - The initial PWM duty cycle, a 24-bit value. + * tmndx - Either TIMER16A or TIMER16B to select the 16-bit timer + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_TIVA_TIMER16_PWM +void tiva_timer16pwm_setduty(TIMER_HANDLE handle, uint32_t duty, int tmndx) +{ + struct tiva_gptmstate_s *priv = (struct tiva_gptmstate_s *)handle; + irqstate_t flags; + uintptr_t base; + uintptr_t tnpmr; + uintptr_t tnmatchr; + uint32_t dutyhi; + + DEBUGASSERT(priv && priv->attr && priv->config && + priv->config->mode == TIMER16_MODE && + (duty & 0x00ffffff) && (unsigned)tmndx < 2); + + base = priv->attr->base; + + /* To set PWM duty cycle: + * Put high byte (8 bits) in prescale match register. + * Put low word (16 bits) in match register. + */ + + if (tmndx) + { + tnpmr = base + TIVA_TIMER_TBPMR_OFFSET; + tnmatchr = base + TIVA_TIMER_TBMATCHR_OFFSET; + } + else + { + tnpmr = base + TIVA_TIMER_TAPMR_OFFSET; + tnmatchr = base + TIVA_TIMER_TAMATCHR_OFFSET; + } + + dutyhi = (duty >> 16) & 0xff; + duty &= 0xffff; + + /* Make the following atomic */ + + flags = enter_critical_section(); + + putreg32(dutyhi, tnpmr); + putreg32(duty, tnmatchr); + + leave_critical_section(flags); +} +#endif diff --git a/arch/arm/src/tiva/hardware/lm/lm3s_timer.h b/arch/arm/src/tiva/hardware/lm/lm3s_timer.h index 5362c4f8bd9..243042302c9 100644 --- a/arch/arm/src/tiva/hardware/lm/lm3s_timer.h +++ b/arch/arm/src/tiva/hardware/lm/lm3s_timer.h @@ -262,15 +262,17 @@ /* GPTM Timer A/B Mode (TAMR and TBMR) */ -#define TIMER_TnMR_TnMR_SHIFT 0 /* Bits 1-0: Timer A/B Mode */ -#define TIMER_TnMR_TnMR_MASK (3 << TIMER_TnMR_TnMR_SHIFT) +#define TIMER_TnMR_TnMR_SHIFT (0) /* Bits 1-0: Timer A/B Mode */ +#define TIMER_TnMR_TnMR_MASK (3 << TIMER_TnMR_TnMR_SHIFT) /* Bits 1-0: Timer A/B Mode */ # define TIMER_TnMR_TnMR_ONESHOT (1 << TIMER_TnMR_TnMR_SHIFT) /* One-Shot Timer mode */ # define TIMER_TnMR_TnMR_PERIODIC (2 << TIMER_TnMR_TnMR_SHIFT) /* Periodic Timer mode */ # define TIMER_TnMR_TnMR_CAPTURE (3 << TIMER_TnMR_TnMR_SHIFT) /* Capture mode */ -#define TIMER_TnMR_TnCMR (1 << 2) /* Bit 2: Timer A/B Capture Mode */ +#define TIMER_TnMR_TnCMR_SHIFT (2) /* Bit 2: Timer A/B Capture Mode */ +#define TIMER_TnMR_TnCMR (1 << TIMER_TnMR_TnCMR_SHIFT) /* Bit 2: Timer A/B Capture Mode */ # define TIMER_TnMR_TnCMR_EDGECOUNT (0 << TIMER_TnMR_TnCMR_SHIFT) /* Edge-Count mode */ # define TIMER_TnMR_TnCMR_EDGETIME (1 << TIMER_TnMR_TnCMR_SHIFT) /* Edge-Time mode */ -#define TIMER_TnMR_TnAMS (1 << 3) /* Bit 3: Timer A/B Alternate Mode Select */ +#define TIMER_TnMR_TnAMS_SHIFT (3) /* Bit 3: Timer A/B Alternate Mode Select */ +#define TIMER_TnMR_TnAMS (1 << TIMER_TnMR_TnAMS_SHIFT) /* Bit 3: Timer A/B Alternate Mode Select */ # define TIMER_TnMR_TnAMS_CAPTURE (0 << TIMER_TnMR_TnAMS_SHIFT) /* Capture mode is enabled */ # define TIMER_TnMR_TnAMS_PWM (1 << TIMER_TnMR_TnAMS_SHIFT) /* PWM mode is enabled */ diff --git a/arch/arm/src/tiva/hardware/lm/lm4f_timer.h b/arch/arm/src/tiva/hardware/lm/lm4f_timer.h index 2c46cce0a72..04001009155 100644 --- a/arch/arm/src/tiva/hardware/lm/lm4f_timer.h +++ b/arch/arm/src/tiva/hardware/lm/lm4f_timer.h @@ -336,20 +336,23 @@ /* GPTM Timer A/B Mode (TAMR and TBMR) */ -#define TIMER_TnMR_TnMR_SHIFT 0 /* Bits 1-0: Timer A/B Mode */ +#define TIMER_TnMR_TnMR_SHIFT (0) /* Bits 1-0: Timer A/B Mode */ #define TIMER_TnMR_TnMR_MASK (3 << TIMER_TnMR_TnMR_SHIFT) # define TIMER_TnMR_TnMR_ONESHOT (1 << TIMER_TnMR_TnMR_SHIFT) /* One-Shot Timer mode */ # define TIMER_TnMR_TnMR_PERIODIC (2 << TIMER_TnMR_TnMR_SHIFT) /* Periodic Timer mode */ # define TIMER_TnMR_TnMR_CAPTURE (3 << TIMER_TnMR_TnMR_SHIFT) /* Capture mode */ -#define TIMER_TnMR_TnCMR (1 << 2) /* Bit 2: Timer A/B Capture Mode */ +#define TIMER_TnMR_TnCMR_SHIFT (2) /* Bit 2: Timer A/B Capture Mode */ +#define TIMER_TnMR_TnCMR (1 << TIMER_TnMR_TnCMR_SHIFT) /* Bit 2: Timer A/B Capture Mode */ # define TIMER_TnMR_TnCMR_EDGECOUNT (0 << TIMER_TnMR_TnCMR_SHIFT) /* Edge-Count mode */ # define TIMER_TnMR_TnCMR_EDGETIME (1 << TIMER_TnMR_TnCMR_SHIFT) /* Edge-Time mode */ -#define TIMER_TnMR_TnAMS (1 << 3) /* Bit 3: Timer A/B Alternate Mode Select */ +#define TIMER_TnMR_TnAMS_SHIFT (3) /* Bit 3: Timer A/B Alternate Mode Select */ +#define TIMER_TnMR_TnAMS (1 << TIMER_TnMR_TnAMS_SHIFT) /* Bit 3: Timer A/B Alternate Mode Select */ # define TIMER_TnMR_TnAMS_CAPTURE (0 << TIMER_TnMR_TnAMS_SHIFT) /* Capture mode is enabled */ # define TIMER_TnMR_TnAMS_PWM (1 << TIMER_TnMR_TnAMS_SHIFT) /* PWM mode is enabled */ -#define TIMER_TnMR_TnCDIR (1 << 4) /* Bit 4: Timer A/B Count Direction */ -# define TIMER_TnMR_TnCDIR_DOWN (0) /* Timer counts down */ -# define TIMER_TnMR_TnCDIR_UP TIMER_TnMR_TnCDIR /* Timer counts up (one-shot/periodic modes) */ +#define TIMER_TnMR_TnCDIR_SHIFT (4) /* Bit 4: Timer A/B Count Direction */ +#define TIMER_TnMR_TnCDIR (1 << TIMER_TnMR_TnCDIR_SHIFT) /* Bit 4: Timer A/B Count Direction */ +# define TIMER_TnMR_TnCDIR_DOWN (0 << TIMER_TnMR_TnCDIR_SHIFT) /* Timer counts down */ +# define TIMER_TnMR_TnCDIR_UP (1 << TIMER_TnMR_TnCDIR_SHIFT) /* Timer counts up (one-shot/periodic modes) */ #define TIMER_TnMR_TnMIE (1 << 5) /* Bit 5: Timer A/B Match Interrupt Enable */ #define TIMER_TnMR_TnWOT (1 << 6) /* Bit 6: GPTM Timer A/B Wait-on-Trigger */ #define TIMER_TnMR_TnSNAPS (1 << 7) /* Bit 7: GPTM Timer A/B Snap-Shot Mode */ diff --git a/arch/arm/src/tiva/hardware/tm4c/tm4c123_timer.h b/arch/arm/src/tiva/hardware/tm4c/tm4c123_timer.h index e1e155a4a00..ed34fa81dde 100644 --- a/arch/arm/src/tiva/hardware/tm4c/tm4c123_timer.h +++ b/arch/arm/src/tiva/hardware/tm4c/tm4c123_timer.h @@ -336,20 +336,23 @@ /* GPTM Timer A/B Mode (TAMR and TBMR) */ -#define TIMER_TnMR_TnMR_SHIFT 0 /* Bits 1-0: Timer A/B Mode */ +#define TIMER_TnMR_TnMR_SHIFT (0) /* Bits 1-0: Timer A/B Mode */ #define TIMER_TnMR_TnMR_MASK (3 << TIMER_TnMR_TnMR_SHIFT) # define TIMER_TnMR_TnMR_ONESHOT (1 << TIMER_TnMR_TnMR_SHIFT) /* One-Shot Timer mode */ # define TIMER_TnMR_TnMR_PERIODIC (2 << TIMER_TnMR_TnMR_SHIFT) /* Periodic Timer mode */ # define TIMER_TnMR_TnMR_CAPTURE (3 << TIMER_TnMR_TnMR_SHIFT) /* Capture mode */ -#define TIMER_TnMR_TnCMR (1 << 2) /* Bit 2: Timer A/B Capture Mode */ +#define TIMER_TnMR_TnCMR_SHIFT (2) /* Bit 2: Timer A/B Capture Mode */ +#define TIMER_TnMR_TnCMR (1 << TIMER_TnMR_TnCMR_SHIFT) /* Bit 2: Timer A/B Capture Mode */ # define TIMER_TnMR_TnCMR_EDGECOUNT (0 << TIMER_TnMR_TnCMR_SHIFT) /* Edge-Count mode */ # define TIMER_TnMR_TnCMR_EDGETIME (1 << TIMER_TnMR_TnCMR_SHIFT) /* Edge-Time mode */ -#define TIMER_TnMR_TnAMS (1 << 3) /* Bit 3: Timer A/B Alternate Mode Select */ +#define TIMER_TnMR_TnAMS_SHIFT (3) /* Bit 3: Timer A/B Alternate Mode Select */ +#define TIMER_TnMR_TnAMS (1 << TIMER_TnMR_TnAMS_SHIFT) /* Bit 3: Timer A/B Alternate Mode Select */ # define TIMER_TnMR_TnAMS_CAPTURE (0 << TIMER_TnMR_TnAMS_SHIFT) /* Capture mode is enabled */ # define TIMER_TnMR_TnAMS_PWM (1 << TIMER_TnMR_TnAMS_SHIFT) /* PWM mode is enabled */ -#define TIMER_TnMR_TnCDIR (1 << 4) /* Bit 4: Timer A/B Count Direction */ -# define TIMER_TnMR_TnCDIR_DOWN (0) /* Timer counts down */ -# define TIMER_TnMR_TnCDIR_UP TIMER_TnMR_TnCDIR /* Timer counts up (one-shot/periodic modes) */ +#define TIMER_TnMR_TnCDIR_SHIFT (4) /* Bit 4: Timer A/B Count Direction */ +#define TIMER_TnMR_TnCDIR (1 << TIMER_TnMR_TnCDIR_SHIFT) /* Bit 4: Timer A/B Count Direction */ +# define TIMER_TnMR_TnCDIR_DOWN (0 << TIMER_TnMR_TnCDIR_SHIFT) /* Timer counts down */ +# define TIMER_TnMR_TnCDIR_UP (1 << TIMER_TnMR_TnCDIR_SHIFT) /* Timer counts up (one-shot/periodic modes) */ #define TIMER_TnMR_TnMIE (1 << 5) /* Bit 5: Timer A/B Match Interrupt Enable */ #define TIMER_TnMR_TnWOT (1 << 6) /* Bit 6: GPTM Timer A/B Wait-on-Trigger */ #define TIMER_TnMR_TnSNAPS (1 << 7) /* Bit 7: GPTM Timer A/B Snap-Shot Mode */ diff --git a/arch/arm/src/tiva/hardware/tm4c/tm4c129_timer.h b/arch/arm/src/tiva/hardware/tm4c/tm4c129_timer.h index 5d336c51d69..8793219651d 100644 --- a/arch/arm/src/tiva/hardware/tm4c/tm4c129_timer.h +++ b/arch/arm/src/tiva/hardware/tm4c/tm4c129_timer.h @@ -363,20 +363,23 @@ /* GPTM Timer A/B Mode (TAMR and TBMR) */ -#define TIMER_TnMR_TnMR_SHIFT 0 /* Bits 1-0: Timer A/B Mode */ +#define TIMER_TnMR_TnMR_SHIFT (0) /* Bits 1-0: Timer A/B Mode */ #define TIMER_TnMR_TnMR_MASK (3 << TIMER_TnMR_TnMR_SHIFT) # define TIMER_TnMR_TnMR_ONESHOT (1 << TIMER_TnMR_TnMR_SHIFT) /* One-Shot Timer mode */ # define TIMER_TnMR_TnMR_PERIODIC (2 << TIMER_TnMR_TnMR_SHIFT) /* Periodic Timer mode */ # define TIMER_TnMR_TnMR_CAPTURE (3 << TIMER_TnMR_TnMR_SHIFT) /* Capture mode */ -#define TIMER_TnMR_TnCMR (1 << 2) /* Bit 2: Timer A/B Capture Mode */ +#define TIMER_TnMR_TnCMR_SHIFT (2) /* Bit 2: Timer A/B Capture Mode */ +#define TIMER_TnMR_TnCMR (1 << TIMER_TnMR_TnCMR_SHIFT) /* Bit 2: Timer A/B Capture Mode */ # define TIMER_TnMR_TnCMR_EDGECOUNT (0 << TIMER_TnMR_TnCMR_SHIFT) /* Edge-Count mode */ # define TIMER_TnMR_TnCMR_EDGETIME (1 << TIMER_TnMR_TnCMR_SHIFT) /* Edge-Time mode */ -#define TIMER_TnMR_TnAMS (1 << 3) /* Bit 3: Timer A/B Alternate Mode Select */ +#define TIMER_TnMR_TnAMS_SHIFT (3) /* Bit 3: Timer A/B Alternate Mode Select */ +#define TIMER_TnMR_TnAMS (1 << TIMER_TnMR_TnAMS_SHIFT) /* Bit 3: Timer A/B Alternate Mode Select */ # define TIMER_TnMR_TnAMS_CAPTURE (0 << TIMER_TnMR_TnAMS_SHIFT) /* Capture mode is enabled */ # define TIMER_TnMR_TnAMS_PWM (1 << TIMER_TnMR_TnAMS_SHIFT) /* PWM mode is enabled */ -#define TIMER_TnMR_TnCDIR (1 << 4) /* Bit 4: Timer A/B Count Direction */ -# define TIMER_TnMR_TnCDIR_DOWN (0) /* Timer counts down */ -# define TIMER_TnMR_TnCDIR_UP TIMER_TnMR_TnCDIR /* Timer counts up (one-shot/periodic modes) */ +#define TIMER_TnMR_TnCDIR_SHIFT (4) /* Bit 4: Timer A/B Count Direction */ +#define TIMER_TnMR_TnCDIR (1 << TIMER_TnMR_TnCDIR_SHIFT) /* Bit 4: Timer A/B Count Direction */ +# define TIMER_TnMR_TnCDIR_DOWN (0 << TIMER_TnMR_TnCDIR_SHIFT) /* Timer counts down */ +# define TIMER_TnMR_TnCDIR_UP (1 << TIMER_TnMR_TnCDIR_SHIFT) /* Timer counts up (one-shot/periodic modes) */ #define TIMER_TnMR_TnMIE (1 << 5) /* Bit 5: Timer A/B Match Interrupt Enable */ #define TIMER_TnMR_TnWOT (1 << 6) /* Bit 6: GPTM Timer A/B Wait-on-Trigger */ #define TIMER_TnMR_TnSNAPS (1 << 7) /* Bit 7: GPTM Timer A/B Snap-Shot Mode */ @@ -407,7 +410,7 @@ # define TIMER_CTL_TAEVENT_BOTH (3 << TIMER_CTL_TAEVENT_SHIFT) /* Both edges */ #define TIMER_CTL_RTCEN (1 << 4) /* Bit 4: GPTM RTC Stall Enable */ #define TIMER_CTL_TAOTE (1 << 5) /* Bit 5: GPTM Timer A Output Trigger Enable */ -#define TIMER_CTL_TAPWML (1 << 6) /* Bit 6: GPTM Timer A PWM Output Level */ +#define TIMER_CTL_TAPWML (1 << 6) /* Bit 6: GPTM Timer A PWM Output Level Inverted */ #define TIMER_CTL_TBEN (1 << 8) /* Bit 8: GPTM Timer B Enable */ #define TIMER_CTL_TBSTALL (1 << 9) /* Bit 9: GPTM Timer B Stall Enable */ #define TIMER_CTL_TBEVENT_SHFIT (10) /* Bits 10-11: GPTM Timer B Event Mode */ @@ -416,7 +419,7 @@ # define TIMER_CTL_TBEVENT_NEG (1 << TIMER_CTL_TBEVENT_SHFIT) /* Negative edge */ # define TIMER_CTL_TBEVENT_BOTH (3 << TIMER_CTL_TBEVENT_SHFIT) /* Both edges */ #define TIMER_CTL_TBOTE (1 << 13) /* Bit 13: GPTM Timer B Output Trigger Enable */ -#define TIMER_CTL_TBPWML (1 << 14) /* Bit 14: GPTM Timer B PWM Output Level */ +#define TIMER_CTL_TBPWML (1 << 14) /* Bit 14: GPTM Timer B PWM Output Level Inverted */ /* GPTM Synchronize (GPTM0 only) */ diff --git a/arch/arm/src/tiva/tiva_timer.h b/arch/arm/src/tiva/tiva_timer.h index c14ec97b0de..025087c7174 100644 --- a/arch/arm/src/tiva/tiva_timer.h +++ b/arch/arm/src/tiva/tiva_timer.h @@ -103,21 +103,29 @@ * c. 32-bit one shot timer * d. 32-bit periodic timer * e. 32-bit RTC timer + * f. 16-bit PWM timer */ -#define TIMER_FLAG_COUNTUP (1 << 0) /* Bit 0: Count up (abcd) */ -#define TIMER_FLAG_ADCTIMEOUT (1 << 1) /* Bit 1: Generate ADC trigger on - * timeout (abcd) */ -#define TIMER_FLAG_ADCRTCM (1 << 2) /* Bit 2: Generate ADC trigger on - * RTC match (e) */ -#define TIMER_FLAG_ADCMATCH (1 << 3) /* Bit 3: Generate ADC trigger on - * match (abcd) */ -#define TIMER_FLAG_DMATIMEOUT (1 << 4) /* Bit 4: Generate uDMA trigger on - * timeout (abcd) */ -#define TIMER_FLAG_DMARTCM (1 << 5) /* Bit 5: Generate uDMA trigger on - * RTC match (e) */ -#define TIMER_FLAG_DMAMATCH (1 << 6) /* Bit 6: Generate uDMA trigger on - * match (abcd) */ +#define TIMER_FLAG_COUNTUP (1 << 0) /* Bit 0: Count up (abcd) */ +#define TIMER_FLAG_ADCTIMEOUT (1 << 1) /* Bit 1: Generate ADC trigger on + * timeout (abcd) */ +#define TIMER_FLAG_ADCRTCM (1 << 2) /* Bit 2: Generate ADC trigger on + * RTC match (e) */ +#define TIMER_FLAG_ADCMATCH (1 << 3) /* Bit 3: Generate ADC trigger on + * match (abcd) */ +#define TIMER_FLAG_DMATIMEOUT (1 << 4) /* Bit 4: Generate uDMA trigger on + * timeout (abcd) */ +#define TIMER_FLAG_DMARTCM (1 << 5) /* Bit 5: Generate uDMA trigger on + * RTC match (e) */ +#define TIMER_FLAG_DMAMATCH (1 << 6) /* Bit 6: Generate uDMA trigger on + * match (abcd) */ +#define TIMER_FLAG_PWMINVERT (1 << 7) /* Bit 7: Invert PWM signal (f) */ +#define TIMER_FLAG_PWMINTPOS (1 << 8) /* Bit 8: Interrupt on PWM positive + * edge (f) */ +#define TIMER_FLAG_PWMINTNEG (1 << 9) /* Bit 9: Interrupt on PWM negative + * edge (f) */ +#define TIMER_FLAG_STALL (1 << 10) /* Bit 10: Stall timer when CPU paused + * in debug breakpoint (abcdef) */ #define TIMER_ISCOUNTUP(c) ((((c)->flags) & TIMER_FLAG_COUNTUP) != 0) #define TIMER_ISADCTIMEOUT(c) ((((c)->flags) & TIMER_FLAG_ADCTIMEOUT) != 0) @@ -126,6 +134,12 @@ #define TIMER_ISDMATIMEOUT(c) ((((c)->flags) & TIMER_FLAG_DMATIMEOUT) != 0) #define TIMER_ISDMARTCM(c) ((((c)->flags) & TIMER_FLAG_DMARTCM) != 0) #define TIMER_ISDMAMATCH(c) ((((c)->flags) & TIMER_FLAG_DMAMATCH) != 0) +#define TIMER_ISPWMINVERT(c) ((((c)->flags) & TIMER_FLAG_PWMINVERT) != 0) +#define TIMER_ISPWMINTPOS(c) ((((c)->flags) & TIMER_FLAG_PWMINTPOS) != 0) +#define TIMER_ISPWMINTNEG(c) ((((c)->flags) & TIMER_FLAG_PWMINTNEG) != 0) +#define TIMER_ISSTALL ((((c)->flags) & TIMER_FLAG_STALL) != 0) + +#define TIMER_ISPWMINTBOTH(c) (TIMER_ISPWMINTPOS(c) && TIMER_ISPWMINTNEG(c)) /**************************************************************************** * Public Types @@ -182,7 +196,7 @@ typedef void (*timer32_handler_t)(TIMER_HANDLE handle, void *arg, struct tiva_timer32config_s { - uint8_t flags; /* See TIMER_FLAG_* definitions */ + uint32_t flags; /* See TIMER_FLAG_* definitions */ timer32_handler_t handler; /* Non-NULL: Interrupts will be enabled * and forwarded to this function */ void *arg; /* Argument that accompanies the handler @@ -213,8 +227,8 @@ typedef void (*timer16_handler_t)(TIMER_HANDLE handle, void *arg, struct tiva_timer16config_s { - uint8_t mode; /* See enum tiva_timermode_e */ - uint8_t flags; /* See TIMER_FLAG_* definitions */ + uint8_t mode; /* See enum tiva_timer16mode_e */ + uint32_t flags; /* See TIMER_FLAG_* definitions */ timer16_handler_t handler; /* Non-NULL: Interrupts will be enabled * and forwarded to this function */ void *arg; /* Argument that accompanies the handler @@ -247,7 +261,7 @@ struct tiva_gptm32config_s #endif /* This structure is cast compatible with struct tiva_gptmconfig_s and - * describes usage of both bit-bit timers A/B on a GPTM module. + * describes usage of both 16-bit half-timers A/B on a GPTM module. */ #ifdef CONFIG_TIVA_TIMER_16BIT @@ -794,6 +808,56 @@ void tiva_timer16_relmatch(TIMER_HANDLE handle, uint32_t relmatch, int tmndx); # define tiva_timer16b_relmatch(h,r) tiva_timer16_relmatch(h,r,TIMER16B) #endif +/**************************************************************************** + * Name: tiva_timer16pwm_setperiodduty + * + * Description: + * Set the period and initial duty cycle for a 16-bit timer operating in + * PWM mode. Also, enable interrupts if a handler is provided. The timer + * is not started until tiva_timer16_start() is called. + * + * Input Parameters: + * handle - The handle value returned by tiva_gptm_configure() + * period - The PWM period, a 24-bit value. + * duty - The initial PWM duty cycle, a 24-bit value. + * tmndx - Either TIMER16A or TIMER16B to select the 16-bit timer + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_TIVA_TIMER16_PWM +void tiva_timer16pwm_setperiodduty(TIMER_HANDLE handle, uint32_t period, + uint32_t duty, int tmndx); + +# define tiva_timer16apwm_setperiodduty(h,p,d) tiva_timer16pwm_setperiodduty(h,p,d,TIMER16A) +# define tiva_timer16bpwm_setperiodduty(h,p,d) tiva_timer16pwm_setperiodduty(h,p,d,TIMER16B) +#endif + +/**************************************************************************** + * Name: tiva_timer16pwm_setduty + * + * Description: + * Update the duty cycle for a 16-bit timer operating in PWM mode. + * + * Input Parameters: + * handle - The handle value returned by tiva_gptm_configure() + * duty - The initial PWM duty cycle, a 24-bit value. + * tmndx - Either TIMER16A or TIMER16B to select the 16-bit timer + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_TIVA_TIMER16_PWM +void tiva_timer16pwm_setduty(TIMER_HANDLE handle, uint32_t duty, int tmndx); + +# define tiva_timer16apwm_setduty(h,d) tiva_timer16pwm_setduty(h,d,TIMER16A) +# define tiva_timer16bpwm_setduty(h,d) tiva_timer16pwm_setduty(h,d,TIMER16B) +#endif + /**************************************************************************** * Name: tiva_gptm0_synchronize *