To generate a square wave, you only need to update the output at a rate of two points per cycle. (Technically, when the Arduino's PWM output is configured for 50% duty cycle, that's a square wave at some frequency.)
But to generate a clean sine wave (without a lot of distortion), you need to update a lot more frequenclly than two points per cycle. Personally I wouldn't want to go much below 20 points per cycle.
Imagine the sine wave is generated by a wheel that spins at some rate. Viewed from the edge, a point on the edge of the wheel traces out a sine wave. Viewed from the axle, you see the point going around in a circle.
Now instead of spinning the wheel continuously, suppose the wheel moves in steps of 30 degrees, 12 steps for a complete turn. Instead of a continuous sine wave, you get discrete steps of 0, 0.5, 0.866, 1, 0.866, 0.5, 0, -0.5, -0.866, -1, -0.866, -0.5, 0, 0.5, ... Although this sequence approximates an ideal sine wave, it's pretty coarse because the steps are so large.
Now try 15 degrees per step (24 steps per cycle). Now you get 0, 0.259, 0.5, 0.707, 0.866, 0.965, 1, ... Much smoother, although the steps are still fairly noticeable.
So there will be less phase error, the more steps there are per cycle of the signal. That's not the only source of distortion however. There is also round-off error due to the limited resolution of the Digital-to-Analog Converter (DAC). For example, the value 0.866 I mentioned above should actually be an irrational value, half the square root of 3. Since it's an irrational number, there's no way for a real DAC to get this value exactly right. DAC output step values are ideally based on powers of two (1/2, 1/4, 3/4, 1/8, 3/8, 5/8, 7/8, etc.). And furthermore a real DAC can have offset error, gain error, non-linearity, as well as uncertainty about precisely when the new programmed value is reached.
There's also frequency error when the system's highest-frequency master clock is divided by an integer. If the Arduino UNO's master clock frequency is 16MHz, and the SPI setup function
setClockDivider() is used to divide the master clock by 2, that's 8MHz. Divide by 3 and you get 5.333MHz. Divide by 4, that's 4MHz. Divide by 5, that's 3.2MHz. There's no way to get a clock frequency that's between these discrete steps. For small divisors, there's a big jump between steps. So if you needed to be able to smoothly adjust the frequency, you'd need a much higher master clock frequency. And, if you needed to configure the 16MHz Arduino UNO to an SPI clock frequency of exactly 5.7MHz, that's just not possible -- setClockDivider(2) is too fast, setClockDivider(3) is too slow, and setClockDivider(2.807017543859649) isn't supported by the hardware.
If your system could write to a DAC at an update rate of 12MHz, then 12 points per cycle gives a 1MHz output, and 24 points per cycle gives a 500kHz output. Or taking it the other way round, if you need to generate a 5.7MHz output waveform, then the DAC update rate needs to be somewhere around 100MHz to get a clean, low-distortion waveform. This is probably beyond the limit of what you can directly synthesize in software using something like an Arduino or a Raspberry Pi. A 16MHz Arduino UNO could maybe synthesize a few 100kHz using software synthesis, but at 1MHz there's going to be significant distortion.
Direct Digital Synthesis is very sensitive to timing, so the actual DAC update would need to be implemented in an interrupt service routine, run by a periodic timer. ( See https://electronics.stackexchange.com/questions/26363/how-do-i-create-a-timer-interrupt-with-arduino ) If you just used a while loop with a delay statement, then whenever the code needs to do something else, the waveform would just freeze up. This is more of a problem if the Arduino is trying to manage several other tasks at the same time as it is synthesizing the waveform.
Direct Digital Synthesis (DDS) is possible. Same principles. There needs to be a
phase accumulator, which is just a counter that keeps track of the phase angle of the "wheel" that's generating the sine wave. (The phase accumulator needs to be modulus 360 degrees or 2 pi radians, but there's no requirement to count in 1 degree steps. Better to divide the circle into 2^N slices so that 360 degress maps to the natural counter overflow value.) And there also needs to be a lookup table with the sine value for each of those steps. This lookup table only needs to cover 90 degrees of the sinewave, because the waveform is symmetrical -- the other three quadrants can be found by 2's complementing the values and indexing from the other end of the table. Or, the sine can be approximated by a polynomial calculation. More steps x more DAC resolution requires a deeper, wider lookup table. There are integrated circuits available that perform the timing-critical actions, all the software needs to do is send some initial configuration to set it up. Changing the frequency only requires configuring a new frequency divisor value into the DDS chip, so the Arduino can manage other things without causing distortion.
If the original problem only needs one fixed frequency under 200MHz, and doesn't need any adjustment to that frequency, then the hardware gets a whole lot simpler. The crystal oscillator circuits that we use to generate the timing for digital circuits, are in fact analog to begin with. You can contact a crystal vendor and request a custom AT cut crystal; google
custom quartz crystal frequency for quartz crystal vendors. Construction requires a careful printed circuit board layout; the white solderless breadboard commonly used in Arduino projects just doesn't work well above 10MHz. Granted, this fixed-frequency solution doesn't involve Arduino in any way, but if it solves the problem, that's what's important.