Skip to content

Pwm: TC/TCC period off-by-one #948

@codepainters

Description

@codepainters

While experimenting with ATSAMD21G18A board I've noticed that TC and TCC period is not what I'd expect, even though the frequency I wanted to obtain is lower than expected, even though the theoretical period is an integer number of cycles.

I believe the problem is here:

pub fn set_period(&mut self, period: Hertz)
{
let params = TimerParams::new(period, self.clock_freq);
let count = self.tc.count16();
count.ctrla().modify(|_, w| w.enable().clear_bit());
while count.status().read().syncbusy().bit_is_set() {}
count.ctrla().modify(|_, w| {
match params.divider {
1 => w.prescaler().div1(),
2 => w.prescaler().div2(),
4 => w.prescaler().div4(),
8 => w.prescaler().div8(),
16 => w.prescaler().div16(),
64 => w.prescaler().div64(),
256 => w.prescaler().div256(),
1024 => w.prescaler().div1024(),
_ => unreachable!(),
}
});
count.ctrla().modify(|_, w| w.enable().set_bit());
while count.status().read().syncbusy().bit_is_set() {}
count.cc(0).write(|w| unsafe { w.cc().bits(params.cycles as u16) });
}

  • TimerParams::new() called in line 62 correctly calculates the number of ticks by dividing the frequencies
  • code in line 81 applies the calculated period:
       count.cc(0).write(|w| unsafe { w.cc().bits(params.cycles as u16) }); 

However, looking at the "SAM D21 Family Data Sheet" section 30.6.1, definition of TOP:

The counter reaches TOP when it becomes equal to the highest value in
the count sequence. The TOP value can be the same as Period (PER)
or the Compare Channel 0 (CC0) register value depending on the
waveform generator mode in Waveform Output Operations.

My understanding is that the timer counts from 0 to CC0 value (inclusive), so in fact it goes through n + 1 distinct values. To generate 1/n frequency, the value loaded to CC0 should be equal to n - 1, and not n.

Changing the line 81 (and similar code in line 49) to

count.cc(0).write(|w| unsafe { w.cc().bits(params.cycles as u16 - 1) });

solves the problem for me (verified with a frequency counter).

The code for TCC updating PER register suffers from the same issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions