Skip to content

Commit 06e97d6

Browse files
committed
Redesign PWM output classes
1 parent 1c9d932 commit 06e97d6

File tree

16 files changed

+647
-465
lines changed

16 files changed

+647
-465
lines changed

examples/streams-generator-pwm/README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ To test the output I am using a piezo electric element
1414
It should also be possible to connect a headphone to the output pins...
1515

1616

17-
On the ESP32 the output is on the Pins GPIO26 and GPIO27
17+
The pins depend on the Processor:
1818

19-
| PIEZO | ESP32
20-
| --------| ---------------
21-
| + | GPIO22 / GPIO23
22-
| - | GND
19+
| PIEZO | ESP32 | AVR | Rpi Pico
20+
| --------| ---------------|-----------------|--------------
21+
| + | GPIO3 / GPIO4 | GPIO3 / GPIO11 | GPIO03/GPIO04
22+
| - | GND | |

examples/streams-generator-pwm/streams-generator-pwm.ino

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ int channels = 2;
1515
uint16_t sample_rate=22000;
1616
SineWaveGenerator<int16_t> sineWave(32000); // subclass of SoundGenerator with max amplitude of 32000
1717
GeneratedSoundStream<int16_t> sound(sineWave, channels); // Stream generated from sine wave
18-
AudioPWM pwm;
18+
PWMAudioStream pwm;
1919
StreamCopy copier(pwm, sound); // copy in to out
2020

2121

@@ -29,12 +29,12 @@ void setup() {
2929
// setup PWM output
3030
auto config = pwm.defaultConfig();
3131
config.sample_rate = sample_rate;
32-
config.resolution = 8; // must be between 8 and 11 -> drives pwm frequency (8 is default)
32+
//config.resolution = 8; // must be between 8 and 11 -> drives pwm frequency (8 is default)
3333
// alternative 1
3434
//config.channels = 2; // not necesarry because 2 is default
35-
//config.start_pin = 22;
35+
//config.start_pin = 3;
3636
// alternative 2: defines pins and channels
37-
config.setPins(pins);
37+
//config.setPins(pins);
3838
pwm.begin(config);
3939
}
4040

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
# Decoding a WAV file
22

3-
In this example we decode a WAV file into RAW output and send it to a PWM pin on a Raspberry Pico
3+
In this example we decode a WAV file into RAW output and send it to a PWM pins (e.g. on a Raspberry Pico)
44

55
MemoryStream -> AudioOutputStream -> WAVDecoder -> AudioPWM
66

7-
For the time beeing we just have an impelemntation of AudioPWM for the Rasperry Pico. But it should be possible to extend in to others as well in the future....
7+
The pins depend on the Processor:
8+
9+
| PIEZO | ESP32 | AVR (Nano) | Rpi Pico
10+
| --------| ---------------|-----------------|--------------
11+
| + | GPIO3 / GPIO4 | GPIO3 / GPIO11 | GPIO03/GPIO04
12+
| - | GND | |
13+

examples/streams-memory_wav-pwm/streams-memory_wav-pwm.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ using namespace audio_tools;
1616

1717
// MemoryStream -> AudioOutputStream -> WAVDecoder -> CsvStream
1818
MemoryStream wav(knghtsng_wav, knghtsng_wav_len);
19-
AudioPWM<int16_t> pwm; // PWM output
19+
PWMAudioStream pwm; // PWM output
2020
WAVDecoder decoder(pwm); // decode wav to pcm and send it to printer
2121
AudioOutputStream out(decoder); // output to decoder
2222
StreamCopy copier(out, wav); // copy in to out

src/AudioConfig.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
*/
1818

1919
#define USE_AUDIO_LOGGING true
20-
#define PRINTF_BUFFER_SIZE 160
20+
#define PRINTF_BUFFER_SIZE 80
2121
#define LOG_LEVEL AudioLogger::Warning
2222
#define LOG_STREAM Serial
2323

@@ -30,18 +30,18 @@
3030
#define LED_BUILTIN 13 // pin number is specific to your esp32 board
3131
#endif
3232

33-
#define DEFAULT_BUFFER_SIZE 1024
33+
#define DEFAULT_BUFFER_SIZE 512
3434
#define DEFAULT_SAMPLE_RATE 44100
3535
#define DEFAULT_CHANNELS 2
3636
#define DEFAULT_BITS_PER_SAMPLE 16
3737
#define I2S_DEFAULT_PORT 0
38-
#define I2S_BUFFER_SIZE 1024
38+
#define I2S_BUFFER_SIZE 512
3939
#define I2S_BUFFER_COUNT 5
4040
#define A2DP_BUFFER_SIZE 4096
4141
#define A2DP_BUFFER_COUNT 8
4242
#define DEFAUT_ADC_PIN 34
43-
#define PWM_BUFFER_SIZE 1024
44-
#define PWM_BUFFERS 4
43+
#define PWM_BUFFER_SIZE 512
44+
#define PWM_BUFFERS 2
4545

4646
/**
4747
* -------------------------------------------------------------------------

src/AudioPWM/PWMAudioStreamAVR.h

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
2+
#pragma once
3+
#include "AudioConfig.h"
4+
#ifdef __AVR__
5+
#include "AudioPWM/PWMAudioStreamBase.h"
6+
7+
namespace audio_tools {
8+
9+
class PWMAudioStreamAVR;
10+
typedef PWMAudioStreamAVR PWMAudioStream;
11+
static PWMAudioStreamAVR *accessAudioPWM = nullptr;
12+
13+
14+
/**
15+
* @brief Experimental: Audio output to PWM pins for the AVR. The AVR supports only up to 2 channels.
16+
* @author Phil Schatzmann
17+
* @copyright GPLv3
18+
*/
19+
20+
class PWMAudioStreamAVR : public PWMAudioStreamBase {
21+
friend void defaultPWMAudioOutputCallback();
22+
23+
public:
24+
25+
PWMAudioStreamAVR(){
26+
LOGD("PWMAudioStreamAVR");
27+
accessAudioPWM = this;
28+
}
29+
30+
virtual int maxChannels() {
31+
return 2;
32+
};
33+
34+
// Ends the output
35+
virtual void end(){
36+
LOGD(__FUNCTION__);
37+
noInterrupts();
38+
// stop timer callback
39+
TCCR1B = 0;
40+
// stop pwm timers
41+
TCCR2A = 0;
42+
interrupts(); // enable all interrupts
43+
44+
data_write_started = false;
45+
}
46+
47+
/// Setup AVR timer with callback
48+
void setupTimer() {
49+
LOGD(__FUNCTION__);
50+
// CPU Frequency 16 MHz
51+
// prescaler 1, 256 or 1024 => no prescaling
52+
uint32_t steps = F_CPU / 8 / audio_config.sample_rate; // e.g. (16000000/8/44100=>45)
53+
if (steps>65535){
54+
LOGE("requested sample rate not supported: %d - we use %d",audio_config.sample_rate, F_CPU / 65536);
55+
steps = 65535;
56+
} else {
57+
LOGD("compare match register set to %d",steps);
58+
}
59+
60+
// setup timer intterupt
61+
noInterrupts();
62+
TCCR1B = 0;
63+
//compare match register
64+
OCR1A = steps;
65+
TCCR1B |= (1 << WGM12); // CTC mode
66+
//TCCR1B |= (1 << CS10); // prescaler 1
67+
TCCR1B |= (1 << CS11); // prescaler 8
68+
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
69+
interrupts(); // enable all interrupts
70+
}
71+
72+
/// Setup LED PWM
73+
void setupPWM(){
74+
LOGD(__FUNCTION__);
75+
if (audio_config.channels>2) {
76+
LOGW("Max 2 channels supported - you requested %d", audio_config.channels);
77+
audio_config.channels = 2;
78+
}
79+
80+
for (int j=0;j<audio_config.channels;j++){
81+
LOGD("Processing channel %d", j);
82+
setupPin(pins[j]);
83+
}
84+
}
85+
86+
87+
// Timer 0 is used by Arduino!
88+
// Timer 1 is used to drive output in sample_rate
89+
// => only Timer2 is available for PWM
90+
void setupPin(int pin){
91+
switch(pin){
92+
case 3:case 11:
93+
// switch PWM frequency to 62500.00 Hz
94+
TCCR2B = TCCR2B & B11111000 | B00000001;
95+
LOGI("PWM Frequency changed for D3 and D11");
96+
break;
97+
98+
default:
99+
LOGE("PWM Unsupported pin: %d", pin);
100+
break;
101+
102+
}
103+
pinMode(pin, OUTPUT);
104+
}
105+
106+
virtual void pwmWrite(int channel, int value){
107+
analogWrite(pins[channel], value);
108+
}
109+
110+
void logConfig(){
111+
audio_config.logConfig();
112+
LOGI("pwm freq: %f khz", 62.5);
113+
if (audio_config.channels==1) {
114+
LOGI("output pin: %d", pins[0]);
115+
} else {
116+
LOGI("output pins: %d / %d", pins[0],pins[1]);
117+
}
118+
}
119+
120+
protected:
121+
int pins[2] = {3, 11};
122+
123+
};
124+
125+
/// separate method that can be defined as friend so that we can access protected information
126+
void defaultPWMAudioOutputCallback(){
127+
if (accessAudioPWM!=nullptr && accessAudioPWM->data_write_started){
128+
accessAudioPWM->playNextFrame();
129+
}
130+
}
131+
132+
/// timer callback: write the next frame to the pins
133+
ISR(TIMER1_COMPA_vect){
134+
defaultPWMAudioOutputCallback();
135+
}
136+
137+
} // Namespace
138+
139+
140+
#endif
141+

0 commit comments

Comments
 (0)