PDM library (Pulse Density Modulation)
Embed:
(wiki syntax)
Show/hide line numbers
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 }
Generated on Wed Jul 20 2022 00:19:18 by 1.7.2