arduino-audio-tools
PWMAudioESP32.h
1 
2 #pragma once
3 #ifdef ESP32
4 #include "AudioTools/CoreAudio/AudioPWM/PWMAudioBase.h"
5 
6 namespace audio_tools {
7 
8 // forward declaration
9 class PWMDriverESP32;
14 using PWMDriver = PWMDriverESP32;
15 
21 struct PinInfoESP32 {
22  int pwm_channel;
23  int gpio;
24 };
25 
26 typedef PinInfoESP32 PinInfo;
27 
36 class PWMDriverESP32 : public DriverPWMBase {
37  public:
38  // friend void pwm_callback(void*ptr);
39 
40  PWMDriverESP32() { TRACED(); }
41 
42  // Ends the output
43  virtual void end() {
44  TRACED();
45  timer.end();
46  is_timer_started = false;
47  for (int j = 0; j < audio_config.channels; j++) {
48 #if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 0, 0)
49  ledcDetach(pins[j].gpio);
50 #else
51  ledcDetachPin(pins[j].gpio);
52 #endif
53  }
54  deleteBuffer();
55  }
56 
59  virtual void startTimer() {
60  if (!timer) {
61  TRACEI();
62  timer.begin(pwm_callback, effectiveOutputSampleRate(), HZ);
63  actual_timer_frequency = effectiveOutputSampleRate();
64  is_timer_started = true;
65  }
66  }
67 
69  virtual void setupPWM() {
70  // frequency is driven by selected resolution
71  if (audio_config.pwm_frequency == 0){
72  audio_config.pwm_frequency = frequency(audio_config.resolution) * 1000;
73  }
74 
75  pins.resize(audio_config.channels);
76  for (int j = 0; j < audio_config.channels; j++) {
77  pins[j].gpio = audio_config.pins()[j];
78 #if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 0, 0)
79  if (!ledcAttach(pins[j].gpio, audio_config.pwm_frequency,
80  audio_config.resolution)) {
81  LOGE("ledcAttach: %d", pins[j].gpio);
82  }
83 #else
84  int pwmChannel = j;
85  pins[j].pwm_channel = pwmChannel;
86  ledcSetup(pins[j].pwm_channel, audio_config.pwm_frequency,
87  audio_config.resolution);
88  ledcAttachPin(pins[j].gpio, pins[j].pwm_channel);
89 #endif
90  LOGI("setupPWM: pin=%d, channel=%d, frequency=%u, resolution=%d",
91  pins[j].gpio, pins[j].pwm_channel, (unsigned)audio_config.pwm_frequency,
92  audio_config.resolution);
93  }
94  logPins();
95  }
96 
97  void logPins() {
98  for (int j = 0; j < pins.size(); j++) {
99  LOGI("pin%d: %d", j, pins[j].gpio);
100  }
101  }
102 
104  virtual void setupTimer() {
105  timer.setCallbackParameter(this);
106  timer.setIsSave(false);
107 
108  if (actual_timer_frequency != effectiveOutputSampleRate()){
109  timer.end();
110  startTimer();
111  }
112  }
113 
116  virtual void pwmWrite(int channel, int value) {
117 #if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 0, 0)
118  ledcWrite(pins[channel].gpio, value);
119 #else
120  ledcWrite(pins[channel].pwm_channel, value);
121 #endif
122  }
123 
124  protected:
125  Vector<PinInfo> pins;
126  TimerAlarmRepeating timer;
127  uint32_t actual_timer_frequency = 0;
128 
130  int maxUnsignedValue(int resolution) { return pow(2, resolution); }
131 
132  virtual int maxChannels() { return 16; };
133 
135  virtual int maxOutputValue() {
136  return maxUnsignedValue(audio_config.resolution);
137  }
138 
140  float frequency(int resolution) {
141 // On ESP32S2 and S3, the frequncy seems off by a factor of 2
142 #if defined(ESP32S2) || defined(ESP32S3)
143  switch (resolution) {
144  case 7:
145  return 312.5;
146  case 8:
147  return 156.25;
148  case 9:
149  return 78.125;
150  case 10:
151  return 39.0625;
152  case 11:
153  return 19.53125;
154  }
155  return 312.5;
156 #else
157  switch (resolution) {
158  case 8:
159  return 312.5;
160  case 9:
161  return 156.25;
162  case 10:
163  return 78.125;
164  case 11:
165  return 39.0625;
166  }
167  return 312.5;
168 #endif
169  }
170 
172  static void pwm_callback(void *ptr) {
173  PWMDriverESP32 *accessAudioPWM = (PWMDriverESP32 *)ptr;
174  if (accessAudioPWM != nullptr) {
175  accessAudioPWM->playNextFrame();
176  }
177  }
178 };
179 
180 } // namespace audio_tools
181 
182 #endif
Base Class for all PWM drivers.
Definition: PWMAudioBase.h:110
virtual int effectiveOutputSampleRate()
Provides the effective sample rate.
Definition: PWMAudioBase.h:242
void playNextFrame()
writes the next frame to the output pins
Definition: PWMAudioBase.h:270
Audio output to PWM pins for the ESP32. The ESP32 supports up to 16 channels.
Definition: PWMAudioESP32.h:36
float frequency(int resolution)
determiens the PWM frequency based on the requested resolution
Definition: PWMAudioESP32.h:140
virtual void setupPWM()
Setup LED PWM.
Definition: PWMAudioESP32.h:69
virtual int maxOutputValue()
provides the max value for the configured resulution
Definition: PWMAudioESP32.h:135
virtual void startTimer()
Definition: PWMAudioESP32.h:59
int maxUnsignedValue(int resolution)
provides the max value for the indicated resulution
Definition: PWMAudioESP32.h:130
virtual void pwmWrite(int channel, int value)
Definition: PWMAudioESP32.h:116
static void pwm_callback(void *ptr)
timer callback: write the next frame to the pins
Definition: PWMAudioESP32.h:172
virtual void setupTimer()
Setup ESP32 timer with callback.
Definition: PWMAudioESP32.h:104
Common Interface definition for TimerAlarmRepeating.
Definition: AudioTimer.h:25
Vector implementation which provides the most important methods as defined by std::vector....
Definition: Vector.h:21
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AudioConfig.h:872
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition: AudioTypes.h:57
uint8_t resolution
Only used by ESP32: must be between 8 and 11 -> drives pwm frequency // 20,000Hz (not used by ESP32)
Definition: PWMAudioBase.h:48
uint32_t pwm_frequency
additinal info which might not be used by all processors
Definition: PWMAudioBase.h:46
Information for a PIN.
Definition: PWMAudioESP32.h:21