arduino-audio-tools
PWMAudioRP2040.h
1 
2 #pragma once
3 #if defined(RP2040_HOWER)
4 #include "AudioTools/CoreAudio/AudioPWM/PWMAudioBase.h"
5 #include "hardware/adc.h"
6 #include "hardware/clocks.h"
7 #include "hardware/gpio.h"
8 #include "hardware/pwm.h"
9 #include "hardware/structs/clocks.h"
10 #include "pico/time.h"
11 
12 namespace audio_tools {
13 
14 // forwrd declaratioin of callback
15 class PWMDriverRP2040;
20 using PWMDriver = PWMDriverRP2040;
21 
27 struct PicoChannelOut {
28  int gpio = -1;
29  int audioChannel;
30  uint slice; // pico pwm slice
31  uint channel; // pico pwm channel
32 };
33 
44 class PWMDriverRP2040 : public DriverPWMBase {
45  // friend bool defaultPWMAudioOutputCallbackPico(repeating_timer* ptr);
46 
47  public:
48  PWMDriverRP2040() { TRACED(); }
49 
51  void end() override {
52  TRACED();
53  ticker.end(); // it does not hurt to call this even if it has not been
54  // started
55  is_timer_started = false;
56  for (auto pin : pins) {
57  if (pin.gpio != -1) {
58  pwm_set_enabled(pin.slice, false);
59  }
60  }
61  deleteBuffer();
62  }
63 
64  protected:
65  Vector<PicoChannelOut> pins;
66  TimerAlarmRepeating ticker;
67 
68  virtual void startTimer() override {
69  TRACED();
70  ticker.setCallbackParameter(this);
71  ticker.begin(defaultPWMAudioOutputCallbackPico, audio_config.sample_rate, HZ);
72 
73  is_timer_started = true;
74  }
75 
76  // setup pwm config and all pins
77  void setupPWM() override {
78  TRACED();
79  pwm_config cfg = setupPWMConfig();
80 
81  // initialize empty pins
82  PicoChannelOut empty;
83  pins.resize(audio_config.channels, empty);
84 
85  // setup pin values
86  for (int j = 0; j < audio_config.channels; j++) {
87  int channel = j;
88  int gpio = audio_config.pins()[j];
89  LOGI("PWM pin %d", gpio);
90  pins[channel].slice = pwm_gpio_to_slice_num(gpio);
91  pins[channel].channel = pwm_gpio_to_channel(gpio);
92  pins[channel].audioChannel = j;
93  pins[channel].gpio = gpio;
94 
95  setupPWMPin(cfg, pins[channel]);
96  }
97  }
98 
99  // defines the pwm_config which will be used to drive the pins
100  pwm_config setupPWMConfig() {
101  TRACED();
102  if (audio_config.pwm_frequency == 0){
103  audio_config.pwm_frequency = PWM_AUDIO_FREQUENCY;
104  }
105  // setup pwm frequency
106  pwm_config pico_pwm_config = pwm_get_default_config();
107  int wrap_value = maxOutputValue(); // amplitude of square wave (pwm values
108  // -amplitude to amplitude) for one byte
109  float pwmClockDivider = static_cast<float>(clock_get_hz(clk_sys)) /
110  (audio_config.pwm_frequency * wrap_value);
111  float clock_speed = static_cast<float>(clock_get_hz(clk_sys));
112  LOGI("->wrap_value = %d", wrap_value);
113  LOGI("->max clock speed = %f", clock_speed);
114  LOGI("->divider = %f", pwmClockDivider);
115  LOGI("->clock speed = %f", clock_speed / pwmClockDivider);
116  pwm_config_set_clkdiv(&pico_pwm_config, pwmClockDivider);
117  pwm_config_set_clkdiv_mode(&pico_pwm_config, PWM_DIV_FREE_RUNNING);
118  // pwm_config_set_phase_correct(&pico_pwm_config, false);
119  pwm_config_set_wrap(&pico_pwm_config, wrap_value);
120  return pico_pwm_config;
121  }
122 
123  // set up pwm
124  void setupPWMPin(pwm_config &cfg, PicoChannelOut &pinInfo) {
125  LOGD("%s for gpio %d", LOG_METHOD, pinInfo.gpio);
126  // setup pwm pin
127  int gpio = pinInfo.gpio;
128  gpio_set_function(gpio, GPIO_FUNC_PWM);
129  pinInfo.slice = pwm_gpio_to_slice_num(gpio);
130  pinInfo.channel = pwm_gpio_to_channel(gpio);
131  pwm_init(pinInfo.slice, &cfg, true);
132 
133  // set initial output value
134  pwm_set_chan_level(pinInfo.slice, pinInfo.channel, 0);
135  }
136 
137  void setupTimer() override {}
138 
140  virtual int maxChannels() override { return 16; };
141 
143  virtual int maxOutputValue() override {
144  return std::pow(audio_config.resolution, 2) - 1;
145  }
146 
149  void pwmWrite(int audioChannel, int value) override {
150  pwm_set_chan_level(pins[audioChannel].slice, pins[audioChannel].channel,
151  value);
152  }
153 
154  // timed output executed at the sampleRate
155  static void defaultPWMAudioOutputCallbackPico(void *ptr) {
156  PWMDriverRP2040 *self = (PWMDriverRP2040 *)ptr;
157  self->playNextFrame();
158  }
159 };
160 
161 } // namespace audio_tools
162 
163 #endif
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AudioConfig.h:872