diff --git a/docs/pwm.rst b/docs/pwm.rst index d7d1297..d178267 100644 --- a/docs/pwm.rst +++ b/docs/pwm.rst @@ -43,10 +43,20 @@ Call before ``PWMAudio::begin()``. When running at high sample rates, it is recommended to increase the ``bufferWords`` to 32 or higher (i.e. ``pwm.setBuffers(4, 32);`` ). +bool setPin(pin_size_t pin) +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Adjusts the pin to connect to the PWM audio output. Only legal before +``PWMAudio::begin()``. + +bool setStereo(bool stereo) +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Adjusts the mono/stereo setting of the PWM audio output. Only legal before +``PWMAudio::begin()``. + bool setFrequency(long sampleRate) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Sets the sample frequency, but does not start the PWM device. Should be called -before ``PWMAudio::begin`` . +Sets the sample frequency, but does not start the PWM device (however if the +device was already running, it will wontinue to run at the new frequency). bool begin()/begin(long sampleRate) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/libraries/AudioBufferManager/src/AudioBufferManager.cpp b/libraries/AudioBufferManager/src/AudioBufferManager.cpp index 255e6f0..a0ef5b6 100644 --- a/libraries/AudioBufferManager/src/AudioBufferManager.cpp +++ b/libraries/AudioBufferManager/src/AudioBufferManager.cpp @@ -69,10 +69,12 @@ AudioBufferManager::AudioBufferManager(size_t bufferCount, size_t bufferWords, i AudioBufferManager::~AudioBufferManager() { if (_running) { + _running = false; for (auto i = 0; i < 2; i++) { dma_channel_set_irq0_enabled(_channelDMA[i], false); - dma_channel_unclaim(_channelDMA[i]); __channelMap[_channelDMA[i]] = nullptr; + dma_channel_abort(_channelDMA[i]); + dma_channel_unclaim(_channelDMA[i]); } __channelCount--; if (!__channelCount) { @@ -237,6 +239,9 @@ void AudioBufferManager::flush() { } void __not_in_flash_func(AudioBufferManager::_dmaIRQ)(int channel) { + if (!_running) { + return; + } if (_isOutput) { if (_active[0] != _silence) { _addToList(&_empty, _active[0]); diff --git a/libraries/PWMAudio/src/PWMAudio.cpp b/libraries/PWMAudio/src/PWMAudio.cpp index 27aa97b..513066a 100644 --- a/libraries/PWMAudio/src/PWMAudio.cpp +++ b/libraries/PWMAudio/src/PWMAudio.cpp @@ -35,6 +35,7 @@ PWMAudio::PWMAudio(pin_size_t pin, bool stereo) { } PWMAudio::~PWMAudio() { + end(); } bool PWMAudio::setBuffers(size_t buffers, size_t bufferWords) { @@ -46,11 +47,48 @@ bool PWMAudio::setBuffers(size_t buffers, size_t bufferWords) { return true; } -bool PWMAudio::setFrequency(int newFreq) { +bool PWMAudio::setPin(pin_size_t pin) { if (_running) { return false; } + _pin = pin; + return true; +} + +bool PWMAudio::setStereo(bool stereo) { + if (_running) { + return false; + } + _stereo = stereo; + return true; +} + +bool PWMAudio::setFrequency(int newFreq) { _freq = newFreq; + + // Figure out the scale factor for PWM values + float fPWM = 65535.0 * _freq; // ideal + + if (fPWM > clock_get_hz(clk_sys)) { + // Need to downscale the range to hit the frequency target + float pwmMax = (float) clock_get_hz(clk_sys) /(float) _freq; + _pwmScale = pwmMax; + fPWM = clock_get_hz(clk_sys); + } else { + _pwmScale = 1 << 16; + } + + pwm_config c = pwm_get_default_config(); + pwm_config_set_clkdiv(&c, clock_get_hz(clk_sys) / fPWM); + pwm_config_set_wrap(&c, _pwmScale); + pwm_init(pwm_gpio_to_slice_num(_pin), &c, _running); + gpio_set_function(_pin, GPIO_FUNC_PWM); + pwm_set_gpio_level(_pin, (0x8000 * _pwmScale) >> 16); + if (_stereo) { + gpio_set_function(_pin + 1, GPIO_FUNC_PWM); + pwm_set_gpio_level(_pin + 1, (0x8000 * _pwmScale) >> 16); + } + return true; } @@ -75,28 +113,7 @@ bool PWMAudio::begin() { _bufferWords = 16; } - // Figure out the scale factor for PWM values - float fPWM = 65535.0 * _freq; // ideal - - if (fPWM > clock_get_hz(clk_sys)) { - // Need to downscale the range to hit the frequency target - float pwmMax = (float) clock_get_hz(clk_sys) /(float) _freq; - _pwmScale = pwmMax; - fPWM = clock_get_hz(clk_sys); - } else { - _pwmScale = 1 << 16; - } - - pwm_config c = pwm_get_default_config(); - pwm_config_set_clkdiv(&c, clock_get_hz(clk_sys) / fPWM); - pwm_config_set_wrap(&c, _pwmScale); - pwm_init(pwm_gpio_to_slice_num(_pin), &c, true); - gpio_set_function(_pin, GPIO_FUNC_PWM); - pwm_set_gpio_level(_pin, (0x8000 * _pwmScale) >> 16); - if (_stereo) { - gpio_set_function(_pin + 1, GPIO_FUNC_PWM); - pwm_set_gpio_level(_pin + 1, (0x8000 * _pwmScale) >> 16); - } + setFrequency(_freq); uint32_t ccAddr = PWM_BASE + PWM_CH0_CC_OFFSET + pwm_gpio_to_slice_num(_pin) * 20; @@ -108,9 +125,15 @@ bool PWMAudio::begin() { } void PWMAudio::end() { - _running = false; - delete _arb; - _arb = nullptr; + if (_running) { + _running = false; + pinMode(_pin, OUTPUT); + if (_stereo) { + pinMode(_pin + 1, OUTPUT); + } + delete _arb; + _arb = nullptr; + } } int PWMAudio::available() { diff --git a/libraries/PWMAudio/src/PWMAudio.h b/libraries/PWMAudio/src/PWMAudio.h index ca457f1..86e61e8 100644 --- a/libraries/PWMAudio/src/PWMAudio.h +++ b/libraries/PWMAudio/src/PWMAudio.h @@ -25,11 +25,13 @@ class PWMAudio : public Stream { public: - PWMAudio(pin_size_t pin, bool stereo = false); + PWMAudio(pin_size_t pin = 0, bool stereo = false); virtual ~PWMAudio(); bool setBuffers(size_t buffers, size_t bufferWords); bool setFrequency(int newFreq); + bool setPin(pin_size_t pin); + bool setStereo(bool stereo = true); bool begin(long sampleRate) { setFrequency(sampleRate);