Pages: 1 ... 11 12 [13] 14   Go Down
Author Topic: New library for PWM playback from SD cards: SimpleSDAudio  (Read 43979 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Jr. Member
**
Karma: 6
Posts: 75
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,
with standard Arduino (with ATmega328) two PWM outputs for SimpleSDAudio are availible, either for stereo 8-bit or mono 16-bit. For mono 16-bit you have to set it up like it would be stereo mode and you have to use the 16-bit SOX batch-files for processing. You end up with 2 PWM outputs, one playing the 8-bit sound and one playing loud "noise". But when you add this noise-channel to the other using those pots, the result will be much less noise.

For start you can also use a 74HC14 chip. Often in catalogs these chips have numbers starting with SN, so SN74AC14 is also the right one.

If you want to use your LM386 amp do the 16-bit combining before routing it to the amp. Use this circuit: http://hackerspace-ffm.de/wiki/index.php?title=Datei:SSDA_Simple16bit.png. But without the 74HC14 or 74AC14 it is hard to get rid of the noise coming from PWM-LED-Dimming.

Good power deblocking is essential for audio quality. Try to add some caps, 100nF but also one much bigger electrolytic cap in the 10uF to 100uF region. This is also done in my Fritzing schematic, so you got it right.

Dual-PWM output does not increase the volume itself (only if you use bridge-mode without any additional amplifiers). I use two PWM outputs with stereo-setting (SSDA_MODE_STEREO) and combine those to 16-bit mono for better audio quality. The 74AC14 will then increase volume and decrease noise if decoupled correctly by filtering the uC-noise out on the PWM outputs.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

I am trying to work on a Tardis project from Dr. Who. Basically I want to play the Tardis theme and have an LED brighten and dim while the Tardis Theme is playing. I have gotten the file and music to play correctly. In a separate sketch I have used timer 0 to brighten and dim the LED, which worked perfectly. When I put the codes together, however, only the light will work, and not the sound. The debug sketch in the library says it cannot initialize the card once I have my LED code in there.

Hopefully I am making sense. I will post my current code and explain what I am trying to do.

Code:
#include <SimpleSDAudio.h>

//Here I have set up an array of integers that start from zero and go to 255, and then decrease to 0. This is so I can brighten and dim an LED while the file is playing.
int array[]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,255,254,253,252,251,250,249,248,247,246,245,244,243,242,241,240,239,238,237,236,235,234,233,232,231,230,229,228,227,226,225,224,223,222,221,220,219,218,217,216,215,214,213,212,211,210,209,208,207,206,205,204,203,202,201,200,199,198,197,196,195,194,193,192,191,190,189,188,187,186,185,184,183,182,181,180,179,178,177,176,175,174,173,172,171,170,169,168,167,166,165,164,163,162,161,160,159,158,157,156,155,154,153,152,151,150,149,148,147,146,145,144,143,142,141,140,139,138,137,136,135,134,133,132,131,130,129,128,127,126,125,124,123,122,121,120,119,118,117,116,115,114,113,112,111,110,109,108,107,106,105,104,103,102,101,100,99,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0};
int y=0;

void setup()
{
  pinMode (6, OUTPUT);   //This is the OC0A pin that I want to use for the LED

 
  cli();
 
 
  TCCR0A = 0x83;         //In the control registers, I have set fast PWM, non inverting mode. I used a prescaler of 256, so that every 4ms the OCR0B would match and set an interrupt.
                         //During the interrupt, I want to increment the element in the array. So every 4ms, the light brigthens slightly.
  TCCR0B = 0x04;
 
  OCR0A = 255;
 
  OCR0B = 249;
 
  TCNT0 = 0;
 
  TIMSK0 = 0x04;
 
  sei();

  SdPlay.setSDCSPin(10); // Enable if your SD card CS-Pin is not at Pin 4...
  SdPlay.init(SSDA_MODE_FULLRATE | SSDA_MODE_MONO | SSDA_MODE_AUTOWORKER);
  SdPlay.setFile("EXAMPLE.AFM");
  SdPlay.play();
}

void loop(void) {
}

ISR(TIMER0_COMPB_vect)
{
  y++;
  OCR0A = (array [y]);
  if(y==512)
  {
    y=0;
  }
 
}

This section of code:

Code:
#include <SimpleSDAudio.h>
void setup()
{
  // SdPlay.setSDCSPin(10); // Enable if your SD card CS-Pin is not at Pin 4...
  SdPlay.init(SSDA_MODE_FULLRATE | SSDA_MODE_MONO | SSDA_MODE_AUTOWORKER);
  SdPlay.setFile("EXAMPLE.AFM");
  SdPlay.play();
}

void loop(void) {
}

comes directly from the AbsoluteMinimum example in the simple sd audio library. The only things I added is the controls for timer 0 to run the light, and an interrupt service routine.

So to set up timer0, I set Bits 7:6 – COM0A1:0 in the timer 0 control register A (TCCR0A) to 1, 0, which is non inverting PWM for the OC0A pin. I set Bits 1:0 – WGM01:0: in the TCCR0A to 1, 1, which selects the fast PWM mode. All I did in the TCCR0B register was set the clock to a 256 prescaler.

The way I set it up, the OCR0A register holds the PWM value for the OC0A pin (pin 6 on the arduino). The OCR0B holds a value that will set an interrupt every 4ms. In this interrupt, I set the next PWM value that needs to be in the OCR0A register.  So in summary, every 4 ms, the OCR0A register is set to the next integer in the array, and the array makes the PWM values increase to 255 and then decrease to 0. This way I get my brightening and dimming LED on pin 6.

So, the SD audio works fine on its own, and the LED works fine on its own. But when I try to combine the two, only the light works; I do not get any audio. So is my ISR taking too much time and ruining the audio? Or does the audio library use all the timers? Note: if I use the BareMinimumWithDebug example in the library, and insert my timer 0 code, it says the SD card will not initialize. I checked the CS pin too, so it has something to do with my timer setup.

I hope my code makes sense and that I have explained my problem well. If anybody could let me know what is wrong, and if there is a possible solution or better way to do this, I would greatly appreciate it.

Thanks,
Thomas Hooper
Logged

Offline Offline
Jr. Member
**
Karma: 6
Posts: 75
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,
the reason is that SimpleSDAudio uses millis() in sd_l0.h for timeout and timing purposes. Unfortunately, timer0 is heavily used by the Arduino library for all kinds of Timings, like millis, delay etc., so it is a good idea not to figure with it. But: two interesting OCR-Outputs are only availible at this timer, that might be used even for 4-channel output with my lib even on ATmega328. On the other hand, timer2 is not as interesting, so I build a patch that moves all internal Arduino timing functions from timer0 to timer2. This patch can help you too. You find it already in the deepths of SimpleSDAudio library. Try it, if you got stuck ask again.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Do you think it would work if I used timer 2 for my pwm settings instead of timer 0? Also, I could not find the patch you said I could try, do I need to download a newer version of the Simple SD audio library?  Thanks for your help.

Thomas Hooper smiley
Logged

Offline Offline
Jr. Member
**
Karma: 6
Posts: 75
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Timer2 is usually not used in Arduino, so if you do your PWM stuff with that timer instead of timer0 it should work. For the other way: The patch is in the "patches" folder of SimpleSDAudio. It provides a patched wiring.c file which replaces the wiring.c in the Arduino folder.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 1
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi, all.
Help me solve the problem - when I call the Play(), I hear a loud clicking before file playback. How to get rid of this very loud clicks?
Logged

Offline Offline
Jr. Member
**
Karma: 6
Posts: 75
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi, usually this lib does not do loud clicks, maybe a little after init, but not when playing files. So maybe your file is not good - add a fade-in to the wav file (e.g. using Audacity) before converting it.

Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I hope people are still working with this library. At least I am smiley

I have got a question. I have built the schematic from the site: http://www.hackerspace-ffm.de/wiki/index.php?title=Datei:SSDA_Better16bit.png.  When I connect my speaker, I hear a very high pitch tone, which is very annoying. I think this tone is there because of the square wave that is constantly present at PIN 9. So when I'm not playing any audio, I would like PIN 9 to be constant 0 V. When I want to play an audiofile, the square wave should be there again. How do I do that? When I use analogWrite(9,0); the tone is indeed gone, but then the audiofiles are almost not hearable anymore.

sincerely,

Marcel
Logged

Offline Offline
Jr. Member
**
Karma: 6
Posts: 75
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi, I see no reason why there should be an audible tone because the PWM frequency is ~62kHz for 16 MHz and ~31kHz for 8 MHz controllers. I have this circuit here in use and if playback stops there is not such a tone. Of course you can try to override the output pin to input when not in use, but I don't think that it will help. BUT: If you really use a 74HC14 or something like that please ensure that all inputs of unused buffers are connected to GND. If there is still noise also try to improve the supply of the buffer by placing a small 100nF capacitor in parallel to the bigger one. Please let us know here if anything of that I've written helps.
Logged

Offline Offline
Jr. Member
**
Karma: 6
Posts: 75
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi, want to add something:

Please also beware of one common made mistake:

If you want to use the 16-Bit feature of the library, you have to set the correct configuration flags: If you want 1 channel mono output but with 16-Bit you have to choose SSDA_MODE_STEREO and not SSDA_MODE_MONO to enable that "magic additional pin that makes audio better".
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello,

Thanks for the quick reaction.

I have used the HEF40106, a 100nF and a 100uF capacitor over the supply. The input pins of the non-used buffers were indeed floating. I have connected them to the ground now but the tone is still very present. The tone isn't introduced by the schmitt triggers anyway since connecting ports 9 and 10 directly to the resistor network still causes the tone to appear on the output.
With the most simple piece of code the tone still appears:
#include <SimpleSDAudio.h>
void setup()
{
 
   if (!SdPlay.init(SSDA_MODE_FULLRATE | SSDA_MODE_STEREO | SSDA_MODE_AUTOWORKER)) {
     while(1); // Error while initialization of SD card -> stop.
  }
 
void loop(void) {
}

I'm using this amplifier: http://www.ebay.com/itm/PAM8403-Mini-Digital-Power-Amplifier-Board-Class-D-2-3W-/221293221137?pt=LH_DefaultDomain_0&hash=item33861a9511
Could that be of any influence?

The PWM frequency is 62 kHz, but can a minor random shift in the duty cycle cause a tone that is hearable?


Marcel
Logged

Offline Offline
Jr. Member
**
Karma: 6
Posts: 75
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,
sorry that I have to say that, but I think both IC's are not the best choice.

Your CMOS inverter is pretty slow - remember that the PWM is operating with full 16 MHz resolution, so 1 bit change means a length of 62ns, whereas your inverter is way slower than that! Even if that might not be the source of your issues this could make the audio quality worse. I recommend fast ones like SN74HC14 or even SN74AC14. The last one is so powerfull that it is often enough to connect the speaker just to a bunch of paralleled inverters. But for 16-Bit you will need a little modification then (the resistors are then too big).

Second: You are using a class-D amplifier. Have you tried it before using some other active speakers or line-in from other amplifier? The issue is that my circuit is lacking a low pass filter and in combination with Class-D amp this might not be a good idea. So just try to add a capacitor between ground and the point where the 1k and 220k are connected together. Experiment with different values e.g. 1nF, 100nF up to 1uF.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello,

Ok I have already a few 74HC14's. I will buy some capacitors tomorrow and order 74AC14's. I will get back at you with the results as soon as possible, but maybe that will be after the weekend.

Thanks.


Marcel

Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

Adding a capacitor after the resistance network helped to decrease the noise. However, still ordered some analog amplifiers to see whether I can get better results. Haven't tested the SN74AC14 yet, that one has arrived today.
To get 16 bit mono output I have to set the flags like: SSDA_MODE_FULLRATE | SSDA_MODE_STEREO | SSDA_MODE_AUTOWORKER ? And I have to convert my .wav file to: .BFM? Because with this combination of settings I do not get good results. I get some kind of very noisy output where I'm trying to play a gunshot. What could be the cause of this? Are there any restrictions for the .wav file, too?


Marcel
Logged

Offline Offline
Jr. Member
**
Karma: 6
Posts: 75
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,
your flags seem to be correct as well as the file format. Of course you need good quality audio material if you want good results. Maybe you have to swap the pwm pins, try playing in 16 bit mode and test what you hear on each of both channels by connecting only one of them to the input of the circuit where the resistor with the lower value is.
On one channel you should hear the sound in good but 8 bit quality and on the other one you should hear loud noise when the 16-bit file is playing. this goes later to the input with the higher value resitor. With both outputs combined you have to adjust the poti the lowest noise. The quality should be then less noisy than 8 bit mode.
Logged

Pages: 1 ... 11 12 [13] 14   Go Up
Jump to: