arduino-audio-tools
PWMAudioAVR.h
1 
2 #pragma once
3 #include "AudioConfig.h"
4 #if defined(USE_PWM) && defined(__AVR__)
5 #include "AudioPWM/PWMAudioBase.h"
6 #include "AudioTimer/AudioTimerAVR.h"
7 
8 namespace audio_tools {
9 
10 class PWMDriverAVR;
11 using PWMDriver = PWMDriverAVR;
12 static PWMDriverAVR *accessAudioPWM = nullptr;
13 
22 class PWMDriverAVR : public DriverPWMBase {
23  friend void defaultPWMAudioOutputCallback();
24 
25  public:
26  PWMDriverAVR() {
27  LOGD("PWMDriverAVR");
28  accessAudioPWM = this;
29  }
30 
31  virtual int maxChannels() { return 2; };
32 
33  // Ends the output
34  virtual void end() {
35  TRACED();
36  noInterrupts();
37  // stop timer callback
38  TCCR1B = 0;
39  // stop pwm timers
40  TCCR2A = 0;
41  interrupts(); // enable all interrupts
42 
43  is_timer_started = false;
44  deleteBuffer();
45  }
46 
47  void setupTimer() {
48  TRACED();
49  // CPU Frequency 16 MHz
50  // prescaler 1, 256 or 1024 => no prescaling
51  uint32_t steps =
52  F_CPU / 8 / audio_config.sample_rate; // e.g. (16000000/8/44100=>45)
53  if (steps > 65535) {
54  LOGE("requested sample rate not supported: %d - we use %d",
55  audio_config.sample_rate, F_CPU / 65536);
56  steps = 65535;
57  } else {
58  LOGD("compare match register set to %d", steps);
59  }
60 
61  // setup timer intterupt
62  noInterrupts();
63  TCCR1B = 0;
64  // compare match register
65  OCR1A = steps;
66  TCCR1B |= (1 << WGM12); // CTC mode
67  // TCCR1B |= (1 << CS10); // prescaler 1
68  TCCR1B |= (1 << CS11); // prescaler 8
69  TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
70  interrupts(); // enable all interrupts
71  }
72 
74  void setupPWM() {
75  TRACED();
76  if (audio_config.channels > 2) {
77  LOGW("Max 2 channels supported - you requested %d",
78  audio_config.channels);
79  audio_config.channels = 2;
80  }
81 
82  for (int j = 0; j < audio_config.channels; j++) {
83  LOGD("Processing channel %d", j);
84  setupPin(pins[j]);
85  }
86  }
87 
88  void startTimer() {}
89 
90  // Timer 0 is used by Arduino!
91  // Timer 1 is used to drive output in sample_rate
92  // => only Timer2 is available for PWM
93  void setupPin(int pin) {
94  switch (pin) {
95  case 3:
96  case 11:
97  // switch PWM frequency to 62500.00 Hz
98  TCCR2B = TCCR2B & B11111000 | B00000001;
99  LOGI("PWM Frequency changed for D3 and D11");
100  break;
101 
102  default:
103  LOGE("PWM Unsupported pin: %d", pin);
104  break;
105  }
106  pinMode(pin, OUTPUT);
107  }
108 
109  virtual void pwmWrite(int channel, int value) {
110  analogWrite(pins[channel], value);
111  }
112 
113  void logConfig() {
114  audio_config.logConfig();
115  LOGI("pwm freq: %f khz", 62.5);
116  if (audio_config.channels == 1) {
117  LOGI("output pin: %d", pins[0]);
118  } else {
119  LOGI("output pins: %d / %d", pins[0], pins[1]);
120  }
121  }
122 
123  protected:
124  int pins[2] = {3, 11};
125 
126  virtual int maxOutputValue() { return 255; }
127 };
128 
132  if (accessAudioPWM != nullptr && accessAudioPWM->is_timer_started) {
133  accessAudioPWM->playNextFrame();
134  }
135 }
136 
138 ISR(TIMER1_COMPA_vect) {
140  TimerAlarmRepeatingDriverAVR::tickerCallback();
141 }
142 
143 } // namespace audio_tools
144 
145 #endif
Base Class for all PWM drivers.
Definition: PWMAudioBase.h:105
void playNextFrame()
writes the next frame to the output pins
Definition: PWMAudioBase.h:248
Experimental: Audio output to PWM pins for the AVR. The AVR supports only up to 2 channels.
Definition: PWMAudioAVR.h:22
void setupPWM()
Setup LED PWM.
Definition: PWMAudioAVR.h:74
friend void defaultPWMAudioOutputCallback()
Definition: PWMAudioAVR.h:131
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AnalogAudio.h:10
void defaultPWMAudioOutputCallback()
Definition: PWMAudioAVR.h:131
ISR(TIMER1_COMPA_vect)
timer callback: write the next frame to the pins
Definition: PWMAudioAVR.h:138
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition: AudioTypes.h:53
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition: AudioTypes.h:55