Category Archives: arduino

SPI control of AD9833

A few months ago I ordered a MSOP to DIP conversion board including an AD9833 from proto advantage.  The AD9833 (LOW POWER, 12.65 MW, 2.3 V TO +5.5 V, PROGRAMMABLE WAVEFORM GENERATOR) looks like an interesting IC, doesn’t cost too much and is perhaps suited for a musical purpose.

Wiring up and controlling the AD9833 took some time and some research but I finally combined the right pieces of the puzzle.

124

At first I wired up the power section as proposed in the datasheet:

Screen Shot 2013-04-15 at 12.35.32 PM

Lots of attention to decoupling and separation of DGND and AGND, which both are a good thing ™ but also clutter my experimental setting on the breadboard. So, time to reduce the number of components with the setup from NXR:

AD9833Connsmall

Much better.

Annem did a great job interfacing the AD9837 with the Arduino. Fortunately, the AD9833 has the same interface. I did however make some adjustments. I removed the delay in re-activating the AD9833. I added the Timer1 library to generate the masterclock for the AD9833. This clock runs in the background at ~1Mhz and is made available through pin 9.


/*
AD9837 Pro Generator sample code
This was written in Arduino 1.0.1,
for an Arduino Pro Mini, 5V, 16MHz
Pete Dokter, 9/2/12
Remixed by Anne Mahaffey, 10/8/12
ReRemixed by sinneb, 15th of april 2013

The connections to the AD9837 board are:

FSYNC -> 2
SCLK -> 13 (SCK)
SDATA -> 11 (MOSI)
MCLK -> 9 (Timer1)
+Vin = VCC on Pro Micro
GND -> GND

This code bears the license of the beer. If you make money off of this,
you gotta beer me.
*/

long freq; //32-bit global frequency variable

#include <SPI.h>
#include "TimerOne.h"

// Define the FSYNC (used for SD funtion)
#define FSYNC 2

&nbsp;

void setup()
{
 Timer1.initialize(1);
 Timer1.pwm(9, 512);

 pinMode(FSYNC, OUTPUT); //FSYNC

 Serial.begin(9600); // start serial communication at 9600bps

 digitalWrite(FSYNC, HIGH);

 SPI.setDataMode(SPI_MODE2); // requires SPI Mode for AD9837
 SPI.begin();

 delay(100); //A little set up time, just to make sure everything's stable

 //Initial frequency
 freq = 4000;
 WriteFrequencyAD9837(freq);

 Serial.print("Frequency is ");
 Serial.print(freq);
 Serial.println("");

}

void loop()
{

}
void WriteFrequencyAD9837(long frequency)
{
 //
 int MSB;
 int LSB;
 int phase = 0;

 //We can't just send the actual frequency, we have to calculate the "frequency word".
 //This amounts to ((desired frequency)/(reference frequency)) x 0x10000000.
 //calculated_freq_word will hold the calculated result.
 long calculated_freq_word;
 float AD9837Val = 0.00000000;

 AD9837Val = (((float)(frequency))/16000000);
 calculated_freq_word = AD9837Val*0x10000000;

 /*
 Serial.println("");
 Serial.print("Frequency word is ");
 Serial.print(calculated_freq_word);
 Serial.println("");
 */

 //Once we've got that, we split it up into separate bytes.
 MSB = (int)((calculated_freq_word & 0xFFFC000)>>14); //14 bits
 LSB = (int)(calculated_freq_word & 0x3FFF);

 //Set control bits DB15 ande DB14 to 0 and one, respectively, for frequency register 0
 LSB |= 0x4000;
 MSB |= 0x4000;

 phase &= 0xC000;

 WriteRegisterAD9837(0x2100);

 //delay(500);

 //Set the frequency==========================
 WriteRegisterAD9837(LSB); //lower 14 bits

WriteRegisterAD9837(MSB); //upper 14 bits

WriteRegisterAD9837(phase); //mid-low

 //Power it back up
 //AD9837Write(0x2020); //square
 WriteRegisterAD9837(0x2000); //sin
 //AD9837Write(0x2002); //triangle

}

//This is the guy that does the actual talking to the AD9837
void WriteRegisterAD9837(int dat)
{
 digitalWrite(FSYNC, LOW); //Set FSYNC low
 delay(10);

 SPI.transfer(highByte(dat)); Serial.println(highByte(dat));
 SPI.transfer(lowByte(dat)); Serial.println(lowByte(dat));

delay(10);
 digitalWrite(FSYNC, HIGH); //Set FSYNC high
}

I added a buffering opamp to listen to the generated sinewave. Sounds pretty OK to me. Now off to further investigate the audio possibilities of this IC.

Control CD4021 and 74HC595 over the same SPI bus

Working on a project I needed extra digital in’s and extra digital out’s for my Arduino Uno (lots of LEDs, lots of buttons). I’ll use a CD4021 to extend the digital in’s and a 74HC595 to gain extra digital out’s. I decided it would be best to both access the data of the CD4021 and send data to the 74HC595 over the hardware SPI bus on the Arduino (see previous post). Turns out te be not that hard (fortunately ;) ). Here’s the eagle schematic for 1 4021 and 1 595. Of course you can cascade more IC’s if you need more in’s or out’s. Only difference is that you’ll have to interpret and send more bytes (1 byte per IC).

Here’s my Arduino code so far:

#include <SPI.h>

#define PIN_SCK          13             // SPI clock
#define PIN_MISO         12             // SPI data input
#define PIN_MOSI         11             // SPI data output
#define PIN_SS1          10             // SPI hardware default SS pin, 4021
#define PIN_595_1        9              // SPI 74HC595

// result byte for 4021
byte buttons8;

// global vars for button timeout and debounce
long button1timeout = 0;
long button2timeout = 0;
long debounce = 200;

void setup() {
  Serial.begin(9600);
  SPI.begin();
  
  // set all IC select pins HIGH
  digitalWrite(PIN_SS1,HIGH);
  pinMode(PIN_595_1, OUTPUT);
  digitalWrite(PIN_595_1,HIGH);
}

void loop() {
   
  // SS1 = HIGH -> 4021 is gathering data from parallel inputs
  
  // select 595
  digitalWrite(PIN_595_1,LOW);
  
  // send BIN number to 595 to light 1 LED (not necessarily the 1 example LED on the schematic)
  SPI.transfer(B00000100);
  
  // deselect 595
  digitalWrite(PIN_595_1,HIGH);
  
  // select 4021
  digitalWrite(PIN_SS1,LOW);
  // read CD4021 IC
  buttons8 = SPI.transfer(0x00);
  
  // button functions and debounces
  // needs refactoring for smaller footprint
  if((B10000000 & buttons8) && (millis() - button1timeout > debounce)) {
    Serial.println("but1");
    button1timeout = millis();
  }
  if((B01000000 & buttons8) && (millis() - button2timeout > debounce)) {
    Serial.println("but2");
    button2timeout = millis();
  }
  
  // deselect 4021
  digitalWrite(PIN_SS1,HIGH);
}

 

 

 

Arduino, CD4021 and SPI

The “ShiftIn” tutorial on the Arduino site (Parallel to Serial Shifting-In with a CD4021BE) is very clear on why and how to setup and test your Arduino in combination with a CD4021 IC. I needed extra digital inputs and decided to communicate via SPI with the CD4021 chip. Figured it out, it was actually pretty simple thanks to the easy SPI implementation in the Arduino software since version 0020 or so (?)

Setup as described in the Arduino tutorial. Reconnect the clock, the MOSI and the slaveselect as the #defines in the following code. And you’re all set.

#include

#define PIN_SCK          13             // SPI clock
#define PIN_MISO         12             // SPI data input
#define PIN_MOSI         11             // SPI data output
#define PIN_SS1          10             // SPI hardware default SS pin

void setup() {
  Serial.begin(9600);
  SPI.begin();
}

void loop() {
  digitalWrite(PIN_SS1,HIGH);

  // while gathering info from parallel inputs
  // do some other processing
  // for now I'll use
  delayMicroseconds(200);

  // select PIN_SS1 CD4021 IC
  digitalWrite(PIN_SS1,LOW);
  // read byte from CD4021 IC
  Serial.println(SPI.transfer(0x00),BIN);
}

tip: buy some resistor arrays instead of all individual resistors

LCD optimizations and additions

One of my first posts contains a LCD prototype. Today I needed LCD functionality and made some optimizations and additions to the LCD prototype.

Speed up

In the LCD3Wire library, I removed two delays:

131c131
<   //delay(1);
---
>   delay(1);
155c155
<   //delayMicroseconds(1);
---
>   delayMicroseconds(10);

This gives a good speed increase when using the LCD3Wire library. Furthermore, reading this post (http://solar-blogg.blogspot.com/2009/02/displaying-custom-5×8-characters-on.html) I copied the code to the Arduino and displayed my own custom character (using the LCD3Wire library)

lcd.commandWrite(0x40);
lcd.print(0b00000);
lcd.print(0b00100);
lcd.print(0b00010);
lcd.print(0b11111);
lcd.print(0b00010);
lcd.print(0b00100);
lcd.print(0b00000);
lcd.print(0b00000);
lcd.cursorTo(1,0);
lcd.print(0x00);

And another great LCD speedup trick by designer2k2 on the Arduino forums is to avoid using lcd.cursorTo. Instead use his direct positioning code

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1240088162

lcd.commandWrite(0x80);                //Line=1, Cursor 0
lcd.commandWrite(0xC0+val);            //Line=2, Cursor val
lcd.commandWrite(0x94+7);              //Line=3, Cursor 7
lcd.commandWrite(0xD4);                //Line=4, Cursor 0

Progress…

Long time no post. Sorry, real-life is sometimes getting in the way ;)

Recently I bought a Leaflabs Maple R5 to replace my Arduino’s. I really like it. Eventually I ported ChibiOS (realtime OS) to it and tried some software filter algorithms from musicdsp.org. Didn’t make me happy; 72Mhz isn’t enough to do serious audio filtering (at least not using my prototype coding).

New plan: use the Maple for the VCO’s (kind of DCO). Number of voices to be determined. Anti-aliasing virtual analog oscillator code will be constructed using research by Valimaki and Huovilainen. The first hardware voltage controlled versions of the VCF(s) and VCA(s) will be based on my own research regarding the VCF/VCA filter chip in the Roland Juno series. These original Roland chips last usually 15 to 20 years. Right now I’m working on a to be open sourced hardware version of these filterchips. The VCA part is solved using a BA6110 voltage controlled opamp. These aren’t in production anymore (as I know of) but easily obtainable via ebay. I used mooger5’s very valuable research to construct a BA6110 based VCA. His solution (using an SSM2044 for the VCF part):

mooger5, http://www.electro-music.com/forum/topic-17995-25.html, 15 march 2011

The VCA part like drawn by mooger5 is working perfectly! In the next few weeks (busy, busy) I’m going to start working on a VCF part using the LM13700 OTA. Fingers crossed! Resources are the great courses of Aaron Lanterman (Georgia Tech) and, ofcourse, the 80017 VCF/VCA teardown from obsoletetechnology. When the VCF part is working, my plan is to replace the BA6110 with, probably, a LM13700 OTA. This solution will be the base on which I’ll build my own hardware filter and amplifier.

To be continued!

waveshaping 101

Time to start work on waveshaping. My synth is now able to generate 6 voices of musically tuned square waves. Nice, but pretty boring ;). First step is to shape the square wave to a sawtooth wave. This is the square wave from 1 voice:

Inspired by the following waveshaping schematic from the Roland Juno 6,

I came up with the following solution:

The OpAmp is a LM324N, suitable for single +5V power (remember my USB requirement). The transistor is a 2N3904 NPN instead of the PNP used in the Roland schematics. All resistor and capacitor values are determined by the parts I have in my stock. The minus voltage on the capacitor integrator loop is generated via an ICL7660 IC (transforms + voltages into – voltages). Result:

Tada: a sawtooth wave. The peak of the wave is not at 5v because of the maximum output swing of the LM324N OpAmp (+V – 1.5V).

Now I have to find the best values for all the components to generate a normalised saw wave (peak at 3.6v) for all frequencies. My synth should be able to handle all frequencies between 8Hz (midinote 0) and 4000Hz (around midinote 107).

the 5v idea

mmmm what if the entire synth could run on 5v? Just power it over USB. It would make a perfect companion for your laptop but also very easy to install with your desktop PC. The development is also a lot more “portable”. Now I have to work with my own bulky +/-15V power supply. It would be fantastic to just work with an USB cable connection. My MacBook can charge my iPad (1A) so the USB power connection should be powerful enough to drive a (tiny) synthesizer.

Leading to this idea was also the fact that I received my sample MAX7403 8th order lowpass filter chips from Maxim today. These operate at a single 5V power supply  and I think they’ll make great audio filters! Cutoff is addressed via square wave so the Arduino PWM can operate this…

re-welcome at sinneb.com ehhh sinneb.net

Hi all and welcome back,

Because I did not pay in time for my .com domain (I do have some excuses but won’t bore you with them ;) ), it got cancelled and I had to switch to a .net domain. Thinking about it, a .net does actually fit perfectly for this website about the build of a synthesizer. So from now on it’s sinneb.net!

Sorry for the downtime. Let’s get to work!