arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
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
12namespace audio_tools {
13
14// forwrd declaratioin of callback
15class PWMDriverRP2040;
20using PWMDriver = PWMDriverRP2040;
21
27struct PicoChannelOut {
28 int gpio = -1;
29 int audioChannel;
30 uint slice; // pico pwm slice
31 uint channel; // pico pwm channel
32};
33
44class 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 AudioCodecsBase.h:10