Summary of On Arduino due PWM frequency
The article discusses PWM frequency capabilities on the Arduino Due, which features an ATSAM3x8E 32-bit ARM Cortex-M3 running at 84 MHz. Unlike the 8-bit ATmega328p, Due can achieve much higher PWM frequencies. Using bit-banging (pin toggling) yields modest frequencies (~200 kHz), but direct port manipulation boosts this to approximately 16.8 MHz. The article suggests using the hardware PWM controller on the Due for even better performance. It also references the Arduino IDE’s use of Atmel’s CMSIS libraries for system clock management.
Parts used in the Arduino Due PWM Frequency project:
- Arduino Due board (ATSAM3x8E 32-bit ARM Cortex-M3)
- Arduino IDE (version 1.5.7 or compatible)
On Arduino Due PWM Frequency
I just got myself a couple of Arduino Due boards. While they were released almost two years ago, I have not really got a chance to look at these until quite recently. Arduino Due is based on Atmel’s ATSAM3x8E 32-bit ARM Cortext-M3 processor. The processor core runs at 84 MHz, which is significantly faster than its 8-bit AVR counterpart ATmega328p which runs at 16 MHz. For an ATmega328p, the highest achievable PWM frequency is 8Mhz (square wave), so we should be able to generate much higher frequency signals on an Arduino Due. But how high can we go? Let’s find out.
If you use the bit-banging method (e.g. pin toggling), the highest achievable output frequency is actually quite abysmal. For example, the following code on Due generates a 200.7 kHz square wave on pin 8 (compiled with Arduino 1.5.7):
The Arduino code base is not very efficient and this code is actually not much faster than the same code on an ATmega328p (126.2 kHz for comparison, compiled with Arduino 1.0.5). By the way, the reason a while loop is used inside the loop() function is that the loop function has some extra instructions for checking the serial port. So if we did not use the while loop, extra instructions would be executed after outputting a LOW, causing the duty cycle to change and lowering the overall waveform frequency. This overhead is not very noticeable on ATmega328p (116.9 kHz without the while loop versus 126.2 kHz with the loop). But on Arduino Due, this difference is much more drastic. If the while loop is removed, the output frequency will drop to 145.4 kHz which is a 30% degradation from 200.7 kHz!
Of course, we can improve the code efficiency above quite a bit by using direct port manipulation. If we replace the digitalWrite with the following code, we will get an output square wave on pin 8 of roughly 16.8 Mhz. This is a huge improvement over the meager 200.7 kHz with digitalWrite.
We can do even better if we use the dedicated hardware (e.g. via PWM controller) to generate our waveform rather than big-banging with software. But before doing that, let’s take a look at how the the 84 Mhz clock frequency is obtained on the Due.
Under the hood, Arduino IDE uses Atmel’s CMSIS compliant libraries. They source code and binaries are located under /arduino-1.5.7/hardware/arduino/sam/system/ with the Arduino IDE distribution.
In /arduino-1.5.7/hardware/arduino/sam/system/CMSIS/Device/ATMEL/sam3xa/source/system_sam3xa.c you will find the following definitions:
For more detail: On Arduino due PWM frequency