PDM library (Pulse Density Modulation)

Dependents:   mbed-shiny

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SoftPdmOut.cpp Source File

SoftPdmOut.cpp

00001 /******************************************************************************************************/
00002 /*  Pulse Density Modulation driver.                                                                  */
00003 /*  FILE: PDM.cpp                                                                                     */
00004 /*                                                                                                    */
00005 /*  Code based on an article and source code released by Ken Wada from Aurium Technologies Inc.       */
00006 /*  http://www.embedded.com/electronics-blogs/embedded-round-table/4414405/Pulse-density-modulation   */
00007 /*                                                                                                    */
00008 /******************************************************************************************************/
00009 
00010 #include "SoftPdmOut.h"
00011 
00012 SoftPdmOut::SoftPdmOut(PinName pdm, uint32_t PulseWidth, uint32_t Dmax, float StartLevel) : _pdm(pdm), _PulseWidth(PulseWidth), _Dmax(Dmax)
00013 {
00014     _pdm = 0;
00015     _running = 0;
00016     if(StartLevel >= 0.0f && StartLevel <= 1.0f) _Level = (uint32_t)(StartLevel * (float)_Dmax);
00017     else _Level = 0;
00018     start();
00019 }
00020 
00021 void SoftPdmOut::start(void)
00022 {
00023     if (!_running) {
00024         // enable ONLY if state has changed
00025         _accumulator  = 0;                                              // zero out the error accumulator
00026         _running      = 1;                                              // NOW ... enable the controller
00027         _pdmTicker.attach_us(this,&SoftPdmOut::pdmTick,_PulseWidth);    // Start the PDM.
00028         wait_ms(5);                                                     // Wait for output to settle
00029     }
00030 }
00031 
00032 void SoftPdmOut::stop(bool idleState)
00033 {
00034     if (_running) {
00035         // disable ONLY if state has changed
00036         _running      = 0;          // disable the controller
00037         _pdmTicker.detach();        // Stop the PDM.
00038         _pdm = idleState;           // Set output (default = 0)
00039     }
00040 }
00041 
00042 void SoftPdmOut::PulseWidth(uint32_t level)
00043 {
00044     if(!_running)                // When pdm is inactive, only change the pulse width and don't start the pdm
00045         _PulseWidth = level;
00046     else
00047     {
00048         stop();
00049         _PulseWidth = level;
00050         start();
00051     }
00052 }
00053 
00054 uint32_t SoftPdmOut::getPulseWidth(void)
00055 {
00056     return _PulseWidth;
00057 }
00058 
00059 void SoftPdmOut::Dmax(uint32_t level)
00060 {
00061     _Level = (uint32_t)((float)_Level * ((float)level / (float)_Dmax));  // Rescale level : level = level * (new level / current DMAX)
00062     _Dmax = level;
00063     _accumulator  = 0;                  // zero out the error accumulator
00064 }
00065 
00066 uint32_t SoftPdmOut::getDmax(void)
00067 {
00068     return _Dmax;
00069 }
00070 
00071 void SoftPdmOut::write(float level)
00072 {
00073     // Only change the level when the desired level is within range
00074     if(level <= 0.0f) _Level = 0;
00075     else if(level >= 1.0f) _Level = _Dmax;
00076     else if (level > 0.0f && level < 1.0f) _Level = (uint32_t)(level * (float)_Dmax);
00077 }
00078 
00079 float SoftPdmOut::read(void)
00080 {
00081     return ((float)_Level / (float)_Dmax);
00082 }
00083 
00084 SoftPdmOut::operator float()
00085 {
00086     return read();
00087 }
00088 
00089 SoftPdmOut & SoftPdmOut::operator= (float value)
00090 {
00091     write(value);
00092     return(*this);
00093 }
00094 
00095 void SoftPdmOut::pdmTick(void)
00096 {
00097     if(_Level == 0) {
00098         _pdm = 0;
00099         return;
00100     }
00101     if(_Level == _Dmax) {
00102         _pdm = 1;
00103         return;
00104     }
00105     _accumulator += _Level;         // accumulate error integral
00106     if (_accumulator > _Dmax) {
00107         _accumulator -= _Dmax;
00108         _pdm = 1;
00109     } else
00110         _pdm = 0;
00111 }