Sunday, January 11, 2015

Arduino Due first project

With all the recent work I have done on Arduino 8 bit processors, I wanted to expand out a little more and have a play around with more capable devices that still maintain similar simplicity of hardware design and cost.  I settled on the Arduino Due for my next set of experiments and was able to obtain a board for less than the cost of eating lunch out due to some discounts I had in hand.  Amazon has them for around $30-$40 which appears to be pretty typical.




The Due is an interesting device with a lot more horsepower than the 8 bit Arduino versions.  Some features:

  • A 32-bit core, that allows operations on 4 bytes wide data within a single CPU clock.
  • CPU Clock at 84Mhz.
  • 96 KBytes of SRAM.
  • 512 KBytes of Flash memory for code.
  • a DMA controller, that can relieve the CPU from doing memory intensive tasks.
  • 54 digital I/O pins
  • 12 bit true Digital to Analogue output
I thought as a first venture into programming this beast, I would implement a simple sine wave generator to play with the 12 bit DAC.  SInce I don't want to dive (yet) into the details of how to implement timers, I thought I would just take advantage of the faster processor and implement any timing delays inline.

So, to begin, I need a table of sine information that is small, in size while still using 12 bit data.  I have posted plenty of code previously that illustrates how I generate this data so I will not repeat it here.  To summarize, I write a simple C, C++ or C# application that generates the data and writes it as a data structure that I can just paste into my code.  I then graph the data using Excel to visualize the data.  I chose to use 120 phase points with a 12 bit range 0-4095.

static int sineTable[] = 
  {
  0x7ff, 0x86a, 0x8d5, 0x93f, 0x9a9, 0xa11, 0xa78, 0xadd, 0xb40, 0xba1,
  0xbff, 0xc5a, 0xcb2, 0xd08, 0xd59, 0xda7, 0xdf1, 0xe36, 0xe77, 0xeb4,
  0xeec, 0xf1f, 0xf4d, 0xf77, 0xf9a, 0xfb9, 0xfd2, 0xfe5, 0xff3, 0xffc,
  0xfff, 0xffc, 0xff3, 0xfe5, 0xfd2, 0xfb9, 0xf9a, 0xf77, 0xf4d, 0xf1f,
  0xeec, 0xeb4, 0xe77, 0xe36, 0xdf1, 0xda7, 0xd59, 0xd08, 0xcb2, 0xc5a,
  0xbff, 0xba1, 0xb40, 0xadd, 0xa78, 0xa11, 0x9a9, 0x93f, 0x8d5, 0x86a,
  0x7ff, 0x794, 0x729, 0x6bf, 0x655, 0x5ed, 0x586, 0x521, 0x4be, 0x45d,
  0x3ff, 0x3a4, 0x34c, 0x2f6, 0x2a5, 0x257, 0x20d, 0x1c8, 0x187, 0x14a,
  0x112, 0x0df, 0x0b1, 0x087, 0x064, 0x045, 0x02c, 0x019, 0x00b, 0x002,
  0x000, 0x002, 0x00b, 0x019, 0x02c, 0x045, 0x064, 0x087, 0x0b1, 0x0df,
  0x112, 0x14a, 0x187, 0x1c8, 0x20d, 0x257, 0x2a5, 0x2f6, 0x34c, 0x3a4,
  0x3ff, 0x45d, 0x4be, 0x521, 0x586, 0x5ed, 0x655, 0x6bf, 0x729, 0x794
  };

Here is the sine data as graphed in Excel:



The following variables define the size of the sine table, the phase index variable and a calculated microsecond delay between phase points.  I will probably regret choosing 120 phase points as the microsecond delay is really 8.33333 microseconds which will truncate to 8 microseconds.

const int cSine       = sizeof(sineTable) / sizeof(int);
const int OnekHzDelay = 8;
int iPhase = 0;

The analog hardware by default will use 8 bits.  I am going to override this for analog read and write to use 12 bit resolution.

void setup()
{
  analogWriteResolution(12);
  analogReadResolution(12);
}

Now in the main loop, I just sequence through the sine table writing each phase point to the DAC and then delaying the requisite number of microseconds before continuing.  This number is going to be too big, but I don't yet know the timing of the main loop.

void loop()
{
  analogWrite(DAC0, sineTable[iPhase++]);
  iPhase %= cSine;
  delayMicroseconds(OnekHzDelay);
}

Now, looking at the DAC0 output with a scope, we see the following output which is a nice clean analogue output without the need to integrate as is needed with PWM output.



CAUTION: Please do not make the mistake of hooking a low impedance speaker or other load directly to the DAC output.  A low impedance load on either of the DAC outputs will result in blowing the DAC output transistor.  You should use a buffer amplifier stage to protect your shiny new Due device.  Loads of 10K impedance or higher should be safe to directly connect to the DAC outputs.

As can be seen on the output trace, the frequency of the output waveform is somewhat less than the expected as the period ended up being 1.68 ms rather than 1 ms as expected.  So to check this out, I thought I would take a few timings.

The Due is pretty quick.  Just testing a digitalWrite to set a pin high and then low in a loop results in the following information:

  • digitalWrite takes about 1.26 us to execute.
  • An empty main loop 4.4 us to execute

So, just looking at these timings, I should be able to time the main loop and see how long it is taking just using a simple pin toggle and looking at it on the scope.

The main loop (ignoring the two digital write calls) is taking 16.4 us to execute.  Without the delayMicroseconds call the main loop takes 8.44 us.  By experimentation, I found that a delay of 3 us produced a 1kHz tone (926Hz specifically).

Ok, so fun initial experiment.  Next I figure out how timers work so I can more accurately generating timing events.

4 comments:

  1. This comment has been removed by a blog administrator.

    ReplyDelete
  2. thank you , Jeff Whitlatch , it's so useful for me ..

    ReplyDelete
  3. thank you the information was very useful.
    i had one question how to interface another spi to due board
    to get the high resolution, as i am using another spi port for some display.
    i would be happy if i get any code for it.
    thank you

    ReplyDelete
    Replies
    1. This question appears to be a completely different topic from this posting. There is insufficient information about what you want to accomplish for me to answer effectively. If you would like to more clearly ask a question, I will do my best to answer. Please contact me by email at ko7m at arrl dot com and I will do my best.

      Delete