Search code examples
arduinopwmarduino-due

Arduino Due PWM


I want to be able to use the Arduino Due PWM at higher resolution and frequency than what is available by default. I use IDE 1.6.8, that was the most recent a few weeks ago when I installed it (I think 1.6.9 may be on its way now). After searching on the internet and experimenting with the board and an oscilloscope, I got to the following conclusions:

  • To get higher PWM frequencies, one has to modify the corresponding lines in variant.h. PWM seems to influence pins 6 included to 9 included, TC the other PWM enabled pins; I guess it is because of which pin is on which timer? It seems micros(), millis() etc are not affected by the modification:

#define PWM_FREQUENCY 20000 // changed from 1000 #define TC_FREQUENCY 20000 // changed from 1000

  • As said in multiple places, the analogWriteResolution() Arduino function is broken, or at least it is not sufficient on its own to increase the Due PWM resolution. For the analogWriteResolution() to work as expected, one also needs to modify the following in variant.h:

#define PWM_MAX_DUTY_CYCLE 4095 // changed from 255 #define PWM_MIN_DUTY_CYCLE 0 #define PWM_RESOLUTION 12 // changed from 8

  • It seems that the physical labeling on the Arduino Due R3-E that is the standard when I bought my board is misleading: it is written on the board DIGITAL (PWM~) and such a ~ is present only on pins 3, 5, 6, 9, 10, 11 while I can get PWM on all pins 2 included to 13 included.

I post this content here as it took me a while to figure out everything and to check on the oscilloscope etc, and I could not find those answers on stackoverflow. I also have two questions:

  • Is it OK (as it looks like from the tests I did) to modify the PWM and TC frequencies? May it interact with other core functions / libraries?

  • Is there a reason for the default values of PWM max duty cycle and resolution, other than backward compatibility?


Solution

  • You can do this with the PWM frequency divisors: http://forum.arduino.cc/index.php?topic=16612#msg121031

    This is implemented in the PWMfrequency library: http://playground.arduino.cc/Code/PwmFrequency which basically looks like this:

    void setPwmFrequency(int pin, int divisor) {
      byte mode;
      if(pin == 5 || pin == 6 || pin == 9 || pin == 10) {
        switch(divisor) {
          case 1: mode = 0x01; break;
          case 8: mode = 0x02; break;
          case 64: mode = 0x03; break;
          case 256: mode = 0x04; break;
          case 1024: mode = 0x05; break;
          default: return;
        }
        if(pin == 5 || pin == 6) {
          TCCR0B = TCCR0B & 0b11111000 | mode;
        } else {
          TCCR1B = TCCR1B & 0b11111000 | mode;
        }
      } else if(pin == 3 || pin == 11) {
        switch(divisor) {
          case 1: mode = 0x01; break;
          case 8: mode = 0x02; break;
          case 32: mode = 0x03; break;
          case 64: mode = 0x04; break;
          case 128: mode = 0x05; break;
          case 256: mode = 0x06; break;
          case 1024: mode = 0x07; break;
          default: return;
        }
        TCCR2B = TCCR2B & 0b11111000 | mode;
      }
    }