Victor, indeed, it seems a good idea to use the DMA burst transfer feature of the timers.
I was reading about it but couldn't imagine before what is that good for. Now it makes sense
If I set the prescaler to only a factor of that what is set now (basically divide it by an integer), I can multiply the PWM frequency by keeping the resolution. Clever.
I try to use as much as possible the HardwareTimer functions because it seems that they offer a wide scale of setup possibilities.
Now that Roger has included the DMA enable/disable functions, it became even more powerful.
My timer setup routine looks like this:
Code: Select all
pinMode(SPEAKER_PIN, PWM); // activate output
// try to set the reload register to a value as close as possible to 256
// to get full range audio 0 - 3.3V for 0 - 255 PWM values (8 bit resolution)
uint32_t prescaler = F_CPU/SAMPLING_RATE_HZ/256;
uint32_t overflow = F_CPU/SAMPLING_RATE_HZ/prescaler;
timer.enableDMA(0); // for update event use channel 0
As you can see, I can set up the timer parameters with only 3 function calls, which is very convenient.
The function naming is not always self-explanatory, but if you know what they do then it is ok. For example, with setOverflow() the reload value (ARR reg) will be set.
I can only use integer values for timer registers, for prescaler = 17 I get a reload value of 264 and 16042 Hz effective playback frequency (0.26% deviation).
If I set the prescaler to 18, I need to limit the sample values to max. 250 by software.
So I will try to set the DMA burst length to 17 and see what happens. Ok, for that I need to use the libmaple timer functions, but I will maybe issue a PR for Roger to add a new corresponding function to the HardwareTimer class.