Go Down

Topic: Arduino library for PAM8803 audio amplifier module (Read 7 times) previous topic - next topic

the-rebel-agent

Nov 18, 2012, 04:34 pm Last Edit: Nov 20, 2012, 04:33 pm by the-rebel-agent Reason: 1
PAM8803 audio amplifier module:



Code: [Select]
/*
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.

robtillaart

Rob Tillaart

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

robtillaart


Simpler implementation?
- getting rid of the if

Code: [Select]

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: [Select]

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: [Select]

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: [Select]

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: [Select]

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


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

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

the-rebel-agent

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

retrolefty

#4
Nov 20, 2012, 05:23 pm Last Edit: Nov 20, 2012, 05:24 pm by retrolefty Reason: 1
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.
;)

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

Lefty





Go Up