Introduction: Scales on the Arduino With an SPI 12 Bit Dac
You will need:
- An arduino DAC shield http://tinyurl.com/AudioShield
- A powered speaker with a 3.5mm plug
- an arduino uno compatible
- a host computer for compiling and uploading code
You will get:
- The ability to play scales
- The ability to play any song you would like to encode
- endless hours of great fun and learning
Step 1: Scales on the Arduino Audio Shield
First download and compile the code
/* freqout(freq, t)
// freq in hz, t in ms a simple tone generation function generates square waves of arbitrary frequency and duration program also includes a top-octave lookup table & transposition function */
#include
#define LDAC 8 #define ChipSel 9 //using macros for pin numbers is better than using a variable -BM
///Danger Will Robinson! /**************************** ***************************** This code will work ONLY with Arduino boards using ATMega 328 or 168 processors! Ex: Uno, Nano, Pro Mini. - BM ***************************** ****************************/
void DACWrite( uint16_t );
int ptime; int k, x, dur, freq, t; int i, j;
float ps; // variable for pow pitchShift routine
float noteval;
// note values for two octave scale // divide them by powers of two to generate other octaves float A = 14080; float AS = 14917.2; float B = 15804.3; float C = 16744; float CS = 17739.7; float D = 18794.5; float DS = 19912.1; float E = 21096.2; float F = 22350.6; float FS = 23679.6; float G = 25087.7; float GS = 26579.5; float AA2 = 28160; float A2S = 29834.5; float B2 = 31608.5; float C2 = 33488.1; float C2S = 35479.4; float D2 = 37589.1; float D2S = 39824.3; float E2 = 42192.3; float F2 = 44701.2; float F2S = 47359.3; float G2 = 50175.4; float G2S = 53159; float AA3 = 56320;
//octaves - corresponds to piano octaves float oct8 = 4; float oct7 = 8; float oct6 = 16; float oct5 = 32; float oct4 = 64; float oct3 = 128; float oct2 = 256; float oct1 = 512; float oct0 = 1024;
//rhythm values int wh = 1024; int h = 512; int dq = 448; int q = 256; int qt = 170; int de = 192; int e = 128; int et = 85; int dsx = 96; int sx = 64; int thx = 32;
// major scale just for demo, hack this
float majScale[] = { A, B, CS, D, E, FS, GS, AA2,
B2, C2S, D2, E2, F2S, G2S, AA3
};void setup() {
pinMode( ChipSel, OUTPUT ); // sets the digital pin as output
pinMode( LDAC, OUTPUT );SPI.begin(); PORTB |= 0b00000011; //set chip select and LDAC to default high state - BM
Serial.begin(115200); }
void loop() {
for (i = 0; i <= 11; i++) {
ps = (float)i / 12;
// choose new transpose interval every loop
for (x = 0; x <= 15; x++) {
noteval = (majScale[x] / oct4) * pow(2, ps);
// transpose scale up 12 tones // pow function generates transposition
// eliminate " * pow(2,ps) " to cut out transpose routine
dur = 100;
freqout((int)noteval, dur); delay(10);
}
}
}void DACWrite( uint16_t outbuf ) {
outbuf |= 0b0111000000000000; //change some bits at the beginning to configure DAC
char* w_bytes;
w_bytes = (char*)&outbuf; //split the two bytes in outbuf into an array
PORTB &= 0b11111101; //pull chip select low
SPI.transfer( w_bytes [1] ); //send them one at a time
SPI.transfer( w_bytes [0] );
PORTB |= 0b00000010; //pull chip select high
PORTB &= 0b11111110; //pull LDAC low
asm volatile("nop"); //wait one clock cycle
PORTB |= 0b00000001; //pull LDAC high
}
// freq in hz, t in ms
void freqout(int freq, int t) {
int hperiod;
//calculate 1/2 period in us
long cycles, i;hperiod = (500000 / freq) - 7; // subtract 7 us to make up for digitalWrite overhead
cycles = ((long)freq * (long)t) / 1000;
// calculate cycles
// Serial.print(freq);
// Serial.print((char)9);
// ascii 9 is tab - you have to coerce it to a char to work
// Serial.print(hperiod);
// Serial.print((char)9);
// Serial.println(cycles);
// play note for t ms
for (i = 0; i <= cycles; i++) {
DACWrite( 4095 );
//send max value to DAC -- equivalent to logic HIGH - BM
delayMicroseconds(hperiod);
DACWrite( 0 );
//send 0 to DAC -- equivalent to logic LOW - BM
delayMicroseconds(hperiod);
// - 1 to make up for digitaWrite overhead
//removed - PORT is much faster - BM
}
}Step 2: Upload
Then upload the code sample to the arudino.
If you have the shield (available at: http://tinyurl.com/AudioShield)
You should be able to hear scales on the speaker.
You will need an amplified speaker with a 3.5mm plug to plug into the shield.
The shield has no amplifier and cannot drive a speaker directly.





