Rather than using microprocessor-specific low-level programming, I was able to get a suitable signal using the core
It can be used to generate a 50% duty cycle square wave of a custom frequency on any individual GPIO pin (I'm using 11 in this case). Given the name, it's obviously designed for producing simple audio output, and 2 MHz is way above the range of human hearing.
The documentation doesn't list any upper limit on the frequency though, and the code it's based on doesn't appear to introduce any limitations. With that said, it clearly can't run faster than the internal timer it's based on (which I think will typically be 8 or 16 MHz).
It seems reasonable to assume that it will be in-sync with the microprocessor's internal clock, although I haven't been able to confirm that empirically as I don't have suitable equipment at home. Similarly, I haven't been able to confirm that it's actually producing a 2 MHz signal, but the LCD display is working properly so it's likely to be in the right vicinity. I had previously tried running it from regular PWM, but that didn't work, so frequency is obviously important here.
The signal can be stopped by calling:
There are a couple of caveats to be aware of when using
tone(). First of all, it can only work on a single pin at a time, so you can't generate multiple signals with it. And secondly, it will prevent some PWM output from working properly (on pins 3 and 11, according to the documentation). This is because it has to reconfigure one of the internal timers which is normally used for PWM.