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"
15 class PWMDriverRP2040;
20 using PWMDriver = PWMDriverRP2040;
27 struct PicoChannelOut {
44 class PWMDriverRP2040 :
public DriverPWMBase {
48 PWMDriverRP2040() { TRACED(); }
55 is_timer_started =
false;
56 for (
auto pin : pins) {
58 pwm_set_enabled(pin.slice,
false);
65 Vector<PicoChannelOut> pins;
66 TimerAlarmRepeating ticker;
68 virtual void startTimer()
override {
70 ticker.setCallbackParameter(
this);
71 ticker.begin(defaultPWMAudioOutputCallbackPico, audio_config.sample_rate, HZ);
73 is_timer_started =
true;
77 void setupPWM()
override {
79 pwm_config cfg = setupPWMConfig();
83 pins.resize(audio_config.channels, empty);
86 for (
int j = 0; j < audio_config.channels; 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;
95 setupPWMPin(cfg, pins[channel]);
100 pwm_config setupPWMConfig() {
102 if (audio_config.pwm_frequency == 0){
103 audio_config.pwm_frequency = PWM_AUDIO_FREQUENCY;
106 pwm_config pico_pwm_config = pwm_get_default_config();
107 int wrap_value = maxOutputValue();
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);
119 pwm_config_set_wrap(&pico_pwm_config, wrap_value);
120 return pico_pwm_config;
124 void setupPWMPin(pwm_config &cfg, PicoChannelOut &pinInfo) {
125 LOGD(
"%s for gpio %d", LOG_METHOD, pinInfo.gpio);
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);
134 pwm_set_chan_level(pinInfo.slice, pinInfo.channel, 0);
137 void setupTimer()
override {}
140 virtual int maxChannels()
override {
return 16; };
143 virtual int maxOutputValue()
override {
144 return std::pow(audio_config.resolution, 2) - 1;
149 void pwmWrite(
int audioChannel,
int value)
override {
150 pwm_set_chan_level(pins[audioChannel].slice, pins[audioChannel].channel,
155 static void defaultPWMAudioOutputCallbackPico(
void *ptr) {
156 PWMDriverRP2040 *
self = (PWMDriverRP2040 *)ptr;
157 self->playNextFrame();