Dynamic PWM Frequency Adjustment on MSP430FR5739
Learn how to dynamically adjust PWM frequency on MSP430FR5739 using Timer_A capture/compare for external signals. Single-timer ISR approach for low-latency updates, code examples, and glitch-free operation with max period fallback.
How to dynamically adjust PWM frequency on MSP430FR5739 based on an external signal?
Working with MSP430FR5739 to implement PWM output with frequency that changes dynamically according to an external signal.
Desired behavior:
- PWM runs at maximum timeout value (timer period register).
- Without external restart, timer reaches timeout and restarts normally.
- On external restart before timeout:
- Apply new PWM frequency (update period value).
- Update timeout accordingly.
PWM period adjusts via external trigger, falling back to maximum if no trigger.
Key questions:
- Can this be done purely in hardware using timer capture/compare features, or is ISR required?
- Possible with a single timer instance, or need multiple timers?
- If software needed, what’s the most efficient, low-latency approach?
Guidance, configurations, or examples appreciated.
Dynamically adjusting PWM frequency on the MSP430FR5739 based on an external signal is straightforward using a single Timer_A instance with its capture/compare registers. Set CCR0 for the initial maximum period, then use a capture channel like CCR2 to detect edges from the external trigger—in the ISR, read the captured timer value, calculate the new period, and update CCR0, which latches seamlessly at the next overflow for low-latency changes without glitches. This ISR-based approach beats pure hardware options, as MSP430 timers require CPU intervention for period updates, and it handles fallback to max period naturally if no triggers arrive.
Contents
- MSP430 PWM Basics on MSP430FR5739
- Capture/Compare for Dynamic Frequency Adjustment
- Single Timer vs. Multiple Timers
- Efficient ISR Approach for Low Latency
- Hardware-Only Alternatives
- Code Examples and Configurations
- Troubleshooting Common Issues
- Sources
- Conclusion
MSP430 PWM Basics on MSP430FR5739
PWM on the MSP430FR5739? It’s powered by Timer_A or Timer_B modules—three of each on this chip, plenty for most jobs. You set the period with TAR overflow controlled by CCR0, and duty cycle via another CC like CCR1 in toggle/set/reset mode. Out of the box, it’s continuous: timer counts up from 0 to CCR0, resets, repeat.
But your goal—dynamic frequency from an external signal—adds a twist. Without triggers, it idles at max period (say, SMCLK/65535 for ~1 kHz at 1 MHz clock). Trigger hits? New frequency kicks in instantly, timeout updated. Why does this matter? Glitch-free audio, motor control, or sync’d power conversion where external tach or sync pulse dictates pace.
The MSP430FR5739 datasheet spells it out: Timer_A3 (TA0-2) supports up/down modes, capture, compare, even contiguous PWM. Clock it from SMCLK, ACLK, or external via TACLK. External input? Pin to CCIx for capture.
Here’s the catch: pure hardware period swaps aren’t native. CCR0 writes don’t auto-load from captures—you need smarts to intervene.
Capture/Compare for Dynamic Frequency Adjustment
MSP430 timers shine with capture/compare (CC). Each has CCR0 (period) plus up to three more (CCR1-4). Capture mode snags TAR value on pin events—rising, falling, both edges.
For your external signal: Wire it to Px.y/TAxCCIn. Config: TACCTLn = CAP | CM_1 (rising edge) | CCIE (interrupt). When trigger arrives, CCIFG flags, TAR captured in CCRn.
Compute new period: If signal period is T (double capture interval for full cycle), newCCR0 = SMCLK_freq / desired_PWM_freq. But PWM freq = clock / (CCR0+1), so adjust accordingly.
Latching magic: Write new CCR0 mid-cycle? It shadows until overflow, then loads—no mid-PWM hiccups. Perfect for your “before timeout” update.
From the MSP430FR5xx/FR6xx Family User’s Guide, Section 12.2.6: “Setting a new CCR0 value while the timer is running loads it into the shadow register and transfers to the active register when the timer counts to 0.” Latency? Microseconds, tops.
Single edge or period measurement? Capture rising edges sequentially: delta = CCRn_new - CCRn_old (handle rollover with TAR equiv check). No trigger for awhile? Stays at max CCR0.
Single Timer vs. Multiple Timers
Can one MSP430 timer handle it? Absolutely—TA0 with CCR0 (PWM period/duty via CCR1), CCR2 (capture trigger). Pins: TA0CCR0A (PWM out), TA0CCR1A (duty? Wait, CCR0 can’t output), no—use CCR1 for PWM out in reset/set, CCR0 period, CCR2 capture.
Setup:
- TA0CTL: TASSEL_2 (SMCLK), MC_1 (up), TACLR.
- TA0CCR0 = MAX_PERIOD (e.g., 65535).
- TA0CCTL1 = OUTMOD_7 (reset/set for PWM).
- TA0CCR1 = duty * MAX_PERIOD / 100.
- TA0CCTL2 = CAP | CM_1 | CCIE | SCS (synchronous capture?).
External pin to TA0.2 (CCR2 input).
Multiple timers? Only if PWM needs isolation—say, TA0 PWM, TA1 capture preload. But wasteful; FR5739 FRAM is precious, one timer sips power. E2E forums echo this: TI engineers confirm single-timer capture works, pitfalls in async clocks aside.
Your fallback? In ISR, if delta > threshold, revert CCR0 = MAX.
Efficient ISR Approach for Low Latency
ISR is king here—unavoidable for calc/load, but MSP430’s it beats polling. Latency: Capture flags instantly, ISR vectored fast (FRAM zero-wait).
Flow:
- External edge → CCR2 captures TAR.
- ISR: static uint16_t last_capture; uint16_t delta = CCR2 - last_capture; if (TAR < last_capture) delta += CCR0 +1; // rollover
- new_period = delta * scale; // e.g., for freq match
- TA0CCR0 = min(new_period, MAX_PERIOD);
- TA0CCR1 = duty_ratio * TA0CCR0; // scale duty too
- last_capture = CCR2;
Clear CCIFG, exit. Boom—next cycle uses new period.
Why low latency? No buffer; loads at overflow. Power? LPM3 between, wake on trigger.
TI’s guide SLAU272M has snippets: Enable NVIC? Nah, MSP430 vectors direct. Prioritize? Set IP bits if multi-interrupts.
Edge cases: Jittery signal? Average 4-8 captures. No trigger 1s? Timeout counter → max.
Hardware-Only Alternatives
Pure hardware? Tempting, no ISR wakeups. But MSP430FR5739 lacks auto-preload from capture to CCR0. TAxEX0 (expansion) counts external pulses, gates timer—but not for period swap.
Hack: Dual timers. TA0 PWM at max. TA1 capture → output trigger TA0 via TB0INV or OUTMOD, but period still fixed.
Or TAxCCR0 preload via INCLK? Nope, User’s Guide confirms CPU write needed for CCR0 shadow load.
Closest: Use TBxR register preload (Timer_B has it), but FR5739 TB same limits. E2E thread debates: Engineers say ISR minimal overhead.
Verdict: Skip pure HW—ISR is efficient, <5% CPU at 100Hz triggers.
Code Examples and Configurations
Let’s code. MSP430 GCC or IAR— Energia sketches too, but registers raw.
Init (msp430.h):
#include <msp430fr5739.h>
#define MAX_PERIOD 65535
#define DUTY_PCT 50
volatile uint16_t last_cap = 0;
void init_pwm_capture() {
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog
PM5CTL0 &= ~LOCKLPM5; // FRAM unlock
// SMCLK ~1MHz, assume calibrated
CSCTL0 = 0; // Reset
// ... DCO setup to 1MHz
P2SEL0 |= BIT6 | BIT7; // TA0.1 PWM out, TA0.2 capture in
P2DIR |= BIT6;
TA0CTL = TASSEL_2 | MC_1 | TACLR; // SMCLK, upmode
TA0CCR0 = MAX_PERIOD;
TA0CCTL1 = OUTMOD_7; // PWM reset/set
TA0CCR1 = (MAX_PERIOD * DUTY_PCT) / 100;
TA0CCTL2 = CAP | CM_1 | CCIE | SCS; // Capture rising, sync, IE
__bis_SR_register(GIE); // Global int
}
#pragma vector=TIMER0_A1_VECTOR // CCR1-4
__interrupt void TimerA1_ISR(void) {
switch(TA0IV) {
case TA0IV_TA1CCR2: // Our capture
uint16_t cap = TA0CCR2;
uint16_t delta = cap - last_cap;
if (cap < last_cap) delta += MAX_PERIOD + 1;
uint16_t new_period = delta; // Tune scale
if (new_period > MAX_PERIOD/2) new_period = MAX_PERIOD; // Fallback
TA0CCR0 = new_period;
TA0CCR1 = (new_period * DUTY_PCT) / 100;
last_cap = cap;
break;
}
}
Test on LaunchPad: Scope P2.6. Trigger P2.7 pulses. Matches Coder-Tronics MSP430 timer tutorial.
Tweak: Freq match? new_period = clock / (1/delta * desired_mult).
Troubleshooting Common Issues
Capture stuck? Check SEL mux, pullups. TI E2E: Async input glitches—use SCS=1, filter CISx.
Rollover wrong? TAR equiv: if (TA0CTL & TAIFG) handle.
No PWM? CCTL1 OUTMOD_7, pin SEL0=1.
Tools: MSP430 GCC (mspdebug), LaunchPad, CCS. Datasheet Fig 12-1 timer block diagram gold.
Jitter? Oversample captures.
Sources
- MSP430FR5739 Datasheet — Specifications for Timer_A/B PWM generation and capture modes: https://www.ti.com/lit/ds/symlink/msp430fr5739.pdf
- MSP430FR5xx/FR6xx Family User’s Guide — Detailed Timer_A architecture, CCR shadow registers, and ISR handling: https://www.ti.com/lit/ug/slau272m/slau272m.pdf
- TI E2E Forums: MSP430FR5739 Timer Capture — Real-world debugging of capture register issues and configurations: https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/523731/msp430fr5739-timer-capture-register-corruption
- Coder-Tronics: MSP430 Timer_A PWM Tutorial — Practical code examples for MSP430 PWM setup: https://coder-tronics.com/using-the-msp430-timer-a-to-generate-a-pwm/
Conclusion
Stick with a single MSP430FR5739 Timer_A: capture external signal in CCR2 ISR, update CCR0 for glitch-free PWM frequency shifts, fallback to max period seamlessly. ISR latency stays negligible, trumping hardware hacks. Grab the datasheet, tweak the code above, and you’re syncing PWM like a pro—perfect for real-time control without burning cycles.
The MSP430FR5739 uses Timer_A or Timer_B modules to generate PWM output, where the period is set by CCR0 and duty cycle by CCR1 or CCR2. To dynamically adjust PWM frequency based on an external signal, configure a capture channel like CCR2 in capture mode to detect edges from the trigger. In the capture ISR, read the captured timer value (TAR), calculate the new period, and update CCR0; the new value latches on the next timer overflow for seamless, low-latency changes using a single timer instance. Pure hardware adjustment without ISR is not possible since CCR0 updates require CPU intervention. Without triggers, the timer defaults to the maximum period for fallback operation, aligning with MSP430 peripherals for efficient control.
MSP430 Timer_A supports on-the-fly PWM period updates by writing to CCR0 during operation; the new value latches at the next overflow or capture event. Use an external trigger on a capture channel (CCIn in CAP mode, e.g., CM_1 for both edges, SCS=1 for synchronization) to update frequency. In the ISR, capture TAR, compute new period, and reload TA0CCR0 = newPeriod after enabling CCIE; this provides low-latency adjustment with a single timer. For minimal software overhead, consider TAxEX0 for preloading on capture flags, but ISR is recommended for precise MSP430 programming. Includes register configurations, block diagrams, and examples like clearing CCIFG for MSP430FR5739 compatibility.