Mozzi  version v1.1.0
sound synthesis library for Arduino
MozziGuts_impl_AVR.hpp
1 /*
2  * MozziGuts.cpp
3  *
4  * Copyright 2012 Tim Barrass.
5  *
6  * This file is part of Mozzi.
7  *
8  * Mozzi by Tim Barrass is licensed under a Creative Commons
9  * Attribution-NonCommercial-ShareAlike 4.0 International License.
10  *
11  */
12 
13 #include "FrequencyTimer2.h"
14 #include "TimerOne.h"
15 
16 #if (F_CPU != 16000000)
17 #warning
18  "Mozzi has been tested with a cpu clock speed of 16MHz on Arduino! Results may vary with other speeds."
19 #endif
20 
21 ////// BEGIN analog input code ////////
22 #define MOZZI_FAST_ANALOG_IMPLEMENTED
23 extern uint8_t analog_reference;
24 
25 #define getADCReading() ADC /* officially (ADCL | (ADCH << 8)) but the compiler works it out */
26 #define channelNumToIndex(channel) channel
27 uint8_t adcPinToChannelNum(uint8_t pin) {
28 #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
29  if (pin >= 54) pin -= 54; // allow for channel or pin numbers
30 #elif defined(__AVR_ATmega32U4__)
31  if (pin >= 18) pin -= 18; // allow for channel or pin numbers
32  pin = analogPinToChannel(pin); // moved from extra #if which was below in Arduino code, and redefined in mozzi_analog.h, with notes
33 #elif defined(__AVR_ATmega1284__)
34  if (pin >= 24) pin -= 24; // allow for channel or pin numbers
35 #else
36  if (pin >= 14) pin -= 14; // allow for channel or pin numbers
37 #endif
38  return pin;
39 }
40 
41 void adcStartConversion(uint8_t channel) {
42 #if defined(__AVR_ATmega32U4__)
43  ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((channel >> 3) & 0x01) << MUX5);
44 #elif defined(ADCSRB) && defined(MUX5)
45  // the MUX5 bit of ADCSRB selects whether we're reading from channels
46  // 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high).
47  ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((channel >> 3) & 0x01) << MUX5);
48 #endif
49 
50 // from wiring_analog.c:
51 // set the analog reference (high two bits of ADMUX) and select the
52 // channel (low 4 bits). this also sets ADLAR (left-adjust result)
53 // to 0 (the default).
54 #if defined(ADMUX)
55 # if defined(TEENSYDUINO) // analog_reference is not part TEENSY 2.0 codebase
56  ADMUX = (1 << REFS0) | (channel & 0x07); // TB2017 this overwrote analog_reference
57 # else
58  ADMUX = (analog_reference << 6) | (channel & 0x07);
59 # endif
60 #endif
61 #if defined(ADCSRA) && defined(ADCL)
62  // start the conversion
63  ADCSRA |= (1 << ADSC);
64 #endif
65 }
66 
67 static void startSecondADCReadOnCurrentChannel() {
68  ADCSRA |= (1 << ADSC); // start a second conversion on the current channel
69 }
70 
71 /*
72 void adcEnableInterrupt(){
73  ADCSRA |= (1 << ADIE);
74 }
75 */
76 
77 ISR(ADC_vect, ISR_BLOCK)
78 {
79  advanceADCStep();
80 }
81 
82 void setupFastAnalogRead(int8_t speed) {
83  if (speed == FAST_ADC){ // divide by 16
84  ADCSRA |= (1 << ADPS2);
85  ADCSRA &= ~(1 << ADPS1);
86  ADCSRA &= ~(1 << ADPS0);
87  } else if(speed == FASTER_ADC){ // divide by 8
88  ADCSRA &= ~(1 << ADPS2);
89  ADCSRA |= (1 << ADPS1);
90  ADCSRA |= (1 << ADPS0);
91  } else if(speed == FASTEST_ADC){ // divide by 4
92  ADCSRA &= ~(1 << ADPS2);
93  ADCSRA |= (1 << ADPS1);
94  ADCSRA &= ~(1 << ADPS0);
95  }
96 }
97 
98 void setupMozziADC(int8_t speed) {
99  ADCSRA |= (1 << ADIE); // adc Enable Interrupt
100  adcDisconnectAllDigitalIns();
101 }
102 
103 ////// END analog input code ////////
104 
105 
106 
107 //// BEGIN AUDIO OUTPUT code ///////
108 /*
109 ATmega328 technical manual, Section 12.7.4:
110 The dual-slope operation [of phase correct pwm] has lower maximum operation
111 frequency than single slope operation. However, due to the symmetric feature
112 of the dual-slope PWM modes, these modes are preferred for motor control
113 applications.
114 Due to the single-slope operation, the operating frequency of the
115 fast PWM mode can be twice as high as the phase correct PWM mode that use
116 dual-slope operation. This high frequency makes the fast PWM mode well suited
117 for power regulation, rectification, and DAC applications. High frequency allows
118 physically small sized external components (coils, capacitors)..
119 
120 DAC, that's us! Fast PWM.
121 
122 PWM frequency tests
123 62500Hz, single 8 or dual 16 bits, bad aliasing
124 125000Hz dual 14 bits, sweet
125 250000Hz dual 12 bits, gritty, if you're gonna have 2 pins, have 14 bits
126 500000Hz dual 10 bits, grittier
127 16384Hz single nearly 9 bits (original mode) not bad for a single pin, but
128 carrier freq noise can be an issue
129 */
130 
131 // to store backups of timer registers so Mozzi can be stopped and pre_mozzi
132 // timer values can be restored
133 static uint8_t pre_mozzi_TCCR1A, pre_mozzi_TCCR1B, pre_mozzi_OCR1A,
134  pre_mozzi_TIMSK1;
135 
136 #if (AUDIO_MODE == HIFI)
137 #if defined(TCCR2A)
138 static uint8_t pre_mozzi_TCCR2A, pre_mozzi_TCCR2B, pre_mozzi_OCR2A,
139  pre_mozzi_TIMSK2;
140 #elif defined(TCCR2)
141 static uint8_t pre_mozzi_TCCR2, pre_mozzi_OCR2, pre_mozzi_TIMSK;
142 #elif defined(TCCR4A)
143 static uint8_t pre_mozzi_TCCR4A, pre_mozzi_TCCR4B, pre_mozzi_TCCR4C,
144  pre_mozzi_TCCR4D, pre_mozzi_TCCR4E, pre_mozzi_OCR4C, pre_mozzi_TIMSK4;
145 #endif
146 #endif
147 
148 static void backupPreMozziTimer1() {
149  // backup pre-mozzi register values for pausing later
150  pre_mozzi_TCCR1A = TCCR1A;
151  pre_mozzi_TCCR1B = TCCR1B;
152  pre_mozzi_OCR1A = OCR1A;
153  pre_mozzi_TIMSK1 = TIMSK1;
154 }
155 
156 #if (AUDIO_MODE == HIFI)
157 #if defined(TCCR2A)
158 static uint8_t mozzi_TCCR2A, mozzi_TCCR2B, mozzi_OCR2A, mozzi_TIMSK2;
159 #elif defined(TCCR2)
160 static uint8_t mozzi_TCCR2, mozzi_OCR2, mozzi_TIMSK;
161 #elif defined(TCCR4A)
162 static uint8_t mozzi_TCCR4A, mozzi_TCCR4B, mozzi_TCCR4C, mozzi_TCCR4D,
163  mozzi_TCCR4E, mozzi_OCR4C, mozzi_TIMSK4;
164 #endif
165 #endif
166 
167 #if (EXTERNAL_AUDIO_OUTPUT == true)
168 static void startAudio() {
169  backupPreMozziTimer1();
170  Timer1.initializeCPUCycles(
171  F_CPU / AUDIO_RATE,
172  PHASE_FREQ_CORRECT); // set period, phase and frequency correct
173  TIMSK1 = _BV(TOIE1); // Overflow Interrupt Enable (when not using
174  // Timer1.attachInterrupt())
175 }
176 
177 ISR(TIMER1_OVF_vect, ISR_BLOCK) {
178  defaultAudioOutput();
179 }
180 #elif (AUDIO_MODE == STANDARD) || (AUDIO_MODE == STANDARD_PLUS)
181 # if (AUDIO_MODE == STANDARD_PLUS)
182 # include "AudioConfigStandardPlus.h"
183 # else
184 # include "AudioConfigStandard9bitPwm.h"
185 # endif
186 inline void audioOutput(const AudioOutput f)
187 {
189 # if (AUDIO_CHANNELS > 1)
190  AUDIO_CHANNEL_2_OUTPUT_REGISTER = f.r()+AUDIO_BIAS;
191 # endif
192 }
193 
194 static void startAudio() {
195  backupPreMozziTimer1();
196 
197  pinMode(AUDIO_CHANNEL_1_PIN, OUTPUT); // set pin to output for audio
198  // pinMode(AUDIO_CHANNEL_2_PIN, OUTPUT); // set pin to output for audio
199 # if (AUDIO_MODE == STANDARD)
200  Timer1.initializeCPUCycles(
201  F_CPU / AUDIO_RATE,
202  PHASE_FREQ_CORRECT); // set period, phase and frequency correct
203 # else // (AUDIO_MODE == STANDARD_PLUS)
204  Timer1.initializeCPUCycles(F_CPU / PWM_RATE,
205  FAST); // fast mode enables higher PWM rate
206 # endif
207  Timer1.pwm(AUDIO_CHANNEL_1_PIN,
208  AUDIO_BIAS); // pwm pin, 50% of Mozzi's duty cycle, ie. 0 signal
209 # if (AUDIO_CHANNELS > 1)
210  Timer1.pwm(AUDIO_CHANNEL_2_PIN, AUDIO_BIAS); // sets pin to output
211 # endif
212  TIMSK1 = _BV(TOIE1); // Overflow Interrupt Enable (when not using
213  // Timer1.attachInterrupt())
214 }
215 
216 /* Interrupt service routine moves sound data from the output buffer to the
217 Arduino output register, running at AUDIO_RATE. */
218 
219 ISR(TIMER1_OVF_vect, ISR_BLOCK) {
220 # if (AUDIO_MODE == STANDARD_PLUS) && (AUDIO_RATE == 16384) // only update every second ISR, if lower audio rate
221  static boolean alternate;
222  alternate = !alternate;
223  if (alternate) return;
224 # endif
225 
226  defaultAudioOutput();
227 }
228 
229 #elif (AUDIO_MODE == HIFI)
230 # if (EXTERNAL_AUDIO_OUTPUT != true)
231 # include "AudioConfigHiSpeed14bitPwm.h"
232 inline void audioOutput(const AudioOutput f) {
233  // read about dual pwm at
234  // http://www.openmusiclabs.com/learning/digital/pwm-dac/dual-pwm-circuits/
235  // sketches at http://wiki.openmusiclabs.com/wiki/PWMDAC,
236  // http://wiki.openmusiclabs.com/wiki/MiniArDSP
237  // if (!output_buffer.isEmpty()){
238  //unsigned int out = output_buffer.read();
239  // 14 bit, 7 bits on each pin
240  // AUDIO_CHANNEL_1_highByte_REGISTER = out >> 7; // B00111111 10000000 becomes
241  // B1111111
242  // try to avoid looping over 7 shifts - need to check timing or disassemble to
243  // see what really happens unsigned int out_high = out<<1; // B00111111
244  // 10000000 becomes B01111111 00000000
245  // AUDIO_CHANNEL_1_highByte_REGISTER = out_high >> 8; // B01111111 00000000
246  // produces B01111111 AUDIO_CHANNEL_1_lowByte_REGISTER = out & 127;
247  /* Atmega manual, p123
248  The high byte (OCR1xH) has to be written first.
249  When the high byte I/O location is written by the CPU,
250  the TEMP Register will be updated by the value written.
251  Then when the low byte (OCR1xL) is written to the lower eight bits,
252  the high byte will be copied into the upper 8-bits of
253  either the OCR1x buffer or OCR1x Compare Register in
254  the same system clock cycle.
255  */
256  AUDIO_CHANNEL_1_highByte_REGISTER = (f.l()+AUDIO_BIAS) >> AUDIO_BITS_PER_REGISTER;
257  AUDIO_CHANNEL_1_lowByte_REGISTER = (f.l()+AUDIO_BIAS) & ((1 << AUDIO_BITS_PER_REGISTER) - 1);
258 }
259 # endif
260 
261 static void setupTimer2();
262 static void startAudio() {
263  backupPreMozziTimer1();
264  // pwm on timer 1
265  pinMode(AUDIO_CHANNEL_1_highByte_PIN,
266  OUTPUT); // set pin to output for audio, use 3.9k resistor
267  pinMode(AUDIO_CHANNEL_1_lowByte_PIN,
268  OUTPUT); // set pin to output for audio, use 499k resistor
269  Timer1.initializeCPUCycles(
270  F_CPU / 125000,
271  FAST); // set period for 125000 Hz fast pwm carrier frequency = 14 bits
272  Timer1.pwm(AUDIO_CHANNEL_1_highByte_PIN,
273  0); // pwm pin, 0% duty cycle, ie. 0 signal
274  Timer1.pwm(AUDIO_CHANNEL_1_lowByte_PIN,
275  0); // pwm pin, 0% duty cycle, ie. 0 signal
276  // audio output interrupt on timer 2, sets the pwm levels of timer 1
277  setupTimer2();
278 }
279 
280 /* set up Timer 2 using modified FrequencyTimer2 library */
281 void dummy() {}
282 
283 static void backupPreMozziTimer2() {
284  // backup Timer2 register values
285 #if defined(TCCR2A)
286  pre_mozzi_TCCR2A = TCCR2A;
287  pre_mozzi_TCCR2B = TCCR2B;
288  pre_mozzi_OCR2A = OCR2A;
289  pre_mozzi_TIMSK2 = TIMSK2;
290 #elif defined(TCCR2)
291  pre_mozzi_TCCR2 = TCCR2;
292  pre_mozzi_OCR2 = OCR2;
293  pre_mozzi_TIMSK = TIMSK;
294 #elif defined(TCCR4A)
295  pre_mozzi_TCCR4B = TCCR4A;
296  pre_mozzi_TCCR4B = TCCR4B;
297  pre_mozzi_TCCR4B = TCCR4C;
298  pre_mozzi_TCCR4B = TCCR4D;
299  pre_mozzi_TCCR4B = TCCR4E;
300  pre_mozzi_OCR4C = OCR4C;
301  pre_mozzi_TIMSK4 = TIMSK4;
302 #endif
303 }
304 
305 // audio output interrupt on timer 2 (or 4 on ATMEGA32U4 cpu), sets the pwm
306 // levels of timer 2
307 static void setupTimer2() {
308  backupPreMozziTimer2(); // to reset while pausing
309  unsigned long period = F_CPU / AUDIO_RATE;
310  FrequencyTimer2::setPeriodCPUCycles(period);
311  FrequencyTimer2::setOnOverflow(dummy);
312  FrequencyTimer2::enable();
313 }
314 
315 #if defined(TIMER2_COMPA_vect)
316 ISR(TIMER2_COMPA_vect)
317 #elif defined(TIMER2_COMP_vect)
318 ISR(TIMER2_COMP_vect)
319 #elif defined(TIMER4_COMPA_vect)
320 ISR(TIMER4_COMPA_vect)
321 #else
322 #error
323  "This board does not have a hardware timer which is compatible with FrequencyTimer2"
324 void dummy_function(void)
325 #endif
326 {
327  defaultAudioOutput();
328 }
329 
330 // end of HIFI
331 
332 #endif
333 
334 //-----------------------------------------------------------------------------------------------------------------
335 
336 
337 void stopMozzi() {
338  noInterrupts();
339 
340  // restore backed up register values
341  TCCR1A = pre_mozzi_TCCR1A;
342  TCCR1B = pre_mozzi_TCCR1B;
343  OCR1A = pre_mozzi_OCR1A;
344 
345  TIMSK1 = pre_mozzi_TIMSK1;
346 
347 #if (AUDIO_MODE == HIFI)
348 #if defined(TCCR2A)
349  TCCR2A = pre_mozzi_TCCR2A;
350  TCCR2B = pre_mozzi_TCCR2B;
351  OCR2A = pre_mozzi_OCR2A;
352  TIMSK2 = pre_mozzi_TIMSK2;
353 #elif defined(TCCR2)
354  TCCR2 = pre_mozzi_TCCR2;
355  OCR2 = pre_mozzi_OCR2;
356  TIMSK = pre_mozzi_TIMSK;
357 #elif defined(TCCR4A)
358  TCCR4B = pre_mozzi_TCCR4A;
359  TCCR4B = pre_mozzi_TCCR4B;
360  TCCR4B = pre_mozzi_TCCR4C;
361  TCCR4B = pre_mozzi_TCCR4D;
362  TCCR4B = pre_mozzi_TCCR4E;
363  OCR4C = pre_mozzi_OCR4C;
364  TIMSK4 = pre_mozzi_TIMSK4;
365 #endif
366 #endif
367  interrupts();
368 }
369 
370 // Unmodified TimerOne.cpp has TIMER3_OVF_vect.
371 // Watch out if you update the library file.
372 // The symptom will be no sound.
373 // ISR(TIMER1_OVF_vect)
374 // {
375 // Timer1.isrCallback();
376 // }
377 //// END AUDIO OUTPUT code ///////
void stopMozzi()
Stops audio and control interrupts and restores the timers to the values they had before Mozzi was st...
#define AUDIO_CHANNEL_1_OUTPUT_REGISTER
#define AUDIO_CHANNEL_1_PIN
void setupFastAnalogRead(int8_t speed)
NOTE: Code needed to set up faster than usual analog reads, e.g.
#define AUDIO_BIAS
Definition: MozziGuts.h:229