To create output signals with the expected accuracy over the whole engine
speed range is not easily possible even with 32bit timers.
After investigating several approaches, I came up with the following solution:
- One of the four timer channels is used to create an angular clock (e.g. 256 ticks per tooth) depending on engine speed
- the output of this angular clock is (physically) connected as input to two other timer channels which are configured to counter mode with external clock input
- On each of these timers, the first two match events are used to create edges on two output channels each (2x2 = 4)
If a new engine speed N is set, the tooth period is calculated as follows:
... where ftimer is the timer frequency of 100MHz, N is engine speed (in rotations per minute) and m is the number of teeth per rotation (typically 60).
For m = 60, this is reduced
Now within this tooth period a given number X
(256) of ticks must be created
The problem is that rounding errors will occur which would lead to a wrong
E.g. with ftimer= 100MHz, N = 515, m = 60 (rounded up):
If this is truncated to 758, the resulting tooth period after 256 ticks
which is quite different from the correct value 194175.
To avoid this inaccuracy, the following approach is used:
First the remainder r of the division (modulo, the "%" operator in C ) is calculated
Now instead of simply repeating the tick period X
(256) times, it is split as follows:
Or with the given values:
These X (256) periods are created
with two DMA transfer descriptors which are linked (after transfer 1 is
finished, it's linked to transfer descriptor 2, if transfer 2 is finished,
it's linked to transfer descriptor 1).
So when a new engine speed is requested, the tick period is calculated and then the two tick periods (ttick and ttick+1) and the two repeat counters (error and X-error) have to be entered into the two linked DMA transfer descriptors.
To avoid consistency issues during the update, a double buffering strategy is used where the new transfer descriptors are prepared offline and then the "next" entry of the currently active transfer descriptor is patched to point to the offline descriptor.
Back to main page