Skip to content

Commit 02465b4

Browse files
Allow on-the-fly changes to PWMAudio when possible (#1098)
Also fix crash on PWMAudio::end()
1 parent 94abf9d commit 02465b4

File tree

4 files changed

+66
-26
lines changed

4 files changed

+66
-26
lines changed

docs/pwm.rst

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,20 @@ Call before ``PWMAudio::begin()``.
4343
When running at high sample rates, it is recommended to increase the
4444
``bufferWords`` to 32 or higher (i.e. ``pwm.setBuffers(4, 32);`` ).
4545

46+
bool setPin(pin_size_t pin)
47+
~~~~~~~~~~~~~~~~~~~~~~~~~~~
48+
Adjusts the pin to connect to the PWM audio output. Only legal before
49+
``PWMAudio::begin()``.
50+
51+
bool setStereo(bool stereo)
52+
~~~~~~~~~~~~~~~~~~~~~~~~~~~
53+
Adjusts the mono/stereo setting of the PWM audio output. Only legal before
54+
``PWMAudio::begin()``.
55+
4656
bool setFrequency(long sampleRate)
4757
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
48-
Sets the sample frequency, but does not start the PWM device. Should be called
49-
before ``PWMAudio::begin`` .
58+
Sets the sample frequency, but does not start the PWM device (however if the
59+
device was already running, it will wontinue to run at the new frequency).
5060

5161
bool begin()/begin(long sampleRate)
5262
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

libraries/AudioBufferManager/src/AudioBufferManager.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,12 @@ AudioBufferManager::AudioBufferManager(size_t bufferCount, size_t bufferWords, i
6969

7070
AudioBufferManager::~AudioBufferManager() {
7171
if (_running) {
72+
_running = false;
7273
for (auto i = 0; i < 2; i++) {
7374
dma_channel_set_irq0_enabled(_channelDMA[i], false);
74-
dma_channel_unclaim(_channelDMA[i]);
7575
__channelMap[_channelDMA[i]] = nullptr;
76+
dma_channel_abort(_channelDMA[i]);
77+
dma_channel_unclaim(_channelDMA[i]);
7678
}
7779
__channelCount--;
7880
if (!__channelCount) {
@@ -237,6 +239,9 @@ void AudioBufferManager::flush() {
237239
}
238240

239241
void __not_in_flash_func(AudioBufferManager::_dmaIRQ)(int channel) {
242+
if (!_running) {
243+
return;
244+
}
240245
if (_isOutput) {
241246
if (_active[0] != _silence) {
242247
_addToList(&_empty, _active[0]);

libraries/PWMAudio/src/PWMAudio.cpp

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ PWMAudio::PWMAudio(pin_size_t pin, bool stereo) {
3535
}
3636

3737
PWMAudio::~PWMAudio() {
38+
end();
3839
}
3940

4041
bool PWMAudio::setBuffers(size_t buffers, size_t bufferWords) {
@@ -46,34 +47,24 @@ bool PWMAudio::setBuffers(size_t buffers, size_t bufferWords) {
4647
return true;
4748
}
4849

49-
bool PWMAudio::setFrequency(int newFreq) {
50+
bool PWMAudio::setPin(pin_size_t pin) {
5051
if (_running) {
5152
return false;
5253
}
53-
_freq = newFreq;
54+
_pin = pin;
5455
return true;
5556
}
5657

57-
void PWMAudio::onTransmit(void(*fn)(void)) {
58-
_cb = fn;
58+
bool PWMAudio::setStereo(bool stereo) {
5959
if (_running) {
60-
_arb->setCallback(_cb);
61-
}
62-
}
63-
64-
bool PWMAudio::begin() {
65-
if (_stereo && (_pin & 1)) {
66-
// Illegal, need to have consecutive pins on the same PWM slice
67-
Serial.printf("ERROR: PWMAudio stereo mode requires pin be even\n");
6860
return false;
6961
}
62+
_stereo = stereo;
63+
return true;
64+
}
7065

71-
_running = true;
72-
_wasHolding = false;
73-
74-
if (!_bufferWords) {
75-
_bufferWords = 16;
76-
}
66+
bool PWMAudio::setFrequency(int newFreq) {
67+
_freq = newFreq;
7768

7869
// Figure out the scale factor for PWM values
7970
float fPWM = 65535.0 * _freq; // ideal
@@ -90,14 +81,40 @@ bool PWMAudio::begin() {
9081
pwm_config c = pwm_get_default_config();
9182
pwm_config_set_clkdiv(&c, clock_get_hz(clk_sys) / fPWM);
9283
pwm_config_set_wrap(&c, _pwmScale);
93-
pwm_init(pwm_gpio_to_slice_num(_pin), &c, true);
84+
pwm_init(pwm_gpio_to_slice_num(_pin), &c, _running);
9485
gpio_set_function(_pin, GPIO_FUNC_PWM);
9586
pwm_set_gpio_level(_pin, (0x8000 * _pwmScale) >> 16);
9687
if (_stereo) {
9788
gpio_set_function(_pin + 1, GPIO_FUNC_PWM);
9889
pwm_set_gpio_level(_pin + 1, (0x8000 * _pwmScale) >> 16);
9990
}
10091

92+
return true;
93+
}
94+
95+
void PWMAudio::onTransmit(void(*fn)(void)) {
96+
_cb = fn;
97+
if (_running) {
98+
_arb->setCallback(_cb);
99+
}
100+
}
101+
102+
bool PWMAudio::begin() {
103+
if (_stereo && (_pin & 1)) {
104+
// Illegal, need to have consecutive pins on the same PWM slice
105+
Serial.printf("ERROR: PWMAudio stereo mode requires pin be even\n");
106+
return false;
107+
}
108+
109+
_running = true;
110+
_wasHolding = false;
111+
112+
if (!_bufferWords) {
113+
_bufferWords = 16;
114+
}
115+
116+
setFrequency(_freq);
117+
101118
uint32_t ccAddr = PWM_BASE + PWM_CH0_CC_OFFSET + pwm_gpio_to_slice_num(_pin) * 20;
102119

103120
_arb = new AudioBufferManager(_buffers, _bufferWords, 0x80008000, OUTPUT, DMA_SIZE_32);
@@ -108,9 +125,15 @@ bool PWMAudio::begin() {
108125
}
109126

110127
void PWMAudio::end() {
111-
_running = false;
112-
delete _arb;
113-
_arb = nullptr;
128+
if (_running) {
129+
_running = false;
130+
pinMode(_pin, OUTPUT);
131+
if (_stereo) {
132+
pinMode(_pin + 1, OUTPUT);
133+
}
134+
delete _arb;
135+
_arb = nullptr;
136+
}
114137
}
115138

116139
int PWMAudio::available() {

libraries/PWMAudio/src/PWMAudio.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@
2525

2626
class PWMAudio : public Stream {
2727
public:
28-
PWMAudio(pin_size_t pin, bool stereo = false);
28+
PWMAudio(pin_size_t pin = 0, bool stereo = false);
2929
virtual ~PWMAudio();
3030

3131
bool setBuffers(size_t buffers, size_t bufferWords);
3232
bool setFrequency(int newFreq);
33+
bool setPin(pin_size_t pin);
34+
bool setStereo(bool stereo = true);
3335

3436
bool begin(long sampleRate) {
3537
setFrequency(sampleRate);

0 commit comments

Comments
 (0)