arduino-audio-tools
PWMAudioSTM32.h
1 
2 #pragma once
3 #if defined(STM32)
4 #include "AudioPWM/PWMAudioBase.h"
5 #include "AudioTimer/AudioTimer.h"
6 
7 namespace audio_tools {
8 
9 // forward declaration
10 class PWMDriverSTM32;
15 using PWMDriver = PWMDriverSTM32;
16 
25 class PWMDriverSTM32 : public DriverPWMBase {
27  struct PWMPin {
28  HardwareTimer *p_timer;
29  int channel;
30  int max_value;
31  bool active = false;
32  int pin;
33  int pwm_frequency;
34 
35  PWMPin() = default;
36 
37  PWMPin(HardwareTimer *p_timer, int channel, int pin, int maxValue,
38  int pwmFrequency = 30000) {
39  this->p_timer = p_timer;
40  this->channel = channel;
41  this->pin = pin;
42  this->max_value = maxValue;
43  this->pwm_frequency = pwmFrequency;
44  }
45 
46  void begin() {
47  TRACEI();
48  p_timer->setPWM(channel, pin, pwm_frequency,
49  50); // 30k Hertz, 50% dutycycle
50  active = true;
51  }
52 
53  void setRate(int rate) {
54  if (active) {
55  uint16_t sample = 100.0 * rate / max_value;
56  p_timer->setCaptureCompare(channel, sample,
57  PERCENT_COMPARE_FORMAT); // 50%
58  }
59  }
60  };
61 
62  class PWM {
63  public:
64  PWM() = default;
65 
66  void begin(HardwareTimer *pwm_timer, int pwm_frequency, int maxValue) {
67  this->p_timer = pwm_timer;
68  this->pwm_frequency = pwm_frequency;
69  this->max_value = maxValue;
70  }
71 
72  void end() {
73  p_timer->pause();
74  deleteBuffer();
75  }
76 
77  bool addPin(int pin) {
78  LOGI("addPin: %d", pin);
79  TIM_TypeDef *p_instance = (TIM_TypeDef *)pinmap_peripheral(
80  digitalPinToPinName(pin), PinMap_PWM);
81  channel = STM_PIN_CHANNEL(
82  pinmap_function(digitalPinToPinName(pin), PinMap_PWM));
83  PWMPin pwm_pin{p_timer, channel, pin, max_value, pwm_frequency};
84  pins.push_back(pwm_pin);
85  // make sure that all pins use the same timer !
86  if (p_timer->getHandle()->Instance != p_instance) {
87  LOGE("Invalid pin %d with timer %s for timer %s", pin,
88  getTimerStr(p_instance),
89  getTimerStr(p_timer->getHandle()->Instance));
90  return false;
91  }
92  LOGI("Using Timer %s for PWM", getTimerStr(p_instance));
93  pins[pins.size() - 1].begin();
94  return true;
95  }
96 
97  void setRate(int idx, int rate) {
98  if (idx < pins.size()) {
99  pins[idx].setRate(rate);
100  } else {
101  LOGE("Invalid index: %d", idx);
102  }
103  }
104 
105  protected:
106  HardwareTimer *p_timer;
108  int channel;
109  int max_value;
110  int pwm_frequency;
111 
112  const char *getTimerStr(TIM_TypeDef *inst) {
113  if (inst == TIM1)
114  return "TIM1";
115  else if (inst == TIM2)
116  return "TIM2";
117  else if (inst == TIM3)
118  return "TIM3";
119  else if (inst == TIM4)
120  return "TIM4";
121  else if (inst == TIM5)
122  return "TIM5";
123  return "N/A";
124  }
125  };
126 
127  public:
128  PWMDriverSTM32() {
129  TRACED();
130  ticker.setTimer(PWM_FREQ_TIMER_NO);
131  }
132 
133  // Ends the output
134  virtual void end() override {
135  TRACED();
136  ticker.end(); // it does not hurt to call this even if it has not been
137  // started
138  pwm.end(); // stop pwm timer
139  is_timer_started = false;
140  if (buffer != nullptr) {
141  delete buffer;
142  buffer = nullptr;
143  }
144  }
145 
147  void setPWMTimer(HardwareTimer &t) { p_pwm_timer = &t; }
148 
149  protected:
150  TimerAlarmRepeating ticker; // calls a callback repeatedly with a timeout
151  HardwareTimer *p_pwm_timer = nullptr;
152  PWM pwm;
153  int64_t max_value;
154 
157  virtual void startTimer() override {
158  if (!is_timer_started) {
159  TRACED();
160  uint32_t time = AudioTime::toTimeUs(audio_config.sample_rate);
161  ticker.setCallbackParameter(this);
162  ticker.begin(defaultPWMAudioOutputCallback, time, US);
163  is_timer_started = true;
164  }
165  }
166 
168  virtual void setupPWM() {
169  TRACED();
170 
171  // setup pwm timer
172  if (p_pwm_timer == nullptr) {
173  p_pwm_timer = new HardwareTimer(PWM_DEFAULT_TIMER);
174  }
175 
176  // setup pins for output
177  int ch = 0;
178  pwm.begin(p_pwm_timer, audio_config.pwm_frequency, maxOutputValue());
179  for (auto gpio : audio_config.pins()) {
180  LOGD("Processing channel %d -> pin: %d", ch++, gpio);
181  pwm.addPin(gpio);
182  }
183  }
184 
185  virtual void setupTimer() {}
186 
188  virtual int maxChannels() { return 4; };
189 
191  virtual int maxOutputValue() { return 10000; }
192 
195  virtual void pwmWrite(int channel, int value) {
196  // analogWrite(pins[channel], value);
197  pwm.setRate(channel, value);
198  }
199 
201  static void defaultPWMAudioOutputCallback(void *obj) {
202  PWMDriverSTM32 *accessAudioPWM = (PWMDriverSTM32 *)obj;
203  if (accessAudioPWM != nullptr) {
204  accessAudioPWM->playNextFrame();
205  }
206  }
207 };
208 
209 } // namespace audio_tools
210 
211 #endif
static uint32_t toTimeUs(uint32_t samplingRate, uint8_t limit=10)
converts sampling rate to delay in microseconds (μs)
Definition: AudioTypes.h:259
Base Class for all PWM drivers.
Definition: PWMAudioBase.h:105
void playNextFrame()
writes the next frame to the output pins
Definition: PWMAudioBase.h:248
Audio output to PWM pins for STM32. We use one timer to generate the sample rate and one timer for th...
Definition: PWMAudioSTM32.h:25
virtual void startTimer() override
Definition: PWMAudioSTM32.h:157
void setPWMTimer(HardwareTimer &t)
Defines the timer which is used to generate the PWM signal.
Definition: PWMAudioSTM32.h:147
virtual int maxChannels()
One timer supports max 4 output pins.
Definition: PWMAudioSTM32.h:188
virtual void setupPWM()
Setup PWM Pins.
Definition: PWMAudioSTM32.h:168
virtual int maxOutputValue()
provides the max value for the configured resulution
Definition: PWMAudioSTM32.h:191
virtual void pwmWrite(int channel, int value)
Definition: PWMAudioSTM32.h:195
static void defaultPWMAudioOutputCallback(void *obj)
timer callback: write the next frame to the pins
Definition: PWMAudioSTM32.h:201
Common Interface definition for TimerAlarmRepeating.
Definition: AudioTimer.h:25
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AnalogAudio.h:10
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition: AudioTypes.h:53