You are on page 1of 6

Registration Number: MT2290

Parts Used: dsPIC33FJ12GP202 and MCP4921

My day job involves developing real-time algorithms for machine vision, but in my spare time I work
with a Physicist doing NOAA research that involves the use of low-power micro-controllers. When I
first read about the dsPIC, I was very curious to see what it could do.

I selected the dsPIC33 for my project and for quick turnaround I went with the 16-bit 28-pin demo
board.

I decided that an audio project would be a fun diversion. I'm not a great keyboardist so I though I
would try and make something simple, like a digital accordion. To start out, I purchase a small MIDI
controller, namely the Oxygen8 v2 from M-Audio. It's a small two-octave keyboard that doesn't make
any sound. I then set out to designed a single voice MIDI synthesizer that I could plug in to the
keyboard.

16-bit 28-
MIDI pin Audio
In Demo Out
Board
Project Block Diagram

The dsPIC33FJ12GP202 that I purchased to fit on the demo board doesn't have a DAC so I added the
MCP4921 12-bit SPI DAC. The other benefit of using an external DAC is that it would give me a
chance to really exercise the SPI of the dsPIC. Here is what I added to the demo board:

RB7->CS! RP10->SCK RP11->SDI


For MIDI-in I used a simple circuit I found on the web. It uses a 6N137 optoisolator, two diodes, and
two resistors. It looks like this:

Rx->RP6

All that was left was to wire up a MIDI cable, run the output of the DAC to my RadioShack 4-channel
mixer, and write the software.
Here is a picture of the completed project:
...and here is a closeup of the prototyping area:

To save on development time, I wanted to write everything is C. The software starts by setting up the
dsPIC to run at 39.614Mhz. To keep the output synchronized, I used a 32,768Hz timer to drive the
sample rate. This left me ample time in the timer ISR to do what I needed for the sound synthesis. To
be safe, I wanted to be able to have a DAC output rate of more that double the target sample rate. At 16
bits per SPI write, the clock rate I used for the SPI came out to about 1.24Mhz which gave me a max
DAC output rate of about 77.4kHz.

Using the formulas provided in the data sheet I came up with the value of 78 was required to obtain the
MIDI standard baud rate of 31.25k. I found, however, that the baud rate from my keyboard was a little
different so I adjusted the baud rate to correspondingly. The value I came up with was 81.

I had two issues come up during development. The first was that the ground pins on the right side of
the demo board, near the prototyping area, were floating (i.e. not connected to ground). The second
issue was that the UART pins are re-mappable, but the Rx pin did not work where I first mapped it to.
This was hard to track down as the Tx pin worked fine, but I could not receive any MIDI command
bytes. Going through a list of possible problems, I tried re-mapping the Rx pin to a different location
and all was well.
Two tables are used for sound creation. One is a 1024 int sine table and the other is the corresponding
frequency of each MIDI note. When a “note on” command is received, the frequency of the note is
stored in a global structure used by the timer ISR. Also stored there is the frequency for the note one
and two octaves up. The frequency is used as a step rate through the sine wave table.

I wrote a small console program to create the sine table, captured its output, and pasted it into my code.
It looked like this:

#include <stdio.h>
#include <math.h>

int main()
{
int i;

for (i=0; i<1024; i++)


{
float theAngle = (((float)i-512.0)/512.0)*3.141593;
float theSine = sin(theAngle);

if (i%16 == 0)
printf("\t%d, ", (int) (theSine * 8191));
else if (i%16 == 15)
printf("%d,\n", (int) (theSine * 8191));
else
printf("%d, ", (int) (theSine * 8191));
}

return 0;
}

The “if” statement simply serves to put 16 values per line separated by a tab. I ran it in cygwin, but it
should run just about anywhere.

The timer ISR mixes the primary tone with one half the tone one octave up and one quarter the tone
two octaves up. This gives the output a more complex waveform and a much richer sound, much like
that of a harpsichord or electric organ.

Initially I could hear a clicking sound at the end of a note or when there was a note transition. To
overcome this I waited for a zero crossing before turning off a note or transitioning to a new note.

To throughly test out the synthesizer, I downloaded a piece of MIDI flute music and imported it into an
evaluation copy of Orion Pro. I played it through the synthesizer and recorded the output, which is
included with this project.

Keeping the wave values as a signed int greatly simplified the task of assembling the wave at each
sample. While I could have spent some time and come up with an unsigned representation that could
have used a simple shift, I didn't need to. The efficiency and performance of the dsPIC and the C
compiler allowed me to use a more straight forward representation. This allowed me to focus my
efforts on the features of the synthesizer as opposed to idiosyncrasies of the micro-controller.
This isn't my first attempt at a Circuit Cellar contest. In the past I've attempted to build similar
complexity audio circuits with other micro-controllers only to find that the peripherals wouldn't work
in the combination I needed or that the audio sub-system carried a lot of internal clock noise or that the
on-board flash was multi-cycle or that I had to keep my ISR routine to just a few lines due to poor
compiler code efficiency.

Having gone through the full life-cycle with the dsPIC, I am very impressed with its capabilities. I have
a very short list of high-performance, feature packed micro-controllers that I use for my applications
and the dsPIC definitely makes the list.

You might also like