Solved: Arduino Uno WAV player audio signal problem

Go To Last Post
31 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Overview information and setup:

 

I am making a small project based on some tutorials i found online in order to make a simple wav player using an ATmega328 processor loaded with an arduino uno bootloader. The test board i made is comprised of  the following main parts:

- an SD card adapter from sparkfun and an sd card that is used to store the WAV files.

- an LM386 audio amplifier set up for a 200 gain (from datasheet application note)

- an 8 ohm magnetic speaker

- an ATmega328-PU processor 

 

The ATmega328 is set up to use SPI communication to talk to the sd card  and uses pin 15 (PB1) as the audio out signal that is hooked up to the amplifier circuit. As far as i understand from the tutorials the micro uses a pwm signal on this pin to generate the sound necessary to replicate the music. I am using the following libraries:

- SD.h for sd card reading 

- SPI.h for communiation 

- TMRpmc for the audio playback

 

 

The SD card is formatted to FAT32 and the 5 second audio file that i am using was converted using an online converter specified in the tutorials that converts it to a wav file with 8 bit resolution, 16KHz sampling rate, mono and unsigned 8 but PCM format.

 

 

Code:  

 

#include "SD.h" //Lib to read SD card

#include "TMRpcm.h" //Lib to play auido

#include "SPI.h" //SPI lib for SD card

 

#define SD_ChipSelectPin 4 //Chip select is pin number 4

TMRpcm music; //Lib object is named "music"

 

 

 

void setup(){

music.speakerPin = 9; //Auido out on pin 9

Serial.begin(9600); //Serial Com for debugging 

if (!SD.begin(SD_ChipSelectPin)) {

Serial.println("SD fail");

return;

}

 

 

pinMode(10, OUTPUT);

 

 

music.setVolume(5);    //   0 to 7. Set volume level

music.quality(1);        //  Set 1 for 2x oversampling Set 0 for normal

//music.volume(0);        //   1(up) or 0(down) to control volume

//music.play("filename",30); plays a file starting at 30 seconds into the track    

}

 

void loop()

   

 music.play("1.wav"); 

  

}

 

 

Problem:

 

I have managed to get the micro to communicate with the SD card adapter and i am getting pwm signal on pin 15. The problem is that it is a 32KHz signal with a fixed duty cycle  so there is no song playing just  a small constant buzz. When the code compiles i get one warning :

"warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings] tmrpcm" which i managed to get rid of by forcing the string to be of type char* as someone suggested online. I am guessing this may be some conversion problem (i am not sure if the format of  SD card with 4096 bytes allocation size has anything to do with it )but i do not know if that is the case what to do which is why am am asking here.  

 

I thank you in advance for your response and please tell me if you need additional info. 

Last Edited: Wed. Aug 23, 2017 - 11:21 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

crys17p wrote:
 based on some tutorials i found online

Which tutorials?

 

How does your code differ?

 

Do the tutorials work unmodified?

 

How to properly post source code: http://www.avrfreaks.net/comment...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok so the main tutorial is this one here: https://circuitdigest.com/microcontroller-projects/arduino-audio-music-playe

 

Right now my code is just made to simply play the audio file on the sd card to see if the setup works so i took out all the lines about buttons and swithching tracks. I did not try the unmodified tutorials because the original one uses two push buttons and i do not need to switch tracks. So the modifications i made should not alter the core of the program since i am just modifying the trigger for the audio file and not how it is processed.

 

Here is the original source code :

 

/*
Arduino Based Music Player

 This example shows how to play three songs from SD card by pressing a push button

 The circuit:
 * Push Button on pin 2 and 3
 * Audio Out - pin 9
 * SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 4 

 created  25 Jun 2017
 by Aswinth Raj

 This example code was created for CircuitDigest.com

 */
 
#include "SD.h" //Lib to read SD card
#include "TMRpcm.h" //Lib to play auido
#include "SPI.h" //SPI lib for SD card

#define SD_ChipSelectPin 4 //Chip select is pin number 4
TMRpcm music; //Lib object is named "music"

int song_number=0;
boolean debounce1=true;
boolean debounce2=true;
boolean play_pause;

void setup(){
music.speakerPin = 9; //Auido out on pin 9
Serial.begin(9600); //Serial Com for debugging 
if (!SD.begin(SD_ChipSelectPin)) {
Serial.println("SD fail");
return;
}

pinMode(2, INPUT_PULLUP); //Button 1 with internal pull up to chage track
pinMode(3, INPUT_PULLUP); //Button 2 with internal pull up to play/pause
pinMode(3, INPUT_PULLUP); //Button 2 with internal pull up to fast forward

music.setVolume(5);    //   0 to 7. Set volume level
music.quality(1);        //  Set 1 for 2x oversampling Set 0 for normal
//music.volume(0);        //   1(up) or 0(down) to control volume
//music.play("filename",30); plays a file starting at 30 seconds into the track    
}

void loop()
{ 
  
  if (digitalRead(2)==LOW  && debounce1 == true) //Button 1 Pressed
  {
  song_number++;
  if (song_number==5)
  {song_number=1;}
  debounce1=false;
  Serial.println("KEY PRESSED");
  Serial.print("song_number=");
  Serial.println(song_number);

  if (song_number ==1)
  {music.play("1.wav",10);} //Play song 1 from 10th second 

  if (song_number ==2)
  {music.play("2.wav",33);} //Play song 2 from 33rd second 

  if (song_number ==3)
  {music.play("3.wav");} //Play song 3 from start

  if (song_number ==4)
  {music.play("4.wav",25);} //Play song 4 from 25th second }

  if (digitalRead(3)==LOW  && debounce2 == true) //Button 2 Pressed
  {
  music.pause();  Serial.println("PLAY / PAUSE");
  debounce2=false;
  }

  if (digitalRead(2)==HIGH) //Avoid debounce
  debounce1=true;

  if (digitalRead(3)==HIGH)//Avoid debounce
  debounce2=true;
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Are you sure you code is correctly reading the SD card?

 

Does the library allow you to play a sinple, fixed tone?

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have used an oscilloscope to look at the signals and all i can say is that it is definitely communicating ...weather it's correctly doing so i am not sure since my setup is not made to output on the console in the Arduino application. 

 

 

 I do not know if it does . I will have to look into how i can do that to verify that the pin is actually being manipulated and not just outputtting that 32 KHz signal beacuse of something else. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

crys17p wrote:
weather it's correctly doing so i am not sure

Better make sure, then!

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Surely the best approach would be to copy the original design first to confirm that the elements work correctly and then, and only then, alter one thing at a time after you understand how the original works. Afterall, it is a simple breadboard configuration.

Ross McKenzie ValuSoft Melbourne Australia

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oh boy, here we go (again).

Verifying if a uSD card is read correctly is hardly possible with an oscilloscope. It is just the wrong tool for the job.

 

The right tool for this job is a Logic Analyser, and since they are so extremely usefull tools and only cost about USD 10 nowadays EVERY hobbyist who takes himself even remotely seriously should get one. sigrok has built in decoders for SD card protocols. You can easily verify correct timing etc and even copy / extract the data which is going over the bus with sigroc-cli.

 

Watch this video. Even though it's over an hour long, it is an hour well spent.

https://www.youtube.com/watch?v=...

 

Another technieuqe is to divide your problem into smaller pieces.

You can try to put a short sound sample into FLASH and play that.

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Paulvdh wrote:
Verifying if a uSD card is read correctly is hardly possible with an oscilloscope. It is just the wrong tool for the job.

agreed

 

The right tool for this job is a Logic Analyser

Given that this is supposed to be a "ready-to-go" working project, I would start with the console output.

 

If that shows that the file IO is working - then no need for the logic analyser.

 

If it shows that the file IO is not working, then I'd go back to the original code and verify that it did actually work.

 

If it did then, as Ross says, work from there incrementally - making sure that each step still works.

 

Of course, if the original doesn't work, you have to decide whether to break out the LA to debug it - or find another example!

 

 

since they are so extremely useful tools and only cost about USD 10 nowadays EVERY hobbyist who takes himself even remotely seriously should get one.

Can't argue with that.

 

sigrok has built in decoders for SD card protocols. You can easily verify correct timing etc and even copy / extract the data which is going over the bus with sigroc-cli.

 

Watch this video. Even though it's over an hour long, it is an hour well spent.

https://www.youtube.com/watch?v=...

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why would either a scope or an LA be the "right tool" here? I would hex edit a WAV file on a PC then I wild file.open() it on the AVR and read the first 20 bytes or something and see if they are the same 20 bytes as I saw back on the PC. Sure, if that shows some difference then maybe that is time to explore the wire wiggling but I'd start with a higher level diagnostic first. Even if that fails I'd still be looking at this at a logical rather than physical level - perhaps seeing what the result of the disk_init() is.

Last Edited: Mon. Aug 21, 2017 - 03:06 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I mentioned the LA because there as aparently daubt if the SD card software as working properly.

If it is, then a LA is not the right tool.

 

crys17p wrote:
I have managed to get the micro to communicate with the SD card

What do you consider "working". You see some bits wiggling on the scope, or you have actually read data from a card?

So let's assume SD stuff works, but no difference in the PWM bit wiggling output...

could be almost anything. and we have almost no info to give any sort of diagnosis.

 

small extension from Clawson's Idea:

Read a text file from the SD card and send it to the PC (LCD, whatever) If that works you know for sure you have working sw / hw for the SD card.

 

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I actually just went ahead and made a breadboard setup so it would be easier to debug the whole thing and i used the Cardinfo and raedWrite example code to see if the card can be accessed and written/red to and it works correctly in both cases. The Cardinfo program shows me that i have the wav file on there. The thing is it also sees some addtional files SYSTEM~1 , WPSETT~1.DAT and INDEX~1. I am assuming those are made automatically and not shown when you access the card normally but i am wondering if it is beacuse of this that the program is failing  and is the reason i am getting the constant pwm signal  instead.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What do you mean by, "access the card normally" ?

 

If using Windows, set it to show hidden files.

 

You need to get that console output working so you can see what it's doing:

 

  • is it opening the card?
  • is it finding the file?
  • is it opening the file?
  • is it reading the file?
  • etc ...

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

crys17p wrote:
the 5 second audio file that i am using was converted using an online converter

There's another possible source of errors ...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I can see the system volume information folder when i open the card. Is there a way to delete that cause normal delete does not work. Is it even ok to delete that ? When i initially saw it i was thinking that it was some temporary folder that wiondows was making in order to access the card or something. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The names you quote are simply the 8.3's for some LFN's so windows will show the long names. Switch to a command prompt and use /x on the dir command and it will show the 8.3 translation.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I suggest a different route.   Instead of getting the AVR to play a WAV file from an SD card, instead search eBay for "Arduino MP3 player modules".  There are two that I have used.  The $1 MP3 module uses long and short button presses to start/stop an MP3 file that plays from an SD card inserted into the MP3 module.  These presses are simulated by on/off digitalWrite() commands on AVR port pins.

   The second module is called DFPlayer: it's $2 on eBay.  It also plays MP3 files that are stored on an SD card.  But it uses UART 9600-baud serial commands from the Arduino SoftwareSerial library to play the song.

    Now that the MP3 patents have expired, you can download WAV to MP3 converters like LAME and others to put your WAV file into MP3 format.  Then copy this MP3 file to the SD card, insert it into the MP3 player, and control the audio using the AVR/Arduino.

 

   This sounds like a lot of work, but all the "heavy lifting" has been done by the designers of the MP3 modules.  My "new stereo" is a DFPlayer module run by a 3.3V Arduino Nano.  The DFPlayer searches the SD card on power-up for all MP3 files in all subdirectories.  Then it plays them either in order or by the selection number sent to it by the softSerial 9600 baud interface.   I have about 2000 1960s-1970s pop songs on an SD card.  I have a potentiometer connected to an Analog input on the AVR.  When the rotary angle sensor (the potentiometer/volume knob) is changed from a previous setting, the ADC result (0-1023) gets multiplied by 2 to get the new song number.  It's not "elegant", but it's one of the best stereos that I've ever had, and its $10 price ($3 Arduino Nano, $2 DFplayer module, + $5 8-gig older SD card) just makes it even better.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Utter rubbish. That's like someone saying "I want to build an alarm clock" and you saying "don't do that, what you actually need is a CAN reading ECU for use in your car".

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Simonetta has been on a mission for several years now, trying hard to dissuade people from undertaking a hobby :) ... Just go buy it!

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you a lot for all your responses. I managed to figure out what the problem was yesterday. It was not on the hardware side.....it was actually software related. It was so simple it caught me by surprise. The problem laid in the fact that in the void(loop) section of the program i was simply saying to the program to play track one from the SD card and for some reason without it being in some kind of trigger like an if statement tied to a button press or any type of outside input it does not run the command(would like to know why though). Once i moved it to  void(setup) it worked. I then moved it back to the loop with a proper trigger and it works as intended. All i have to do now is figure out how to increase the volume of the speaker through the amplifier. I am going to try modifying the amplifying circuit to have a 200 gain on the opamp. My only other option is to increase the supply voltage but i am already using 5 batteries in series. 

 

But again thanks for all the help it is much appreciated ;)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

loop() is called repeatedly so if play() does not run to completion (synchronous) but just asynchronously begins playback your loop () would just be starting it pver and over so it kept resetting.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A yes of course that makes sense. Dummy me didn't think of that :))))

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I wonder if you would need to have any analog amplification of the audio signal.   The PWM approach to reproducing an analog waveform by using a single port pin is like a Class-D audio amplifier.  The values in the WAV file should be varied enough to provide a 2 volt peak-to-peak signal right off of the pin.  A gain of 200 would make that a 400V signal.  Far out of the range of the five batteries [I assume that these are 1.5V or 1.2V cells]

 

I suggest instead connecting the output of the PWM pin (through a 1 to 10 microFarad capacitor) to the input of a PAM8403 or PAM8406 audio amplifier module.  They cost only a dollar or two on eBay, are easy to use, and have great sound and specs.  Here is a link:

http://www.ebay.com/itm/Mini-5V-...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yeah i managed to do the amplification with the 200 gain thing i mentioned and i got it sounding a noticeable bit better even with the just the original 5 batteries. But yeah that looks interesting , i will look into into it . Thanks 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

One of the most important things I've found when playing WAV samples is the "sound chamber" that the speaker is enclosed in. To get an idea of what I am talking about - assuming you just have the LM386 playing into a loose small speaker on a couple of flying wires - take a plastic drinking cup and invert it over the speaker and then play again. I bet you find it sounds "10 times better" ;-) So it isn't necessarily all about the electronics or the software mechanism.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Actually, that's nothing specifically to do with WAV samples: that's the basic physics of how loudspeakers work - whatever the source.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:
that's the basic physics of how loudspeakers work
Is that why my daughter puts her hands over her ears when I am talking?indecision

David (aka frog_jr)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think i need to go for the Class d amplifier solution. My question is if the setup will work with PWM signal. Is that 10 micro farad cap (also should it be electrolytic ? ) really enough to make it work . Because from what i understand these amplifiers need an analog signal at the input. Don't i need some kind of DAC for the PWM signal? I found this mono amplifier instead since it is easier for me to order: https://www.digikey.dk/product-detail/en/sparkfun-electronics/BOB-11044/1568-1025-ND/5140790

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Does the uC's PWM output signal go through an RC filter, (or even better an op-amp based LPF), to convert the pulse train to an analog signal before you feed it to the amplifier?

 

A PWM signal is a series of pulses of 0 V and Vcc volts, and that might well saturate a small audio amp's input circuitry, giving a very noisy output.

 

JC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Goodness gracious!    Don't buy any $50 1-watt mono audio amp board!  eBay has many audio amp boards that are stereo, have volume/on/off heavy switches, selection between Class AB and Class D, terminal strips for speaker connections, and a 3.5mm stereo jack for input.  Most use the PAM8406 IC that runs on a 18650 battery or +5V and cost about $3-5 for the entire module board.

 

http://www.ebay.com/itm/2-Channe...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I solved the volume issue i was having by simply having a bigger speaker.  My only concern now is about power consumption. It seems that in idle before the first trigger it consumes 30 mA but after the first time it is triggered it consumes 90 mA. I am trying to reduce it by using the low.power library but haven't had much luck so far. It may be that the LM386 is acting like a switch that when it receives the  PWM signal from the Micro it stays open and drains current. But i don't know yet. I have to look into it more.