I thought the Due would be faster!

I'm not sure I believe that. I get about 123kHz on an Uno, and only 78kHz on a Mega ADK (which should be the same as a Mega.)

I get 113kHz on a Due, so I confirm the "bad" numbers there.
231kHz if I add semicolons to your direct port access version, and 2.6MHz if I put it inside it's own while loop. Almost 17MHz for a stripped-down loop:

void loop() {
  while (1) {
      PIOB->PIO_SODR = (1 << 25);
      PIOB->PIO_CODR = (1 << 25);
  }
}

2.6MHz is about the same speed as a similarly optimized AVR loop, though. (See Maximum pin toggle speed ), so in a way the Due is still a bit disappointing: 5x faster clock, 32bit CPU... About the same speed. :frowning:

Here are some of the reasons:

  1. ARM CPUs do not have specialized IO instructions like the AVR; all of the peripherals are manipulated as though they were memory. Since ARM only does load and store on memory, and pretty much only via addresses that are in registers, that means that the minimum to store a bit is about three instructions - load the address into one register, load the value into another register, and then do the store. On the birght side, if you're in a tight loop, you don't have to do some of those every time. The 17MHz loop loads the address, loads the bit value, and then it can just do single stores for each change. Also on the bright side, this means that ARMs generally do not have the asymmetry of "this is much faster if your port and bit are constants" that is present in the AVR.
  2. While the "instructions" on the Due ARM are mostly single-cycle, that isn't true of the memory buses. Flash memory is relatively slow - running at 84MHz means it takes 5 "wait states" to access flash memory (but this is complicated by some "flash acceleration" that fetches more than one instruction at a time.) The GPIO peripheral is also on a bus where accesses take more than one clock cycle.
  3. digitalWrite() on most non-AVR platforms suffers because it has to duplicate behavior that is a side-effect on AVRs. Like switching on the internal pullup if you write a HIGH while the pin is in input mode. It also turns off PWM (which also happens on AVRs, so some pins digitalWrite faster than others. Sigh.)
  4. It MIGHT be a feature that digitalWrite() is about the same speed on Due as on AVR. Weird things can happen when you try to drive pins too quickly, and ~100kHz is a pretty safe rate.
  5. No one seems to care much about speeding up digitalWrite (on any of the platforms, actually.) digitalWrite() is embarassingly slow on Due... · Issue #16 · arduino/ArduinoCore-sam · GitHub was submitted a long time ago, complaining that digitalWrite() on Due calls a libsam function that duplicates significant amounts of effort. Fixing this would about double the digitalWrite speed, and everyone seemed to think it was a reasonable idea, but the patch has still not been incorporated or released.