loading

Record Audio to your Audino Mega SD card.

The audio file can be played back on a standard audio application or analysed byte by byte.

This Instructable will show you how audio input can be repeatedly added to a 512 byte buffer and then transferred to a SD card in real time. The period recorded can be altered.

The sample rate is 9.4 KHz and the wav file output 8 bit, mono. Whilst not hi-fidelity, the sound quality is perfectly adequate.

The recorded wav file can be saved as tabulated data. It can also be displayed as a simple scrolling graph on the monitor.

All files are time stamped using a unix time code sent from the serial monitor.

The inspiration for this article came from reading Amanda Ghassaei: https://www.instructables.com/id/Arduino-Audio-Inp...

.

My latest program update at the end of this instructable, increases the sample rate to 19 KHz with a significant improvement in audio quality.

.

You may also be interested in my instructables on:

A high speed Arduino Oscilloscope: https://www.instructables.com/id/Arduino-High-speed...

Playing wav files from the Arduino: https://www.instructables.com/id/Arduino-playing-wa...

.

Inevitably SD card technology has already improved. I have tested with a Sandisk Ultra 8GB sd card. This is significantly faster than the Kingston 4GB card I started with. Using my updated software I am able to record at 38.3KHz, with no degradation in quality. (4/8/2014)

Step 1: Requirements

Arduino Mega 2560

The following components work- alternatives may be viable (with program tweaking- I leave that to you!)

LCD Keypad Shield http://www.hobbytronics.co.uk/arduino-lcd-keypad-...

MicroSD Breakout Board Regulated with Logic Conversion V2

http://www.hobbytronics.co.uk/microsd-card-regula...

4GB Micro SD Memory Card http://www.hobbytronics.co.uk/microsd-card-regula...

Microphone pre-amplifier-

ac coupled with a potential divider to centre the voltage between Arduino 0-5 V rail

Amanda Ghassaei has published a circuit at https://www.instructables.com/id/Arduino-Audio-Inpu...

I designed my own with bass, treble and volume controls. However there are plenty of pre-amp designs on the web.

Step 2: The Specifications

Serial, LCD, SD and flash memory support.

Serial set at 115200 baud.

Time stamp in Linux format from Serial monitor.

Serial Input can initiate new data capture- using the command 'again' .

Serial input can set the number of Kbytes of data read and therefore the duration of the audio file- using the command 'alter' .

Serial output of data after input request- command 'read' - output can be stopped with command 'q'

Basic graph plotted on serial monitor.

Raw data saved in wav compatible file.

Raw data translated to tabulated file- command 'write'.

Repeated 60 s time update to eeprom. LCD dims during time update to eeprom.

PWM 3 Square wave available for testing- toggle with command 'test'.

Input 2 set high avoids wait for serial time set.

Uno use may be possible with program tweaking including the the relocation of the time storage bytes (variable ememory). I leave that work to you.

NB best quality audio is obtained with the input varying around the mid voltage value of 128. This is important!

Lcd output of basic information.

Lcd adc port specified with variable lcdport.

Lcd button support:

Select initiates a new sample Left alters Sample Kbyte number- then up +10, down -10, left -1, right +1

Step 3: Getting Started

Connect the LCD keypad shield.

Connect the SD card reader

0, 5V

CLK to pin 52

D0 to pin 50

D1 to pin 51

CS to pin 53

I mounted the SD reader on a bit of strip board with pass through pins to match the required connection points.

(Details to follow)

You will probably want to test the lcd and sd card reader using sample scripts from the point of purchase.

This will sound a little casual, but it is all detailed else-where:

Build a microphone pre-amp and connect it through a potential divider- as described by Amanda.

Or use another design.

I recommend that you include a variable resistor in the potential divider section so that the input can be carefully adjusted to centre around a measured input value of 128 (Half of the 0-5 supply voltage. On my PC "5V" is less than 5V when powered by the USB.)

The lcd screen I specified uses analogue port zero for the lcd buttons- so connect your audio input to A1.

Step 4: Mounting the Sdcard Reader

The sdcard can be easily mounted on a piece of strip board and located using pass through pins.

I used two sets of pin connectors (top and bottom), to stabilize the board.

The connections are next to each other on the Arduino Mega. So the copper strip board tracks between the connections must be cut. I used a hand held junior hack saw blade (not in the saw frame) with one locating pin knocked out. Make sure you use a good quality fine toothed blade. It is also very useful for cleaning the gap between the copper strips. I found it easier to cut the 5V track whilst cutting the next two. (See picture 4) It is then a simple matter to solder a wire across the cut.

For the pins I used standard pin strip. The pin length on the Copper side was adjusted to the depth of the Arduino socket, prior to soldering. Spare pin length on the component side was cut and filed clean following soldering.

An eight way header connecter was soldered on and a 90 degree pin connecter plugged in. A small piece of fine dowel was used to support the reader. A small hole drilled through the corner of the board allows a screw to hold the dowel, although glue would be ok.

I added a pin header to the 0V line on the strip board. This ensured that I had not lost the availability of the 0V connection point.

The SDcard reader will need a soldered 90 degree socket header.

The 5V power supply can be collected with a flying lead to one of the pins between 21 and 22 (marked 5V).

Check that you have cut all the tracks shown in the picture, including the tracks cut with a drill bit!

Check your layout and soldering before plugging in!

Step 5: Wave File Format

A wave file header is a 44 byte block.

The header is at the start of the wav file.

The header block must be initialised globally with:

byte wavheader[44];

Audio data follows the header.

For an 8 bit, mono wav file data is a number between 0 and 255.

The script reads the A1 port, interpreting the incoming audio as a voltage between 0 and 255. Perfect!

Only 4 sections of the header need to be updated when the a wav file is saved.

These are shown as the commented sections in the picture.

The bytes at offset 4 contain the length of the data + the length of the header - 2*4 bytes

Or more simply the data count +36.

Each commented section is a 4 byte number.

The four bytes occur with the least significant byte first- this is "little endian format".

The following routine will accept a long value and write it to a specified point in the wav header as 4 succesive bytes:

void headmod(long value, byte location){
// write four bytes for a long

tempfile.seek(location); // find the location in the file

byte tbuf[4];

tbuf[0] = value & 0xFF; // lo byte

tbuf[1] = (value >> 8) & 0xFF;

tbuf[2] = (value >> 16) & 0xFF;

tbuf[3] = (value >> 24) & 0xFF; // hi byte

tempfile.write(tbuf,4); // write the 4 byte buffer

}

Step 6: Setting the Interrupt That Reads the Analogue Port

We can set up an interrupt so that one analogue port is repeatedly read.

(See Amanda's article for further details)

My "startad" subroutine uses a pre-scalar of 128.

This creates a repeated interrupt so that port A1 is continually read at 9.4KHz.

The interrupt subroutine has a two fold function:

1) If the counter is less than the number of readings:

  • Add the audio data byte to the 512 byte buffer.
  • when the buffer is full, write the buffer in one go to the sdcard- 512 bytes is the optimal size for fast data saves. Reset the buffer count to zero for the next incoming audio byte.

2) When the counter is equal to the required number of readings:

Stop the interrupt occurring again

  • Calculate how long the process took, frequency etc.
  • Use the frequency and file size to update the wave file header.
  • Release analogue port A1 and enable port A0 so that the lcd buttons will work.

Step 7: Setting the Date and Time and Sneaky Saving

The Arduino can keep track of time, but has to be told a starting point.

When it is restarted- it has to be told again. (Unless you fit a real time clock).

The time can be specified as a unix time string- which is the number of seconds elapsed since the " standard epoch of 1/1/1970"

The serial console can be used to send a T followed by the unix time string.

T1403524800 represents 12am June 3rd 2014

See subroutine "waitfordate" and "processSyncMessage"

if (Serial.find(TIME_HEADER)) { // Look for the T
pctime = Serial.parseInt(); // extract the time

if( pctime >= DEFAULT_TIME) { // limited check that the time is after default_time

setTime(pctime); // Sync Arduino clock to the time received on the serial port

This site offers unix time values: http://www.onlineconversion.com/unix_time.htm

Time values can be stored in eeprom memory, which is retained after reset.

The values stored are historic- they are not updated during reset.

However they are useful as a starting point for new filenames. When the script is run without time-stamping the previous time value is used with a 60s addition.

writeeeprom and readeeprom allow the storage and retrieval of time strings.

The time is written to the eeprom memory every 60 seconds.

Be aware that eeprom memory has a re-use limit - but the board sockets will probably wear out first.

Step 8: What Is the Output and How Is It Controlled

A folder called adlog is used for the data.

The following output is available:

1) A wav file for each read. The filename is in the format ddhhmmss.wav Audio capture can be repeated with the command "again".

2) Following the serial console command "write", a text file is produced with the data number and data value in columns. This is comma delimited and can readily be imported into other programs for graphical analysis. The filename format is ddhhmmss.txt

3) The serial console command "read" produces a vertically scrolling graphical representation of the audio. This can be stopped by sending a "q" from the console.

The lcd buttons can also be used to record a new audio file and alter the number of logged bytes. Select starts a new file and left starts the "select" function which updates the data number. The lcd A0 port is read and depending on whether the up, down, left or right button is pressed the data number is altered.

The serial console command "test" generates a square wave on PWM3. This is useful for testing without a microphone and pre-amp..

If PWM2 is taken high, the program will not wait for a timestamp from the serial console. The date and time will no longer be current. However this is useful if the usb is not connected.

Step 9: Program Update

I have successfully increased the data acquisition frequency to 19 KHz.

This has entailed using two 512byte buffers (double buffering) and a rewrite of the interrupt and void loop sections.

The audio is very much cleaner.

I also tested at 38 Khz, with very promising results. However at this frequency occasional buffer wait periods are present. It is probable that future improvements in SDCard design and the SD library function speed, will overcome this issue. For those that want to experiment alter the prescalar variable just before void setup.

I have set up bufa and bufb.

In the interrupt routine I set a flag called aready - it is true when writing to bufa, false for bufb.

The flag writeit is true when a write is required and set false when the SdCard finishes.

When a buffer is full (buffcount==BUF_SIZE):

  • I check if the Sdcard is finished writing, in which case writeit==false and I reset the buffer pointer back to zero, switch the buffer flag aready and set the writeit flag true.
  • If the Sdcard is still writing I go one reading back (bufcount--; and counter--;) and exit the interrupt.

Once I have the correct number of readings I shut down the interrupt, write the last data block and tidy up.

The majority of the data is written in void loop:

if(writeit){ // Data is ready to be written

if (aready){

tempfile.write(bufb, BUF_SIZE); // write the data block from bufb

} else {

// initiate block write from bufa

tempfile.write(bufa, BUF_SIZE); // write the data block

}

writeit=false; // flag that the write is done

}

<p>Hi,</p><p> can it be simultaneously played and recorded in the sd card</p><blockquote><br></blockquote>
<p>Hi,</p><p>the application does real time audio recording.</p><p>To play the recording back on the Arduino, see my instructable on playing wav files</p><p><a href="https://www.instructables.com/id/Arduino-playing-wav-files/" rel="nofollow">https://www.instructables.com/id/Arduino-playing-wa...</a></p><p>It may be possible to add code from that project to this one, to create a unified record and play system. (I leave that up to you.)</p><p>David<br></p>
<p>Sir,</p><p>Do I need exactly Mega 2560 or I can use an Ordinary ATMEGA328 on a veroboard? I'm asking this because ATMEGA2560 offers same speed and it is also 8-bit, but offers a few extra pins. If I can use an ordinary ATMEGA328 uC then it will be great. If it can be done without problem, please mention it and also tell me something about the modifications.</p>
<p>Hi Pinakig,</p><p>sorry I have no advise to offer on that setup.</p><p>I use Megas for all of my Arduino applications.</p><p>Cheers,</p><p>David</p>
<p>Hi , im new to arduino , i need to record wav to SD card without the LCD , can you please modify the code , for the arduino due.</p><p>any help will be appreciated .</p>
<p>Please re-phrase with a specific question about the article as published.</p>
<p>Hi David!<br>Thanks a lot for this instructable!</p><p>I am planning on building the circuit but want to use a Winbond SPI flash (W25Q64 - 64Mbit) instead of the SD card.</p><p>If I am not mistaken then the buffer size for the Winbond should probably be 256bytes instead of the 512bytes.</p><p>Did you ever play around with flash chips?</p>
<p>Hi,</p><p>I haven't used an SPI flash device.</p><p>I cannot think of a downside in reducing the buffer size to 256.</p><p>If the flash write cycle is faster than the sdcard write time (512bytes in 1.6 ms)- you should be able to easily achieve 38KHz. (Assuming you adapt my double buffering code.).</p><p>What is the write-rate for your flash?</p><p>Let me know what happens.</p><p>David</p>
<p>Science marches on!</p><p>I tested the latest Sandisk extreme 16GB card today: (On special offer at Tesco)</p><p>512 bytes are read in 1.56 mS. That is 25% faster than the previous card (2.07mS)</p><p>The sound quality is very good!</p>
<p>Hi David,</p><p>This is an awesome article, thanks for posting. </p><p>I have recently started working with arduino UNO and the &quot;write&quot; function in sd Card library is not working. Below is my code. I have tried with &quot;println&quot; which is working fine. Any help regarding this is welcome.</p><p>void loop()</p><p>{</p><p> byte b=10;</p><p> File dataFile = SD.open(&quot;datalog.txt&quot;, FILE_WRITE);</p><p> if (dataFile) </p><p> {</p><p> dataFile.write(b);</p><p> }</p><p>} </p>
<p>Hello Nareshkumar,</p><p>Check you have the latest version of the SD library installed.</p><p>I wrote the following code to test your problem.</p><p>It works if you send byte 10 as a single variable b, or send 10 as the first byte in buffer bufa.</p><p>I presume you are testing how to send bytes, not strings? The suffix &quot;.txt&quot; in your filename was confusing.</p><p><br>#include &lt;SD.h&gt;<br>// set up variables using the SD utility library functions:<br><br>const int defaultselect= 10; // uno (mega is 53)<br>const int chipselect = 10; // any pin you want, including default<br><br>File datafile;<br>Sd2Card card;<br><br>void setup(){<br>Serial.begin(115200); // start serial for output<br>Serial.flush();<br>// setup 2 buffers, any size you might need<br>uint8_t bufa[20];<br>uint8_t bufb[20];<br>// initilise buffers<br>bufa[0]=10;<br>bufb[0]=0;<br>byte b =10;<br>Serial.print(&quot;bufa[0] &quot;);Serial.println(bufa[0]);<br>Serial.print(&quot;bufb[0] &quot;);Serial.println(bufb[0]);<br>// make sure default select line is set to output<br><br> if (chipselect != defaultselect) { pinMode(defaultselect, OUTPUT); } <br> <br> if (SD.begin(chipselect)) {<br> card.init(SPI_FULL_SPEED, chipselect);<br> Serial.println(&quot;Card works&quot;);<br> // delete old file<br> if (SD.exists(&quot;datalog.txt&quot;)) SD.remove(&quot;datalog.txt&quot;);<br> // write the byte<br> File datafile = SD.open(&quot;datalog.txt&quot;, FILE_WRITE);<br> if (datafile){<br><br> // comment out one at a time to test<br> datafile.write(bufa,1);<br> //datafile.write(b);<br> // ___________________________________________<br> datafile.close();<br> Serial.println(&quot;Byte written!&quot;);<br> // try to read the byte back<br> datafile = SD.open(&quot;datalog.txt&quot;, FILE_READ);<br> if (!datafile){<br> Serial.println(&quot;File failed to open for read&quot;);<br> } else{<br> datafile.read(bufb,1);<br> datafile.close();<br> Serial.print(&quot;Byte returned &quot;);<br> Serial.println(bufb[0]);<br> } <br> } else{<br> Serial.println(&quot;File failed to open for write&quot;);<br> }<br> } else{<br> Serial.println(&quot;Card failed to initialise&quot;);<br> }<br>}<br><br>void loop(){<br>}</p><p>David</p>
<p>I have tried the above code but still I am unable to &quot;<strong>write&quot; </strong>to the sd card. I am using arduino 1.0.6 and the SD library is up to date as shown in the image below. I am trying to use your code to capture audio and I am unable to do with <strong>write function </strong>of SD library; when I am using for loops and then printing each byte of the buffer arrays to the SD card, the frequency is decreasing to 3 KHz as opposed to 9 KHz . The code of yours I am using is pasted below. Is there any way to overcome this? Thanks!</p><strong>Code:</strong><p>#include &lt;SD.h&gt;</p><p>#include &lt;SPI.h&gt;</p><p>// set up variables using the SD utility library functions:</p><p>Sd2Card card;</p><p>SdVolume volume;</p><p>SdFile root;</p><p>const int chipSelect = 10; // (Or any suitable pin!)</p><p>File tempfile;</p><p>boolean hascard=false;</p><p>boolean written, aready, writeit;</p><p>unsigned long starttime , endtime, filesize;</p><p>float frequency;</p><p>float period , interval;</p><p>int const adport = 2; // Set the port to be used for input!</p><p>// buf is used to store icoming data and is written to file when full</p><p>// 512 bytes is optimized for sdcard</p><p>#define BUF_SIZE 128</p><p>int bufa[BUF_SIZE];//uint8_t bufa[BUF_SIZE];</p><p>int bufb[BUF_SIZE];//uint8_t bufb[BUF_SIZE];</p><p>uint16_t bufcount;</p><p>char bufFile[]=&quot;/adlog/00112233.txt&quot;;</p><p>unsigned long readings = 100000; // initial sample size- kept small to avoid delay- enough to create data to look at</p><p>int i;</p><p>unsigned long counter;</p><p>// Defines for clearing register bits</p><p>#ifndef cbi</p><p>#define cbi(sfr, bit) (_SFR_BYTE(sfr) &amp;= ~_BV(bit))</p><p>#endif</p><p>// Defines for setting register bits</p><p>#ifndef sbi</p><p>#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))</p><p>#endif</p><p>// alter prescalar here 32, 64, 128</p><p>// 32 is the fastest sampling rate</p><p>byte prescalar=128;</p><p>void setup(){</p><p> //Specimem frequency used for first reading to estimate initial sample duration</p><p> /* if(prescalar==32) frequency = 38.3829;</p><p> if(prescalar==64) frequency= 19.2300;</p><p> if(prescalar==128) frequency= 9.6182;*/</p><p> pinMode(10, OUTPUT); </p><p>Serial.begin(115200); // start serial for output</p><p>Serial.flush();</p><p>if (SD.begin(chipSelect)) {</p><p> hascard=true;</p><p> aready=true;</p><p> card.init(SPI_FULL_SPEED, chipSelect);</p><p> // Create adlog sub-directory</p><p> if (SD.exists(&quot;/adlog&quot;) == false) {</p><p> SD.mkdir(&quot;/adlog&quot;);</p><p> }</p><p> hascard=fileopen();</p><p> }</p><p>cli();</p><p>startad();</p><p>}</p><p>void startad(){</p><p>// Setup continuous reading of the adc port 'adport' using an interrupt</p><p>cli();//disable interrupts</p><p>//clear ADCSRA and ADCSRB registers</p><p>ADCSRA = 0;</p><p>ADCSRB = 0;</p><p>ADMUX |= adport; //set up continuous sampling of analog pin adport </p><p>//ADMUX |= (1 &lt;&lt; REFS0); //set reference voltage</p><p>ADMUX |= (1 &lt;&lt; ADLAR); //left align the ADC value- so we can read highest 8 bits from ADCH register only</p><p>// pre scalar to set interrupt frequency:</p><p>//ADCSRA |= (1 &lt;&lt; ADPS2); // 16 prescalar 72Khz, but what could you do at that rate?</p><p>// 128 prescalar - 9.4 Khz sampling</p><p>if (prescalar==128) ADCSRA |= (1 &lt;&lt; ADPS2) | (1 &lt;&lt; ADPS1) | (1 &lt;&lt; ADPS0);</p><p>//32 prescaler - 16mHz/32=500kHz - produces 37 Khz sampling</p><p>if (prescalar==32) ADCSRA |= (1 &lt;&lt; ADPS2) | (1 &lt;&lt; ADPS0);</p><p>// 64 prescalar produces 19.2 Khz sampling</p><p>if(prescalar==64) ADCSRA |= (1 &lt;&lt; ADPS2) | (1 &lt;&lt; ADPS1);</p><p>ADCSRA |= (1 &lt;&lt; ADATE); //enable auto trigger</p><p>ADCSRA |= (1 &lt;&lt; ADIE); </p><p>//ADCSRA |= (1 &lt;&lt; ADEN); //enable ADC- works fine, but so does the next line</p><p>sbi(ADCSRA,ADEN); // //enable ADC</p><p>ADCSRA |= (1 &lt;&lt; ADSC); //start ADC measurements on interrupt</p><p>writeit=false;</p><p>starttime=millis();</p><p>sei();//enable interrupts</p><p>} </p><p>// Interrupt routine *******************************************</p><p>// this is the key to the program!!</p><p>ISR(ADC_vect) {</p><p> if (counter &lt; readings) {</p><p> if(aready) { // get the new value from analogue port</p><p> bufa[bufcount]=ADCH;</p><p> } else {</p><p> bufb[bufcount]=ADCH;</p><p> }</p><p> counter++; // increment data counter</p><p> bufcount++; // increment buffer counter</p><p> if(bufcount==BUF_SIZE){</p><p> if(writeit==false) {</p><p> bufcount=0;</p><p> aready = ! aready;</p><p> writeit=true; // flag that a write is needed</p><p> } else { // wait for file write to complete</p><p> bufcount--;</p><p> counter--;</p><p> }</p><p> }</p><p> } else {</p><p> // All data collected</p><p> cli();//disable interrupts</p><p> cbi(ADCSRA,ADEN); // disable ADC</p><p> sei();//enable interrupts</p><p> endtime=millis();</p><p> // write the last block</p><p> if (aready){</p><p> for(int i=0;i&lt;BUF_SIZE;i++)</p><p> {</p><p> tempfile.println(bufa[i]); </p><p> }/// write the data block</p><p> // tempfile.write(bufa, BUF_SIZE); </p><p> } else {</p><p> for(int i=0;i&lt;BUF_SIZE;i++)</p><p> {</p><p> tempfile.println(bufb[i]); </p><p> }</p><p> // initiate block write from B</p><p> //tempfile.write(bufb, BUF_SIZE); // write the data block</p><p> }</p><p> Serial.println(F(&quot;Logging stopped&quot;));</p><p> period= endtime-starttime;</p><p> frequency = float(readings)/period;</p><p> Serial.println(frequency);</p><p> interval = 1000/frequency;</p><p> tempfile.flush();</p><p> }</p><p>}</p><p>// End Interupt section *******************************************</p><p>void loop(){</p><p> if(writeit){</p><p> if (aready){</p><p> for(int i=0;i&lt;BUF_SIZE;i++)</p><p> {</p><p> tempfile.println(bufb[i]); </p><p> } </p><p> //tempfile.write(bufb, BUF_SIZE); // write the data block</p><p> } else {</p><p> for(int i=0;i&lt;BUF_SIZE;i++)</p><p> {</p><p> tempfile.println(bufa[i]); </p><p> }</p><p> // initiate block write from buf A</p><p> //tempfile.write(bufa, BUF_SIZE); // write the data block</p><p> }</p><p> writeit=false; // the write is done!</p><p> }</p><p>}</p><p>// End Void Loop section ******************************************</p><p>boolean fileopen(){</p><p> if (SD.exists(bufFile)) {SD.remove(bufFile);}</p><p>tempfile = SD.open(bufFile, FILE_WRITE | O_TRUNC);</p><p> if (!tempfile) {</p><p> Serial.println(F(&quot;Tempfile failed to open&quot;));</p><p> return(false);</p><p> } else{</p><p> // hasdata=false;</p><p> written=false;</p><p> counter=0;</p><p> bufcount=0;</p><p> float var = float(readings)/1000;</p><p> float estimate = var / frequency;</p><p> Serial.print(F(&quot;\nLogging (&quot;));</p><p> Serial.print(estimate,2);</p><p> Serial.println(F(&quot; S)&quot;));</p><p> return(true);</p><p> }</p><p>}</p>
<p>Hi,</p><p>What happened when you tried the write one byte example?</p><p>What output appeared in the serial monitor?</p><p>The Uno runs at a lower frequency than the mega and has considerably less memory. Both these factors are working against you!</p>
<p>Hi,</p><p>In the one byte example,the text file gets created but the byte doesn't get printed to the text file. I can't rely on the serial monitor output because you are directly printing <b>bufb[0] </b>in the end<b>,</b> by only checking whether the text file has been created. Thanks!</p>
<p>Hi,</p><p>You can rely on the serial output:</p><p>bufb(0) is initialised with zero</p><p>bufb(0) is read from the file in the line </p><p>datafile.read(bufb,1);</p><p>a one byte buffer is read into the array bufb!</p><p>.</p><p>If bufb(0) is still zero, then the file is in error.</p><p>It would be helpful to supply a screen capture from your serial monitor after each of the test routine options have executed.</p>
<p>Hi,</p><p>I have understood the issue; number 10 happens to be new line character in ASCII. So, I was unable to view the character in the text file. When I try with different numbers their respective ASCII values are getting printed. When we are reading them in an arduino code they are again being converted to their respective human understandable values. Thanks for your help for the whole day. Cheers! </p>
<p>Thank you for posting this, this is a great project and you have clearly laid out all the steps. </p><p>In your comments on your latest version, it states that 32 is the fastest sampling rate, even though you left in the code for a prescaler of 16. </p><p>Have you been able to get any faster rates with lower prescalers?</p>
<p>Hi,</p><p>The 32 prescalar works well with the latest high speed sd card, producing a sample rate of 38.3Khz on my arduino mega.</p><p>A prescalar of 16 should interrupt at 72Khz- this rate will not leave enough time for the buffer writes to complete. 512 bytes would be read in 512*1000/72000 mS:</p><p>7.1ms</p><p>This will almost certainly be less than the write time for the buffer at the current speed of software and sdcard.</p><p>So the interrupt will prevent the completion of the write- hence the degradation in observed frequency response. (As you observed)</p><p>I find the audio quality for 38.3Khz very acceptable-</p><p>Have you got it working?</p><p>.</p><p>Reducing the buffer size is not an option- according to best advice 512 bytes is the optimal block size.</p><p>A future development might be stereo- two preamps and a 512byte buffer comprising 256 left channel, right channel data pairs......</p><p>My follow up instructable detals how to play back the wav files from the sdcard- I have had no problem with files recorded at 44Khz. So 38.3Khz files will work quite happily.</p>
<p>The 16 prescaler actually slows down the sample rate compared to the 32 prescaler. With the 32 prescaler, i was showing ~38kHz sample rate. With the 16 prescaler, I was showing ~31.8kHz sample rate. Is this because of the interrupts?</p>
<p>thanks for posting this! a lot of great info here. Do you think it's possible to increase the sampling rate above 9.4kHz? is there a limit to how fast you can interface with the sd card?</p>
<p>I did a re-write this evening, utilizing double buffering.</p><p>I now have the frequency easily up to 19Khz, with very good clarity.</p><p>Further testing at higher frequencies is needed, but results are very promising.</p>
<p>I investigated sampling with pre-scalars of 16 (72Khz), 32,(36Khz), 64(18.6Khz) and 128 (9.4Khz). I have left the necessary code in the startad subroutine for those who wish to try.</p><p>Without doubt, the limiting factor is the 512 byte block transfer to the sd card.</p><p>I believe that it is unlikely that further optimization is possible within the block write section of the code.</p><p>Obviously, if it takes longer than the sample period to write a sd block, then the audio is missed (or the frequency perverted) and the sound quality collapses.</p><p>At present, 9.4Khz is the limit for my SDcard writer.</p><p>No doubt card writer technology will speed up.</p><p>I have read claims for faster (beta) versions for sd libraries. However I wanted to use the standard sd library.</p><p>Faster sampling is possible if memory is used as the buffer, rather than the sd card.</p><p>My best optimization for that system allowed for a 6000 byte buffer on a Mega.</p><p>At 38 Khz, only a fraction of a second can be read. This is no good for recording audio, but has applications as an oscilloscope / fast logger.</p>
<p>This is simply incredible. I love how you go over wav files. I always thought about this but I never thought it could actually be done with an arduino. Thanks for sharing </p>
<p>Thanks for that.</p><p>Let us know if you you get it up and running.</p>

About This Instructable

43,273views

131favorites

License:

More by DavidPatterson:Arduino Mega GPS with LCD and SD Logging Arduino High speed Oscilloscope with PC interface Playing audio sound files ( wav ) with an Arduino 
Add instructable to: