Allow on-the-fly changes to PWMAudio when possible (#1098)

Also fix crash on PWMAudio::end()
This commit is contained in:
Earle F. Philhower, III 2023-01-03 16:02:43 -08:00 committed by GitHub
parent 94abf9d19f
commit 02465b48b3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 70 additions and 30 deletions

View file

@ -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)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -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]);

View file

@ -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() {

View file

@ -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);