I am trying to generate sine waveforms with Arduino Uno using timer interrupts.
Basically, I have a pre-calculated array of 100 integers that holds values of a whole sine wave period. Every dt seconds a timer interrupt occurs, and the ISR (interrupt service routine) outputs a single sine value. The process is repeated, so in the end I get a sine wave on my oscilloscope.
At some point I realized that it's impossible to set a timer interrupt for a value less than 20 µs, so I made a series of experiments to show what I get (I am sorry for the quality of pictures): Imgur album with oscillograms
So I tried setting different OCR1A values for timer1 (16-bit timer) to get different timer interrupt values. I also ran two different kinds of experiments:
- Sine wave. Analog signal is generated using DAC8512 (12-bit DAC), and the data is sent to it from Arduino over SPI with a setValue() inline function I wrote;
- [Square wave. I simply invert square wave polarity every dt µseconds.
As you can see from the pictures above, for a dt of 20 µs the sine wave period is wider than expected. I expect to see the period: T= 100 samples * 20 µs = 2000 µs = 2 ms, but I get a period of approx. 2.2 µs.
The square wave at dt = 20 µs looks like a trapezoid, no matter whether I use 1x or 10x probe.
However, if I increase dt to 25 µs, the pictures start to look fine - there's no frequency deviation anymore for sine wave, and square wave looks more like a square wave.
If I take a value even lower than 20 µs (i.e. 5 µs; not shown in the pictures), I get almost the same results as for 20 µs. Square wave seems to have a pulse width of approx. 18 µs, and sine wave period is also wider than expected
Even if I don't use a DAC for square wave and simply use digitalWrite, it still works no faster than 20 µs, so it's not a DAC limitation.
In the end I want to generate a 200 Hz sine wave, and I need no less than 720 points per period for that (0.5 degrees precision). And so I get: T = 1/f = 1/200 Hz = 5 ms; dt = T / samples = 5 ms / 720 = 6.94 µs
This means that I need to set dt equal to 5 or 6 if I want to get the precision right. Not to mention that I need to modulate this signal, as well as perform some complex calculations (solving system of linear differential calculations in loop() ), and 5 µs limit leaves me almost no time for such calculations, since (for Uno): time_per_instruction = 1/freq = 1 / 16 MHz = 62.5 ns; number_of_instructions = time/(time_per_instruction) = 5 µs / 62.5 ns = 80. And I have 10 equations in the system, each with multiplications, dozens of them.
So I have a few questions about this problem:
- Am I running into some sort of a timer1 limitation? What if I use a different timer (timer0, timer2)? Is there any way to see a 5 µs long pulse from Arduino Uno?
- How much time I lose when I use SPI for data transfer? Is there any way to optimize it?
- Will it help to improve performance if I replace my DAC with R2R ladder (at the cost of number of pins used, of course)?
- Is it a better idea to use Arduino Due instead, with its analog outputs? Is it possible to perform a 5 µs interrupt on Due?