Pages: [1] 2   Go Down
Author Topic: Arduino library for PAM8803 audio amplifier module  (Read 7645 times)
0 Members and 1 Guest are viewing this topic.
Argentina
Offline Offline
Full Member
***
Karma: 5
Posts: 160
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

 PAM8803 audio amplifier module:



Code:
/*
 Example: Control a PAM8803 amplifier module from an Arduino board.
 Created by Diego J. Arevalo, November 20, 2012.
 Released into the public domain.
 */

#include <Pam8803.h>

int ampVolumeDownPin = 8; // The pin number of the volume down pin.
int ampVolumeUpPin = 9; // The pin number of the volume up pin.
int ampResetPin = 10; // The pin number of the reset pin.

/*
Create an instance of the Pam8803 class.
 1st parameter: Reset pin number.
 2nd parameter: Volume Up pin number.
 3rd parameter: Volume Down pin number.
 */

Pam8803 pam8803(ampResetPin, ampVolumeUpPin, ampVolumeDownPin);

void setup() {
  //Initializes the amplifier module.
  pam8803.reset();
  //Set amplifier volumen in half output power.
  pam8803.setVolume(50);
}

void loop() {
};

Documentation:
http://www.poweranalog.com/pdf/PAM8803.pdf

Unzip Pam8803.zip into your library folder and that's all. There is a .volumeUp, .volumenDown that raise 1 level or decrement in 1 level the volume. You will have a getVolume to get the current level and setVolumen which accepts from 0 to 100 in percentage. Check Pam8803.h for more details or just ask me. Hope this helps.

PD: Thanks robtillaart for your suggestions. They were considered and implemented.

* Pam8803.zip (4.65 KB - downloaded 60 times.)
« Last Edit: November 20, 2012, 10:33:59 am by the-rebel-agent » Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 223
Posts: 13910
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


Thanks for sharing!

Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 223
Posts: 13910
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


Simpler implementation?
- getting rid of the if

Code:
int Pam8803::setVolumeInHalf()
{
  while (_gainSetting <= MAX_GAIN_SETTING/2) volumeUp();
  while (_gainSetting >= MAX_GAIN_SETTING/2) volumeDown();
  return MAX_GAIN_SETTING/2;
}

why not a generic percentage function, ?

Code:
int Pam8803::setVolumePercentage(int percentage)
{
  int newGain = (MAX_GAIN_SETTING * percentage)/100;
  newGain = constrain(newGain , MIN_GAIN_SETTING, MAX_GAIN_SETTING);  // to prevent 125% ;)
  while (_gainSetting <= newGain ) volumeUp();
  while (_gainSetting >= newGain ) volumeDown();
  return newGain;
}

// the setVolumeInHalf() becomes then much simpler
int Pam8803::setVolumeInHalf()
{
  return setVolumePercentage(50);
}

better is to return _gainsetting;  in both cases as that is the inner state representing the volume.

I've thought for a while about this variation which removes (some of) the function calls, and unneeded tests,
Code:
int Pam8803::setVolumeInHalf()
{
  while (_gainSetting <= MAX_GAIN_SETTING/2)
  {
    setGainSetting(_volumeUpPin);
    _gainSetting++;
  }
  while (_gainSetting >= MAX_GAIN_SETTING/2)
  {
    setGainSetting(_volumeDownPin);
    _gainSetting--;
  }
  return _gainSetting;
}

but most of the time is spent in setGainSetting(_volumeDownPin); so the above would not be a significant optimization @ cost of readability.

This line is trouble  delay(30*3.5); == delay(105); but the compiler will optimize that. The real trouble is delay() blocks, and for 0.105 second.
If I want to put the volume to the max it blocks 64 x 0.105 sec == 6.5 seconds!! That is way to long imho, but for now this works.

idea for release 0.2

Imagine a timer interrupt that runs in the background and takes care of setting the volume.
It has the following pseudo code. (not engineered just a concept)
Code:
void TimerISR()
{
  if (_gainSetting < desiredGain)
  {
    digitalWrite(volumePinUp, HIGH);  // This takes care of the pulse run it with pen and paper
    digitalWrite(volumePinUp, LOW); 
    rescheduleISR(105);
    return;
  }
  if (_gainSetting > desiredGain)
  {
    digitalWrite(volumePinDown, HIGH); 
    digitalWrite(volumePinDown, LOW); 
    rescheduleISR(105);
    return;
  }
 // reached the desired gain => pull pins HIGH and stop timer interrupt
  digitalWrite(volumePinUp, HIGH); 
  digitalWrite(volumePinDown, HIGH); 
  stopISR();
}

The other functions only need to set the (volatile!!) desiredGain variable and start the ISR() routine [if not started] to adjust the volume in the background.

this gives the lib + responsiveness + allows the arduino to do other things simultaneously like leds and servo's and ...
This allows to set the volume to MAX or a certain percentage and change your mind directly and set a new desired gain value. ==> responsiveness

Code:
void setVolume(percentage)
{
  desiredGain = percentage * max;
  if (not started ISR) startISR();
}

Got the idea? (but then again for a next release)
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Argentina
Offline Offline
Full Member
***
Karma: 5
Posts: 160
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Updated the library. Now, I will work in improve the volumeUp and Down speed without modify class protocol.
Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17303
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Nice contribution, thanks.

By the way I did a quick search on ebay for this type module and found a very nice one that already has terminal connectors and jacks and has an internal voltage regulator so you can power it from either batteries or external DC wall wart type power packs. It also has solder pads to make all connections via wires instead of the on board terminals and jacks, so it would still be easy to connect to an arduino. The price is just $5.78 with free shipping. I've bought from this ebay seller many times and have never been disappointed with any of their offerings. So I bought one.
 smiley-wink

 http://www.ebay.com/itm/350604041652?ssPageName=STRK:MEWAX:IT&_trksid=p3984.m1423.l2649

Lefty




« Last Edit: November 20, 2012, 11:24:58 am by retrolefty » Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 223
Posts: 13910
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Updated the library. Now, I will work in improve the volumeUp and Down speed without modify class protocol.

Link to the latest version?
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Argentina
Offline Offline
Full Member
***
Karma: 5
Posts: 160
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Latest lib could be downloaded from the very first post once you are logged in. About the PAM8803 retrolefty found, the price is great but the size is huge. In my laser gun project size and room are quite important. The one I bought, even If the a few bucks expensive, only measures 2cm x 2xm and could be powered from 3.3 up to 6 v.
Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17303
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

In the library code:

Code:
void Pam8803::setDigitalVolumeControl(int volumePin){
  digitalWrite(volumePin, LOW);
  delay(30*3.5);
  digitalWrite(volumePin, HIGH);
  delay(30);
};


What is the purpose of the 3.5 value in the delay statement? Would that cause the floating point math library to be pulled into the compiled code? Why not just a delay(105) statement?

Lefty
Logged

Argentina
Offline Offline
Full Member
***
Karma: 5
Posts: 160
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

That's why each volume transition requires VUP or VDOWN pin remais active low for 3.5 clock cycles. I did not floating point lib would be included. I will put 105 instead. Thanks for the suggestion.
Logged

Seattle
Offline Offline
Newbie
*
Karma: 0
Posts: 46
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

This library and module work nicely.

However, I'm using it for a clock like application for late night use, and even at the lowest setting

pam8803.setVolume(0);

it's still far too loud...

It's definitely adjusting by setVolume.  setVolume(100) is very loud, and setVolume(10) is modest, but even setVolume(0) is far louder than what a simple PWM out would be (which is what I was using before).  I had assumed that setVolume(0) would effectively be no volume.

I'm wondering if I'm using it correctly?

I'm using this one:
http://www.ebay.com/itm/2-2W-4O-PAM8803-Class-D-Audio-Amplifier-Board-Simple-/350604041652?pt=US_Home_Audio_Amplifiers_Preamps&hash=item51a1a11db4

--creatrope
Logged

Seattle
Offline Offline
Newbie
*
Karma: 0
Posts: 46
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

on  this module:

http://www.ebay.com/itm/2-2W-4O-PAM8803-Class-D-Audio-Amplifier-Board-Simple-/350604041652?pt=US_Home_Audio_Amplifiers_Preamps&hash=item51a1a11db4

There's no explicit access to the reset RST pin as far as I can see, which pam8803.reset() invokes.  It's apparently pin 15 on the main chip, and it's brought out to a tiny switch on this module instead.

Is the ability to reset critical? If so it could be wired into this module.

-creatrope
Logged

Argentina
Offline Offline
Full Member
***
Karma: 5
Posts: 160
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

That's the problem. reset() method set the vol to level close to 20%. That's why setVolumen(10) is not working the proper way.
Logged

Seattle
Offline Offline
Newbie
*
Karma: 0
Posts: 46
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

That's the problem. reset() method set the vol to level close to 20%. That's why setVolumen(10) is not working the proper way.

Sorry, I'm still not clear.

The volumes are decreasing noticeably as setVolume decreases.

setVolume(100) is quite loud - even distorted.  setVolume(10) is still pretty loud. and setVolume(0) is more amplified than I'd expected.

I've manually wired in the reset pin, however, is my understanding correct that the setVolume() parameter is a percentage of the entire range of the amplifier?

e.g. setVolume(0) is OFF and setVolume(100) is maximum?  It's not a percentage of the previous state or something odd like that is it?

If so, I'd expect setVolume(0) to be (nearly) silent no matter whether I've reset() the module or not? Is setVolume(0) silent for you?
If yours is silent at setVolume(0) then something is off with my unit or setup.


thanks!  --creatrope
Logged

Argentina
Offline Offline
Full Member
***
Karma: 5
Posts: 160
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

As a matter of fact, If you don't reset the module, internal volume won't match internal variable holding the current volume. So, If you decrement the vol without reset or initialize the module, you will suffer of weird behavior like this. I will re-check the source code and will post some recommendations.
Logged

Seattle
Offline Offline
Newbie
*
Karma: 0
Posts: 46
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I was able to get nearly inaudible levels to reasonable amplification by putting a fairly large resistor inline from the speaker pin output to the input of the PAM8803.  It still surprises me that level 0 is so loud, but at least I have a work-around.

I was able to ensure a reset by soldering a pin to connect to the arduino to the reset pin input.

-creatrope
Logged

Pages: [1] 2   Go Up
Jump to: